getprismo 0.1.25 → 0.1.26

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
@@ -552,6 +552,16 @@ watch reads local session logs from codex and claude code. it detects:
552
552
 
553
553
  watch tells you the single most useful action to take right now. usually: start a fresh session, or switch to a scoped context pack.
554
554
 
555
+ if you run multiple agents in the same repo, use:
556
+
557
+ ```bash
558
+ npx getprismo watch --agents
559
+ ```
560
+
561
+ multi-agent watch shows every visible local Codex/Claude Code session for the repo, ranks each agent by context pressure, and flags coordination risks like two agents repeatedly loading the same file, shared artifact leaks, multiple high-pressure sessions, or agents that should move noisy commands into `shield`.
562
+
563
+ the same multi-agent coordination signal is included in `usage --json`, `scan --usage --json`, doctor output, and the generated markdown report whenever multiple local sessions are visible for the repo.
564
+
555
565
  `watch --rescue` prints a paste-ready prompt for the active coding session. use it when the agent is looping, reading too many files, or flooding context with logs:
556
566
 
557
567
  ```bash
@@ -644,6 +654,8 @@ npx getprismo doctor --json # machine-readable output
644
654
  ```bash
645
655
  npx getprismo watch # live refresh
646
656
  npx getprismo watch --once # single snapshot
657
+ npx getprismo watch --agents # multi-agent coordination view
658
+ npx getprismo watch --agents --json # machine-readable multi-agent state
647
659
  npx getprismo watch --once --report # write .prismo/watch-report.md
648
660
  npx getprismo watch --once --json # machine-readable
649
661
  npx getprismo watch --auto # guardrails + throttle + 600k budget
@@ -681,6 +693,7 @@ npx getprismo mcp /path/to/repo
681
693
  - `prismo_scan`
682
694
  - `prismo_doctor_dry_run`
683
695
  - `prismo_watch_snapshot`
696
+ - `prismo_multi_agent_watch`
684
697
  - `prismo_shield_run`
685
698
  - `prismo_shield_search`
686
699
  - `prismo_shield_last`
@@ -688,7 +701,7 @@ npx getprismo mcp /path/to/repo
688
701
  - `prismo_firewall`
689
702
  - `prismo_cc_timeline`
690
703
 
691
- 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.
704
+ This lets an MCP-compatible agent search prior shielded test/build output, request scoped context packs, inspect token-waste signals, or coordinate multiple local agents without pasting giant logs into the conversation.
692
705
 
693
706
  Generic MCP client config:
694
707
 
package/docs/mcp.md CHANGED
@@ -49,6 +49,7 @@ For local development from this repo:
49
49
  - `prismo_scan`: scan repo context/token waste
50
50
  - `prismo_doctor_dry_run`: preview doctor payoff without writing files
51
51
  - `prismo_watch_snapshot`: inspect live context pressure
52
+ - `prismo_multi_agent_watch`: inspect coordination risks across parallel local agents
52
53
  - `prismo_shield_run`: run a noisy command and store full output locally
53
54
  - `prismo_shield_search`: search stored shield output
54
55
  - `prismo_shield_last`: list recent shielded command runs
@@ -324,6 +324,7 @@ function toDoctorJsonPayload(result) {
324
324
  confidence: usage.confidence,
325
325
  totals: usage.totals,
326
326
  sources: usage.sources,
327
+ multiAgent: usage.multiAgent || null,
327
328
  }
328
329
  : null;
