getprismo 0.1.13 → 0.1.15

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 CHANGED
@@ -22,18 +22,21 @@ prismodev catches it before, during, and after.
22
22
 
23
23
  ## the loop
24
24
 
25
- prismodev is three commands that cover an entire coding session:
25
+ prismodev covers the full AI coding session:
26
26
 
27
27
  ```
28
28
  before you code npx getprismo doctor
29
29
  while you code npx getprismo watch
30
+ noisy commands npx getprismo shield -- npm test
30
31
  after you code npx getprismo cc timeline
32
+ agent-native npx getprismo mcp
31
33
  ```
32
34
 
33
35
  **doctor** diagnoses the repo, applies safe fixes, and shows the before/after score.
34
36
  **watch** monitors context pressure live and warns when things go wrong.
35
37
  **cc timeline** reconstructs what happened in the session so you learn from it.
36
38
  **shield** runs noisy commands without dumping full output back into the agent context.
39
+ **mcp** exposes PrismoDev as local tools so compatible agents can scan, search shield output, and request scoped context directly.
37
40
 
38
41
  ---
39
42
 
@@ -179,6 +182,15 @@ npx getprismo shield search "auth expected 200"
179
182
  npx getprismo shield search "AUTH_FAILURE" --json
180
183
  ```
181
184
 
185
+ when `watch` detects tool-output floods or repeated command loops, it now recommends this flow directly:
186
+
187
+ ```text
188
+ Shield Plan
189
+ Run: npx getprismo shield -- <noisy command>
190
+ Then: npx getprismo shield search "<error text>"
191
+ MCP: prismo_shield_run -> prismo_shield_search
192
+ ```
193
+
182
194
  this is intentionally not magic interception yet. it is a safe local-first primitive you can tell agents to use for noisy commands.
183
195
 
184
196
  ---
@@ -532,6 +544,7 @@ no install needed. npx runs it directly.
532
544
  | `optimize` | generate `.prismo/` context packs |
533
545
  | `context` | print paste-ready prompt for agents |
534
546
  | `shield` | run noisy commands while keeping full output out of chat |
547
+ | `mcp` | expose PrismoDev tools over local MCP stdio |
535
548
  | `setup` | detect tools, logs, proxy readiness |
536
549
  | `usage` | show raw session token usage |
537
550
  | `init` | add npm scripts and .prismo/README.md |
@@ -583,6 +596,53 @@ npx getprismo shield last
583
596
  npx getprismo shield search "auth failure"
584
597
  ```
585
598
 
599
+ ### mcp mode
600
+
601
+ ```bash
602
+ npx getprismo mcp
603
+ npx getprismo mcp /path/to/repo
604
+ ```
605
+
606
+ `mcp` starts a local stdio MCP server for agent clients. It exposes:
607
+
608
+ - `prismo_scan`
609
+ - `prismo_doctor_dry_run`
610
+ - `prismo_watch_snapshot`
611
+ - `prismo_shield_run`
612
+ - `prismo_shield_search`
613
+ - `prismo_shield_last`
614
+ - `prismo_context_pack`
615
+ - `prismo_firewall`
616
+ - `prismo_cc_timeline`
617
+
618
+ This lets an MCP-compatible agent search prior shielded test/build output, request scoped context packs, or inspect token-waste signals without pasting giant logs into the conversation.
619
+
620
+ Generic MCP client config:
621
+
622
+ ```json
623
+ {
624
+ "mcpServers": {
625
+ "prismodev": {
626
+ "command": "npx",
627
+ "args": ["-y", "getprismo", "mcp", "/path/to/your/repo"]
628
+ }
629
+ }
630
+ }
631
+ ```
632
+
633
+ For local development from this repo:
634
+
635
+ ```json
636
+ {
637
+ "mcpServers": {
638
+ "prismodev": {
639
+ "command": "node",
640
+ "args": ["/path/to/prismodev/bin/prismo.js", "mcp", "/path/to/your/repo"]
641
+ }
642
+ }
643
+ }
644
+ ```
645
+
586
646
  ---
587
647
 
588
648
  ## cc modes
@@ -728,8 +788,10 @@ lib/prismo-dev/constants.js shared defaults, pricing, patterns
728
788
  lib/prismo-dev/context-optimize.js context packs, scoped prompts
729
789
  lib/prismo-dev/doctor.js doctor/dev/init orchestration
730
790
  lib/prismo-dev/fixes.js safe ignore/template generation
791
+ lib/prismo-dev/mcp.js local MCP server and Prismo tool bindings
731
792
  lib/prismo-dev/report.js terminal, markdown, ci reports
732
793
  lib/prismo-dev/scan.js repo scanning, scoring, readiness
