getprismo 0.1.32 → 0.1.34
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 +77 -7
- package/lib/prismo-dev/agent.js +399 -0
- package/lib/prismo-dev/cli.js +868 -0
- package/lib/prismo-dev/cloud-sync.js +492 -0
- package/lib/prismo-dev/guard.js +426 -0
- package/lib/prismo-dev/help.js +520 -0
- package/lib/prismo-dev/instructions.js +179 -0
- package/lib/prismo-dev/receipt.js +79 -1
- package/lib/prismo-dev-scan.js +168 -1017
- package/package.json +1 -1
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { printHelp, printCommandHelp } = require("./help");
|
|
3
|
+
|
|
4
|
+
const VALID_COMMANDS = new Set([
|
|
5
|
+
"dev", "init", "doctor", "firewall", "benchmark", "shield", "mcp",
|
|
6
|
+
"connect", "sync", "status", "disconnect", "agent", "setup", "scan",
|
|
7
|
+
"optimize", "context", "cc", "cursor", "receipt", "instructions",
|
|
8
|
+
"timeline", "replay", "boundaries", "usage", "guard", "watch", "demo",
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
function parseTokenBudget(value) {
|
|
12
|
+
const raw = String(value || "").trim().toLowerCase();
|
|
13
|
+
if (!raw) return null;
|
|
14
|
+
const match = raw.match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
15
|
+
if (!match) return null;
|
|
16
|
+
const amount = Number.parseFloat(match[1]);
|
|
17
|
+
const multiplier = match[2] === "m" ? 1000000 : match[2] === "k" ? 1000 : 1;
|
|
18
|
+
const parsed = Math.round(amount * multiplier);
|
|
19
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createCli(deps) {
|
|
23
|
+
const {
|
|
24
|
+
PACKAGE_VERSION,
|
|
25
|
+
NPX_COMMAND,
|
|
26
|
+
DEFAULT_PRISMO_PROXY_URL,
|
|
27
|
+
AGENT_VALID_MODES,
|
|
28
|
+
printStep,
|
|
29
|
+
getPositionals,
|
|
30
|
+
parsePositiveInt,
|
|
31
|
+
parseScopeAndTarget,
|
|
32
|
+
applyFixes,
|
|
33
|
+
createOptimizeContext,
|
|
34
|
+
getContextFileForScope,
|
|
35
|
+
renderContextCommand,
|
|
36
|
+
renderStarterPrompt,
|
|
37
|
+
renderOptimizeTerminal,
|
|
38
|
+
runOptimize,
|
|
39
|
+
renderDemoTerminal,
|
|
40
|
+
renderDevTerminal,
|
|
41
|
+
renderDoctorTerminal,
|
|
42
|
+
renderInitTerminal,
|
|
43
|
+
runDevFlow,
|
|
44
|
+
runDoctor,
|
|
45
|
+
runInit,
|
|
46
|
+
toDoctorJsonPayload,
|
|
47
|
+
renderFirewallTerminal,
|
|
48
|
+
runFirewall,
|
|
49
|
+
runTimelineFirewallSuggestions,
|
|
50
|
+
renderShieldLastTerminal,
|
|
51
|
+
renderShieldSearchTerminal,
|
|
52
|
+
renderShieldTerminal,
|
|
53
|
+
runShieldLast,
|
|
54
|
+
runShieldSearch,
|
|
55
|
+
runShield,
|
|
56
|
+
renderBenchmarkTerminal,
|
|
57
|
+
runBenchmark,
|
|
58
|
+
renderReceiptTerminal,
|
|
59
|
+
buildReceipt,
|
|
60
|
+
renderConnectTerminal,
|
|
61
|
+
renderDisconnectTerminal,
|
|
62
|
+
renderStatusTerminal,
|
|
63
|
+
renderSyncTerminal,
|
|
64
|
+
runConnect,
|
|
65
|
+
runDisconnect,
|
|
66
|
+
runStatus,
|
|
67
|
+
runSync,
|
|
68
|
+
renderGuardTerminal,
|
|
69
|
+
runGuard,
|
|
70
|
+
renderAgentTerminal,
|
|
71
|
+
runAgent,
|
|
72
|
+
renderInstructionsAblationTerminal,
|
|
73
|
+
renderInstructionsApplyTerminal,
|
|
74
|
+
renderInstructionsAuditTerminal,
|
|
75
|
+
buildInstructionsAblationPlan,
|
|
76
|
+
buildInstructionsApply,
|
|
77
|
+
buildInstructionsAudit,
|
|
78
|
+
renderMultiSessionTimelineTerminal,
|
|
79
|
+
buildMultiSessionTimeline,
|
|
80
|
+
renderReplayTerminal,
|
|
81
|
+
buildReplay,
|
|
82
|
+
renderBoundaryTerminal,
|
|
83
|
+
buildBoundaryCheck,
|
|
84
|
+
renderMcpDoctorTerminal,
|
|
85
|
+
runMcpDoctor,
|
|
86
|
+
runMcpServer,
|
|
87
|
+
renderSetupTerminal,
|
|
88
|
+
runSetup,
|
|
89
|
+
renderClaudeCostTerminal,
|
|
90
|
+
getClaudeCodeCostSummary,
|
|
91
|
+
renderCursorTerminal,
|
|
92
|
+
getCursorSessionSummary,
|
|
93
|
+
getUsageSummary,
|
|
94
|
+
compactUsageSummary,
|
|
95
|
+
renderUsageTerminal,
|
|
96
|
+
watchUsage,
|
|
97
|
+
scanRepo,
|
|
98
|
+
toJsonPayload,
|
|
99
|
+
evaluateCi,
|
|
100
|
+
renderCiReport,
|
|
101
|
+
renderTerminalReport,
|
|
102
|
+
renderSimpleScanReport,
|
|
103
|
+
renderOptimizerFitTerminal,
|
|
104
|
+
renderReportCardTerminal,
|
|
105
|
+
writeReport,
|
|
106
|
+
formatBytes,
|
|
107
|
+
formatTokenCount,
|
|
108
|
+
buildMultiAgentView,
|
|
109
|
+
buildBoundaryCheck: _boundaryCheck,
|
|
110
|
+
buildMultiSessionTimeline: _timeline,
|
|
111
|
+
buildSyncPayload,
|
|
112
|
+
loadConfig,
|
|
113
|
+
buildReceipt: _receipt,
|
|
114
|
+
buildReplay: _replay,
|
|
115
|
+
runFirewall: _firewall,
|
|
116
|
+
} = deps;
|
|
117
|
+
|
|
118
|
+
async function runCli(argv) {
|
|
119
|
+
const [command, ...rest] = argv;
|
|
120
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
121
|
+
console.log(PACKAGE_VERSION);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!command || command === "--help" || command === "-h") {
|
|
125
|
+
printHelp();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
129
|
+
printCommandHelp(command);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (!VALID_COMMANDS.has(command)) {
|
|
133
|
+
throw new Error(`Unknown command: ${command}. Try: prismo connect, prismo agent, prismo guard, prismo sync, prismo doctor, prismo watch, prismo receipt, prismo benchmark, prismo shield, prismo mcp, prismo firewall, prismo init, prismo scan, prismo optimize, prismo context, prismo cc, prismo cursor, or prismo usage`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (command === "demo") {
|
|
137
|
+
console.log(renderDemoTerminal());
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (command === "dev") {
|
|
142
|
+
const json = rest.includes("--json");
|
|
143
|
+
const limitIndex = rest.indexOf("--limit");
|
|
144
|
+
const target = getPositionals(rest, new Set(["--limit"]))[0] || process.cwd();
|
|
145
|
+
const result = runDevFlow(target, {
|
|
146
|
+
json,
|
|
147
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 3),
|
|
148
|
+
});
|
|
149
|
+
if (json) {
|
|
150
|
+
console.log(JSON.stringify({
|
|
151
|
+
score: result.scan.score,
|
|
152
|
+
riskLevel: result.scan.risk,
|
|
153
|
+
tokenLeaks: result.scan.issues.length,
|
|
154
|
+
realUsage: result.scan.realUsage,
|
|
155
|
+
generatedFiles: result.optimize.generatedFiles,
|
|
156
|
+
nextCommands: result.nextCommands,
|
|
157
|
+
prompt: renderStarterPrompt(createOptimizeContext(result.optimize.root, result.scope), result.scope),
|
|
158
|
+
scannedPath: result.scan.root,
|
|
159
|
+
generatedAt: result.scan.generatedAt,
|
|
160
|
+
}, null, 2));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
console.log(renderDevTerminal(result));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (command === "init") {
|
|
168
|
+
const json = rest.includes("--json");
|
|
169
|
+
const target = getPositionals(rest)[0] || process.cwd();
|
|
170
|
+
const result = runInit(target, { dryRun: rest.includes("--dry-run") });
|
|
171
|
+
if (json) {
|
|
172
|
+
console.log(JSON.stringify(result, null, 2));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
console.log(renderInitTerminal(result));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (command === "doctor") {
|
|
180
|
+
const json = rest.includes("--json");
|
|
181
|
+
const limitIndex = rest.indexOf("--limit");
|
|
182
|
+
const { scope, target } = parseScopeAndTarget(rest, new Set(["--limit"]));
|
|
183
|
+
const result = runDoctor(target, {
|
|
184
|
+
json,
|
|
185
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 3),
|
|
186
|
+
scope,
|
|
187
|
+
dryRun: rest.includes("--dry-run"),
|
|
188
|
+
applyIgnoresOnly: rest.includes("--apply-ignores-only"),
|
|
189
|
+
applySuggestions: rest.includes("--apply-suggestions"),
|
|
190
|
+
noContextPacks: rest.includes("--no-context-packs"),
|
|
191
|
+
});
|
|
192
|
+
if (json) {
|
|
193
|
+
console.log(JSON.stringify(toDoctorJsonPayload(result), null, 2));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
console.log(renderDoctorTerminal(result));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (command === "firewall") {
|
|
201
|
+
const json = rest.includes("--json");
|
|
202
|
+
const { scope, target } = parseScopeAndTarget(rest);
|
|
203
|
+
const result = runFirewall(target, {
|
|
204
|
+
task: scope || "general",
|
|
205
|
+
scope,
|
|
206
|
+
dryRun: rest.includes("--dry-run"),
|
|
207
|
+
});
|
|
208
|
+
if (json) {
|
|
209
|
+
console.log(JSON.stringify(result, null, 2));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
console.log(renderFirewallTerminal(result));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (command === "benchmark") {
|
|
217
|
+
const json = rest.includes("--json");
|
|
218
|
+
const limitIndex = rest.indexOf("--limit");
|
|
219
|
+
const separatorIndex = rest.indexOf("--");
|
|
220
|
+
const beforeSeparator = separatorIndex >= 0 ? rest.slice(0, separatorIndex) : rest;
|
|
221
|
+
const commandArgs = separatorIndex >= 0 ? rest.slice(separatorIndex + 1) : [];
|
|
222
|
+
const positional = getPositionals(beforeSeparator, new Set(["--limit"]));
|
|
223
|
+
const sessionOnly = positional[0] === "session" || commandArgs.length === 0;
|
|
224
|
+
const target = positional[0] === "session" ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
225
|
+
const result = runBenchmark(target, commandArgs, {
|
|
226
|
+
sessionOnly,
|
|
227
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
228
|
+
});
|
|
229
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
230
|
+
else console.log(renderBenchmarkTerminal(result));
|
|
231
|
+
if (result.mode === "command") process.exitCode = result.exitCode;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (command === "shield") {
|
|
236
|
+
const json = rest.includes("--json");
|
|
237
|
+
const limitIndex = rest.indexOf("--limit");
|
|
238
|
+
const limit = parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5);
|
|
239
|
+
const positional = getPositionals(rest, new Set(["--limit"]));
|
|
240
|
+
if (positional[0] === "last") {
|
|
241
|
+
const target = positional[1] || process.cwd();
|
|
242
|
+
const result = runShieldLast(target, { limit });
|
|
243
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
244
|
+
else console.log(renderShieldLastTerminal(result));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (positional[0] === "search") {
|
|
248
|
+
const query = positional[1];
|
|
249
|
+
const target = positional[2] || process.cwd();
|
|
250
|
+
const result = runShieldSearch(target, query, { limit });
|
|
251
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
252
|
+
else console.log(renderShieldSearchTerminal(result));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const separatorIndex = rest.indexOf("--");
|
|
256
|
+
const beforeSeparator = separatorIndex >= 0 ? rest.slice(0, separatorIndex) : [];
|
|
257
|
+
const commandArgs = separatorIndex >= 0 ? rest.slice(separatorIndex + 1) : getPositionals(rest);
|
|
258
|
+
const target = getPositionals(beforeSeparator)[0] || process.cwd();
|
|
259
|
+
const result = runShield(target, commandArgs);
|
|
260
|
+
if (json) {
|
|
261
|
+
console.log(JSON.stringify(result, null, 2));
|
|
262
|
+
} else {
|
|
263
|
+
console.log(renderShieldTerminal(result));
|
|
264
|
+
}
|
|
265
|
+
process.exitCode = result.exitCode;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (command === "mcp") {
|
|
270
|
+
const json = rest.includes("--json");
|
|
271
|
+
const positional = getPositionals(rest);
|
|
272
|
+
const subcommand = positional[0] === "doctor" ? "doctor" : "server";
|
|
273
|
+
const target = subcommand === "doctor" ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
274
|
+
const mcpDeps = {
|
|
275
|
+
rootDir: path.resolve(target),
|
|
276
|
+
packageVersion: PACKAGE_VERSION,
|
|
277
|
+
scanRepo,
|
|
278
|
+
toJsonPayload,
|
|
279
|
+
runDoctor,
|
|
280
|
+
toDoctorJsonPayload,
|
|
281
|
+
getUsageSummary,
|
|
282
|
+
getClaudeCodeCostSummary,
|
|
283
|
+
getCursorSessionSummary,
|
|
284
|
+
buildBoundaryCheck,
|
|
285
|
+
buildInstructionsAblationPlan,
|
|
286
|
+
buildInstructionsAudit,
|
|
287
|
+
buildMultiSessionTimeline,
|
|
288
|
+
buildReceipt,
|
|
289
|
+
buildReplay,
|
|
290
|
+
runOptimize,
|
|
291
|
+
createOptimizeContext,
|
|
292
|
+
renderStarterPrompt,
|
|
293
|
+
runFirewall,
|
|
294
|
+
runShield,
|
|
295
|
+
runShieldLast,
|
|
296
|
+
runShieldSearch,
|
|
297
|
+
};
|
|
298
|
+
if (subcommand === "doctor") {
|
|
299
|
+
const result = await runMcpDoctor(mcpDeps);
|
|
300
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
301
|
+
else console.log(renderMcpDoctorTerminal(result));
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
runMcpServer(mcpDeps);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (command === "connect") {
|
|
309
|
+
const json = rest.includes("--json");
|
|
310
|
+
const tokenIndex = rest.indexOf("--token");
|
|
311
|
+
const apiUrlIndex = rest.indexOf("--api-url");
|
|
312
|
+
const orgIndex = rest.indexOf("--org");
|
|
313
|
+
const userIndex = rest.indexOf("--user");
|
|
314
|
+
const deviceIndex = rest.indexOf("--device");
|
|
315
|
+
const limitIndex = rest.indexOf("--limit");
|
|
316
|
+
const result = runConnect({
|
|
317
|
+
token: tokenIndex >= 0 ? rest[tokenIndex + 1] : null,
|
|
318
|
+
apiUrl: apiUrlIndex >= 0 ? rest[apiUrlIndex + 1] : null,
|
|
319
|
+
org: orgIndex >= 0 ? rest[orgIndex + 1] : null,
|
|
320
|
+
user: userIndex >= 0 ? rest[userIndex + 1] : null,
|
|
321
|
+
device: deviceIndex >= 0 ? rest[deviceIndex + 1] : null,
|
|
322
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
323
|
+
});
|
|
324
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
325
|
+
else console.log(renderConnectTerminal(result));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (command === "sync") {
|
|
330
|
+
const json = rest.includes("--json");
|
|
331
|
+
const limitIndex = rest.indexOf("--limit");
|
|
332
|
+
const toolIndex = rest.indexOf("--tool");
|
|
333
|
+
const apiUrlIndex = rest.indexOf("--api-url");
|
|
334
|
+
const intervalIndex = rest.indexOf("--interval");
|
|
335
|
+
const positional = getPositionals(rest, new Set(["--limit", "--tool", "--api-url", "--interval"]));
|
|
336
|
+
const target = positional[0] || process.cwd();
|
|
337
|
+
const syncOptions = {
|
|
338
|
+
dryRun: rest.includes("--dry-run") || rest.includes("--preview"),
|
|
339
|
+
preview: rest.includes("--preview"),
|
|
340
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
341
|
+
tool: toolIndex >= 0 ? rest[toolIndex + 1] : "all",
|
|
342
|
+
endpoint: apiUrlIndex >= 0 ? `${String(rest[apiUrlIndex + 1] || "").replace(/\/$/, "")}/v1/dev/sessions/sync` : null,
|
|
343
|
+
};
|
|
344
|
+
if (rest.includes("--watch")) {
|
|
345
|
+
const intervalMs = parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 60) * 1000;
|
|
346
|
+
while (true) {
|
|
347
|
+
const result = await runSync(target, syncOptions);
|
|
348
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
349
|
+
else console.log(renderSyncTerminal(result));
|
|
350
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const result = await runSync(target, syncOptions);
|
|
354
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
355
|
+
else console.log(renderSyncTerminal(result));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (command === "agent") {
|
|
360
|
+
const json = rest.includes("--json");
|
|
361
|
+
const intervalIndex = rest.indexOf("--interval");
|
|
362
|
+
const limitIndex = rest.indexOf("--limit");
|
|
363
|
+
const budgetIndex = rest.indexOf("--budget");
|
|
364
|
+
const modeIndex = rest.indexOf("--mode");
|
|
365
|
+
const modeValue = modeIndex >= 0 ? rest[modeIndex + 1] : "autopilot";
|
|
366
|
+
if (!AGENT_VALID_MODES.has(modeValue)) {
|
|
367
|
+
throw new Error(`Invalid agent mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
|
|
368
|
+
}
|
|
369
|
+
const positional = getPositionals(rest, new Set(["--interval", "--limit", "--budget", "--mode"]));
|
|
370
|
+
const target = positional[0] || process.cwd();
|
|
371
|
+
const agentOptions = {
|
|
372
|
+
json,
|
|
373
|
+
mode: modeValue,
|
|
374
|
+
watch: rest.includes("--watch") && !rest.includes("--once"),
|
|
375
|
+
interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
|
|
376
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
377
|
+
tokenBudget: parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || 600000,
|
|
378
|
+
};
|
|
379
|
+
const result = await runAgent(target, agentOptions);
|
|
380
|
+
if (!agentOptions.watch) {
|
|
381
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
382
|
+
else console.log(renderAgentTerminal(result));
|
|
383
|
+
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (command === "status") {
|
|
388
|
+
const json = rest.includes("--json");
|
|
389
|
+
const result = runStatus();
|
|
390
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
391
|
+
else console.log(renderStatusTerminal(result));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (command === "disconnect") {
|
|
396
|
+
const json = rest.includes("--json");
|
|
397
|
+
const result = runDisconnect();
|
|
398
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
399
|
+
else console.log(renderDisconnectTerminal(result));
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (command === "setup") {
|
|
404
|
+
const json = rest.includes("--json");
|
|
405
|
+
const limitIndex = rest.indexOf("--limit");
|
|
406
|
+
const proxyIndex = rest.indexOf("--proxy-url");
|
|
407
|
+
const target = getPositionals(rest, new Set(["--limit", "--proxy-url"]))[0] || process.cwd();
|
|
408
|
+
const result = await runSetup(target, {
|
|
409
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 3),
|
|
410
|
+
proxyUrl: proxyIndex >= 0 ? rest[proxyIndex + 1] : DEFAULT_PRISMO_PROXY_URL,
|
|
411
|
+
skipProxyCheck: rest.includes("--skip-proxy-check"),
|
|
412
|
+
});
|
|
413
|
+
if (json) {
|
|
414
|
+
console.log(JSON.stringify(result, null, 2));
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
console.log(renderSetupTerminal(result));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (command === "cc") {
|
|
422
|
+
const json = rest.includes("--json");
|
|
423
|
+
const limitIndex = rest.indexOf("--limit");
|
|
424
|
+
const firewall = rest.includes("--firewall");
|
|
425
|
+
const taskIndex = rest.indexOf("--task");
|
|
426
|
+
const firewallTask = taskIndex >= 0 && rest[taskIndex + 1] && !rest[taskIndex + 1].startsWith("-")
|
|
427
|
+
? rest[taskIndex + 1]
|
|
428
|
+
: "timeline-followup";
|
|
429
|
+
const ccArgs = rest.filter((_, index) => {
|
|
430
|
+
if (index === rest.indexOf("--firewall")) return false;
|
|
431
|
+
if (taskIndex >= 0 && (index === taskIndex || index === taskIndex + 1)) return false;
|
|
432
|
+
return true;
|
|
433
|
+
});
|
|
434
|
+
const positional = getPositionals(ccArgs, new Set(["--limit"]));
|
|
435
|
+
const subcommand = positional[0] && ["list", "last", "all", "timeline"].includes(positional[0].toLowerCase()) ? positional[0].toLowerCase() : "latest";
|
|
436
|
+
const lastCount = subcommand === "last" ? parsePositiveInt(positional[1], 5) : null;
|
|
437
|
+
const limit = subcommand === "list"
|
|
438
|
+
? parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 10)
|
|
439
|
+
: subcommand === "last"
|
|
440
|
+
? lastCount
|
|
441
|
+
: 1;
|
|
442
|
+
const targetIndex = subcommand === "last" ? 2 : subcommand === "latest" ? 0 : 1;
|
|
443
|
+
const hasTarget = Boolean(positional[targetIndex]);
|
|
444
|
+
const target = hasTarget ? positional[targetIndex] : process.cwd();
|
|
445
|
+
const summary = getClaudeCodeCostSummary({
|
|
446
|
+
cwd: path.resolve(target),
|
|
447
|
+
limit,
|
|
448
|
+
all: subcommand === "all",
|
|
449
|
+
allProjects: !hasTarget,
|
|
450
|
+
mode: subcommand,
|
|
451
|
+
});
|
|
452
|
+
if (json) {
|
|
453
|
+
if (subcommand === "timeline") {
|
|
454
|
+
const latest = summary.sessions[0] || null;
|
|
455
|
+
const firewallSuggestions = firewall && latest
|
|
456
|
+
? runTimelineFirewallSuggestions(path.resolve(target), latest, { task: firewallTask, dryRun: false })
|
|
457
|
+
: null;
|
|
458
|
+
console.log(JSON.stringify({
|
|
459
|
+
schemaVersion: 1,
|
|
460
|
+
generatedAt: summary.generatedAt,
|
|
461
|
+
scannedPath: summary.scannedPath,
|
|
462
|
+
command: "cc timeline",
|
|
463
|
+
session: latest
|
|
464
|
+
? {
|
|
465
|
+
sessionId: latest.sessionId,
|
|
466
|
+
model: latest.model || latest.cost?.model || null,
|
|
467
|
+
updatedAt: latest.updatedAt,
|
|
468
|
+
risk: latest.contextRisk,
|
|
469
|
+
turns: latest.turns,
|
|
470
|
+
toolCalls: latest.toolCalls,
|
|
471
|
+
}
|
|
472
|
+
: null,
|
|
473
|
+
timeline: latest ? latest.timeline || [] : [],
|
|
474
|
+
firewallSuggestions,
|
|
475
|
+
suggestedAction: latest?.prismo?.recommendations?.[0] || `${NPX_COMMAND} doctor`,
|
|
476
|
+
}, null, 2));
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const output = [renderClaudeCostTerminal(summary)];
|
|
483
|
+
if (subcommand === "timeline" && firewall) {
|
|
484
|
+
const latest = summary.sessions[0] || null;
|
|
485
|
+
if (latest) {
|
|
486
|
+
const suggestions = runTimelineFirewallSuggestions(path.resolve(target), latest, { task: firewallTask, dryRun: false });
|
|
487
|
+
output.push("");
|
|
488
|
+
output.push("Timeline Firewall Suggestions");
|
|
489
|
+
output.push(`Wrote: ${suggestions.generatedFiles.join(", ")}`);
|
|
490
|
+
output.push(`Session-derived allowed: ${suggestions.sessionAllowed.length}`);
|
|
491
|
+
output.push(`Session-derived blocked: ${suggestions.sessionBlocked.length}`);
|
|
492
|
+
output.push("Tell your agent: Use .prismo/context-firewall.suggested.md for the next scoped session.");
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
console.log(output.join("\n"));
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (command === "cursor") {
|
|
500
|
+
const json = rest.includes("--json");
|
|
501
|
+
const limitIndex = rest.indexOf("--limit");
|
|
502
|
+
const positional = getPositionals(rest, new Set(["--limit"]));
|
|
503
|
+
const subcommand = positional[0] && ["list", "authorship", "timeline", "files", "all"].includes(positional[0].toLowerCase())
|
|
504
|
+
? positional[0].toLowerCase()
|
|
505
|
+
: "latest";
|
|
506
|
+
const target = (subcommand !== "latest" ? positional[1] : positional[0]) || process.cwd();
|
|
507
|
+
const limit = parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, subcommand === "all" ? 200 : 20);
|
|
508
|
+
const summary = getCursorSessionSummary({
|
|
509
|
+
cwd: path.resolve(target),
|
|
510
|
+
limit,
|
|
511
|
+
mode: subcommand,
|
|
512
|
+
});
|
|
513
|
+
if (json) {
|
|
514
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
console.log(renderCursorTerminal(summary, subcommand));
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (command === "receipt") {
|
|
522
|
+
const json = rest.includes("--json");
|
|
523
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
524
|
+
const positional = getPositionals(rest, new Set(["--limit"]));
|
|
525
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
526
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
527
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
528
|
+
const limitIndex = rest.indexOf("--limit");
|
|
529
|
+
const receipt = buildReceipt({
|
|
530
|
+
cwd: path.resolve(target),
|
|
531
|
+
tool,
|
|
532
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
533
|
+
});
|
|
534
|
+
if (json) {
|
|
535
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
console.log(renderReceiptTerminal(receipt));
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (command === "instructions") {
|
|
543
|
+
const json = rest.includes("--json");
|
|
544
|
+
const limitIndex = rest.indexOf("--limit");
|
|
545
|
+
const samplesIndex = rest.indexOf("--samples");
|
|
546
|
+
const positional = getPositionals(rest, new Set(["--limit", "--samples"]));
|
|
547
|
+
const subcommand = ["audit", "ablate", "apply"].includes(positional[0]?.toLowerCase()) ? positional[0].toLowerCase() : "audit";
|
|
548
|
+
const target = ["audit", "ablate", "apply"].includes(positional[0]?.toLowerCase())
|
|
549
|
+
? positional[1] || process.cwd()
|
|
550
|
+
: positional[0] || process.cwd();
|
|
551
|
+
if (subcommand === "ablate") {
|
|
552
|
+
const plan = buildInstructionsAblationPlan({
|
|
553
|
+
cwd: path.resolve(target),
|
|
554
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
555
|
+
samples: parsePositiveInt(samplesIndex >= 0 ? rest[samplesIndex + 1] : null, 10),
|
|
556
|
+
});
|
|
557
|
+
if (json) {
|
|
558
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
console.log(renderInstructionsAblationTerminal(plan));
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (subcommand === "apply") {
|
|
565
|
+
const result = buildInstructionsApply({
|
|
566
|
+
cwd: path.resolve(target),
|
|
567
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
568
|
+
dryRun: rest.includes("--dry-run"),
|
|
569
|
+
});
|
|
570
|
+
if (json) {
|
|
571
|
+
console.log(JSON.stringify(result, null, 2));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
console.log(renderInstructionsApplyTerminal(result));
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const audit = buildInstructionsAudit({
|
|
578
|
+
cwd: path.resolve(target),
|
|
579
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
580
|
+
});
|
|
581
|
+
if (json) {
|
|
582
|
+
console.log(JSON.stringify(audit, null, 2));
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
console.log(renderInstructionsAuditTerminal(audit));
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (command === "timeline") {
|
|
590
|
+
const json = rest.includes("--json");
|
|
591
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
592
|
+
const positional = getPositionals(rest, new Set(["--last", "--limit"]));
|
|
593
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
594
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
595
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
596
|
+
const lastIndex = rest.indexOf("--last");
|
|
597
|
+
const limitIndex = rest.indexOf("--limit");
|
|
598
|
+
const limitValue = lastIndex >= 0 ? rest[lastIndex + 1] : limitIndex >= 0 ? rest[limitIndex + 1] : null;
|
|
599
|
+
const timeline = buildMultiSessionTimeline({
|
|
600
|
+
cwd: path.resolve(target),
|
|
601
|
+
tool,
|
|
602
|
+
limit: parsePositiveInt(limitValue, 20),
|
|
603
|
+
});
|
|
604
|
+
if (json) {
|
|
605
|
+
console.log(JSON.stringify(timeline, null, 2));
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
console.log(renderMultiSessionTimelineTerminal(timeline));
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if (command === "replay") {
|
|
613
|
+
const json = rest.includes("--json");
|
|
614
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
615
|
+
const positional = getPositionals(rest, new Set(["--limit"]));
|
|
616
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
617
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
618
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
619
|
+
const limitIndex = rest.indexOf("--limit");
|
|
620
|
+
const replay = buildReplay({
|
|
621
|
+
cwd: path.resolve(target),
|
|
622
|
+
tool,
|
|
623
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
624
|
+
});
|
|
625
|
+
if (json) {
|
|
626
|
+
console.log(JSON.stringify(replay, null, 2));
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
console.log(renderReplayTerminal(replay));
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (command === "boundaries") {
|
|
634
|
+
const json = rest.includes("--json");
|
|
635
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
636
|
+
const positional = getPositionals(rest, new Set(["--limit"]));
|
|
637
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
638
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
639
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
640
|
+
const limitIndex = rest.indexOf("--limit");
|
|
641
|
+
const check = buildBoundaryCheck({
|
|
642
|
+
cwd: path.resolve(target),
|
|
643
|
+
tool,
|
|
644
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 10),
|
|
645
|
+
});
|
|
646
|
+
if (json) {
|
|
647
|
+
console.log(JSON.stringify(check, null, 2));
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
console.log(renderBoundaryTerminal(check));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (command === "guard") {
|
|
655
|
+
const json = rest.includes("--json");
|
|
656
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
657
|
+
const positional = getPositionals(rest, new Set(["--limit", "--interval", "--budget", "--api-url"]));
|
|
658
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
659
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
660
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
661
|
+
const limitIndex = rest.indexOf("--limit");
|
|
662
|
+
const intervalIndex = rest.indexOf("--interval");
|
|
663
|
+
const budgetIndex = rest.indexOf("--budget");
|
|
664
|
+
const apiUrlIndex = rest.indexOf("--api-url");
|
|
665
|
+
const guardOptions = {
|
|
666
|
+
tool,
|
|
667
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
668
|
+
tokenBudget: parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || 600000,
|
|
669
|
+
dryRun: rest.includes("--dry-run") || rest.includes("--preview"),
|
|
670
|
+
noSync: rest.includes("--no-sync"),
|
|
671
|
+
watch: rest.includes("--watch") && !rest.includes("--once"),
|
|
672
|
+
endpoint: apiUrlIndex >= 0 ? `${String(rest[apiUrlIndex + 1] || "").replace(/\/$/, "")}/v1/dev/guardrails/sync` : null,
|
|
673
|
+
};
|
|
674
|
+
if (guardOptions.watch) {
|
|
675
|
+
const intervalMs = parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 60) * 1000;
|
|
676
|
+
while (true) {
|
|
677
|
+
const result = await runGuard(target, guardOptions);
|
|
678
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
679
|
+
else console.log(renderGuardTerminal(result));
|
|
680
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
const result = await runGuard(target, guardOptions);
|
|
684
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
685
|
+
else console.log(renderGuardTerminal(result));
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (command === "usage" || command === "watch") {
|
|
690
|
+
const json = rest.includes("--json");
|
|
691
|
+
const knownTools = new Set(["codex", "claude", "cursor", "all"]);
|
|
692
|
+
const positional = getPositionals(rest, new Set(["--limit", "--interval", "--budget"]));
|
|
693
|
+
const explicitTool = positional[0] && knownTools.has(positional[0].toLowerCase());
|
|
694
|
+
const tool = explicitTool ? positional[0].toLowerCase() : "all";
|
|
695
|
+
const target = explicitTool ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
696
|
+
const limitIndex = rest.indexOf("--limit");
|
|
697
|
+
const intervalIndex = rest.indexOf("--interval");
|
|
698
|
+
const budgetIndex = rest.indexOf("--budget");
|
|
699
|
+
const auto = rest.includes("--auto");
|
|
700
|
+
const noEvents = rest.includes("--no-events");
|
|
701
|
+
const limit = parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5);
|
|
702
|
+
const intervalMs = parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 3) * 1000;
|
|
703
|
+
const tokenBudget = parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || (auto ? 600000 : null);
|
|
704
|
+
const usageOptions = {
|
|
705
|
+
tool,
|
|
706
|
+
cwd: path.resolve(target),
|
|
707
|
+
limit,
|
|
708
|
+
tokenBudget,
|
|
709
|
+
auto,
|
|
710
|
+
agents: rest.includes("--agents"),
|
|
711
|
+
json,
|
|
712
|
+
once: rest.includes("--once"),
|
|
713
|
+
report: rest.includes("--report"),
|
|
714
|
+
rescue: rest.includes("--rescue"),
|
|
715
|
+
guardrails: auto || rest.includes("--guardrails"),
|
|
716
|
+
throttle: auto || rest.includes("--throttle"),
|
|
717
|
+
events: (auto && !noEvents) || rest.includes("--events"),
|
|
718
|
+
noEvents,
|
|
719
|
+
updateFirewall: auto ? (summary) => {
|
|
720
|
+
const live = summary.live;
|
|
721
|
+
if (!live || live.liveAction.cause === "healthy" || live.liveAction.cause === "no-active-session") return null;
|
|
722
|
+
return runFirewall(summary.scannedPath || target, {
|
|
723
|
+
task: live.liveAction.cause,
|
|
724
|
+
dryRun: false,
|
|
725
|
+
live: true,
|
|
726
|
+
});
|
|
727
|
+
} : null,
|
|
728
|
+
redactPaths: rest.includes("--redact-paths"),
|
|
729
|
+
intervalMs,
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
if (command === "watch") {
|
|
733
|
+
await watchUsage(usageOptions);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const summary = getUsageSummary(usageOptions);
|
|
738
|
+
if (json) {
|
|
739
|
+
console.log(JSON.stringify(compactUsageSummary(summary), null, 2));
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
console.log(renderUsageTerminal(summary));
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (command === "context") {
|
|
747
|
+
const json = rest.includes("--json");
|
|
748
|
+
const { scope, target } = parseScopeAndTarget(rest);
|
|
749
|
+
const ctx = createOptimizeContext(target, scope);
|
|
750
|
+
const prompt = renderStarterPrompt(ctx, scope);
|
|
751
|
+
const output = renderContextCommand(ctx, scope);
|
|
752
|
+
if (json) {
|
|
753
|
+
console.log(JSON.stringify({
|
|
754
|
+
scope,
|
|
755
|
+
prompt,
|
|
756
|
+
contextFile: getContextFileForScope(ctx, scope),
|
|
757
|
+
supportingFiles: [
|
|
758
|
+
!scope && ctx.backendDetected ? ".prismo/backend-summary.md" : null,
|
|
759
|
+
!scope && ctx.frontendDetected ? ".prismo/frontend-summary.md" : null,
|
|
760
|
+
scope === "frontend" ? ".prismo/frontend-summary.md" : null,
|
|
761
|
+
scope === "backend" ? ".prismo/backend-summary.md" : null,
|
|
762
|
+
].filter(Boolean),
|
|
763
|
+
scannedPath: ctx.root,
|
|
764
|
+
generatedAt: ctx.generatedAt,
|
|
765
|
+
}, null, 2));
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
console.log(output);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (command === "optimize") {
|
|
773
|
+
const json = rest.includes("--json");
|
|
774
|
+
const { scope, target } = parseScopeAndTarget(rest);
|
|
775
|
+
const result = runOptimize(target, { scope });
|
|
776
|
+
if (json) {
|
|
777
|
+
console.log(JSON.stringify(result, null, 2));
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
console.log(renderOptimizeTerminal(result));
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const fix = rest.includes("--fix");
|
|
785
|
+
const noReport = rest.includes("--no-report");
|
|
786
|
+
const json = rest.includes("--json");
|
|
787
|
+
const simple = rest.includes("--simple");
|
|
788
|
+
const optimizerFit = rest.includes("--optimizer-fit");
|
|
789
|
+
const reportCard = rest.includes("--report-card");
|
|
790
|
+
const ciMode = rest.includes("--ci");
|
|
791
|
+
const includeUsage = rest.includes("--usage") || optimizerFit || reportCard;
|
|
792
|
+
const limitIndex = rest.indexOf("--limit");
|
|
793
|
+
const usageToolIndex = rest.indexOf("--usage-tool");
|
|
794
|
+
const target = getPositionals(rest, new Set(["--limit", "--usage-tool"]))[0] || process.cwd();
|
|
795
|
+
const scanDone = printStep(includeUsage ? "Scanning repo and local usage" : "Scanning repo", json || simple || optimizerFit || reportCard);
|
|
796
|
+
const result = scanRepo(target, {
|
|
797
|
+
includeUsage,
|
|
798
|
+
usageLimit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
799
|
+
usageTool: usageToolIndex >= 0 ? rest[usageToolIndex + 1] : "all",
|
|
800
|
+
});
|
|
801
|
+
scanDone();
|
|
802
|
+
|
|
803
|
+
if (json) {
|
|
804
|
+
let fixActions = [];
|
|
805
|
+
let report = null;
|
|
806
|
+
if (fix) {
|
|
807
|
+
fixActions = applyFixes(result);
|
|
808
|
+
} else if (!noReport && !optimizerFit) {
|
|
809
|
+
report = writeReport(result);
|
|
810
|
+
}
|
|
811
|
+
const payload = toJsonPayload(result);
|
|
812
|
+
if (ciMode) {
|
|
813
|
+
payload.ci = evaluateCi(result);
|
|
814
|
+
if (!payload.ci.passed) process.exitCode = 1;
|
|
815
|
+
}
|
|
816
|
+
if (optimizerFit || reportCard) {
|
|
817
|
+
console.log(JSON.stringify({
|
|
818
|
+
schemaVersion: 1,
|
|
819
|
+
scannedPath: result.root,
|
|
820
|
+
score: result.score,
|
|
821
|
+
riskLevel: result.risk,
|
|
822
|
+
optimizerFit: result.optimizerFit,
|
|
823
|
+
reportCard: reportCard ? {
|
|
824
|
+
biggestWaste: result.optimizerFit.summary,
|
|
825
|
+
startWith: result.optimizerFit.recommendedStack[0]?.command || null,
|
|
826
|
+
then: result.optimizerFit.recommendedStack[1]?.command || null,
|
|
827
|
+
roundTripRisk: result.optimizerFit.roundTripContext.level,
|
|
828
|
+
} : undefined,
|
|
829
|
+
generatedAt: result.generatedAt,
|
|
830
|
+
}, null, 2));
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
if (fixActions.length) payload.fixActions = fixActions;
|
|
834
|
+
if (report) payload.reportPath = report.reportPath;
|
|
835
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (reportCard) {
|
|
840
|
+
console.log(renderReportCardTerminal(result));
|
|
841
|
+
} else if (optimizerFit) {
|
|
842
|
+
console.log(renderOptimizerFitTerminal(result));
|
|
843
|
+
} else if (simple) {
|
|
844
|
+
console.log(renderSimpleScanReport(result));
|
|
845
|
+
} else if (ciMode) {
|
|
846
|
+
const ci = evaluateCi(result);
|
|
847
|
+
console.log(renderCiReport(result, ci));
|
|
848
|
+
if (!ci.passed) process.exitCode = 1;
|
|
849
|
+
} else {
|
|
850
|
+
console.log(renderTerminalReport(result, { reportEnabled: !noReport || fix }));
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (fix) {
|
|
854
|
+
const actions = applyFixes(result);
|
|
855
|
+
console.log("\nFix Mode:");
|
|
856
|
+
actions.forEach((action) => console.log(`- ${action}`));
|
|
857
|
+
} else if (!noReport && !simple && !optimizerFit && !reportCard) {
|
|
858
|
+
const report = writeReport(result);
|
|
859
|
+
if (report.backupPath) {
|
|
860
|
+
console.log(`\nExisting report backed up to ${path.basename(report.backupPath)}.`);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return { runCli, parseTokenBudget };
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
module.exports = createCli;
|