@agentbridge1/cli 0.0.6 → 0.0.8

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.
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCP_SERVER_NAME = void 0;
4
+ exports.buildLocalMcpServerEntry = buildLocalMcpServerEntry;
5
+ exports.buildServerMcpServerEntry = buildServerMcpServerEntry;
6
+ exports.mergeAgentbridgeIntoCursorMcp = mergeAgentbridgeIntoCursorMcp;
7
+ exports.writeLocalMcpConfig = writeLocalMcpConfig;
8
+ exports.writeServerMcpConfig = writeServerMcpConfig;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const node_process_1 = require("node:process");
12
+ const mcp_runtime_1 = require("./mcp-runtime");
13
+ exports.MCP_SERVER_NAME = "agentbridge";
14
+ function buildLocalMcpServerEntry(cliDistDir) {
15
+ const runtime = (0, mcp_runtime_1.resolveMcpRuntime)(cliDistDir);
16
+ const repoRoot = (0, node_path_1.resolve)((0, node_process_1.cwd)());
17
+ const entry = runtime
18
+ ? { command: runtime.command, args: runtime.args }
19
+ : { command: "agentbridge", args: ["mcp"] };
20
+ entry.env = { AGENTBRIDGE_REPO_ROOT: repoRoot };
21
+ return entry;
22
+ }
23
+ function buildServerMcpServerEntry(projectId, apiKey, apiBaseUrl) {
24
+ return {
25
+ command: "agentbridge",
26
+ args: ["mcp"],
27
+ env: {
28
+ AGENTBRIDGE_PROJECT_ID: projectId,
29
+ AGENTBRIDGE_API_KEY: apiKey,
30
+ AGENTBRIDGE_BASE_URL: apiBaseUrl,
31
+ AGENTBRIDGE_REPO_ROOT: (0, node_path_1.resolve)((0, node_process_1.cwd)()),
32
+ },
33
+ };
34
+ }
35
+ /** Merge AgentBridge into project-level `.cursor/mcp.json` (preserves other servers). */
36
+ function mergeAgentbridgeIntoCursorMcp(entry) {
37
+ const cursorDir = (0, node_path_1.join)((0, node_process_1.cwd)(), ".cursor");
38
+ const mcpPath = (0, node_path_1.join)(cursorDir, "mcp.json");
39
+ let existing = {};
40
+ if ((0, node_fs_1.existsSync)(mcpPath)) {
41
+ try {
42
+ existing = JSON.parse((0, node_fs_1.readFileSync)(mcpPath, "utf8"));
43
+ }
44
+ catch {
45
+ // Malformed file — start fresh
46
+ }
47
+ }
48
+ const mcpServers = existing.mcpServers && typeof existing.mcpServers === "object"
49
+ ? existing.mcpServers
50
+ : {};
51
+ mcpServers[exports.MCP_SERVER_NAME] = entry;
52
+ const updated = { ...existing, mcpServers };
53
+ if (!(0, node_fs_1.existsSync)(cursorDir)) {
54
+ (0, node_fs_1.mkdirSync)(cursorDir, { recursive: true });
55
+ }
56
+ (0, node_fs_1.writeFileSync)(mcpPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
57
+ return mcpPath;
58
+ }
59
+ function writeLocalMcpConfig(cliDistDir) {
60
+ return mergeAgentbridgeIntoCursorMcp(buildLocalMcpServerEntry(cliDistDir));
61
+ }
62
+ function writeServerMcpConfig(projectId, apiKey, apiBaseUrl) {
63
+ return mergeAgentbridgeIntoCursorMcp(buildServerMcpServerEntry(projectId, apiKey, apiBaseUrl));
64
+ }
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROTOCOL_RULES_MARKER = exports.LOCAL_RULES_HEADER = void 0;
4
+ exports.rulesArtifactPaths = rulesArtifactPaths;
5
+ exports.extractProjectIdFromRulesText = extractProjectIdFromRulesText;
6
+ exports.classifyRulesFormat = classifyRulesFormat;
7
+ exports.analyzeRulesArtifacts = analyzeRulesArtifacts;
8
+ exports.fetchProjectRules = fetchProjectRules;
9
+ exports.writeRulesFiles = writeRulesFiles;
10
+ exports.markProjectRulesInstalled = markProjectRulesInstalled;
11
+ exports.extractProjectNameFromRulesResponse = extractProjectNameFromRulesResponse;
12
+ const node_fs_1 = require("node:fs");
13
+ const node_path_1 = require("node:path");
14
+ const http_1 = require("./http");
15
+ exports.LOCAL_RULES_HEADER = "# AgentBridge Local Rules";
16
+ exports.PROTOCOL_RULES_MARKER = "This repo is coordinated through AgentBridge";
17
+ function rulesArtifactPaths(workspaceRoot) {
18
+ return {
19
+ rulesMarkdownPath: (0, node_path_1.resolve)(workspaceRoot, "AGENTBRIDGE.md"),
20
+ rulesMdcPath: (0, node_path_1.resolve)(workspaceRoot, ".cursor", "rules", "agentbridge.mdc"),
21
+ };
22
+ }
23
+ function extractProjectIdFromRulesText(content) {
24
+ const markdownMatch = content.match(/\*\*Project ID:\*\*\s*`([^`]+)`/);
25
+ if (markdownMatch?.[1]) {
26
+ return markdownMatch[1].trim();
27
+ }
28
+ const inlineMatch = content.match(/project ID:\s*`([^`]+)`/i);
29
+ if (inlineMatch?.[1]) {
30
+ return inlineMatch[1].trim();
31
+ }
32
+ return null;
33
+ }
34
+ function classifyRulesFormat(markdownContent, mdcContent) {
35
+ const md = markdownContent ?? "";
36
+ const mdc = mdcContent ?? "";
37
+ if (!md.trim() && !mdc.trim()) {
38
+ return "missing";
39
+ }
40
+ if (md.startsWith(exports.LOCAL_RULES_HEADER) || mdc.includes("Recovered domains:")) {
41
+ return "local";
42
+ }
43
+ if (md.includes(exports.PROTOCOL_RULES_MARKER) ||
44
+ mdc.includes("AgentBridge Protocol Rules") ||
45
+ mdc.includes("AgentBridge protocol rules")) {
46
+ return "protocol";
47
+ }
48
+ return "unknown";
49
+ }
50
+ function readOptionalFile(path) {
51
+ if (!(0, node_fs_1.existsSync)(path))
52
+ return null;
53
+ return (0, node_fs_1.readFileSync)(path, "utf8");
54
+ }
55
+ function analyzeRulesArtifacts(workspaceRoot, expectedProjectId) {
56
+ const paths = rulesArtifactPaths(workspaceRoot);
57
+ const markdownContent = readOptionalFile(paths.rulesMarkdownPath);
58
+ const mdcContent = readOptionalFile(paths.rulesMdcPath);
59
+ const filesPresent = markdownContent !== null && mdcContent !== null;
60
+ const format = classifyRulesFormat(markdownContent, mdcContent);
61
+ const projectIds = new Set();
62
+ if (markdownContent) {
63
+ const id = extractProjectIdFromRulesText(markdownContent);
64
+ if (id)
65
+ projectIds.add(id);
66
+ }
67
+ if (mdcContent) {
68
+ const id = extractProjectIdFromRulesText(mdcContent);
69
+ if (id)
70
+ projectIds.add(id);
71
+ }
72
+ const issues = [];
73
+ let projectIdInRepo = null;
74
+ if (projectIds.size === 1) {
75
+ projectIdInRepo = [...projectIds][0] ?? null;
76
+ }
77
+ else if (projectIds.size > 1) {
78
+ issues.push("AGENTBRIDGE.md and .cursor/rules/agentbridge.mdc reference different project IDs.");
79
+ projectIdInRepo = [...projectIds][0] ?? null;
80
+ }
81
+ else if (filesPresent) {
82
+ issues.push("Rules files are present but no project ID could be parsed.");
83
+ }
84
+ let projectIdMatchesConfig = null;
85
+ if (expectedProjectId) {
86
+ if (projectIdInRepo) {
87
+ projectIdMatchesConfig = projectIdInRepo === expectedProjectId;
88
+ if (!projectIdMatchesConfig) {
89
+ issues.push(`Rules reference project ${projectIdInRepo}, but configured project is ${expectedProjectId}.`);
90
+ }
91
+ }
92
+ else if (filesPresent) {
93
+ projectIdMatchesConfig = false;
94
+ }
95
+ }
96
+ if (!filesPresent) {
97
+ issues.push("Missing AGENTBRIDGE.md or .cursor/rules/agentbridge.mdc.");
98
+ }
99
+ else if (format === "local") {
100
+ issues.push("Rules are in local watch format (from agentbridge init), not server protocol rules.");
101
+ }
102
+ else if (format === "unknown") {
103
+ issues.push("Rules files exist but do not match the expected AgentBridge protocol format.");
104
+ }
105
+ const protocolRulesValid = filesPresent &&
106
+ format === "protocol" &&
107
+ (projectIdMatchesConfig ?? true) &&
108
+ issues.length === 0;
109
+ return {
110
+ paths,
111
+ filesPresent,
112
+ format,
113
+ projectIdInRepo,
114
+ projectIdMatchesConfig,
115
+ protocolRulesValid,
116
+ issues,
117
+ };
118
+ }
119
+ async function fetchProjectRules(ctx) {
120
+ return (0, http_1.getJson)(ctx, `/v1/dev/projects/${encodeURIComponent(ctx.projectId)}/rules`);
121
+ }
122
+ function writeRulesFiles(workspaceRoot, files) {
123
+ for (const file of files) {
124
+ const fullPath = (0, node_path_1.resolve)(workspaceRoot, file.path);
125
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(fullPath), { recursive: true });
126
+ (0, node_fs_1.writeFileSync)(fullPath, file.content, "utf8");
127
+ }
128
+ }
129
+ async function markProjectRulesInstalled(ctx) {
130
+ return (0, http_1.postJson)(ctx, `/v1/dev/projects/${encodeURIComponent(ctx.projectId)}/rules/mark-installed`, {});
131
+ }
132
+ function extractProjectNameFromRulesResponse(files) {
133
+ const markdown = files.find((file) => file.path === "AGENTBRIDGE.md")?.content;
134
+ if (!markdown)
135
+ return null;
136
+ const match = markdown.match(/^# AgentBridge — (.+)$/m);
137
+ return match?.[1]?.trim() ?? null;
138
+ }
@@ -1,5 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STALE_MCP_ACTIVITY_MINUTES = void 0;
4
+ exports.resolveWatchStartupSupervision = resolveWatchStartupSupervision;
5
+ exports.computeMcpActivityStaleMinutes = computeMcpActivityStaleMinutes;
6
+ exports.effectiveWatchSupervisionStatus = effectiveWatchSupervisionStatus;
7
+ exports.buildWatchSupervisionRenderContext = buildWatchSupervisionRenderContext;
3
8
  exports.inferSupervisionWorkType = inferSupervisionWorkType;
4
9
  exports.requiredProofHints = requiredProofHints;
5
10
  exports.computeScopeDriftAlerts = computeScopeDriftAlerts;
@@ -8,10 +13,113 @@ exports.fallbackSupervisionSnapshot = fallbackSupervisionSnapshot;
8
13
  exports.enrichSupervisionWithLocalState = enrichSupervisionWithLocalState;
9
14
  exports.supervisionSignature = supervisionSignature;
10
15
  exports.renderSupervisionSummary = renderSupervisionSummary;
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
11
18
  const claimed_paths_1 = require("./claimed-paths");
12
19
  const domain_resolution_1 = require("./domain-resolution");
13
20
  const preflight_changed_files_1 = require("./preflight-changed-files");
14
21
  const memory_context_render_1 = require("./memory-context-render");
22
+ /** Minutes without MCP activity before watch downgrades READY → DEGRADED. */
23
+ exports.STALE_MCP_ACTIVITY_MINUTES = 15;
24
+ function readWatchMcpConfig(workspaceRoot) {
25
+ const mcpConfigPath = (0, node_path_1.resolve)(workspaceRoot, ".cursor", "mcp.json");
26
+ if (!(0, node_fs_1.existsSync)(mcpConfigPath)) {
27
+ return { configured: false, projectId: null };
28
+ }
29
+ try {
30
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(mcpConfigPath, "utf8"));
31
+ const entry = parsed?.mcpServers?.["agentbridge"] ?? parsed?.mcpServers?.["agentbridge-mcp"];
32
+ return {
33
+ configured: Boolean(entry),
34
+ projectId: entry?.env?.AGENTBRIDGE_PROJECT_ID ?? null,
35
+ };
36
+ }
37
+ catch {
38
+ return { configured: false, projectId: null };
39
+ }
40
+ }
41
+ function watchRulesInstalled(workspaceRoot) {
42
+ return ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(workspaceRoot, "AGENTBRIDGE.md")) ||
43
+ (0, node_fs_1.existsSync)((0, node_path_1.resolve)(workspaceRoot, ".cursor", "rules", "agentbridge.mdc")));
44
+ }
45
+ /** Startup decision tree for watch's four-state supervision model. */
46
+ function resolveWatchStartupSupervision(input) {
47
+ const mcp = readWatchMcpConfig(input.workspaceRoot);
48
+ const rulesInstalled = watchRulesInstalled(input.workspaceRoot);
49
+ const credentialMismatch = mcp.configured && mcp.projectId !== null && input.cliProjectId !== undefined
50
+ ? mcp.projectId !== input.cliProjectId
51
+ : false;
52
+ const base = {
53
+ mcpConfigured: mcp.configured,
54
+ rulesInstalled,
55
+ mcpProjectId: mcp.projectId,
56
+ credentialMismatch,
57
+ };
58
+ if (credentialMismatch) {
59
+ return {
60
+ ...base,
61
+ supervisionStatus: "broken",
62
+ warningBanner: "\n⚠ SUPERVISION BROKEN: CLI and MCP are using different project identities.\n" +
63
+ ` CLI project id: ${input.cliProjectId ?? "?"}\n` +
64
+ ` MCP project id: ${mcp.projectId ?? "?"}\n` +
65
+ " watch cannot reliably correlate CLI sessions with MCP evidence.\n" +
66
+ " Fix: run `agentbridge connect` to re-write the MCP config with the correct credentials.\n",
67
+ };
68
+ }
69
+ if (!mcp.configured && !rulesInstalled) {
70
+ return {
71
+ ...base,
72
+ supervisionStatus: "blind",
73
+ warningBanner: "\n⚠ SUPERVISION BLIND: MCP is not configured and no AgentBridge rules are installed.\n" +
74
+ " watch can observe filesystem changes only — agent actions inside Cursor are invisible.\n" +
75
+ " Fix: run `agentbridge connect` to configure MCP and install rules automatically.\n",
76
+ };
77
+ }
78
+ if (!mcp.configured) {
79
+ return {
80
+ ...base,
81
+ supervisionStatus: "degraded",
82
+ warningBanner: "\n⚠ SUPERVISION DEGRADED: MCP is not configured.\n" +
83
+ " watch cannot see MCP-recorded evidence, implementation packets, or agent tool usage.\n" +
84
+ " Fix: run `agentbridge connect` or `agentbridge setup-mcp` then restart Cursor.\n",
85
+ };
86
+ }
87
+ if (!rulesInstalled) {
88
+ return {
89
+ ...base,
90
+ supervisionStatus: "degraded",
91
+ warningBanner: "\n⚠ SUPERVISION DEGRADED: AgentBridge rules are not installed in this project.\n" +
92
+ " The agent is not operating under AgentBridge protocol — no task discipline enforced.\n" +
93
+ " Fix: run `agentbridge install-rules` to add rules to this project.\n",
94
+ };
95
+ }
96
+ return { ...base, supervisionStatus: "ready" };
97
+ }
98
+ function computeMcpActivityStaleMinutes(updatedAt, nowMs = Date.now()) {
99
+ if (updatedAt == null)
100
+ return undefined;
101
+ const updatedMs = new Date(updatedAt).getTime();
102
+ if (Number.isNaN(updatedMs))
103
+ return undefined;
104
+ return Math.floor((nowMs - updatedMs) / 60_000);
105
+ }
106
+ function effectiveWatchSupervisionStatus(baseStatus, mcpConfigured, mcpActivityStaleMinutes) {
107
+ if (baseStatus === "ready" &&
108
+ mcpConfigured &&
109
+ mcpActivityStaleMinutes != null &&
110
+ mcpActivityStaleMinutes > exports.STALE_MCP_ACTIVITY_MINUTES) {
111
+ return "degraded";
112
+ }
113
+ return baseStatus;
114
+ }
115
+ function buildWatchSupervisionRenderContext(input) {
116
+ const mcpActivityStaleMinutes = computeMcpActivityStaleMinutes(input.agentDeclaredUpdatedAt, input.nowMs);
117
+ return {
118
+ supervisionStatus: effectiveWatchSupervisionStatus(input.baseStatus, input.mcpConfigured, mcpActivityStaleMinutes),
119
+ mcpConfigured: input.mcpConfigured,
120
+ mcpActivityStaleMinutes,
121
+ };
122
+ }
15
123
  const CLI_GIT_REQUIRED_PROOF = [
16
124
  "tracked modified file handled",
17
125
  "untracked new file handled",
@@ -28,6 +136,20 @@ function inferSupervisionWorkType(changedFiles) {
28
136
  if (changedFiles.length === 0)
29
137
  return "unknown";
30
138
  const lower = changedFiles.map((file) => file.toLowerCase());
139
+ const isUiSurfaceFile = (file) => {
140
+ if (file.endsWith(".html") ||
141
+ file.endsWith(".css") ||
142
+ file.endsWith(".scss") ||
143
+ file.endsWith(".sass") ||
144
+ file.endsWith(".less") ||
145
+ file.endsWith(".tsx") ||
146
+ file.endsWith(".jsx")) {
147
+ return true;
148
+ }
149
+ // Keep this narrow: only treat plain .ts/.js as UI when clearly in public assets.
150
+ return ((file.endsWith(".ts") || file.endsWith(".js")) &&
151
+ (file.startsWith("src/public/") || file.includes("/public/")));
152
+ };
31
153
  const cliSignal = lower.some((file) => file.includes("cli/src/") &&
32
154
  (file.includes("watch") || file.includes("precommit") || file.includes("revert-crossing")));
33
155
  if (cliSignal)
@@ -35,6 +157,9 @@ function inferSupervisionWorkType(changedFiles) {
35
157
  const docsOnly = lower.every((file) => file.startsWith("docs/") || file.endsWith(".md") || file.endsWith(".mdx") || file.includes("/docs/"));
36
158
  if (docsOnly)
37
159
  return "documentation";
160
+ const uiSurfaceOnly = lower.every(isUiSurfaceFile);
161
+ if (uiSurfaceOnly)
162
+ return "ui_copy";
38
163
  return "general";
39
164
  }
40
165
  function requiredProofHints(workType) {
@@ -42,6 +167,12 @@ function requiredProofHints(workType) {
42
167
  return [...CLI_GIT_REQUIRED_PROOF];
43
168
  if (workType === "documentation")
44
169
  return ["explicit verification evidence for changed docs/files"];
170
+ if (workType === "ui_copy") {
171
+ return [
172
+ "visual confirmation/screenshot of updated UI copy",
173
+ "optional quick smoke command: agentbridge verify -- npm run build",
174
+ ];
175
+ }
45
176
  return [
46
177
  "explicit verification evidence for changed files",
47
178
  "run agentbridge verify, then rerun agentbridge watch",
@@ -210,7 +341,7 @@ function enrichSupervisionWithLocalState(state, supervision) {
210
341
  : supervision.scopeStatus,
211
342
  };
212
343
  }
213
- function supervisionSignature(snapshot) {
344
+ function supervisionSignature(snapshot, renderContext) {
214
345
  return JSON.stringify({
215
346
  workSessionId: snapshot.workSessionId,
216
347
  changedFiles: snapshot.changedFiles,
@@ -225,52 +356,81 @@ function supervisionSignature(snapshot) {
225
356
  ? `${snapshot.agentDeclared.intent ?? ""}:${snapshot.agentDeclared.lastEvent ?? ""}`
226
357
  : "",
227
358
  declaredDrift: snapshot.declaredDriftFiles?.join(",") ?? "",
359
+ supervisionStatus: renderContext?.supervisionStatus ?? "",
360
+ mcpConfigured: renderContext?.mcpConfigured ?? false,
361
+ mcpActivityStale: renderContext?.mcpActivityStaleMinutes != null
362
+ ? renderContext.mcpActivityStaleMinutes > exports.STALE_MCP_ACTIVITY_MINUTES
363
+ : false,
228
364
  });
229
365
  }
366
+ const SUPERVISION_STATUS_LABEL = {
367
+ ready: "✓ READY",
368
+ degraded: "⚠ DEGRADED",
369
+ blind: "⚠ BLIND",
370
+ broken: "✗ BROKEN",
371
+ };
230
372
  function renderSupervisionSummary(snapshot, options) {
231
373
  const lines = [];
232
- lines.push(options?.compact ? "AgentBridge watch:" : "AgentBridge supervision:");
374
+ lines.push("AgentBridge watch:");
375
+ lines.push("");
376
+ lines.push("1) Actions performed");
377
+ lines.push(`- Reviewed ${snapshot.changedFiles.length} changed file(s)`);
378
+ lines.push(`- Work type detected: ${snapshot.workType}`);
379
+ lines.push(`- Scope status: ${snapshot.scopeStatus}`);
380
+ lines.push(`- Boundary status: ${snapshot.boundaryStatus}`);
381
+ lines.push(`- Files (disk): ${snapshot.diskObserved?.postBaselineFiles.length ?? snapshot.changedFiles.length} changed since session start`);
233
382
  if (!options?.compact) {
234
- lines.push(`Current run: ${snapshot.workSessionId}${snapshot.changeRequestId ? ` / task ${snapshot.changeRequestId}` : ""}`);
383
+ lines.push(`- Active run: ${snapshot.workSessionId}${snapshot.changeRequestId ? ` (task ${snapshot.changeRequestId})` : ""}`);
384
+ }
385
+ if (options?.supervisionStatus) {
386
+ lines.push(`- Supervision: ${SUPERVISION_STATUS_LABEL[options.supervisionStatus] ?? options.supervisionStatus}`);
235
387
  }
236
388
  const declared = snapshot.agentDeclared;
237
389
  if (declared) {
238
390
  const intentLabel = declared.intent?.trim() || declared.summary?.trim() || "(no intent text)";
239
- const eventSuffix = declared.lastEvent && declared.updatedAt
240
- ? ` [${declared.lastEvent} @ ${formatMcpEventTime(declared.updatedAt)}]`
241
- : declared.lastEvent
242
- ? ` [${declared.lastEvent}]`
243
- : "";
244
- lines.push(`Agent (MCP): ${intentLabel}${eventSuffix}`);
391
+ lines.push(`- Agent (MCP): ${intentLabel}`);
245
392
  if (declared.claimedPaths.length > 0) {
246
393
  const scopePreview = declared.claimedPaths.length > 6
247
394
  ? `${declared.claimedPaths.slice(0, 6).join(", ")} (+${declared.claimedPaths.length - 6} more)`
248
395
  : declared.claimedPaths.join(", ");
249
- lines.push(`Declared scope: ${scopePreview}`);
250
- }
251
- else {
252
- lines.push("Declared scope: (none yet)");
396
+ lines.push(`- Declared scope: ${scopePreview}`);
253
397
  }
254
398
  }
255
- const diskCount = snapshot.diskObserved?.postBaselineFiles.length ?? snapshot.changedFiles.length;
256
- lines.push(`Files (disk): ${diskCount} changed since session start`);
257
- if (snapshot.declaredVsObservedDrift === "warn" && snapshot.declaredDriftFiles?.length) {
258
- const preview = snapshot.declaredDriftFiles.length > 4
259
- ? `${snapshot.declaredDriftFiles.slice(0, 4).join(", ")} (+${snapshot.declaredDriftFiles.length - 4} more)`
260
- : snapshot.declaredDriftFiles.join(", ");
261
- lines.push(`Note: ${snapshot.declaredDriftFiles.length} file(s) outside declared scope (${preview}) — warn only, not blocked`);
399
+ else if (options?.mcpConfigured) {
400
+ lines.push("- Agent (MCP): not yet active");
401
+ }
402
+ lines.push(`- Changed files: ${snapshot.changedFiles.length}`);
403
+ lines.push("");
404
+ lines.push("2) Proof present / missing");
405
+ if (snapshot.decision === "accepted") {
406
+ lines.push("- Present: proof accepted for current changes");
407
+ }
408
+ else if (snapshot.serverAcceptanceUnavailable) {
409
+ lines.push(`- Unknown: proof check unavailable (${snapshot.serverAcceptanceUnavailable})`);
410
+ }
411
+ else {
412
+ lines.push(`- Missing/blocked: watch result is ${snapshot.decision}`);
262
413
  }
263
- lines.push(`Changed files: ${snapshot.changedFiles.length}`);
264
- lines.push(`Detected work type: ${snapshot.workType}`);
265
- lines.push(`Scope: ${snapshot.scopeStatus}`);
266
- lines.push(`Boundary: ${snapshot.boundaryStatus}`);
267
- lines.push(`Watch result: ${snapshot.decision}`);
268
414
  if (snapshot.requiredProof.length > 0) {
269
- lines.push("");
270
- lines.push("Likely required proof:");
271
- for (const proof of snapshot.requiredProof) {
272
- lines.push(`- ${proof}`);
273
- }
415
+ lines.push(`- Still needed: ${snapshot.requiredProof.slice(0, 3).join("; ")}`);
416
+ }
417
+ if (snapshot.declaredVsObservedDrift === "warn" && snapshot.declaredDriftFiles?.length) {
418
+ lines.push(`- Scope warning: ${snapshot.declaredDriftFiles.length} file(s) appear outside declared scope`);
419
+ lines.push("- Note: warn only, not blocked");
420
+ }
421
+ if (snapshot.serverAcceptanceUnavailable) {
422
+ lines.push(`- Watch result unavailable: ${snapshot.serverAcceptanceUnavailable}`);
423
+ }
424
+ lines.push("");
425
+ lines.push("3) Next move");
426
+ lines.push(`- ${snapshot.nextAction}`);
427
+ if (snapshot.driftAlerts.length > 0) {
428
+ lines.push("- Resolve out-of-scope files or explicitly update scope before continuing");
429
+ }
430
+ if (options?.mcpActivityStaleMinutes != null &&
431
+ options.mcpActivityStaleMinutes > exports.STALE_MCP_ACTIVITY_MINUTES) {
432
+ lines.push("- Reconnect or wake MCP activity so supervision returns to ready state");
433
+ lines.push(`- MCP activity stale — last update ${options.mcpActivityStaleMinutes}m ago`);
274
434
  }
275
435
  if (snapshot.knownTraps.length > 0) {
276
436
  lines.push("");
@@ -282,25 +442,8 @@ function renderSupervisionSummary(snapshot, options) {
282
442
  const watchMemoryLines = (0, memory_context_render_1.renderWatchMemoryContext)(snapshot.memoryContext);
283
443
  if (watchMemoryLines.length > 0) {
284
444
  lines.push("");
445
+ lines.push("Context:");
285
446
  lines.push(...watchMemoryLines);
286
447
  }
287
- if (snapshot.driftAlerts.length > 0) {
288
- for (const alert of snapshot.driftAlerts) {
289
- lines.push("");
290
- lines.push("Files outside scope detected:");
291
- lines.push(`- file: ${alert.file}`);
292
- lines.push(`- claimed paths: [${alert.claimedPaths.join(", ")}]`);
293
- lines.push(`- likely domain: ${alert.likelyDomain}`);
294
- lines.push(`- severity: ${alert.severity}`);
295
- lines.push("- suggested action: update scope or confirm this belongs to the current work");
296
- }
297
- }
298
- if (snapshot.serverAcceptanceUnavailable) {
299
- lines.push("");
300
- lines.push(`Watch result unavailable: ${snapshot.serverAcceptanceUnavailable}`);
301
- }
302
- lines.push("");
303
- lines.push("Before saying done:");
304
- lines.push(`- ${snapshot.nextAction}`);
305
448
  return lines.join("\n");
306
449
  }