794
+ lib/prismo-dev/shield.js local command shield and searchable output index
733
795
  lib/prismo-dev/usage-watch.js local logs, watch, cost, timeline
734
796
  ```
735
797
 
@@ -739,8 +801,16 @@ lib/prismo-dev/usage-watch.js local logs, watch, cost, timeline
739
801
 
740
802
  ```bash
741
803
  npx getprismo --help
804
+ npx getprismo --version
742
805
  npx getprismo doctor --help
743
806
  npx getprismo watch --help
807
+ npx getprismo shield --help
808
+ npx getprismo mcp --help
744
809
  npx getprismo cc --help
745
810
  npx getprismo scan --help
746
811
  ```
812
+
813
+ More docs:
814
+
815
+ - [MCP setup and tools](docs/mcp.md)
816
+ - [Live demo flow](docs/live-demo.md)
@@ -0,0 +1,115 @@
1
+ # PrismoDev Live Demo
2
+
3
+ Use this flow to show the full product loop on a real repo.
4
+
5
+ ## 1. Before Session: Doctor
6
+
7
+ ```bash
8
+ npx getprismo doctor
9
+ ```
10
+
11
+ Shows:
12
+
13
+ - before/after repo score
14
+ - missing `.claudeignore` / `.cursorignore`
15
+ - generated artifacts exposed to AI context
16
+ - compact `.prismo/` context packs
17
+ - recommended next starting context
18
+
19
+ ## 2. During Session: Watch
20
+
21
+ ```bash
22
+ npx getprismo watch --once
23
+ ```
24
+
25
+ Shows:
26
+
27
+ - context pressure
28
+ - session size
29
+ - recent context growth
30
+ - repeated file reads
31
+ - generated artifact leaks
32
+ - possible loops
33
+ - shield recommendation when command output is flooding context
34
+
35
+ If watch sees noisy output, the important part is:
36
+
37
+ ```text
38
+ Shield Plan
39
+ Run: npx getprismo shield -- <noisy command>
40
+ Then: npx getprismo shield search "<error text>"
41
+ MCP: prismo_shield_run -> prismo_shield_search
42
+ ```
43
+
44
+ ## 3. Noisy Commands: Shield
45
+
46
+ ```bash
47
+ npx getprismo shield -- npm test
48
+ npx getprismo shield search "AUTH_FAILURE"
49
+ npx getprismo shield last
50
+ ```
51
+
52
+ Shows:
53
+
54
+ - compact command summary
55
+ - useful error lines
56
+ - full output stored locally
57
+ - searchable SQLite FTS index when `sqlite3` is available
58
+
59
+ Full output stays in:
60
+
61
+ ```text
62
+ .prismo/shield/runs/
63
+ ```
64
+
65
+ ## 4. Agent-Native Mode: MCP
66
+
67
+ ```bash
68
+ npx getprismo mcp /path/to/repo
69
+ ```
70
+
71
+ Demo prompt:
72
+
73
+ ```text
74
+ Use Prismo MCP to run the failing test through shield. Search the stored output for the root error. Do not paste the full test log into the chat.
75
+ ```
76
+
77
+ Expected MCP tool flow:
78
+
79
+ 1. `prismo_shield_run`
80
+ 2. `prismo_shield_search`
81
+ 3. `prismo_context_pack` if the agent needs scoped repo context
82
+
83
+ ## 5. After Session: Timeline
84
+
85
+ ```bash
86
+ npx getprismo cc timeline
87
+ ```
88
+
89
+ Shows:
90
+
91
+ - generated artifacts that entered context
92
+ - repeated file/path mentions
93
+ - repeated command/tool patterns
94
+ - suggested cleanup action
95
+
96
+ ## Screenshot Commands
97
+
98
+ For a quick terminal screenshot:
99
+
100
+ ```bash
101
+ npx getprismo doctor
102
+ ```
103
+
104
+ For the proactive story:
105
+
106
+ ```bash
107
+ npx getprismo watch --once
108
+ ```
109
+
110
+ For the MCP/shield story:
111
+
112
+ ```bash
113
+ npx getprismo shield -- npm test
114
+ npx getprismo shield search "error"
115
+ ```
package/docs/mcp.md ADDED
@@ -0,0 +1,76 @@
1
+ # PrismoDev MCP
2
+
3
+ PrismoDev can run as a local MCP server so compatible coding agents can inspect token waste, run noisy commands through shield, search stored output, and request scoped context without pasting huge logs into chat.
4
+
5
+ ## Start
6
+
7
+ ```bash
8
+ npx getprismo mcp /path/to/your/repo
9
+ ```
10
+
11
+ ## Generic MCP Config
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "prismodev": {
17
+ "command": "npx",
18
+ "args": ["-y", "getprismo", "mcp", "/path/to/your/repo"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ For local development from this repo:
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "prismodev": {
30
+ "command": "node",
31
+ "args": ["/path/to/prismodev/bin/prismo.js", "mcp", "/path/to/your/repo"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## Tools
38
+
39
+ - `prismo_scan`: scan repo context/token waste
40
+ - `prismo_doctor_dry_run`: preview doctor payoff without writing files
41
+ - `prismo_watch_snapshot`: inspect live context pressure
42
+ - `prismo_shield_run`: run a noisy command and store full output locally
43
+ - `prismo_shield_search`: search stored shield output
44
+ - `prismo_shield_last`: list recent shielded command runs
45
+ - `prismo_context_pack`: generate or preview scoped context packs
46
+ - `prismo_firewall`: create a scoped context policy for a task
47
+ - `prismo_cc_timeline`: inspect Claude Code session postmortems
48
+
49
+ ## Best Workflow
50
+
51
+ Ask your agent:
52
+
53
+ ```text
54
+ Run the failing test command through Prismo shield, then search the stored output for the real error. Do not paste the full log into chat.
55
+ ```
56
+
57
+ The agent should call:
58
+
59
+ 1. `prismo_shield_run`
60
+ 2. `prismo_shield_search`
61
+
62
+ This keeps full stdout/stderr in `.prismo/shield/runs/` and only brings the useful failure snippet back into the model context.
63
+
64
+ ## Watch Integration
65
+
66
+ When `npx getprismo watch` detects a tool-output flood or repeated command loop, it now prints a Shield Plan:
67
+
68
+ ```text
69
+ Shield Plan
70
+ Tool output is flooding context; shield the command so full logs stay local.
71
+ Run: npx getprismo shield -- <noisy command>
72
+ Then: npx getprismo shield search "<error text>"
73
+ MCP: prismo_shield_run -> prismo_shield_search
74
+ ```
75
+
76
+ That is the intended live-session recovery path.
@@ -0,0 +1,264 @@
1
+ function createTextResult(payload) {
2
+ const text = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2);
3
+ return {
4
+ content: [{ type: "text", text }],
5
+ };
6
+ }
7
+
8
+ function normalizeArgs(args) {
9
+ return args && typeof args === "object" ? args : {};
10
+ }
11
+
12
+ function makeTool(name, description, properties = {}, required = []) {
13
+ return {
14
+ name,
15
+ description,
16
+ inputSchema: {
17
+ type: "object",
18
+ properties,
19
+ required,
20
+ additionalProperties: false,
21
+ },
22
+ };
23
+ }
24
+
25
+ function createMcpTools(deps) {
26
+ const {
27
+ rootDir,
28
+ scanRepo,
29
+ toJsonPayload,
30
+ runDoctor,
31
+ toDoctorJsonPayload,
32
+ getUsageSummary,
33
+ getClaudeCodeCostSummary,
34
+ runOptimize,
35
+ createOptimizeContext,
36
+ renderStarterPrompt,
37
+ runFirewall,
38
+ runShield,
39
+ runShieldLast,
40
+ runShieldSearch,
41
+ } = deps;
42
+
43
+ const pathProperty = {
44
+ type: "string",
45
+ description: "Repository path. Defaults to the repo used when the MCP server started.",
46
+ };
47
+ const limitProperty = {
48
+ type: "number",
49
+ description: "Maximum number of recent sessions or runs to inspect.",
50
+ };
51
+ const scopeProperty = {
52
+ type: "string",
53
+ description: "Optional scope such as frontend, backend, auth, tests, billing, or routing.",
54
+ };
55
+
56
+ const tools = [
57
+ makeTool("prismo_scan", "Scan a repo for AI coding token/context waste.", {
58
+ path: pathProperty,
59
+ includeUsage: { type: "boolean", description: "Include local Claude/Codex usage logs when available." },
60
+ limit: limitProperty,
61
+ }),
62
+ makeTool("prismo_doctor_dry_run", "Preview PrismoDev doctor fixes and before/after payoff without writing files.", {
63
+ path: pathProperty,
64
+ scope: scopeProperty,
65
+ limit: limitProperty,
66
+ }),
67
+ makeTool("prismo_watch_snapshot", "Return a one-shot local session/context pressure snapshot.", {
68
+ path: pathProperty,
69
+ tool: { type: "string", enum: ["all", "codex", "claude"], description: "Which local session logs to inspect." },
70
+ limit: limitProperty,
71
+ }),
72
+ makeTool("prismo_shield_run", "Run a noisy command through Prismo shield and store full output locally.", {
73
+ path: pathProperty,
74
+ command: {
75
+ type: "array",
76
+ items: { type: "string" },
77
+ description: "Command argv array, for example [\"npm\", \"test\"].",
78
+ },
79
+ }, ["command"]),
80
+ makeTool("prismo_shield_search", "Search stored shield stdout/stderr without loading full logs into context.", {
81
+ path: pathProperty,
82
+ query: { type: "string", description: "Text to search for in stored shield output." },
83
+ limit: limitProperty,
84
+ }, ["query"]),
85
+ makeTool("prismo_shield_last", "List recent shielded command runs.", {
86
+ path: pathProperty,
87
+ limit: limitProperty,
88
+ }),
89
+ makeTool("prismo_context_pack", "Generate or preview a scoped Prismo context pack/starter prompt.", {
90
+ path: pathProperty,
91
+ scope: scopeProperty,
92
+ dryRun: { type: "boolean", description: "When true, do not write .prismo files." },
93
+ }),
94
+ makeTool("prismo_firewall", "Generate a scoped context firewall policy for a task.", {
95
+ path: pathProperty,
96
+ task: { type: "string", description: "Task description such as auth-bug or frontend-test-failure." },
97
+ scope: scopeProperty,
98
+ dryRun: { type: "boolean", description: "When true, preview allowed/blocked context without writing files." },
99
+ }),
100
+ makeTool("prismo_cc_timeline", "Return the latest Claude Code session timeline/postmortem data.", {
101
+ path: pathProperty,
102
+ limit: limitProperty,
103
+ }),
104
+ ];
105
+
106
+ function resolveRoot(args) {
107
+ return args.path || rootDir || process.cwd();
108
+ }
109
+
110
+ async function callTool(name, rawArgs) {
111
+ const args = normalizeArgs(rawArgs);
112
+ const target = resolveRoot(args);
113
+
114
+ if (name === "prismo_scan") {
115
+ return createTextResult(toJsonPayload(scanRepo(target, {
116
+ includeUsage: Boolean(args.includeUsage),
117
+ usageLimit: Number(args.limit) || 5,
118
+ })));
119
+ }
120
+
121
+ if (name === "prismo_doctor_dry_run") {
122
+ const result = runDoctor(target, {
123
+ dryRun: true,
124
+ scope: args.scope || null,
125
+ limit: Number(args.limit) || 3,
126
+ });
127
+ return createTextResult(toDoctorJsonPayload(result));
128
+ }
129
+
130
+ if (name === "prismo_watch_snapshot") {
131
+ const summary = getUsageSummary({
132
+ cwd: target,
133
+ limit: Number(args.limit) || 3,
134
+ usageTool: args.tool || "all",
135
+ });
136
+ return createTextResult(summary);
137
+ }
138
+
139
+ if (name === "prismo_shield_run") {
140
+ return createTextResult(runShield(target, args.command));
141
+ }
142
+
143
+ if (name === "prismo_shield_search") {
144
+ return createTextResult(runShieldSearch(target, args.query, { limit: Number(args.limit) || 5 }));
145
+ }
146
+
147
+ if (name === "prismo_shield_last") {
148
+ return createTextResult(runShieldLast(target, { limit: Number(args.limit) || 5 }));
149
+ }
150
+
151
+ if (name === "prismo_context_pack") {
152
+ const scope = args.scope || null;
153
+ const result = runOptimize(target, { scope, dryRun: args.dryRun !== false });
154
+ const context = createOptimizeContext(target, scope);
155
+ return createTextResult({
156
+ ...result,
157
+ starterPrompt: renderStarterPrompt(context, scope),
158
+ });
159
+ }
160
+
161
+ if (name === "prismo_firewall") {
162
+ return createTextResult(runFirewall(target, {
163
+ task: args.task || args.scope || "general",
164
+ scope: args.scope || null,
165
+ dryRun: args.dryRun !== false,
166
+ }));
167
+ }
168
+
169
+ if (name === "prismo_cc_timeline") {
170
+ return createTextResult(getClaudeCodeCostSummary({
171
+ cwd: target,
172
+ limit: Number(args.limit) || 1,
173
+ mode: "timeline",
174
+ }));
175
+ }
176
+
177
+ throw new Error(`Unknown MCP tool: ${name}`);
178
+ }
179
+
180
+ return { tools, callTool };
181
+ }
182
+
183
+ function runMcpServer(deps) {
184
+ const readline = require("readline");
185
+ const { packageVersion = "0.0.0" } = deps;
186
+ const { tools, callTool } = createMcpTools(deps);
187
+ const rl = readline.createInterface({
188
+ input: process.stdin,
189
+ output: process.stdout,
190
+ terminal: false,
191
+ });
192
+
193
+ function send(message) {
194
+ process.stdout.write(`${JSON.stringify(message)}\n`);
195
+ }
196
+
197
+ async function handle(message) {
198
+ if (!message || !message.method) return;
199
+ if (!Object.prototype.hasOwnProperty.call(message, "id")) return;
200
+
201
+ try {
202
+ if (message.method === "initialize") {
203
+ send({
204
+ jsonrpc: "2.0",
205
+ id: message.id,
206
+ result: {
207
+ protocolVersion: "2024-11-05",
208
+ capabilities: { tools: {} },
209
+ serverInfo: { name: "prismodev", version: packageVersion },
210
+ },
211
+ });
212
+ return;
213
+ }
214
+
215
+ if (message.method === "tools/list") {
216
+ send({ jsonrpc: "2.0", id: message.id, result: { tools } });
217
+ return;
218
+ }
219
+
220
+ if (message.method === "tools/call") {
221
+ const params = normalizeArgs(message.params);
222
+ const result = await callTool(params.name, params.arguments);
223
+ send({ jsonrpc: "2.0", id: message.id, result });
224
+ return;
225
+ }
226
+
227
+ send({
228
+ jsonrpc: "2.0",
229
+ id: message.id,
230
+ error: { code: -32601, message: `Method not found: ${message.method}` },
231
+ });
232
+ } catch (error) {
233
+ send({
234
+ jsonrpc: "2.0",
235
+ id: message.id,
236
+ error: {
237
+ code: -32000,
238
+ message: error && error.message ? error.message : String(error),
239
+ },
240
+ });
241
+ }
242
+ }
243
+
244
+ rl.on("line", (line) => {
245
+ if (!line.trim()) return;
246
+ try {
247
+ handle(JSON.parse(line));
248
+ } catch (error) {
249
+ send({
250
+ jsonrpc: "2.0",
251
+ id: null,
252
+ error: {
253
+ code: -32700,
254
+ message: error && error.message ? error.message : String(error),
255
+ },
256
+ });
257
+ }
258
+ });
259
+ }
260
+
261
+ module.exports = {
262
+ createMcpTools,
263
+ runMcpServer,
264
+ };
@@ -947,7 +947,7 @@ function getTokenBudgetStatus(activeSession, tokenBudget) {
947
947
 
948
948
  function getRecommendedWatchAction(activeSession, warnings) {
949
949
  if (!activeSession) return `${NPX_COMMAND} setup`;
950
- if (activeSession.loopSuspicion) return "Pause the loop, summarize the failure once, then start a fresh scoped session.";
950
+ if (activeSession.estimatedToolTokens >= 150000 || activeSession.loopSuspicion) return `${NPX_COMMAND} shield -- <noisy command>`;
951
951
  if ((activeSession.generatedArtifacts || []).length || getActionableRepeatedPaths(activeSession, 1).length) return `${NPX_COMMAND} doctor`;
952
952
  if (activeSession.recentContextGrowth >= 250000) return "Start a fresh coding-agent session with a scoped Prismo context prompt.";
953
953
  if (warnings.some((warning) => warning.includes("Tool/output"))) return `${NPX_COMMAND} context`;
@@ -956,6 +956,41 @@ function getRecommendedWatchAction(activeSession, warnings) {
956
956
  return `${NPX_COMMAND} scan --usage`;
957
957
  }
958
958
 
959
+ function buildShieldPlan(activeSession, liveAction) {
960
+ if (!activeSession || !liveAction) return null;
961
+ const shieldCauses = new Set(["tool-output-flood", "possible-loop"]);
962
+ const hasRepeatedCommand = Boolean(activeSession.repeatedCommands?.[0]);
963
+ const highToolOutput = activeSession.estimatedToolTokens >= 150000;
964
+ if (!shieldCauses.has(liveAction.cause) && !hasRepeatedCommand && !highToolOutput) return null;
965
+
966
+ const repeatedCommand = activeSession.repeatedCommands?.[0]?.value || null;
967
+ const cliCommand = repeatedCommand
968
+ ? `${NPX_COMMAND} shield -- ${repeatedCommand}`
969
+ : `${NPX_COMMAND} shield -- <noisy command>`;
970
+ const searchHint = liveAction.cause === "possible-loop"
971
+ ? "Search the stored output for the stable error text before rerunning the command."
972
+ : "Search the stored output for the failure token, filename, or exception instead of loading the full log.";
973
+
974
+ return {
975
+ reason: liveAction.cause === "possible-loop"
976
+ ? "Repeated command/output loop detected; shield the command and search stored output before reruns."
977
+ : "Tool output is flooding context; shield the command so full logs stay local.",
978
+ command: cliCommand,
979
+ commandTemplate: `${NPX_COMMAND} shield -- <command>`,
980
+ searchCommand: `${NPX_COMMAND} shield search "<error text>"`,
981
+ mcp: {
982
+ runTool: "prismo_shield_run",
983
+ searchTool: "prismo_shield_search",
984
+ workflow: "Call prismo_shield_run with the noisy command, then prismo_shield_search for the relevant error text.",
985
+ },
986
+ next: [
987
+ repeatedCommand ? `Run the command through shield: ${cliCommand}` : `Run the noisy command through shield: ${cliCommand}`,
988
+ searchHint,
989
+ "Give the agent the compact shield summary first; inspect full stdout/stderr only if needed.",
990
+ ],
991
+ };
992
+ }
993
+
959
994
  function buildLiveAction(activeSession, warnings, budgetStatus = null) {
960
995
  if (!activeSession) {
961
996
  return {
@@ -1103,6 +1138,7 @@ function buildLiveSessionView(summary) {
1103
1138
  const actionableRepeatedPaths = activeSession ? getActionableRepeatedPaths(activeSession, 5) : [];
1104
1139
  const generatedArtifactGroups = activeSession ? summarizeGeneratedArtifacts(activeSession.generatedArtifacts || [], 5) : [];
1105
1140
  const liveAction = buildLiveAction(activeSession, warnings, budgetStatus);
1141
+ const shieldPlan = buildShieldPlan(activeSession, liveAction);
1106
1142
  return {
1107
1143
  activeSession: activeSession
1108
1144
  ? {
@@ -1137,7 +1173,10 @@ function buildLiveSessionView(summary) {
1137
1173
  highestRisk: summary.sessions.reduce((risk, session) => (getRiskRank(session.contextRisk) > getRiskRank(risk) ? session.contextRisk : risk), "Low"),
1138
1174
  budget: budgetStatus,
1139
1175
  warnings,
1140
- liveAction,
1176
+ liveAction: {
1177
+ ...liveAction,
1178
+ shieldPlan,
1179
+ },
1141
1180
  recommendedAction: getRecommendedWatchAction(activeSession, warnings),
1142
1181
  nextCommands: Array.from(new Set([
1143
1182
  `${NPX_COMMAND} doctor`,
@@ -1316,6 +1355,14 @@ function renderWatchTerminal(summary) {
1316
1355
  lines.push(live.liveAction.summary);
1317
1356
  live.liveAction.now.slice(0, 4).forEach((step, index) => lines.push(`${index + 1}. ${step}`));
1318
1357
  if (live.liveAction.rescueAvailable) lines.push(`Rescue: ${live.liveAction.rescueCommand}`);
1358
+ if (live.liveAction.shieldPlan) {
1359
+ lines.push("");
1360
+ lines.push("Shield Plan");
1361
+ lines.push(live.liveAction.shieldPlan.reason);
1362
+ lines.push(`Run: ${live.liveAction.shieldPlan.command}`);
1363
+ lines.push(`Then: ${live.liveAction.shieldPlan.searchCommand}`);
1364
+ lines.push(`MCP: ${live.liveAction.shieldPlan.mcp.runTool} -> ${live.liveAction.shieldPlan.mcp.searchTool}`);
1365
+ }
1319
1366
  lines.push("");
1320
1367
  if (active.actionableRepeatedPaths?.length || active.generatedArtifactGroups?.length || active.repeatedCommands.length) {
1321
1368
  lines.push("Signals");
@@ -1366,6 +1413,13 @@ function renderRescuePrompt(summary) {
1366
1413
  lines.push("");
1367
1414
  lines.push("Do this now:");
1368
1415
  live.liveAction.now.forEach((step, index) => lines.push(`${index + 1}. ${step}`));
1416
+ if (live.liveAction.shieldPlan) {
1417
+ lines.push("");
1418
+ lines.push("For noisy commands, use Prismo shield instead of loading full output into this chat:");
1419
+ lines.push(`- CLI: ${live.liveAction.shieldPlan.command}`);
1420
+ lines.push(`- Search stored output: ${live.liveAction.shieldPlan.searchCommand}`);
1421
+ lines.push(`- MCP workflow: ${live.liveAction.shieldPlan.mcp.workflow}`);
1422
+ }
1369
1423
  lines.push("");
1370
1424
  lines.push("Before reading or editing anything else, summarize:");
1371
1425
  lines.push("- files changed so far");
@@ -1405,6 +1459,11 @@ function renderLiveGuardrails(summary) {
1405
1459
  lines.push("## Effective Immediately");
1406
1460
  lines.push("");
1407
1461
  live.liveAction.now.forEach((step) => lines.push(`- ${step}`));
1462
+ if (live.liveAction.shieldPlan) {
1463
+ lines.push(`- Run noisy commands through Prismo shield: \`${live.liveAction.shieldPlan.command}\`.`);
1464
+ lines.push(`- Search stored command output with: \`${live.liveAction.shieldPlan.searchCommand}\`.`);
1465
+ lines.push(`- If MCP tools are available, use \`${live.liveAction.shieldPlan.mcp.runTool}\` then \`${live.liveAction.shieldPlan.mcp.searchTool}\`.`);
1466
+ }
1408
1467
  lines.push("- Keep command output short; prefer filtered errors, small ranges, and summaries over full logs.");
