agentrinse 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -6
- package/dist/adapters/artifacts/adapter.d.ts +3 -1
- package/dist/adapters/artifacts/adapter.d.ts.map +1 -1
- package/dist/adapters/artifacts/adapter.js +23 -1
- package/dist/adapters/artifacts/adapter.js.map +1 -1
- package/dist/adapters/git/adapter.d.ts +8 -1
- package/dist/adapters/git/adapter.d.ts.map +1 -1
- package/dist/adapters/git/adapter.js +247 -13
- package/dist/adapters/git/adapter.js.map +1 -1
- package/dist/adapters/git/status.d.ts +14 -0
- package/dist/adapters/git/status.d.ts.map +1 -0
- package/dist/adapters/git/status.js +81 -0
- package/dist/adapters/git/status.js.map +1 -0
- package/dist/adapters/provider-adapter.d.ts +3 -0
- package/dist/adapters/provider-adapter.d.ts.map +1 -1
- package/dist/adapters/provider-adapter.js +16 -0
- package/dist/adapters/provider-adapter.js.map +1 -1
- package/dist/adapters/provider-reachability.d.ts +6 -0
- package/dist/adapters/provider-reachability.d.ts.map +1 -0
- package/dist/adapters/provider-reachability.js +207 -0
- package/dist/adapters/provider-reachability.js.map +1 -0
- package/dist/adapters/provider-specs.d.ts +1 -1
- package/dist/adapters/provider-specs.d.ts.map +1 -1
- package/dist/adapters/registry.d.ts +7 -1
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +44 -4
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/runtime/adapter.d.ts +24 -0
- package/dist/adapters/runtime/adapter.d.ts.map +1 -0
- package/dist/adapters/runtime/adapter.js +319 -0
- package/dist/adapters/runtime/adapter.js.map +1 -0
- package/dist/commands/adapters.d.ts.map +1 -1
- package/dist/commands/adapters.js +1 -0
- package/dist/commands/adapters.js.map +1 -1
- package/dist/commands/clean.d.ts +61 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +224 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +2 -1
- package/dist/commands/completion.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +23 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +48 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/reachability.d.ts +29 -0
- package/dist/core/reachability.d.ts.map +1 -0
- package/dist/core/reachability.js +121 -0
- package/dist/core/reachability.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +38 -0
- package/dist/main.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access, lstat, readdir, realpath } from "node:fs/promises";
|
|
4
|
+
import { delimiter, join, resolve } from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { sha256 } from "../../core/digest.js";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
const RUNTIMES = [
|
|
9
|
+
{ tool: "codex", command: "codex", displayName: "Codex CLI" },
|
|
10
|
+
{ tool: "claude", command: "claude", displayName: "Claude Code" },
|
|
11
|
+
{ tool: "cursor", command: "cursor-agent", displayName: "Cursor Agent" },
|
|
12
|
+
{ tool: "copilot", command: "copilot", displayName: "GitHub Copilot CLI" },
|
|
13
|
+
{ tool: "opencode", command: "opencode", displayName: "OpenCode" },
|
|
14
|
+
{ tool: "grok", command: "grok", displayName: "Grok Build" },
|
|
15
|
+
];
|
|
16
|
+
function isMissing(error) {
|
|
17
|
+
return (error instanceof Error && "code" in error && error.code === "ENOENT");
|
|
18
|
+
}
|
|
19
|
+
function isUnavailableExecutable(error) {
|
|
20
|
+
return (error instanceof Error &&
|
|
21
|
+
"code" in error &&
|
|
22
|
+
["EACCES", "ENOENT", "EPERM"].includes(error.code ?? ""));
|
|
23
|
+
}
|
|
24
|
+
async function defaultRunVersion(executable) {
|
|
25
|
+
const result = await execFileAsync(executable, ["--version"], {
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
maxBuffer: 256 * 1024,
|
|
28
|
+
timeout: 5_000,
|
|
29
|
+
});
|
|
30
|
+
return result.stdout.trim() === "" ? result.stderr : result.stdout;
|
|
31
|
+
}
|
|
32
|
+
function versionLine(output) {
|
|
33
|
+
const value = output.split(/\r?\n/u)[0]?.trim();
|
|
34
|
+
return value === undefined || value === "" ? undefined : value.slice(0, 200);
|
|
35
|
+
}
|
|
36
|
+
export class RuntimeAuditAdapter {
|
|
37
|
+
options;
|
|
38
|
+
id = "runtime";
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
this.options = options;
|
|
41
|
+
}
|
|
42
|
+
executableNames(command) {
|
|
43
|
+
return this.options.platform === "win32"
|
|
44
|
+
? [`${command}.exe`, `${command}.cmd`, command]
|
|
45
|
+
: [command];
|
|
46
|
+
}
|
|
47
|
+
async resolveCommand(command) {
|
|
48
|
+
const environment = this.options.environment ?? process.env;
|
|
49
|
+
const pathValue = environment.PATH ?? environment.Path;
|
|
50
|
+
if (pathValue === undefined || pathValue === "") {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
for (const directory of pathValue.split(delimiter)) {
|
|
54
|
+
if (directory === "") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const name of this.executableNames(command)) {
|
|
58
|
+
const candidate = resolve(directory, name);
|
|
59
|
+
try {
|
|
60
|
+
const stats = await lstat(candidate);
|
|
61
|
+
if (stats.isFile() || stats.isSymbolicLink()) {
|
|
62
|
+
if (this.options.platform !== "win32") {
|
|
63
|
+
try {
|
|
64
|
+
await access(candidate, constants.X_OK);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (isUnavailableExecutable(error)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return candidate;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (!isMissing(error)) {
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
async discovered(context) {
|
|
86
|
+
for (const runtime of RUNTIMES) {
|
|
87
|
+
if ((await this.resolveCommand(runtime.command)) !== undefined) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const stats = await lstat(join(context.home, ".local", "share", "claude", "versions"));
|
|
93
|
+
return stats.isDirectory() && !stats.isSymbolicLink();
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (isMissing(error)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async probe(context) {
|
|
103
|
+
try {
|
|
104
|
+
return (await this.discovered(context))
|
|
105
|
+
? {
|
|
106
|
+
adapter: this.id,
|
|
107
|
+
status: "available",
|
|
108
|
+
detail: "Agent runtime installations found",
|
|
109
|
+
diagnostics: [],
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
adapter: this.id,
|
|
113
|
+
status: "absent",
|
|
114
|
+
detail: "No supported agent runtime installation found",
|
|
115
|
+
diagnostics: [],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
return {
|
|
120
|
+
adapter: this.id,
|
|
121
|
+
status: "degraded",
|
|
122
|
+
detail: "Agent runtime installations could not be inspected",
|
|
123
|
+
diagnostics: [
|
|
124
|
+
{
|
|
125
|
+
severity: "warning",
|
|
126
|
+
code: "RUNTIME_PROBE_FAILED",
|
|
127
|
+
message: error instanceof Error ? error.message : String(error),
|
|
128
|
+
adapter: this.id,
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
resource(context, input) {
|
|
135
|
+
const path = resolve(input.path);
|
|
136
|
+
const canonicalKey = `runtime:agent-runtime:${input.tool}:${path}`;
|
|
137
|
+
return {
|
|
138
|
+
resource: {
|
|
139
|
+
id: `runtime:agent-runtime:${sha256(canonicalKey)}`,
|
|
140
|
+
adapter: this.id,
|
|
141
|
+
kind: "agent-runtime",
|
|
142
|
+
canonicalKey,
|
|
143
|
+
displayName: input.displayName,
|
|
144
|
+
path,
|
|
145
|
+
},
|
|
146
|
+
observedAt: context.now.toISOString(),
|
|
147
|
+
exists: true,
|
|
148
|
+
...(input.measuredBytes === undefined ? {} : { measuredBytes: input.measuredBytes }),
|
|
149
|
+
facts: {
|
|
150
|
+
tool: input.tool,
|
|
151
|
+
reportOnly: true,
|
|
152
|
+
...input.facts,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async collectClaudeNative(context) {
|
|
157
|
+
const root = join(context.home, ".local", "share", "claude", "versions");
|
|
158
|
+
const launcher = join(context.home, ".local", "bin", "claude");
|
|
159
|
+
const resources = [];
|
|
160
|
+
const paths = new Set();
|
|
161
|
+
const diagnostics = [];
|
|
162
|
+
let activePath;
|
|
163
|
+
try {
|
|
164
|
+
activePath = await realpath(launcher);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
activePath = undefined;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const rootStats = await lstat(root);
|
|
171
|
+
if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) {
|
|
172
|
+
diagnostics.push({
|
|
173
|
+
severity: "warning",
|
|
174
|
+
code: "CLAUDE_RUNTIME_ROOT_UNSAFE",
|
|
175
|
+
message: "Claude native version root must be a real directory.",
|
|
176
|
+
adapter: this.id,
|
|
177
|
+
});
|
|
178
|
+
return { resources, paths, diagnostics };
|
|
179
|
+
}
|
|
180
|
+
for (const entry of await readdir(root, { withFileTypes: true })) {
|
|
181
|
+
context.signal?.throwIfAborted();
|
|
182
|
+
if (!entry.isFile()) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const path = await realpath(resolve(root, entry.name));
|
|
186
|
+
const stats = await lstat(path);
|
|
187
|
+
paths.add(path);
|
|
188
|
+
resources.push(this.resource(context, {
|
|
189
|
+
tool: "claude",
|
|
190
|
+
displayName: `Claude Code ${entry.name}`,
|
|
191
|
+
path,
|
|
192
|
+
measuredBytes: stats.size,
|
|
193
|
+
facts: {
|
|
194
|
+
version: entry.name,
|
|
195
|
+
selected: activePath === path,
|
|
196
|
+
installManager: "claude-native",
|
|
197
|
+
recommendation: "Use `claude install stable` to manage this installation.",
|
|
198
|
+
mtimeMs: stats.mtimeMs,
|
|
199
|
+
},
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (!isMissing(error)) {
|
|
205
|
+
diagnostics.push({
|
|
206
|
+
severity: "warning",
|
|
207
|
+
code: "CLAUDE_RUNTIME_INSPECTION_FAILED",
|
|
208
|
+
message: error instanceof Error ? error.message : String(error),
|
|
209
|
+
adapter: this.id,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { resources, paths, diagnostics };
|
|
214
|
+
}
|
|
215
|
+
async collect(context, probe) {
|
|
216
|
+
if (probe.status !== "available") {
|
|
217
|
+
return { resources: [], diagnostics: [] };
|
|
218
|
+
}
|
|
219
|
+
const resources = [];
|
|
220
|
+
const diagnostics = [];
|
|
221
|
+
const resolved = new Map();
|
|
222
|
+
for (const runtime of RUNTIMES) {
|
|
223
|
+
const executable = await this.resolveCommand(runtime.command);
|
|
224
|
+
if (executable !== undefined) {
|
|
225
|
+
resolved.set(runtime.tool, executable);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const claudeNative = await this.collectClaudeNative(context);
|
|
229
|
+
resources.push(...claudeNative.resources);
|
|
230
|
+
diagnostics.push(...claudeNative.diagnostics);
|
|
231
|
+
for (const runtime of RUNTIMES) {
|
|
232
|
+
context.signal?.throwIfAborted();
|
|
233
|
+
const launcherPath = resolved.get(runtime.tool);
|
|
234
|
+
if (launcherPath === undefined) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
let executablePath;
|
|
238
|
+
try {
|
|
239
|
+
executablePath = await realpath(launcherPath);
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
diagnostics.push({
|
|
243
|
+
severity: "warning",
|
|
244
|
+
code: "RUNTIME_EXECUTABLE_UNREADABLE",
|
|
245
|
+
message: error instanceof Error ? error.message : String(error),
|
|
246
|
+
adapter: this.id,
|
|
247
|
+
});
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const stats = await lstat(executablePath);
|
|
251
|
+
if (!stats.isFile()) {
|
|
252
|
+
diagnostics.push({
|
|
253
|
+
severity: "warning",
|
|
254
|
+
code: "RUNTIME_EXECUTABLE_INVALID",
|
|
255
|
+
message: "Resolved runtime executable is not a regular file.",
|
|
256
|
+
adapter: this.id,
|
|
257
|
+
});
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (runtime.tool === "claude" && claudeNative.paths.has(executablePath)) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
let version;
|
|
264
|
+
try {
|
|
265
|
+
version = versionLine(await (this.options.runVersion ?? defaultRunVersion)(executablePath));
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
diagnostics.push({
|
|
269
|
+
severity: "warning",
|
|
270
|
+
code: "RUNTIME_VERSION_FAILED",
|
|
271
|
+
message: error instanceof Error ? error.message : String(error),
|
|
272
|
+
adapter: this.id,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
resources.push(this.resource(context, {
|
|
276
|
+
tool: runtime.tool,
|
|
277
|
+
displayName: runtime.displayName,
|
|
278
|
+
path: executablePath,
|
|
279
|
+
measuredBytes: stats.size,
|
|
280
|
+
facts: {
|
|
281
|
+
selected: true,
|
|
282
|
+
launcherPath,
|
|
283
|
+
executablePath,
|
|
284
|
+
installManager: "unknown",
|
|
285
|
+
recommendation: "Use the owning installer or package manager for updates and removal.",
|
|
286
|
+
...(version === undefined ? {} : { version }),
|
|
287
|
+
mtimeMs: stats.mtimeMs,
|
|
288
|
+
},
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
resources.sort((left, right) => left.resource.canonicalKey.localeCompare(right.resource.canonicalKey));
|
|
292
|
+
return { resources, diagnostics };
|
|
293
|
+
}
|
|
294
|
+
async classify(context, resource) {
|
|
295
|
+
const observedAt = context.now.toISOString();
|
|
296
|
+
return {
|
|
297
|
+
schemaVersion: 1,
|
|
298
|
+
findingId: `${resource.resource.id}:${sha256(context.auditId)}`,
|
|
299
|
+
auditId: context.auditId,
|
|
300
|
+
observedAt,
|
|
301
|
+
resource: resource.resource,
|
|
302
|
+
state: "protected",
|
|
303
|
+
confidence: "certain",
|
|
304
|
+
roots: [
|
|
305
|
+
{
|
|
306
|
+
code: "runtime-owner-report-only",
|
|
307
|
+
source: this.id,
|
|
308
|
+
observedAt,
|
|
309
|
+
detail: "Agent runtime maintenance remains owned by its installer or package manager.",
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
facts: resource.facts,
|
|
313
|
+
candidateActions: [],
|
|
314
|
+
...(resource.measuredBytes === undefined ? {} : { measuredBytes: resource.measuredBytes }),
|
|
315
|
+
warnings: [],
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/runtime/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../../src/commands/adapters.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../../src/commands/adapters.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,IAAI,MAAM,CAgBvC"}
|
|
@@ -8,6 +8,7 @@ export function renderAdapters() {
|
|
|
8
8
|
.map((spec) => `${spec.id.padEnd(10)} audit-only ${spec.displayName}`),
|
|
9
9
|
"",
|
|
10
10
|
"git audit-only Git worktrees (explicit root)",
|
|
11
|
+
"runtime audit-only Installed agent runtimes",
|
|
11
12
|
"docker audit-only Docker images and containers (opt-in)",
|
|
12
13
|
"artifacts safe-clean Explicit rebuildable project directories",
|
|
13
14
|
"",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../../src/commands/adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG;QACZ,qBAAqB;QACrB,EAAE;QACF,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;aAC7B,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;aACtD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC;QACzE,EAAE;QACF,sDAAsD;QACtD,8DAA8D;QAC9D,iEAAiE;QACjE,EAAE;KACH,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../../src/commands/adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG;QACZ,qBAAqB;QACrB,EAAE;QACF,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;aAC7B,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;aACtD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC;QACzE,EAAE;QACF,sDAAsD;QACtD,iDAAiD;QACjD,8DAA8D;QAC9D,iEAAiE;QACjE,EAAE;KACH,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type ActionRisk } from "../contracts/action.js";
|
|
2
|
+
import type { CleanupPlan } from "../contracts/plan.js";
|
|
3
|
+
import type { AuditReport } from "../contracts/report.js";
|
|
4
|
+
import type { CleanupRun } from "../contracts/run.js";
|
|
5
|
+
export type CleanCommandOptions = {
|
|
6
|
+
home: string;
|
|
7
|
+
config?: string;
|
|
8
|
+
stateDir?: string;
|
|
9
|
+
profile: "closeout";
|
|
10
|
+
cwd?: string;
|
|
11
|
+
apply: boolean;
|
|
12
|
+
yes: boolean;
|
|
13
|
+
json: boolean;
|
|
14
|
+
maxRisk?: ActionRisk;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
dependencies?: {
|
|
17
|
+
platform?: NodeJS.Platform;
|
|
18
|
+
now?: () => Date;
|
|
19
|
+
runCommand?: (command: string, args: string[]) => Promise<{
|
|
20
|
+
stdout: string;
|
|
21
|
+
stderr: string;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type MoleHandoff = {
|
|
26
|
+
status: "available" | "absent" | "not-applicable";
|
|
27
|
+
suggestions: string[];
|
|
28
|
+
};
|
|
29
|
+
export type CloseoutSummary = {
|
|
30
|
+
profile: "closeout";
|
|
31
|
+
repositoryRoot: string;
|
|
32
|
+
currentWorktree: string;
|
|
33
|
+
auditId: string;
|
|
34
|
+
planId: string;
|
|
35
|
+
auditPath: string;
|
|
36
|
+
planPath: string;
|
|
37
|
+
configPath: string;
|
|
38
|
+
worktrees: number;
|
|
39
|
+
protectedWorktrees: number;
|
|
40
|
+
eligibleActions: number;
|
|
41
|
+
expectedReclaimBytes: number;
|
|
42
|
+
mole: MoleHandoff;
|
|
43
|
+
run?: {
|
|
44
|
+
runId: string;
|
|
45
|
+
status: CleanupRun["status"];
|
|
46
|
+
journalPath: string;
|
|
47
|
+
reclaimedBytes: number;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export type CleanCommandResult = {
|
|
51
|
+
audit: AuditReport;
|
|
52
|
+
plan: CleanupPlan;
|
|
53
|
+
run?: CleanupRun;
|
|
54
|
+
status: "ok" | "degraded" | "failed";
|
|
55
|
+
summary: CloseoutSummary;
|
|
56
|
+
output: string;
|
|
57
|
+
};
|
|
58
|
+
export declare function cleanCommandExitCode(result: Pick<CleanCommandResult, "run" | "status">): number | undefined;
|
|
59
|
+
export declare function cleanCommandStatus(audit: Pick<AuditReport, "diagnostics" | "probes">, run?: Pick<CleanupRun, "status">): CleanCommandResult["status"];
|
|
60
|
+
export declare function executeCleanCommand(options: CleanCommandOptions): Promise<CleanCommandResult>;
|
|
61
|
+
//# sourceMappingURL=clean.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../src/commands/clean.ts"],"names":[],"mappings":"AASA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAWtD,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC3B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;QACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC/F,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,gBAAgB,CAAC;IAClD,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC7B,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,QAAQ,CAAC;IACrC,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,KAAK,GAAG,QAAQ,CAAC,GACjD,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,QAAQ,CAAC,EAClD,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAC/B,kBAAkB,CAAC,QAAQ,CAAC,CAO9B;AA6FD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAgI7B"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { parseWorktreePorcelain } from "../adapters/git/porcelain.js";
|
|
5
|
+
import { createAuditAdapters } from "../adapters/registry.js";
|
|
6
|
+
import { confirmApply } from "./apply.js";
|
|
7
|
+
import { loadConfigForHome } from "../config/load.js";
|
|
8
|
+
import { actionRiskSchema } from "../contracts/action.js";
|
|
9
|
+
import { applyCleanupPlan } from "../core/apply.js";
|
|
10
|
+
import { runAudit } from "../core/audit.js";
|
|
11
|
+
import { CommandInterruptedError } from "../core/interruption.js";
|
|
12
|
+
import { createCleanupPlan } from "../core/plan.js";
|
|
13
|
+
import { createCommandEnvelope, jsonDocument } from "../machine-output.js";
|
|
14
|
+
import { writeJsonAtomic } from "../state/json-file.js";
|
|
15
|
+
import { resolveStateRoot, stateLayout } from "../state/layout.js";
|
|
16
|
+
const execFileAsync = promisify(execFile);
|
|
17
|
+
export function cleanCommandExitCode(result) {
|
|
18
|
+
if (result.run?.status === "interrupted") {
|
|
19
|
+
return 130;
|
|
20
|
+
}
|
|
21
|
+
if (result.run !== undefined && ["failed", "partial"].includes(result.run.status)) {
|
|
22
|
+
return 2;
|
|
23
|
+
}
|
|
24
|
+
return result.status === "degraded" ? 1 : undefined;
|
|
25
|
+
}
|
|
26
|
+
export function cleanCommandStatus(audit, run) {
|
|
27
|
+
if (run !== undefined && ["failed", "interrupted", "partial"].includes(run.status)) {
|
|
28
|
+
return "failed";
|
|
29
|
+
}
|
|
30
|
+
return audit.probes.some((probe) => probe.status === "degraded") || audit.diagnostics.length > 0
|
|
31
|
+
? "degraded"
|
|
32
|
+
: "ok";
|
|
33
|
+
}
|
|
34
|
+
async function defaultRunCommand(command, args) {
|
|
35
|
+
const result = await execFileAsync(command, args, {
|
|
36
|
+
encoding: "utf8",
|
|
37
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
38
|
+
timeout: 10_000,
|
|
39
|
+
});
|
|
40
|
+
return { stdout: result.stdout, stderr: result.stderr };
|
|
41
|
+
}
|
|
42
|
+
function isInside(root, candidate) {
|
|
43
|
+
const result = relative(resolve(root), resolve(candidate));
|
|
44
|
+
return result === "" || (!result.startsWith("..") && !isAbsolute(result));
|
|
45
|
+
}
|
|
46
|
+
function scopedConfig(config, currentWorktree, worktrees, maxRisk) {
|
|
47
|
+
const scoped = structuredClone(config);
|
|
48
|
+
for (const id of ["cursor", "copilot", "zed", "opencode", "grok", "runtime", "docker"]) {
|
|
49
|
+
scoped.adapters[id] = { enabled: false };
|
|
50
|
+
}
|
|
51
|
+
scoped.adapters.git = { enabled: true, root: currentWorktree };
|
|
52
|
+
scoped.artifacts.projects = scoped.artifacts.projects.filter((project) => worktrees.some((worktree) => isInside(worktree, project.root)));
|
|
53
|
+
if (maxRisk !== undefined) {
|
|
54
|
+
scoped.plan.maxRisk = maxRisk;
|
|
55
|
+
}
|
|
56
|
+
return scoped;
|
|
57
|
+
}
|
|
58
|
+
async function moleHandoff(platform, runCommand) {
|
|
59
|
+
if (platform !== "darwin") {
|
|
60
|
+
return { status: "not-applicable", suggestions: [] };
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
await runCommand("mo", ["--version"]);
|
|
64
|
+
return {
|
|
65
|
+
status: "available",
|
|
66
|
+
suggestions: ["mo purge --dry-run", "mo clean --dry-run"],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return {
|
|
71
|
+
status: "absent",
|
|
72
|
+
suggestions: ["Install Mole to preview broad macOS cleanup outside AgentRinse."],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function renderCloseout(summary) {
|
|
77
|
+
const lines = [
|
|
78
|
+
"AgentRinse closeout",
|
|
79
|
+
"",
|
|
80
|
+
`Repository: ${summary.repositoryRoot}`,
|
|
81
|
+
`Worktrees: ${summary.worktrees} (${summary.protectedWorktrees} protected)`,
|
|
82
|
+
`Eligible actions: ${summary.eligibleActions}`,
|
|
83
|
+
`Expected reclaim: ${summary.expectedReclaimBytes} bytes`,
|
|
84
|
+
`Audit: ${summary.auditPath}`,
|
|
85
|
+
`Plan: ${summary.planPath}`,
|
|
86
|
+
`Config: ${summary.configPath}`,
|
|
87
|
+
];
|
|
88
|
+
if (summary.run !== undefined) {
|
|
89
|
+
lines.push(`Run: ${summary.run.status} (${summary.run.reclaimedBytes} bytes)`, `Journal: ${summary.run.journalPath}`);
|
|
90
|
+
}
|
|
91
|
+
if (summary.mole.suggestions.length > 0) {
|
|
92
|
+
lines.push("", "Mole handoff:", ...summary.mole.suggestions.map((item) => ` ${item}`));
|
|
93
|
+
}
|
|
94
|
+
return `${lines.join("\n")}\n`;
|
|
95
|
+
}
|
|
96
|
+
function interruptionFrom(signal) {
|
|
97
|
+
if (signal?.aborted !== true) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
return signal.reason instanceof CommandInterruptedError
|
|
101
|
+
? signal.reason
|
|
102
|
+
: new CommandInterruptedError("clean interrupted");
|
|
103
|
+
}
|
|
104
|
+
export async function executeCleanCommand(options) {
|
|
105
|
+
if (options.profile !== "closeout") {
|
|
106
|
+
throw new Error(`unsupported clean profile: ${options.profile}`);
|
|
107
|
+
}
|
|
108
|
+
if (options.json && options.apply && !options.yes) {
|
|
109
|
+
throw new Error("clean --json --apply requires --yes");
|
|
110
|
+
}
|
|
111
|
+
const runCommand = options.dependencies?.runCommand ?? defaultRunCommand;
|
|
112
|
+
const platform = options.dependencies?.platform ?? process.platform;
|
|
113
|
+
const clock = options.dependencies?.now ?? (() => new Date());
|
|
114
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
115
|
+
const home = resolve(options.home);
|
|
116
|
+
const currentWorktree = (await runCommand("git", ["-C", cwd, "rev-parse", "--show-toplevel"])).stdout.trim();
|
|
117
|
+
if (currentWorktree === "") {
|
|
118
|
+
throw new Error("closeout requires a Git worktree");
|
|
119
|
+
}
|
|
120
|
+
const worktreeOutput = (await runCommand("git", ["-C", currentWorktree, "worktree", "list", "--porcelain", "-z"])).stdout;
|
|
121
|
+
const worktrees = parseWorktreePorcelain(worktreeOutput).map((record) => resolve(record.path));
|
|
122
|
+
const repositoryRoot = worktrees[0] ?? currentWorktree;
|
|
123
|
+
const { config } = await loadConfigForHome(home, options.config);
|
|
124
|
+
const maxRisk = options.maxRisk === undefined ? undefined : actionRiskSchema.parse(options.maxRisk);
|
|
125
|
+
const scoped = scopedConfig(config, currentWorktree, worktrees, maxRisk);
|
|
126
|
+
const audit = await runAudit({
|
|
127
|
+
home,
|
|
128
|
+
config: scoped,
|
|
129
|
+
adapters: createAuditAdapters(scoped, platform, {
|
|
130
|
+
providerInventory: false,
|
|
131
|
+
roots: [
|
|
132
|
+
{
|
|
133
|
+
path: currentWorktree,
|
|
134
|
+
code: "current-worktree",
|
|
135
|
+
source: "closeout",
|
|
136
|
+
detail: "The worktree running the closeout profile is protected.",
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
}),
|
|
140
|
+
now: clock,
|
|
141
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
142
|
+
});
|
|
143
|
+
const plan = createCleanupPlan(audit, scoped, clock());
|
|
144
|
+
const layout = stateLayout(resolveStateRoot(home, options.stateDir));
|
|
145
|
+
const auditPath = resolve(layout.audits, `${audit.auditId}.json`);
|
|
146
|
+
const planPath = resolve(layout.plans, `${plan.planId}.json`);
|
|
147
|
+
const configPath = resolve(layout.plans, `${plan.planId}.config.json`);
|
|
148
|
+
await writeJsonAtomic(auditPath, audit, {
|
|
149
|
+
privateDirectories: [layout.root, layout.audits],
|
|
150
|
+
});
|
|
151
|
+
await writeJsonAtomic(planPath, plan, {
|
|
152
|
+
privateDirectories: [layout.root, layout.plans],
|
|
153
|
+
});
|
|
154
|
+
await writeJsonAtomic(configPath, scoped, {
|
|
155
|
+
privateDirectories: [layout.root, layout.plans],
|
|
156
|
+
});
|
|
157
|
+
let run;
|
|
158
|
+
let journalPath;
|
|
159
|
+
if (options.apply) {
|
|
160
|
+
const interruption = interruptionFrom(options.signal);
|
|
161
|
+
if (interruption !== undefined) {
|
|
162
|
+
throw interruption;
|
|
163
|
+
}
|
|
164
|
+
if (!options.yes && !(await confirmApply(plan.actions.length, options.signal))) {
|
|
165
|
+
throw new Error("clean apply cancelled");
|
|
166
|
+
}
|
|
167
|
+
const result = await applyCleanupPlan({
|
|
168
|
+
input: plan,
|
|
169
|
+
config: scoped,
|
|
170
|
+
stateRoot: layout.root,
|
|
171
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
172
|
+
dependencies: { clock },
|
|
173
|
+
});
|
|
174
|
+
run = result.run;
|
|
175
|
+
journalPath = result.journalPath;
|
|
176
|
+
}
|
|
177
|
+
const gitFindings = audit.findings.filter((finding) => finding.resource.kind === "git-worktree");
|
|
178
|
+
const summary = {
|
|
179
|
+
profile: "closeout",
|
|
180
|
+
repositoryRoot,
|
|
181
|
+
currentWorktree,
|
|
182
|
+
auditId: audit.auditId,
|
|
183
|
+
planId: plan.planId,
|
|
184
|
+
auditPath,
|
|
185
|
+
planPath,
|
|
186
|
+
configPath,
|
|
187
|
+
worktrees: gitFindings.length,
|
|
188
|
+
protectedWorktrees: gitFindings.filter((finding) => finding.state !== "eligible").length,
|
|
189
|
+
eligibleActions: plan.actions.length,
|
|
190
|
+
expectedReclaimBytes: plan.expectedReclaimBytes,
|
|
191
|
+
mole: await moleHandoff(platform, runCommand),
|
|
192
|
+
...(run === undefined || journalPath === undefined
|
|
193
|
+
? {}
|
|
194
|
+
: {
|
|
195
|
+
run: {
|
|
196
|
+
runId: run.runId,
|
|
197
|
+
status: run.status,
|
|
198
|
+
journalPath,
|
|
199
|
+
reclaimedBytes: run.reclaimedBytes,
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
202
|
+
};
|
|
203
|
+
const startedAt = audit.startedAt;
|
|
204
|
+
const completedAt = clock().toISOString();
|
|
205
|
+
const status = cleanCommandStatus(audit, run);
|
|
206
|
+
return {
|
|
207
|
+
audit,
|
|
208
|
+
plan,
|
|
209
|
+
...(run === undefined ? {} : { run }),
|
|
210
|
+
status,
|
|
211
|
+
summary,
|
|
212
|
+
output: options.json
|
|
213
|
+
? jsonDocument(createCommandEnvelope({
|
|
214
|
+
command: "clean",
|
|
215
|
+
startedAt,
|
|
216
|
+
completedAt,
|
|
217
|
+
status,
|
|
218
|
+
data: summary,
|
|
219
|
+
diagnostics: audit.diagnostics,
|
|
220
|
+
}))
|
|
221
|
+
: renderCloseout(summary),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=clean.js.map
|