getprismo 0.1.21 → 0.1.22
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 +29 -0
- package/lib/prismo-dev/benchmark.js +122 -0
- package/lib/prismo-dev/report.js +37 -0
- package/lib/prismo-dev/scan.js +27 -0
- package/lib/prismo-dev-scan.js +59 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -180,6 +180,33 @@ Recommended Stack
|
|
|
180
180
|
|
|
181
181
|
This makes PrismoDev the measure-first layer: it tells you whether you need ignore cleanup, output sandboxing, code indexing, repo packing, instruction trimming, session splitting, or MCP/tool hygiene.
|
|
182
182
|
|
|
183
|
+
For the short version:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx getprismo scan --report-card
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
That prints the simplest decision:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
PrismoDev Report Card
|
|
193
|
+
|
|
194
|
+
Biggest waste: Generated artifacts / ignore cleanup: High
|
|
195
|
+
Start with: npx getprismo doctor --apply-suggestions --dry-run
|
|
196
|
+
Then: npx getprismo shield -- <noisy command>
|
|
197
|
+
Code index needed: not yet
|
|
198
|
+
Round-trip risk: Low
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
To benchmark a noisy command:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npx getprismo benchmark -- npm test
|
|
205
|
+
npx getprismo benchmark session
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`benchmark -- <command>` measures raw command output tokens versus the compact shield summary. `benchmark session` summarizes recent local Claude/Codex sessions, including round-trip context signals like tool calls, repeated commands, repeated source reads, and MCP/tool surface.
|
|
209
|
+
|
|
183
210
|
---
|
|
184
211
|
|
|
185
212
|
## new: context shield
|
|
@@ -580,6 +607,8 @@ no install needed. npx runs it directly.
|
|
|
580
607
|
| `cc timeline` | session reconstruction with events |
|
|
581
608
|
| `scan --usage` | full repo scan with local usage data |
|
|
582
609
|
| `scan --optimizer-fit` | recommend which token-optimization path fits your repo/session |
|
|
610
|
+
| `scan --report-card` | shortest decision-layer summary |
|
|
611
|
+
| `benchmark` | measure command-output reduction or recent session round-trip context |
|
|
583
612
|
| `scan --simple` | plain-english summary |
|
|
584
613
|
| `scan --fix` | create safe fix files |
|
|
585
614
|
| `scan --ci` | fail CI when token-risk gates fail |
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module.exports = function createBenchmark(deps) {
|
|
2
|
+
const {
|
|
3
|
+
NPX_COMMAND,
|
|
4
|
+
estimateTokens,
|
|
5
|
+
formatTokenCount,
|
|
6
|
+
getUsageSummary,
|
|
7
|
+
runShield,
|
|
8
|
+
scanRepo,
|
|
9
|
+
color,
|
|
10
|
+
} = deps;
|
|
11
|
+
|
|
12
|
+
function estimateSummaryTokens(shieldResult) {
|
|
13
|
+
const lines = shieldResult.output && Array.isArray(shieldResult.output.interestingLines)
|
|
14
|
+
? shieldResult.output.interestingLines.join("\n")
|
|
15
|
+
: "";
|
|
16
|
+
return estimateTokens([
|
|
17
|
+
`Command: ${shieldResult.command}`,
|
|
18
|
+
`Exit: ${shieldResult.exitCode}`,
|
|
19
|
+
`Duration: ${shieldResult.durationMs}ms`,
|
|
20
|
+
lines,
|
|
21
|
+
].join("\n"));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function runBenchmark(rootDir = process.cwd(), commandArgs = [], options = {}) {
|
|
25
|
+
if (options.sessionOnly || !commandArgs.length) {
|
|
26
|
+
const scan = scanRepo(rootDir, { includeUsage: true, usageLimit: options.limit || 5 });
|
|
27
|
+
const usage = getUsageSummary({ cwd: scan.root, limit: options.limit || 5, tool: "all" });
|
|
28
|
+
const fit = scan.optimizerFit;
|
|
29
|
+
return {
|
|
30
|
+
schemaVersion: 1,
|
|
31
|
+
mode: "session",
|
|
32
|
+
scannedPath: scan.root,
|
|
33
|
+
score: scan.score,
|
|
34
|
+
riskLevel: scan.risk,
|
|
35
|
+
sessions: usage.sessions.length,
|
|
36
|
+
tokens: usage.totals,
|
|
37
|
+
roundTripContext: fit.roundTripContext,
|
|
38
|
+
optimizerFit: fit.summary,
|
|
39
|
+
recommendedStack: fit.recommendedStack,
|
|
40
|
+
next: [`${NPX_COMMAND} scan --optimizer-fit`, `${NPX_COMMAND} watch --once`, `${NPX_COMMAND} cc timeline`],
|
|
41
|
+
generatedAt: new Date().toISOString(),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const shield = runShield(rootDir, commandArgs);
|
|
46
|
+
const rawTokens = shield.output.estimatedTokens || 0;
|
|
47
|
+
const summaryTokens = estimateSummaryTokens(shield);
|
|
48
|
+
const reductionPercent = rawTokens > 0 ? Math.max(0, Math.round(((rawTokens - summaryTokens) / rawTokens) * 100)) : 0;
|
|
49
|
+
return {
|
|
50
|
+
schemaVersion: 1,
|
|
51
|
+
mode: "command",
|
|
52
|
+
scannedPath: shield.cwd,
|
|
53
|
+
command: shield.command,
|
|
54
|
+
exitCode: shield.exitCode,
|
|
55
|
+
durationMs: shield.durationMs,
|
|
56
|
+
rawOutput: {
|
|
57
|
+
bytes: shield.output.totalBytes,
|
|
58
|
+
estimatedTokens: rawTokens,
|
|
59
|
+
},
|
|
60
|
+
shieldedSummary: {
|
|
61
|
+
estimatedTokens: summaryTokens,
|
|
62
|
+
interestingLines: shield.output.interestingLines,
|
|
63
|
+
},
|
|
64
|
+
estimatedTokenReductionPercent: reductionPercent,
|
|
65
|
+
stored: shield.stored,
|
|
66
|
+
next: [
|
|
67
|
+
"Give the shield summary to the agent first.",
|
|
68
|
+
`${NPX_COMMAND} shield search "<error text>"`,
|
|
69
|
+
`${NPX_COMMAND} scan --optimizer-fit`,
|
|
70
|
+
],
|
|
71
|
+
generatedAt: new Date().toISOString(),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function renderBenchmarkTerminal(result) {
|
|
76
|
+
const lines = [];
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push(color("Prismo Benchmark", "bold"));
|
|
79
|
+
lines.push("");
|
|
80
|
+
if (result.mode === "session") {
|
|
81
|
+
lines.push(`Mode: session`);
|
|
82
|
+
lines.push(`Score: ${result.score}/100 (${result.riskLevel} risk)`);
|
|
83
|
+
lines.push(`Sessions: ${result.sessions}`);
|
|
84
|
+
lines.push(`Tokens: ${formatTokenCount(result.tokens.displayTokens || 0)} (${result.tokens.exactTokens ? "exact-local-log" : "estimated/local"})`);
|
|
85
|
+
lines.push(`Optimizer fit: ${result.optimizerFit}`);
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push("Round-Trip Context:");
|
|
88
|
+
lines.push(`- Level: ${result.roundTripContext.level}`);
|
|
89
|
+
lines.push(`- Tool calls: ${result.roundTripContext.toolCalls}`);
|
|
90
|
+
lines.push(`- Repeated commands: ${result.roundTripContext.repeatedCommandMentions}`);
|
|
91
|
+
lines.push(`- Repeated source reads: ${result.roundTripContext.repeatedSourceReads}`);
|
|
92
|
+
lines.push("");
|
|
93
|
+
lines.push("Next:");
|
|
94
|
+
result.next.forEach((item, index) => lines.push(`${index + 1}. ${item}`));
|
|
95
|
+
return lines.join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
lines.push(`Mode: command`);
|
|
99
|
+
lines.push(`Command: ${result.command}`);
|
|
100
|
+
lines.push(`Exit: ${result.exitCode}`);
|
|
101
|
+
lines.push(`Duration: ${result.durationMs}ms`);
|
|
102
|
+
lines.push(`Raw output: ${result.rawOutput.bytes.toLocaleString()} bytes (~${result.rawOutput.estimatedTokens.toLocaleString()} tokens)`);
|
|
103
|
+
lines.push(`Shield summary: ~${result.shieldedSummary.estimatedTokens.toLocaleString()} tokens`);
|
|
104
|
+
lines.push(`Estimated reduction: ${result.estimatedTokenReductionPercent}%`);
|
|
105
|
+
lines.push("");
|
|
106
|
+
lines.push("Stored Output:");
|
|
107
|
+
lines.push(`- ${result.stored.stdout}`);
|
|
108
|
+
lines.push(`- ${result.stored.stderr}`);
|
|
109
|
+
lines.push("");
|
|
110
|
+
lines.push("Useful Lines:");
|
|
111
|
+
result.shieldedSummary.interestingLines.slice(0, 12).forEach((line) => lines.push(`- ${line}`));
|
|
112
|
+
lines.push("");
|
|
113
|
+
lines.push("Next:");
|
|
114
|
+
result.next.forEach((item, index) => lines.push(`${index + 1}. ${item}`));
|
|
115
|
+
return lines.join("\n");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
renderBenchmarkTerminal,
|
|
120
|
+
runBenchmark,
|
|
121
|
+
};
|
|
122
|
+
};
|
package/lib/prismo-dev/report.js
CHANGED
|
@@ -141,11 +141,47 @@ function renderOptimizerFitTerminal(result, options = {}) {
|
|
|
141
141
|
lines.push(` ${item.reason}`);
|
|
142
142
|
});
|
|
143
143
|
lines.push("");
|
|
144
|
+
lines.push(color("Round-Trip Context", "bold", useColor));
|
|
145
|
+
lines.push(`- Level: ${fit.roundTripContext.level}`);
|
|
146
|
+
lines.push(`- Tool calls: ${fit.roundTripContext.toolCalls}`);
|
|
147
|
+
lines.push(`- Repeated command mentions: ${fit.roundTripContext.repeatedCommandMentions}`);
|
|
148
|
+
lines.push(`- Repeated source reads: ${fit.roundTripContext.repeatedSourceReads}`);
|
|
149
|
+
lines.push(`- MCP/tool servers: ${fit.roundTripContext.mcpServers}`);
|
|
150
|
+
lines.push(`- ${fit.roundTripContext.recommendation}`);
|
|
151
|
+
lines.push("");
|
|
144
152
|
lines.push("Notes:");
|
|
145
153
|
fit.caveats.forEach((caveat) => lines.push(`- ${caveat}`));
|
|
146
154
|
return lines.join("\n");
|
|
147
155
|
}
|
|
148
156
|
|
|
157
|
+
function renderReportCardTerminal(result, options = {}) {
|
|
158
|
+
const useColor = options.color !== false;
|
|
159
|
+
const fit = result.optimizerFit;
|
|
160
|
+
const top = fit.recommendedStack[0];
|
|
161
|
+
const second = fit.recommendedStack[1];
|
|
162
|
+
const lines = [];
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push(color("PrismoDev Report Card", "bold", useColor));
|
|
165
|
+
lines.push("");
|
|
166
|
+
lines.push(`Score: ${result.score}/100 (${result.risk} risk)`);
|
|
167
|
+
lines.push(`Biggest waste: ${fit.summary}`);
|
|
168
|
+
lines.push("");
|
|
169
|
+
if (top) lines.push(`Start with: ${top.command}`);
|
|
170
|
+
if (second) lines.push(`Then: ${second.command}`);
|
|
171
|
+
lines.push("");
|
|
172
|
+
const codeIndex = fit.bottlenecks.find((item) => item.id === "code-indexing");
|
|
173
|
+
const output = fit.bottlenecks.find((item) => item.id === "output-sandboxing");
|
|
174
|
+
const ignore = fit.bottlenecks.find((item) => item.id === "ignore-cleanup");
|
|
175
|
+
lines.push(`Code index needed: ${codeIndex && codeIndex.level === "High" ? "yes" : codeIndex && codeIndex.level === "Medium" ? "maybe" : "not yet"}`);
|
|
176
|
+
lines.push(`Output sandbox needed: ${output && output.level !== "Low" ? "yes" : "not yet"}`);
|
|
177
|
+
lines.push(`Ignore cleanup needed: ${ignore && ignore.level !== "Low" ? "yes" : "not urgent"}`);
|
|
178
|
+
lines.push(`Round-trip risk: ${fit.roundTripContext.level}`);
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push("Why:");
|
|
181
|
+
fit.bottlenecks.slice(0, 3).forEach((item) => lines.push(`- ${item.label}: ${item.evidence[0]}`));
|
|
182
|
+
return lines.join("\n");
|
|
183
|
+
}
|
|
184
|
+
|
|
149
185
|
function evaluateCi(result, options = {}) {
|
|
150
186
|
const minScore = Number(options.minScore || 80);
|
|
151
187
|
const failures = [];
|
|
@@ -434,6 +470,7 @@ function writeReport(result) {
|
|
|
434
470
|
renderCiReport,
|
|
435
471
|
renderMarkdownReport,
|
|
436
472
|
renderOptimizerFitTerminal,
|
|
473
|
+
renderReportCardTerminal,
|
|
437
474
|
renderSimpleScanReport,
|
|
438
475
|
renderTerminalReport,
|
|
439
476
|
writeReport,
|
package/lib/prismo-dev/scan.js
CHANGED
|
@@ -390,12 +390,21 @@ function detectOptimizationStack(root, claudeConfig, codexConfig) {
|
|
|
390
390
|
const projectHeadroom = fs.existsSync(path.join(root, ".headroom")) || fs.existsSync(path.join(os.homedir(), ".headroom"));
|
|
391
391
|
const projectDistill = fs.existsSync(path.join(os.homedir(), ".config", "distill")) || commandExists("distill");
|
|
392
392
|
const projectRtk = fs.existsSync(path.join(root, ".rtk")) || commandExists("rtk");
|
|
393
|
+
const packageText = readIfText(path.join(root, "package.json"), 512 * 1024) || "";
|
|
394
|
+
const readmeText = readIfText(path.join(root, "README.md"), 512 * 1024) || "";
|
|
395
|
+
const projectText = `${packageText}\n${readmeText}`.toLowerCase();
|
|
396
|
+
const hasText = (pattern) => pattern.test(projectText);
|
|
393
397
|
|
|
394
398
|
const tools = {
|
|
395
399
|
rtk: { detected: projectRtk, source: projectRtk ? "binary-or-project-config" : "not-detected" },
|
|
396
400
|
headroom: { detected: projectHeadroom || commandExists("headroom"), source: projectHeadroom ? "local-config" : commandExists("headroom") ? "binary" : "not-detected" },
|
|
397
401
|
distill: { detected: projectDistill, source: projectDistill ? "binary-or-user-config" : "not-detected" },
|
|
398
402
|
mana: { detected: projectMana || commandExists("mana"), source: projectMana ? "local-config" : commandExists("mana") ? "binary" : "not-detected" },
|
|
403
|
+
contextMode: { detected: commandExists("context-mode") || hasText(/context-mode/), source: commandExists("context-mode") ? "binary" : hasText(/context-mode/) ? "project-reference" : "not-detected" },
|
|
404
|
+
leanCtx: { detected: commandExists("lean-ctx") || hasText(/lean-ctx|lean ctx/), source: commandExists("lean-ctx") ? "binary" : hasText(/lean-ctx|lean ctx/) ? "project-reference" : "not-detected" },
|
|
405
|
+
repomix: { detected: commandExists("repomix") || hasText(/repomix/), source: commandExists("repomix") ? "binary" : hasText(/repomix/) ? "project-reference" : "not-detected" },
|
|
406
|
+
codegraph: { detected: commandExists("codegraph") || hasText(/codegraph|codebase-memory-mcp|jcodemunch|sigmap/), source: commandExists("codegraph") ? "binary" : hasText(/codegraph|codebase-memory-mcp|jcodemunch|sigmap/) ? "project-reference" : "not-detected" },
|
|
407
|
+
tokf: { detected: commandExists("tokf") || hasText(/tokf/), source: commandExists("tokf") ? "binary" : hasText(/tokf/) ? "project-reference" : "not-detected" },
|
|
399
408
|
};
|
|
400
409
|
|
|
401
410
|
return {
|
|
@@ -908,6 +917,13 @@ function buildOptimizerFit(result) {
|
|
|
908
917
|
const mcpEvidence = [];
|
|
909
918
|
let mcpScore = result.optimizationStack.mcpServerTotal >= 10 ? 70 : result.optimizationStack.mcpServerTotal >= 5 ? 45 : 10;
|
|
910
919
|
if (result.optimizationStack.mcpServerTotal) addEvidence(mcpEvidence, `${result.optimizationStack.mcpServerTotal} MCP/tool servers detected`);
|
|
920
|
+
const totalToolCalls = realUsage ? realUsage.sessions.reduce((sum, session) => sum + Number(session.toolCalls || 0), 0) : 0;
|
|
921
|
+
const repeatedCommands = realUsage ? realUsage.sessions.reduce((sum, session) => sum + (session.repeatedCommands || []).reduce((inner, item) => inner + Number(item.count || 0), 0), 0) : 0;
|
|
922
|
+
if (totalToolCalls >= 500) mcpScore += 30;
|
|
923
|
+
else if (totalToolCalls >= 100) mcpScore += 15;
|
|
924
|
+
if (repeatedCommands >= 20) mcpScore += 20;
|
|
925
|
+
if (totalToolCalls) addEvidence(mcpEvidence, `${totalToolCalls} tool calls in recent local sessions`);
|
|
926
|
+
if (repeatedCommands) addEvidence(mcpEvidence, `${repeatedCommands} repeated command/tool mentions`);
|
|
911
927
|
bottlenecks.push({
|
|
912
928
|
id: "tool-surface",
|
|
913
929
|
label: "Tool/MCP surface overhead",
|
|
@@ -1006,6 +1022,17 @@ function buildOptimizerFit(result) {
|
|
|
1006
1022
|
reason: "Best for one-shot repo handoff, less ideal for long live coding sessions.",
|
|
1007
1023
|
},
|
|
1008
1024
|
],
|
|
1025
|
+
roundTripContext: {
|
|
1026
|
+
level: levelFromScore(Math.max(mcpScore, repeatedSourceReads >= 50 ? 60 : repeatedSourceReads >= 12 ? 35 : 0)),
|
|
1027
|
+
toolCalls: totalToolCalls,
|
|
1028
|
+
repeatedCommandMentions: repeatedCommands,
|
|
1029
|
+
repeatedSourceReads,
|
|
1030
|
+
mcpServers: result.optimizationStack.mcpServerTotal,
|
|
1031
|
+
summary: totalToolCalls || repeatedCommands || repeatedSourceReads || result.optimizationStack.mcpServerTotal
|
|
1032
|
+
? "Round-trip context risk includes tool calls, repeated commands, repeated source reads, and MCP/tool surface."
|
|
1033
|
+
: "No strong round-trip context signal found in local logs.",
|
|
1034
|
+
recommendation: "Measure workflow-level savings, not only compressed payload size. Fewer tool round trips can beat smaller individual responses.",
|
|
1035
|
+
},
|
|
1009
1036
|
caveats: [
|
|
1010
1037
|
"Do not stack optimizers blindly; measure one real workflow before and after.",
|
|
1011
1038
|
"Payload reduction is not the same as workflow savings; repeated tool calls can erase compression wins.",
|
package/lib/prismo-dev-scan.js
CHANGED
|
@@ -194,6 +194,7 @@ const {
|
|
|
194
194
|
renderCiReport,
|
|
195
195
|
renderMarkdownReport,
|
|
196
196
|
renderOptimizerFitTerminal,
|
|
197
|
+
renderReportCardTerminal,
|
|
197
198
|
renderSimpleScanReport,
|
|
198
199
|
renderTerminalReport,
|
|
199
200
|
writeReport,
|
|
@@ -285,6 +286,19 @@ const {
|
|
|
285
286
|
color,
|
|
286
287
|
});
|
|
287
288
|
|
|
289
|
+
const {
|
|
290
|
+
renderBenchmarkTerminal,
|
|
291
|
+
runBenchmark,
|
|
292
|
+
} = require("./prismo-dev/benchmark")({
|
|
293
|
+
NPX_COMMAND,
|
|
294
|
+
estimateTokens,
|
|
295
|
+
formatTokenCount,
|
|
296
|
+
getUsageSummary,
|
|
297
|
+
runShield,
|
|
298
|
+
scanRepo: (...args) => scanRepo(...args),
|
|
299
|
+
color,
|
|
300
|
+
});
|
|
301
|
+
|
|
288
302
|
const {
|
|
289
303
|
renderMcpDoctorTerminal,
|
|
290
304
|
runMcpDoctor,
|
|
@@ -300,13 +314,14 @@ Usage:
|
|
|
300
314
|
prismo init [--json] [--dry-run] [path]
|
|
301
315
|
prismo doctor [--json] [--dry-run] [--apply-ignores-only] [--apply-suggestions] [--no-context-packs] [--limit N] [path]
|
|
302
316
|
prismo firewall [task] [--json] [--dry-run] [path]
|
|
317
|
+
prismo benchmark [session] [--json] [--limit N] [path] [-- <command ...>]
|
|
303
318
|
prismo shield [--json] [path] -- <command ...>
|
|
304
319
|
prismo shield last [--json] [--limit N] [path]
|
|
305
320
|
prismo shield search <query> [--json] [--limit N] [path]
|
|
306
321
|
prismo mcp [path]
|
|
307
322
|
prismo mcp doctor [--json] [path]
|
|
308
323
|
prismo setup [--json] [--proxy-url URL] [path]
|
|
309
|
-
prismo scan [--fix] [--ci] [--json] [--usage] [--optimizer-fit] [--simple] [--no-report] [path]
|
|
324
|
+
prismo scan [--fix] [--ci] [--json] [--usage] [--optimizer-fit] [--report-card] [--simple] [--no-report] [path]
|
|
310
325
|
prismo optimize [scope] [--json] [path]
|
|
311
326
|
prismo context [scope] [--json] [path]
|
|
312
327
|
prismo cc [list|last N|all] [--json] [--limit N] [path]
|
|
@@ -319,6 +334,7 @@ Commands:
|
|
|
319
334
|
init Add local PrismoDev helper docs and npm scripts when package.json exists.
|
|
320
335
|
doctor Diagnose, safely optimize, re-scan, and show before/after payoff.
|
|
321
336
|
firewall Generate allowed/blocked context policy files for an AI coding task.
|
|
337
|
+
benchmark Measure command-output savings or recent session round-trip context.
|
|
322
338
|
shield Run a noisy command, store full output locally, and return a compact summary.
|
|
323
339
|
mcp Start a local MCP server exposing Prismo tools over stdio.
|
|
324
340
|
scan Run PrismoDev for Claude Code, Codex, Cursor, and AI coding workflows.
|
|
@@ -336,6 +352,7 @@ Options:
|
|
|
336
352
|
--json Output valid JSON only for CI or future dashboard ingestion.
|
|
337
353
|
--usage Include real local Codex/Claude Code session usage in scan diagnostics.
|
|
338
354
|
--optimizer-fit Recommend the right optimization path for this repo/session.
|
|
355
|
+
--report-card Print a short plain-English optimization report card.
|
|
339
356
|
--simple Print a plain-English scan summary for first-time or non-technical users.
|
|
340
357
|
--no-report Do not write .prismo/prismo-dev-report.md.
|
|
341
358
|
--limit N Number of recent local sessions to show.
|
|
@@ -375,12 +392,13 @@ function printCommandHelp(command) {
|
|
|
375
392
|
scan: `PrismoDev
|
|
376
393
|
|
|
377
394
|
Usage:
|
|
378
|
-
prismo scan [--fix] [--ci] [--json] [--usage] [--optimizer-fit] [--simple] [--no-report] [--limit N] [path]
|
|
395
|
+
prismo scan [--fix] [--ci] [--json] [--usage] [--optimizer-fit] [--report-card] [--simple] [--no-report] [--limit N] [path]
|
|
379
396
|
|
|
380
397
|
Examples:
|
|
381
398
|
prismo scan
|
|
382
399
|
prismo scan --usage
|
|
383
400
|
prismo scan --optimizer-fit
|
|
401
|
+
prismo scan --report-card
|
|
384
402
|
prismo scan --simple
|
|
385
403
|
prismo scan --fix
|
|
386
404
|
prismo scan --ci
|
|
@@ -390,6 +408,7 @@ Examples:
|
|
|
390
408
|
Notes:
|
|
391
409
|
--usage reads local Codex/Claude Code logs when present.
|
|
392
410
|
--optimizer-fit explains whether ignore cleanup, output sandboxing, code indexing, repo packing, instruction trimming, or session splitting fits this repo best.
|
|
411
|
+
--report-card prints the shortest decision-layer summary.
|
|
393
412
|
--simple keeps the output short and does not write a report unless combined with --fix.
|
|
394
413
|
--fix creates safe recommendation files and never overwrites CLAUDE.md or AGENTS.md.`,
|
|
395
414
|
optimize: `Prismo Optimize
|
|
@@ -608,8 +627,8 @@ async function runCli(argv) {
|
|
|
608
627
|
printCommandHelp(command);
|
|
609
628
|
return;
|
|
610
629
|
}
|
|
611
|
-
if (!["dev", "init", "doctor", "firewall", "shield", "mcp", "setup", "scan", "optimize", "context", "cc", "usage", "watch", "demo"].includes(command)) {
|
|
612
|
-
throw new Error(`Unknown command: ${command}. Try: prismo doctor, prismo watch, prismo shield, prismo mcp, prismo firewall, prismo init, prismo scan, prismo optimize, prismo context, prismo cc, or prismo usage`);
|
|
630
|
+
if (!["dev", "init", "doctor", "firewall", "benchmark", "shield", "mcp", "setup", "scan", "optimize", "context", "cc", "usage", "watch", "demo"].includes(command)) {
|
|
631
|
+
throw new Error(`Unknown command: ${command}. Try: prismo doctor, prismo watch, prismo benchmark, prismo shield, prismo mcp, prismo firewall, prismo init, prismo scan, prismo optimize, prismo context, prismo cc, or prismo usage`);
|
|
613
632
|
}
|
|
614
633
|
|
|
615
634
|
if (command === "demo") {
|
|
@@ -692,6 +711,25 @@ async function runCli(argv) {
|
|
|
692
711
|
return;
|
|
693
712
|
}
|
|
694
713
|
|
|
714
|
+
if (command === "benchmark") {
|
|
715
|
+
const json = rest.includes("--json");
|
|
716
|
+
const limitIndex = rest.indexOf("--limit");
|
|
717
|
+
const separatorIndex = rest.indexOf("--");
|
|
718
|
+
const beforeSeparator = separatorIndex >= 0 ? rest.slice(0, separatorIndex) : rest;
|
|
719
|
+
const commandArgs = separatorIndex >= 0 ? rest.slice(separatorIndex + 1) : [];
|
|
720
|
+
const positional = getPositionals(beforeSeparator, new Set(["--limit"]));
|
|
721
|
+
const sessionOnly = positional[0] === "session" || commandArgs.length === 0;
|
|
722
|
+
const target = positional[0] === "session" ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
723
|
+
const result = runBenchmark(target, commandArgs, {
|
|
724
|
+
sessionOnly,
|
|
725
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
726
|
+
});
|
|
727
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
728
|
+
else console.log(renderBenchmarkTerminal(result));
|
|
729
|
+
if (result.mode === "command") process.exitCode = result.exitCode;
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
|
|
695
733
|
if (command === "shield") {
|
|
696
734
|
const json = rest.includes("--json");
|
|
697
735
|
const limitIndex = rest.indexOf("--limit");
|
|
@@ -926,12 +964,13 @@ async function runCli(argv) {
|
|
|
926
964
|
const json = rest.includes("--json");
|
|
927
965
|
const simple = rest.includes("--simple");
|
|
928
966
|
const optimizerFit = rest.includes("--optimizer-fit");
|
|
967
|
+
const reportCard = rest.includes("--report-card");
|
|
929
968
|
const ciMode = rest.includes("--ci");
|
|
930
|
-
const includeUsage = rest.includes("--usage") || optimizerFit;
|
|
969
|
+
const includeUsage = rest.includes("--usage") || optimizerFit || reportCard;
|
|
931
970
|
const limitIndex = rest.indexOf("--limit");
|
|
932
971
|
const usageToolIndex = rest.indexOf("--usage-tool");
|
|
933
972
|
const target = getPositionals(rest, new Set(["--limit", "--usage-tool"]))[0] || process.cwd();
|
|
934
|
-
const scanDone = printStep(includeUsage ? "Scanning repo and local usage" : "Scanning repo", json || simple || optimizerFit);
|
|
973
|
+
const scanDone = printStep(includeUsage ? "Scanning repo and local usage" : "Scanning repo", json || simple || optimizerFit || reportCard);
|
|
935
974
|
const result = scanRepo(target, {
|
|
936
975
|
includeUsage,
|
|
937
976
|
usageLimit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
@@ -952,13 +991,19 @@ async function runCli(argv) {
|
|
|
952
991
|
payload.ci = evaluateCi(result);
|
|
953
992
|
if (!payload.ci.passed) process.exitCode = 1;
|
|
954
993
|
}
|
|
955
|
-
if (optimizerFit) {
|
|
994
|
+
if (optimizerFit || reportCard) {
|
|
956
995
|
console.log(JSON.stringify({
|
|
957
996
|
schemaVersion: 1,
|
|
958
997
|
scannedPath: result.root,
|
|
959
998
|
score: result.score,
|
|
960
999
|
riskLevel: result.risk,
|
|
961
1000
|
optimizerFit: result.optimizerFit,
|
|
1001
|
+
reportCard: reportCard ? {
|
|
1002
|
+
biggestWaste: result.optimizerFit.summary,
|
|
1003
|
+
startWith: result.optimizerFit.recommendedStack[0]?.command || null,
|
|
1004
|
+
then: result.optimizerFit.recommendedStack[1]?.command || null,
|
|
1005
|
+
roundTripRisk: result.optimizerFit.roundTripContext.level,
|
|
1006
|
+
} : undefined,
|
|
962
1007
|
generatedAt: result.generatedAt,
|
|
963
1008
|
}, null, 2));
|
|
964
1009
|
return;
|
|
@@ -969,7 +1014,9 @@ async function runCli(argv) {
|
|
|
969
1014
|
return;
|
|
970
1015
|
}
|
|
971
1016
|
|
|
972
|
-
if (
|
|
1017
|
+
if (reportCard) {
|
|
1018
|
+
console.log(renderReportCardTerminal(result));
|
|
1019
|
+
} else if (optimizerFit) {
|
|
973
1020
|
console.log(renderOptimizerFitTerminal(result));
|
|
974
1021
|
} else if (simple) {
|
|
975
1022
|
console.log(renderSimpleScanReport(result));
|
|
@@ -985,7 +1032,7 @@ async function runCli(argv) {
|
|
|
985
1032
|
const actions = applyFixes(result);
|
|
986
1033
|
console.log("\nFix Mode:");
|
|
987
1034
|
actions.forEach((action) => console.log(`- ${action}`));
|
|
988
|
-
} else if (!noReport && !simple && !optimizerFit) {
|
|
1035
|
+
} else if (!noReport && !simple && !optimizerFit && !reportCard) {
|
|
989
1036
|
const report = writeReport(result);
|
|
990
1037
|
if (report.backupPath) {
|
|
991
1038
|
console.log(`\nExisting report backed up to ${path.basename(report.backupPath)}.`);
|
|
@@ -1006,10 +1053,13 @@ module.exports = {
|
|
|
1006
1053
|
renderWatchTerminal,
|
|
1007
1054
|
renderWatchReport,
|
|
1008
1055
|
renderTerminalReport,
|
|
1056
|
+
renderOptimizerFitTerminal,
|
|
1057
|
+
renderReportCardTerminal,
|
|
1009
1058
|
renderDoctorTerminal,
|
|
1010
1059
|
renderInitTerminal,
|
|
1011
1060
|
runSetup,
|
|
1012
1061
|
runOptimize,
|
|
1062
|
+
runBenchmark,
|
|
1013
1063
|
runDoctor,
|
|
1014
1064
|
runInit,
|
|
1015
1065
|
runCli,
|
package/package.json
CHANGED