1409
1468
  lines.push("- Do not read generated artifacts, lockfiles, caches, build output, coverage, or logs unless explicitly required.");
1410
1469
  lines.push("- Before broad exploration, summarize the current task, changed files, current failure, and next smallest useful file/test.");
@@ -1477,6 +1536,10 @@ function renderContextThrottle(summary) {
1477
1536
  live.liveAction.now.slice(0, 4).forEach((step) => lines.push(`- ${step}`));
1478
1537
  lines.push("- Keep the next tool call narrow enough to summarize in one screen.");
1479
1538
  }
1539
+ if (live.liveAction.shieldPlan) {
1540
+ lines.push(`- Run noisy commands through shield: \`${live.liveAction.shieldPlan.command}\`.`);
1541
+ lines.push(`- Search shield output instead of reloading full logs: \`${live.liveAction.shieldPlan.searchCommand}\`.`);
1542
+ }
1480
1543
  if (active?.actionableRepeatedPaths?.length) {
1481
1544
  lines.push("");
1482
1545
  lines.push("## Blocked Re-Reads");
@@ -1547,6 +1610,7 @@ function buildWatchEvent(summary) {
1547
1610
  toolOutputTokens: active.estimatedToolTokens || 0,
1548
1611
  budget,
1549
1612
  warnings: live.warnings || [],
1613
+ shieldPlan: live.liveAction.shieldPlan || null,
1550
1614
  repeatedFiles: repeated.slice(0, 5),
1551
1615
  artifactGroups: artifacts.slice(0, 5),
1552
1616
  signature: signatureParts.join("::"),
@@ -1621,6 +1685,11 @@ function renderWatchReport(summary) {
1621
1685
  lines.push(`- Cause: ${live.liveAction.cause} (${live.liveAction.confidence} confidence)`);
1622
1686
  lines.push(`- ${live.liveAction.summary}`);
1623
1687
  live.liveAction.now.forEach((step) => lines.push(`- ${step}`));
1688
+ if (live.liveAction.shieldPlan) {
1689
+ lines.push(`- Shield noisy command output: \`${live.liveAction.shieldPlan.command}\``);
1690
+ lines.push(`- Search shielded output: \`${live.liveAction.shieldPlan.searchCommand}\``);
1691
+ lines.push(`- MCP workflow: \`${live.liveAction.shieldPlan.mcp.runTool}\` -> \`${live.liveAction.shieldPlan.mcp.searchTool}\``);
1692
+ }
1624
1693
  if (summary.guardrailsPath) {
1625
1694
  lines.push(`- Guardrails: ${summary.guardrailsPath}`);
1626
1695
  lines.push(`- Rescue prompt: ${summary.rescuePath}`);
@@ -3,6 +3,7 @@ const http = require("http");
3
3
  const https = require("https");
4
4
  const os = require("os");
5
5
  const path = require("path");
6
+ const { version: PACKAGE_VERSION } = require("../package.json");
6
7
 
7
8
  const {
8
9
  HIGH_RISK_DIRS,
@@ -282,10 +283,13 @@ const {
282
283
  color,
283
284
  });
284
285
 
286
+ const { runMcpServer } = require("./prismo-dev/mcp");
287
+
285
288
  function printHelp() {
286
289
  console.log(`Prismo CLI
287
290
 
288
291
  Usage:
292
+ prismo --version
289
293
  prismo dev [path]
290
294
  prismo init [--json] [--dry-run] [path]
291
295
  prismo doctor [--json] [--dry-run] [--apply-ignores-only] [--no-context-packs] [--limit N] [path]
@@ -293,6 +297,7 @@ Usage:
293
297
  prismo shield [--json] [path] -- <command ...>
294
298
  prismo shield last [--json] [--limit N] [path]
295
299
  prismo shield search <query> [--json] [--limit N] [path]
300
+ prismo mcp [path]
296
301
  prismo setup [--json] [--proxy-url URL] [path]
297
302
  prismo scan [--fix] [--ci] [--json] [--usage] [--simple] [--no-report] [path]
298
303
  prismo optimize [scope] [--json] [path]
@@ -308,6 +313,7 @@ Commands:
308
313
  doctor Diagnose, safely optimize, re-scan, and show before/after payoff.
309
314
  firewall Generate allowed/blocked context policy files for an AI coding task.
310
315
  shield Run a noisy command, store full output locally, and return a compact summary.
316
+ mcp Start a local MCP server exposing Prismo tools over stdio.
311
317
  scan Run PrismoDev for Claude Code, Codex, Cursor, and AI coding workflows.
312
318
  optimize Generate lightweight AI-readable project context files in .prismo/.
313
319
  context Print a copy-pasteable compact context prompt for AI coding tools.
@@ -511,6 +517,28 @@ Examples:
511
517
  Output:
512
518
  Runs the command locally, stores full stdout/stderr under .prismo/shield/runs/, indexes output in SQLite FTS5 when available, and prints only a compact summary plus useful error lines.
513
519
  Search and last retrieve prior shield runs without re-feeding full output into agent context.`,
520
+ mcp: `Prismo MCP Server
521
+
522
+ Usage:
523
+ prismo mcp [path]
524
+
525
+ Examples:
526
+ prismo mcp
527
+ prismo mcp /path/to/repo
528
+
529
+ Tools exposed:
530
+ prismo_scan
531
+ prismo_doctor_dry_run
532
+ prismo_watch_snapshot
533
+ prismo_shield_run
534
+ prismo_shield_search
535
+ prismo_shield_last
536
+ prismo_context_pack
537
+ prismo_firewall
538
+ prismo_cc_timeline
539
+
540
+ Output:
541
+ Starts a local JSON-RPC MCP server over stdio. Use it from MCP-compatible clients so agents can scan context waste, search shielded command output, and request scoped context without loading huge logs into chat.`,
514
542
  ci: `Prismo CI
515
543
 
516
544
  Usage:
@@ -549,6 +577,10 @@ Good first command for people who want to see the value before scanning a repo.`
549
577
 
550
578
  async function runCli(argv) {
551
579
  const [command, ...rest] = argv;
580
+ if (command === "--version" || command === "-v" || command === "version") {
581
+ console.log(PACKAGE_VERSION);
582
+ return;
583
+ }
552
584
  if (!command || command === "--help" || command === "-h") {
553
585
  printHelp();
554
586
  return;
@@ -557,8 +589,8 @@ async function runCli(argv) {
557
589
  printCommandHelp(command);
558
590
  return;
559
591
  }
560
- if (!["dev", "init", "doctor", "firewall", "shield", "setup", "scan", "optimize", "context", "cc", "usage", "watch", "demo"].includes(command)) {
561
- throw new Error(`Unknown command: ${command}. Try: prismo doctor, prismo watch, prismo shield, prismo firewall, prismo init, prismo scan, prismo optimize, prismo context, prismo cc, or prismo usage`);
592
+ if (!["dev", "init", "doctor", "firewall", "shield", "mcp", "setup", "scan", "optimize", "context", "cc", "usage", "watch", "demo"].includes(command)) {
593
+ 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`);
562
594
  }
563
595
 
564
596
  if (command === "demo") {
@@ -674,6 +706,28 @@ async function runCli(argv) {
674
706
  return;
675
707
  }
676
708
 
709
+ if (command === "mcp") {
710
+ const target = getPositionals(rest)[0] || process.cwd();
711
+ runMcpServer({
712
+ rootDir: path.resolve(target),
713
+ packageVersion: PACKAGE_VERSION,
714
+ scanRepo,
715
+ toJsonPayload,
716
+ runDoctor,
717
+ toDoctorJsonPayload,
718
+ getUsageSummary,
719
+ getClaudeCodeCostSummary,
720
+ runOptimize,
721
+ createOptimizeContext,
722
+ renderStarterPrompt,
723
+ runFirewall,
724
+ runShield,
725
+ runShieldLast,
726
+ runShieldSearch,
727
+ });
728
+ return;
729
+ }
730
+
677
731
  if (command === "setup") {
678
732
  const json = rest.includes("--json");
679
733
  const limitIndex = rest.indexOf("--limit");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getprismo",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Local AI coding workflow scanner for Codex, Claude Code, Cursor, and token-waste diagnostics.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/shanirsh/prismodev#readme",
@@ -29,7 +29,7 @@
29
29
  "files": [
30
30
  "bin/",
31
31
  "lib/",
32
- "docs/prismodev-user-testing.md",
32
+ "docs/",
33
33
  "README.md",
34
34
  "LICENSE",
35
35
  "NOTICE"