329
330
  return {
@@ -381,6 +382,13 @@ function renderDoctorTerminal(result) {
381
382
  if (result.before.realUsage && result.before.realUsage.sessions.length) {
382
383
  lines.push(`Local usage: ${formatTokenCount(result.before.realUsage.totals.displayTokens)} tokens across ${result.before.realUsage.sessions.length} recent session(s)`);
383
384
  }
385
+ const multiAgent = result.before.realUsage && result.before.realUsage.multiAgent;
386
+ if (multiAgent && multiAgent.agentCount > 1) {
387
+ lines.push(`Multi-agent: ${multiAgent.agentCount} agents visible; highest pressure ${multiAgent.highestPressure}`);
388
+ if (multiAgent.coordinationWarnings && multiAgent.coordinationWarnings[0]) {
389
+ lines.push(`Coordination warning: ${multiAgent.coordinationWarnings[0]}`);
390
+ }
391
+ }
384
392
  if (!(result.dryRun && result.applySuggestions)) lines.push(`Estimated exposed context reduction: ${result.exposedTokenReductionPercent}%`);
385
393
  if (!result.dryRun) {
386
394
  lines.push(`Payoff: ${scoreDelta > 0 ? `repo is ${scoreDelta} points cleaner for AI coding sessions` : "safe fixes applied; remaining risk needs manual cleanup"}`);
@@ -457,6 +465,10 @@ function renderDevTerminal(result) {
457
465
  } else if (result.scan.realUsage) {
458
466
  lines.push("Real local usage: no matching local sessions found for this repo");
459
467
  }
468
+ const multiAgent = result.scan.realUsage && result.scan.realUsage.multiAgent;
469
+ if (multiAgent && multiAgent.agentCount > 1) {
470
+ lines.push(`Multi-agent: ${multiAgent.agentCount} agents visible; highest pressure ${multiAgent.highestPressure}`);
471
+ }
460
472
  lines.push("");
461
473
  lines.push("Generated:");
462
474
  result.optimize.generatedFiles.slice(0, 8).forEach((file) => lines.push(`- ${file}`));
@@ -69,6 +69,11 @@ function createMcpTools(deps) {
69
69
  tool: { type: "string", enum: ["all", "codex", "claude"], description: "Which local session logs to inspect." },
70
70
  limit: limitProperty,
71
71
  }),
72
+ makeTool("prismo_multi_agent_watch", "Return multi-agent coordination risks across visible local Codex/Claude sessions.", {
73
+ path: pathProperty,
74
+ tool: { type: "string", enum: ["all", "codex", "claude"], description: "Which local session logs to inspect." },
75
+ limit: limitProperty,
76
+ }),
72
77
  makeTool("prismo_shield_run", "Run a noisy command through Prismo shield and store full output locally.", {
73
78
  path: pathProperty,
74
79
  command: {
@@ -131,11 +136,27 @@ function createMcpTools(deps) {
131
136
  const summary = getUsageSummary({
132
137
  cwd: target,
133
138
  limit: Number(args.limit) || 3,
134
- usageTool: args.tool || "all",
139
+ tool: args.tool || "all",
135
140
  });
136
141
  return createTextResult(summary);
137
142
  }
138
143
 
144
+ if (name === "prismo_multi_agent_watch") {
145
+ const summary = getUsageSummary({
146
+ cwd: target,
147
+ limit: Number(args.limit) || 8,
148
+ tool: args.tool || "all",
149
+ });
150
+ return createTextResult({
151
+ schemaVersion: 1,
152
+ generatedAt: summary.generatedAt,
153
+ scannedPath: summary.scannedPath,
154
+ tool: summary.tool,
155
+ totals: summary.totals,
156
+ multiAgent: summary.multiAgent,
157
+ });
158
+ }
159
+
139
160
  if (name === "prismo_shield_run") {
140
161
  return createTextResult(runShield(target, args.command));
141
162
  }
@@ -265,6 +286,7 @@ async function runMcpDoctor(deps) {
265
286
  "prismo_scan",
266
287
  "prismo_doctor_dry_run",
267
288
  "prismo_watch_snapshot",
289
+ "prismo_multi_agent_watch",
268
290
  "prismo_shield_run",
269
291
  "prismo_shield_search",
270
292
  "prismo_shield_last",
@@ -315,7 +337,7 @@ async function runMcpDoctor(deps) {
315
337
  next: [
316
338
  "Add the config snippet to your MCP-compatible client.",
317
339
  "Restart the client and confirm prismodev appears in the MCP tool list.",
318
- "Ask the agent to call prismo_scan or prismo_shield_run.",
340
+ "Ask the agent to call prismo_scan, prismo_multi_agent_watch, or prismo_shield_run.",
319
341
  ],
320
342
  };
321
343
  }
@@ -45,6 +45,10 @@ function renderTerminalReport(result, options = {}) {
45
45
  if (result.realUsage && result.realUsage.sessions.length) {
46
46
  lines.push(`- Real local usage: ${formatTokenCount(result.realUsage.totals.displayTokens)} tokens across ${result.realUsage.sessions.length} session(s)`);
47
47
  lines.push(`- Usage confidence: ${result.realUsage.confidence}`);
48
+ if (result.realUsage.multiAgent && result.realUsage.multiAgent.agentCount > 1) {
49
+ lines.push(`- Multi-agent: ${result.realUsage.multiAgent.agentCount} agents visible; highest pressure ${result.realUsage.multiAgent.highestPressure}`);
50
+ if (result.realUsage.multiAgent.coordinationWarnings[0]) lines.push(`- Coordination warning: ${result.realUsage.multiAgent.coordinationWarnings[0]}`);
51
+ }
48
52
  } else if (result.realUsage) {
49
53
  lines.push("- Real local usage: no matching local Codex/Claude Code sessions found for this repo");
50
54
  }
@@ -116,6 +120,9 @@ function renderOptimizerFitTerminal(result, options = {}) {
116
120
  lines.push(`Primary bottleneck: ${color(fit.summary, tone, useColor)}`);
117
121
  if (result.realUsage && result.realUsage.sessions.length) {
118
122
  lines.push(`Local usage: ${formatTokenCount(result.realUsage.totals.displayTokens)} tokens across ${result.realUsage.sessions.length} session(s)`);
123
+ if (result.realUsage.multiAgent && result.realUsage.multiAgent.agentCount > 1) {
124
+ lines.push(`Multi-agent: ${result.realUsage.multiAgent.agentCount} agents visible; highest pressure ${result.realUsage.multiAgent.highestPressure}`);
125
+ }
119
126
  } else if (result.realUsage) {
120
127
  lines.push("Local usage: no matching local Claude/Codex sessions found");
121
128
  }
@@ -261,6 +268,9 @@ function renderMarkdownReport(result) {
261
268
  if (result.realUsage) {
262
269
  lines.push(`- **Real Local Usage:** ${result.realUsage.totals.displayTokens.toLocaleString()} tokens across ${result.realUsage.sessions.length} session(s)`);
263
270
  lines.push(`- **Usage Confidence:** ${result.realUsage.confidence}`);
271
+ if (result.realUsage.multiAgent && result.realUsage.multiAgent.agentCount > 1) {
272
+ lines.push(`- **Multi-Agent:** ${result.realUsage.multiAgent.agentCount} agents visible; highest pressure ${result.realUsage.multiAgent.highestPressure}`);
273
+ }
264
274
  }
265
275
  lines.push("");
266
276
  lines.push("Estimates are based on local file-size and configuration heuristics. They are not provider billing data and are not guaranteed savings.");
@@ -346,6 +356,20 @@ function renderMarkdownReport(result) {
346
356
  lines.push(`- Estimated tool/output tokens: ${result.realUsage.totals.toolTokens.toLocaleString()}`);
347
357
  lines.push(`- Confidence: ${result.realUsage.confidence}`);
348
358
  lines.push("");
359
+ if (result.realUsage.multiAgent && result.realUsage.multiAgent.agentCount > 1) {
360
+ lines.push("### Multi-Agent Coordination");
361
+ lines.push("");
362
+ lines.push(`- Agents visible: ${result.realUsage.multiAgent.agentCount}`);
363
+ lines.push(`- Highest pressure: ${result.realUsage.multiAgent.highestPressure}`);
364
+ result.realUsage.multiAgent.coordinationWarnings.slice(0, 5).forEach((warning) => lines.push(`- ${warning}`));
365
+ if (result.realUsage.multiAgent.sharedFiles.length) {
366
+ lines.push(`- Shared repeated files: ${result.realUsage.multiAgent.sharedFiles.slice(0, 5).map((item) => `\`${item.path}\` (${item.agents} agents)`).join(", ")}`);
367
+ }
368
+ if (result.realUsage.multiAgent.sharedArtifacts.length) {
369
+ lines.push(`- Shared artifact leaks: ${result.realUsage.multiAgent.sharedArtifacts.slice(0, 5).map((item) => `${item.type} (${item.agents} agents)`).join(", ")}`);
370
+ }
371
+ lines.push("");
372
+ }
349
373
  result.realUsage.sessions.slice(0, 5).forEach((session, index) => {
350
374
  lines.push(`${index + 1}. ${session.tool} - ${session.title || session.sessionId}`);
351
375
  lines.push(` - Tokens: ${session.displayTokens.toLocaleString()} (${session.confidence})`);
@@ -53,6 +53,7 @@ const {
53
53
 
54
54
  const {
55
55
  buildLiveSessionView,
56
+ buildMultiAgentView,
56
57
  } = require("./watch-live")({
57
58
  NPX_COMMAND,
58
59
  formatTokenCount,
@@ -65,7 +66,7 @@ const {
65
66
  getAllClaudeSessionFiles,
66
67
  getClaudeSessionFiles,
67
68
  getCodexSessionFiles,
68
- getUsageSummary,
69
+ getUsageSummary: getBaseUsageSummary,
69
70
  } = require("./usage-sessions")({
70
71
  fs,
71
72
  os,
@@ -76,15 +77,25 @@ const {
76
77
  readIfText,
77
78
  });
78
79
 
80
+ function getUsageSummary(options = {}) {
81
+ const summary = getBaseUsageSummary(options);
82
+ if ((summary.sessions || []).length > 1) {
83
+ summary.multiAgent = buildMultiAgentView(summary);
84
+ }
85
+ return summary;
86
+ }
87
+
79
88
  const {
80
89
  renderContextThrottle,
81
90
  renderLiveGuardrails,
91
+ renderMultiAgentWatchTerminal,
82
92
  renderRescuePrompt,
83
93
  renderUsageTerminal,
84
94
  renderWatchTerminal,
85
95
  } = require("./watch-render")({
86
96
  NPX_COMMAND,
87
97
  buildLiveSessionView,
98
+ buildMultiAgentView,
88
99
  color,
89
100
  formatTokenCount,
90
101
  getActionableRepeatedPaths,
@@ -199,24 +210,6 @@ function parseScopeAndTarget(args, valueFlags = new Set()) {
199
210
  return { scope: null, target: positional[0] || process.cwd() };
200
211
  }
201
212
 
202
- function formatTokenCount(value) {
203
- const n = Number(value || 0);
204
- if (n >= 1000000) return `${(n / 1000000).toFixed(2)}M`;
205
- if (n >= 1000) return `${Math.round(n / 1000)}k`;
206
- return String(Math.round(n));
207
- }
208
-
209
- function formatMoney(value) {
210
- const n = Number(value || 0);
211
- if (n >= 1) return `$${n.toFixed(2)}`;
212
- return `$${n.toFixed(4)}`;
213
- }
214
-
215
-
216
-
217
-
218
-
219
-
220
213
  function writeLiveFile(root, relPath, contents) {
221
214
  const fullPath = path.join(root || process.cwd(), relPath);
222
215
  fs.mkdirSync(path.dirname(fullPath), { recursive: true });
@@ -432,6 +425,7 @@ function compactUsageSummary(summary) {
432
425
  totals: summary.totals,
433
426
  sources: summary.sources,
434
427
  sessions: (summary.sessions || []).map(compactWatchSession),
428
+ multiAgent: summary.multiAgent || ((summary.sessions || []).length > 1 ? buildMultiAgentView(summary) : null),
435
429
  };
436
430
  }
437
431
 
@@ -484,6 +478,7 @@ function toWatchJsonPayload(summary) {
484
478
  sources: summary.sources,
485
479
  sessions: summary.sessions.map(compactWatchSession),
486
480
  live: summary.live || buildLiveSessionView(summary),
481
+ multiAgent: summary.multiAgent || (summary.agents ? buildMultiAgentView(summary) : null),
487
482
  auto: Boolean(summary.auto),
488
483
  rescuePrompt: summary.includeRescuePrompt ? renderRescuePrompt(summary) : null,
489
484
  guardrailsPath: summary.guardrailsPath || null,
@@ -502,7 +497,11 @@ async function watchUsage(options = {}) {
502
497
  for (let i = 0; i < iterations; i += 1) {
503
498
  const summary = getUsageSummary(options);
504
499
  summary.auto = Boolean(options.auto);
500
+ summary.agents = Boolean(options.agents);
505
501
  summary.live = buildLiveSessionView(summary);
502
+ if (options.agents) {
503
+ summary.multiAgent = buildMultiAgentView(summary);
504
+ }
506
505
  if (options.guardrails) {
507
506
  const written = writeLiveGuardrails(summary);
508
507
  summary.guardrailsPath = written.guardrailsPath;
@@ -524,7 +523,11 @@ async function watchUsage(options = {}) {
524
523
  }
525
524
  summary.redactPaths = Boolean(options.redactPaths);
526
525
  summary.includeRescuePrompt = Boolean(options.rescue);
527
- if (options.rescue && !options.json) {
526
+ if (options.agents && !options.json) {
527
+ console.clear();
528
+ console.log(renderMultiAgentWatchTerminal(summary));
529
+ if (!options.once) console.log(`\nRefreshing every ${Math.round(intervalMs / 1000)}s. Press Ctrl+C to stop.`);
530
+ } else if (options.rescue && !options.json) {
528
531
  console.log(renderRescuePrompt(summary));
529
532
  } else if (options.json) {
530
533
  console.log(JSON.stringify(toWatchJsonPayload(summary), null, 2));
@@ -345,8 +345,111 @@ module.exports = function createWatchLive(deps) {
345
345
  };
346
346
  }
347
347
 
348
+ function agentLabel(session, index) {
349
+ const tool = session.tool === "claude-code" ? "claude" : session.tool || "agent";
350
+ const id = String(session.sessionId || index + 1).slice(0, 8);
351
+ return `${tool}-${id}`;
352
+ }
353
+
354
+ function buildMultiAgentView(summary) {
355
+ const agents = (summary.sessions || []).map((session, index) => {
356
+ const singleSummary = {
357
+ ...summary,
358
+ sessions: [session],
359
+ totals: {
360
+ sessions: 1,
361
+ displayTokens: session.displayTokens || 0,
362
+ contextTokens: session.contextTokens || 0,
363
+ estimatedTokens: session.estimatedTotalTokens || 0,
364
+ exactTokens: session.exactAvailable ? session.exactTotalTokens || 0 : 0,
365
+ toolTokens: session.estimatedToolTokens || 0,
366
+ },
367
+ };
368
+ const live = buildLiveSessionView(singleSummary);
369
+ return {
370
+ label: agentLabel(session, index),
371
+ tool: session.tool,
372
+ sessionId: session.sessionId,
373
+ title: session.title,
374
+ model: session.model,
375
+ updatedAt: session.updatedAt,
376
+ contextPressure: live.contextPressure,
377
+ tokens: session.displayTokens || 0,
378
+ contextTokens: session.contextTokens || 0,
379
+ toolOutputTokens: session.estimatedToolTokens || 0,
380
+ turns: session.turns || 0,
381
+ toolCalls: session.toolCalls || 0,
382
+ liveAction: live.liveAction,
383
+ warnings: live.warnings,
384
+ repeatedFiles: live.activeSession?.actionableRepeatedPaths || [],
385
+ artifactGroups: live.activeSession?.generatedArtifactGroups || [],
386
+ repeatedCommands: session.repeatedCommands || [],
387
+ };
388
+ });
389
+
390
+ const warnings = [];
391
+ const highPressureAgents = agents.filter((agent) => agent.contextPressure === "High");
392
+ if (highPressureAgents.length >= 2) {
393
+ warnings.push(`${highPressureAgents.length} agents are under high context pressure; pause broad exploration and split work by task boundary.`);
394
+ }
395
+ const noisyAgents = agents.filter((agent) => ["tool-output-flood", "possible-loop"].includes(agent.liveAction?.cause));
396
+ if (noisyAgents.length) {
397
+ warnings.push(`${noisyAgents.length} agent${noisyAgents.length === 1 ? "" : "s"} should route noisy commands through shield before rerunning.`);
398
+ }
399
+
400
+ const fileOwners = new Map();
401
+ for (const agent of agents) {
402
+ for (const item of agent.repeatedFiles || []) {
403
+ const owners = fileOwners.get(item.value) || [];
404
+ owners.push({ agent: agent.label, count: item.count });
405
+ fileOwners.set(item.value, owners);
406
+ }
407
+ }
408
+ const sharedFiles = Array.from(fileOwners.entries())
409
+ .filter(([, owners]) => owners.length >= 2)
410
+ .map(([path, owners]) => ({ path, owners }))
411
+ .slice(0, 5);
412
+ for (const item of sharedFiles.slice(0, 3)) {
413
+ warnings.push(`${item.path} is repeatedly entering context across ${item.owners.length} agents.`);
414
+ }
415
+
416
+ const artifactOwners = new Map();
417
+ for (const agent of agents) {
418
+ for (const group of agent.artifactGroups || []) {
419
+ const owners = artifactOwners.get(group.type) || [];
420
+ owners.push({ agent: agent.label, count: group.count, example: group.examples?.[0] || null });
421
+ artifactOwners.set(group.type, owners);
422
+ }
423
+ }
424
+ const sharedArtifacts = Array.from(artifactOwners.entries())
425
+ .filter(([, owners]) => owners.length >= 2)
426
+ .map(([type, owners]) => ({ type, owners }))
427
+ .slice(0, 5);
428
+ for (const item of sharedArtifacts.slice(0, 2)) {
429
+ warnings.push(`${item.type} artifacts appear across ${item.owners.length} agents; add/verify ignore coverage before continuing.`);
430
+ }
431
+
432
+ const recommendedActions = [];
433
+ if (noisyAgents.length) recommendedActions.push(`${NPX_COMMAND} shield -- <noisy command>`);
434
+ if (sharedFiles.length || sharedArtifacts.length) recommendedActions.push(`${NPX_COMMAND} doctor --apply-suggestions --dry-run`);
435
+ if (highPressureAgents.length) recommendedActions.push("Ask each high-pressure agent for a compact handoff summary, then restart scoped sessions.");
436
+ if (!recommendedActions.length) recommendedActions.push("Keep agents scoped to separate files/tasks and continue watching.");
437
+
438
+ return {
439
+ enabled: true,
440
+ agentCount: agents.length,
441
+ agents,
442
+ highestPressure: agents.reduce((pressure, agent) => (getRiskRank(agent.contextPressure) > getRiskRank(pressure) ? agent.contextPressure : pressure), "Low"),
443
+ coordinationWarnings: Array.from(new Set(warnings)).slice(0, 8),
444
+ sharedFiles,
445
+ sharedArtifacts,
446
+ recommendedActions: Array.from(new Set(recommendedActions)).slice(0, 5),
447
+ };
448
+ }
449
+
348
450
  return {
349
451
  buildLiveSessionView,
452
+ buildMultiAgentView,
350
453
  getRiskRank,
351
454
  getTokenBudgetStatus,
352
455
  };
@@ -2,6 +2,7 @@ module.exports = function createWatchRender(deps) {
2
2
  const {
3
3
  NPX_COMMAND,
4
4
  buildLiveSessionView,
5
+ buildMultiAgentView,
5
6
  color,
6
7
  formatTokenCount,
7
8
  getActionableRepeatedPaths,
@@ -33,6 +34,15 @@ function renderUsageTerminal(summary, title = "Prismo Usage") {
33
34
  }
34
35
  lines.push("");
35
36
  lines.push("Notes: exact means the local tool log exposed token fields. Estimated means Prismo used local text size heuristics only.");
37
+ const multi = summary.multiAgent || ((summary.sessions || []).length > 1 && buildMultiAgentView ? buildMultiAgentView(summary) : null);
38
+ if (multi && multi.agentCount > 1) {
39
+ lines.push("");
40
+ lines.push("Multi-Agent Coordination:");
41
+ lines.push(`- Agents visible: ${multi.agentCount}`);
42
+ lines.push(`- Highest pressure: ${multi.highestPressure}`);
43
+ if (multi.coordinationWarnings.length) lines.push(`- Top warning: ${multi.coordinationWarnings[0]}`);
44
+ lines.push(`- Live view: ${NPX_COMMAND} watch --agents`);
45
+ }
36
46
  return lines.join("\n");
37
47
  }
38
48
  function renderWatchTerminal(summary) {
@@ -107,6 +117,60 @@ function renderWatchTerminal(summary) {
107
117
  lines.push("Expected project instruction files are muted unless they combine with stronger context-pressure signals.");
108
118
  return lines.join("\n");
109
119
  }
120
+ function renderMultiAgentWatchTerminal(summary) {
121
+ const multi = summary.multiAgent;
122
+ const lines = [];
123
+ lines.push("");
124
+ lines.push(color("Prismo Multi-Agent Watch", "bold"));
125
+ lines.push("");
126
+ if (!multi || !multi.agentCount) {
127
+ lines.push("Agents: 0");
128
+ lines.push("- No local Codex/Claude Code sessions detected for this repo yet.");
129
+ lines.push("");
130
+ lines.push("Suggested Action");
131
+ lines.push(`Run: ${NPX_COMMAND} setup`);
132
+ return lines.join("\n");
133
+ }
134
+
135
+ const pressureTone = multi.highestPressure === "High" ? "red" : multi.highestPressure === "Medium" ? "yellow" : "green";
136
+ lines.push(`Agents: ${multi.agentCount}`);
137
+ lines.push(`Highest Pressure: ${color(String(multi.highestPressure).toUpperCase(), pressureTone)}`);
138
+ lines.push("");
139
+ lines.push("Active Agents");
140
+ multi.agents.slice(0, 8).forEach((agent) => {
141
+ const tone = agent.contextPressure === "High" ? "red" : agent.contextPressure === "Medium" ? "yellow" : "green";
142
+ lines.push(`- ${agent.label} ${agent.tool} ${color(agent.contextPressure.toUpperCase(), tone)} ${formatTokenCount(agent.tokens)} tokens ${agent.liveAction.cause}`);
143
+ if (agent.updatedAt) lines.push(` updated: ${agent.updatedAt}`);
144
+ });
145
+
146
+ lines.push("");
147
+ lines.push("Coordination Warnings");
148
+ if (multi.coordinationWarnings.length) multi.coordinationWarnings.forEach((warning) => lines.push(`- ${warning}`));
149
+ else lines.push("- No cross-agent coordination risks detected.");
150
+
151
+ if (multi.sharedFiles.length) {
152
+ lines.push("");
153
+ lines.push("Shared Repeated Files");
154
+ multi.sharedFiles.slice(0, 5).forEach((item) => {
155
+ lines.push(`- ${item.path} (${item.owners.map((owner) => `${owner.agent}:${owner.count}x`).join(", ")})`);
156
+ });
157
+ }
158
+
159
+ if (multi.sharedArtifacts.length) {
160
+ lines.push("");
161
+ lines.push("Shared Artifact Leaks");
162
+ multi.sharedArtifacts.slice(0, 5).forEach((item) => {
163
+ lines.push(`- ${item.type} (${item.owners.map((owner) => `${owner.agent}:${owner.count}x`).join(", ")})`);
164
+ });
165
+ }
166
+
167
+ lines.push("");
168
+ lines.push("Do This Now");
169
+ multi.recommendedActions.forEach((action, index) => lines.push(`${index + 1}. ${action}`));
170
+ lines.push("");
171
+ lines.push("Signals are local estimates from available coding-agent logs. Use this view to coordinate parallel agents before they duplicate work or flood context.");
172
+ return lines.join("\n");
173
+ }
110
174
  function renderRescuePrompt(summary) {
111
175
  const live = summary.live || buildLiveSessionView(summary);
112
176
  const active = live.activeSession;
@@ -283,6 +347,7 @@ function renderContextThrottle(summary) {
283
347
  return {
284
348
  renderContextThrottle,
285
349
  renderLiveGuardrails,
350
+ renderMultiAgentWatchTerminal,
286
351
  renderRescuePrompt,
287
352
  renderUsageTerminal,
288
353
  renderWatchTerminal,
@@ -265,7 +265,7 @@ Usage:
265
265
  prismo context [scope] [--json] [path]
266
266
  prismo cc [list|last N|all] [--json] [--limit N] [path]
267
267
  prismo usage [codex|claude|all] [--json] [--limit N] [path]
268
- prismo watch [codex|claude|all] [--json] [--once] [--report] [--rescue] [--guardrails] [--throttle] [--events] [--no-events] [--auto] [--budget N] [--redact-paths] [--interval N] [path]
268
+ prismo watch [codex|claude|all] [--json] [--once] [--agents] [--report] [--rescue] [--guardrails] [--throttle] [--events] [--no-events] [--auto] [--budget N] [--redact-paths] [--interval N] [path]
269
269
  prismo demo
270
270
 
271
271
  Commands:
@@ -301,6 +301,7 @@ Options:
301
301
  --apply-suggestions Append missing recommended ignore rules with backups.
302
302
  --no-context-packs Skip .prismo context-pack generation in doctor mode.
303
303
  --report Write .prismo/watch-report.md in watch mode.
304
+ --agents Show multi-agent coordination view for parallel local sessions.
304
305
  --rescue Print a paste-ready live-session rescue prompt in watch mode.
305
306
  --guardrails Write/update .prismo/live-guardrails.md and .prismo/live-rescue-prompt.md.
306
307
  --throttle Write/update .prismo/live-context-throttle.md in watch mode.
@@ -405,11 +406,12 @@ Examples:
405
406
  watch: `Prismo Watch
406
407
 
407
408
  Usage:
408
- prismo watch [codex|claude|all] [--json] [--once] [--report] [--rescue] [--guardrails] [--throttle] [--events] [--no-events] [--auto] [--budget N] [--redact-paths] [--interval N] [path]
409
+ prismo watch [codex|claude|all] [--json] [--once] [--agents] [--report] [--rescue] [--guardrails] [--throttle] [--events] [--no-events] [--auto] [--budget N] [--redact-paths] [--interval N] [path]
409
410
 
410
411
  Examples:
411
412
  prismo watch codex
412
413
  prismo watch claude --once --json
414
+ prismo watch --agents --once
413
415
  prismo watch --once --report
414
416
  prismo watch --once --redact-paths
415
417
  prismo watch --rescue
@@ -421,6 +423,7 @@ Examples:
421
423
 
422
424
  Output:
423
425
  Shows context pressure, recent growth, likely context leaks, repeated reads/commands, loop suspicion, one suggested action, and live intervention steps.
426
+ --agents shows all visible local sessions for this repo and coordination warnings.
424
427
  --rescue prints a paste-ready prompt to recover a noisy or looping active session.
425
428
  --guardrails continuously updates .prismo/live-guardrails.md and .prismo/live-rescue-prompt.md for the active session.
426
429
  --throttle writes a stricter live context budget file for the current agent session.
@@ -825,6 +828,7 @@ async function runCli(argv) {
825
828
  limit,
826
829
  tokenBudget,
827
830
  auto,
831
+ agents: rest.includes("--agents"),
828
832
  json,
829
833
  once: rest.includes("--once"),
830
834
  report: rest.includes("--report"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getprismo",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
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",