@agentbridge1/cli 0.0.5 → 0.0.7

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "builtAt": "2026-06-03T09:58:38.231Z",
3
- "gitHead": "6fcc74c",
4
- "sourceLatestMtime": "2026-06-03T05:08:44.109Z",
5
- "sourceLatestFile": "src/commands/doctor.ts"
2
+ "builtAt": "2026-06-07T04:20:05.843Z",
3
+ "gitHead": "aa4b2fb",
4
+ "sourceLatestMtime": "2026-06-07T04:16:53.273Z",
5
+ "sourceLatestFile": "src/commands/room.ts"
6
6
  }
@@ -10,6 +10,7 @@ const server_sync_1 = require("../server-sync");
10
10
  const operator_snapshot_1 = require("../operator-snapshot");
11
11
  const work_context_resolver_1 = require("../work-context-resolver");
12
12
  const error_catalog_1 = require("../error-catalog");
13
+ const proof_obligations_1 = require("../proof-obligations");
13
14
  const acceptance_preflight_1 = require("../acceptance-preflight");
14
15
  const acceptance_block_1 = require("../acceptance-block");
15
16
  function resolveNetworkContext() {
@@ -36,10 +37,9 @@ function blockedErrorCode(report) {
36
37
  if ((report.out_of_scope_files ?? []).length > 0 || report.scope_status === "drift") {
37
38
  return "SCOPE_DRIFT_OUT_OF_SCOPE_FILE";
38
39
  }
39
- if (report.decision === "needs_proof")
40
- return "PROOF_MISSING";
41
- if (report.decision === "stale_evidence")
42
- return "PROOF_STALE_AFTER_CHANGE";
40
+ const proofCode = (0, proof_obligations_1.resolveProofBlockingErrorCode)(report);
41
+ if (proofCode)
42
+ return proofCode;
43
43
  return "ACCEPTANCE_BLOCKED";
44
44
  }
45
45
  function buildStructuredBlockedOutput(report) {
@@ -9,6 +9,7 @@ const acceptance_preflight_1 = require("../acceptance-preflight");
9
9
  const work_context_resolver_1 = require("../work-context-resolver");
10
10
  const operator_snapshot_1 = require("../operator-snapshot");
11
11
  const proof_guidance_1 = require("../proof-guidance");
12
+ const proof_obligations_1 = require("../proof-obligations");
12
13
  const memory_context_render_1 = require("../memory-context-render");
13
14
  const acceptance_block_1 = require("../acceptance-block");
14
15
  function resolveNetworkContext() {
@@ -184,8 +185,16 @@ function renderAcceptanceReport(report) {
184
185
  }
185
186
  }
186
187
  }
188
+ const obligationSection = (0, proof_obligations_1.renderProofObligationSection)(report);
189
+ if (obligationSection.length > 0) {
190
+ lines.push(...obligationSection);
191
+ }
187
192
  lines.push(`Decision: ${report.decision}`);
188
- if (report.decision === "needs_proof") {
193
+ const obligationErrorLines = (0, proof_obligations_1.renderProofObligationErrorLines)(report);
194
+ if (obligationErrorLines.length > 0) {
195
+ lines.push(...obligationErrorLines);
196
+ }
197
+ else if (report.decision === "needs_proof") {
189
198
  lines.push("✗ Error code: PROOF_MISSING");
190
199
  lines.push(" What happened: No verification proof exists for this work session.");
191
200
  lines.push(" Why it matters: Unverified work cannot be accepted — proof is required.");
@@ -293,6 +293,9 @@ async function runConnect(options = {}) {
293
293
  diagnostics.bootstrapStatus = "skipped";
294
294
  diagnostics.rotateStatus = "skipped";
295
295
  }
296
+ if (connectionUpgraded) {
297
+ await verifyCredentials(projectId, effectiveApiKey, apiBaseUrl);
298
+ }
296
299
  if (!executionSurfaceId) {
297
300
  (0, config_1.updateConfig)({
298
301
  projectId,
@@ -358,7 +361,7 @@ async function runConnect(options = {}) {
358
361
  "",
359
362
  "Next:",
360
363
  " agentbridge doctor",
361
- " agentbridge start",
364
+ " agentbridge watch",
362
365
  "",
363
366
  ].join("\n"));
364
367
  }
@@ -366,6 +369,6 @@ async function runConnect(options = {}) {
366
369
  process.stdout.write("✓ Connected.\n");
367
370
  process.stdout.write("Run `agentbridge use <agent-id>` and then:\n");
368
371
  process.stdout.write(" agentbridge doctor\n");
369
- process.stdout.write(" agentbridge start\n");
372
+ process.stdout.write(" agentbridge watch\n");
370
373
  }
371
374
  }
@@ -10,9 +10,16 @@ const http_1 = require("../http");
10
10
  const dist_freshness_1 = require("./dist-freshness");
11
11
  const session_state_1 = require("../session-state");
12
12
  const server_sync_1 = require("../server-sync");
13
+ const recovery_reconcile_1 = require("../recovery-reconcile");
14
+ const rules_sync_1 = require("../rules-sync");
13
15
  function cliRootFromCommandDir() {
14
16
  return (0, node_path_1.resolve)(__dirname, "..", "..");
15
17
  }
18
+ function isRecoveryBaselinePendingHello(hello) {
19
+ return (hello.setup_required === true ||
20
+ hello.agentbridge_status === "recovery_baseline_pending" ||
21
+ hello.instruction?.recovery_status === "baseline_required");
22
+ }
16
23
  function normalizeReasonCandidate(value) {
17
24
  if (!value)
18
25
  return undefined;
@@ -86,11 +93,70 @@ function extractHttpReason(error) {
86
93
  }
87
94
  return `http_${error.status}`;
88
95
  }
89
- function recoveryRequiredByPacket(packet) {
90
- if (!packet || packet.project_mode !== "recovery")
91
- return false;
92
- const status = packet.recovery_status ?? null;
93
- return status === "baseline_required" || status === "pending" || status === null;
96
+ function detectGovernanceSignals(workspaceRoot, expectedProjectId) {
97
+ const analysis = (0, rules_sync_1.analyzeRulesArtifacts)(workspaceRoot, expectedProjectId);
98
+ const mcpConfigPath = (0, node_path_1.resolve)(workspaceRoot, ".cursor", "mcp.json");
99
+ let mcpConfigured = false;
100
+ if ((0, node_fs_1.existsSync)(mcpConfigPath)) {
101
+ try {
102
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(mcpConfigPath, "utf8"));
103
+ mcpConfigured = Boolean(parsed?.mcpServers &&
104
+ (parsed.mcpServers["agentbridge"] || parsed.mcpServers["agentbridge-mcp"]));
105
+ }
106
+ catch {
107
+ mcpConfigured = false;
108
+ }
109
+ }
110
+ return {
111
+ rulesFilesPresent: analysis.filesPresent,
112
+ rulesFormat: analysis.format,
113
+ rulesProjectIdInRepo: analysis.projectIdInRepo,
114
+ rulesProjectIdMatches: analysis.projectIdMatchesConfig,
115
+ rulesInstalled: analysis.protocolRulesValid,
116
+ rulesIssues: analysis.issues,
117
+ mcpConfigured,
118
+ governanceStatus: analysis.protocolRulesValid && mcpConfigured ? "active" : "inactive",
119
+ };
120
+ }
121
+ function isRouteMissingBody(body) {
122
+ return body.toLowerCase().includes("route not found");
123
+ }
124
+ function mapProjectAccessFailure(error) {
125
+ if (error instanceof http_1.CliHttpError) {
126
+ const reason = extractHttpReason(error);
127
+ if (reason === "not_project_member") {
128
+ return {
129
+ status: "failed",
130
+ reason,
131
+ suggestedNextAction: "use an API key/agent that is a member of this project, or add this agent to the project.",
132
+ };
133
+ }
134
+ if (reason === "unauthorized") {
135
+ return {
136
+ status: "failed",
137
+ reason,
138
+ suggestedNextAction: "verify AGENTBRIDGE_API_KEY is valid for this environment and has project read access.",
139
+ };
140
+ }
141
+ if (reason === "project_not_found") {
142
+ return {
143
+ status: "failed",
144
+ reason,
145
+ suggestedNextAction: "verify AGENTBRIDGE_PROJECT_ID points to an existing project in this API environment.",
146
+ };
147
+ }
148
+ return {
149
+ status: "failed",
150
+ reason,
151
+ suggestedNextAction: "confirm project ID, API key, and base URL are correct and that this key has project read access.",
152
+ };
153
+ }
154
+ const messageReason = error instanceof Error ? normalizeReasonCandidate(error.message) : undefined;
155
+ return {
156
+ status: "failed",
157
+ reason: messageReason ?? "network_error",
158
+ suggestedNextAction: "check network reachability to the API base URL and retry doctor.",
159
+ };
94
160
  }
95
161
  async function checkProjectAccess(ctx) {
96
162
  if (!ctx.configComplete) {
@@ -102,46 +168,33 @@ async function checkProjectAccess(ctx) {
102
168
  const projectId = ctx.projectId;
103
169
  const apiKey = ctx.apiKey;
104
170
  const apiBaseUrl = ctx.apiBaseUrl;
171
+ const syncCtx = { projectId, apiKey, apiBaseUrl, apiKeySource: "config" };
172
+ const summaryPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/summary`;
173
+ const packetPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/packet`;
105
174
  try {
106
- const packet = await (0, http_1.getJson)({ projectId, apiKey, apiBaseUrl, apiKeySource: "config" }, `/v1/dev/projects/${encodeURIComponent(projectId)}/packet`);
175
+ await (0, http_1.getJson)(syncCtx, summaryPath);
176
+ let packet;
177
+ try {
178
+ packet = await (0, http_1.getJson)(syncCtx, packetPath);
179
+ }
180
+ catch {
181
+ // Summary proves access; packet is optional (recovery metadata only).
182
+ }
107
183
  return { status: "ok", packet };
108
184
  }
109
185
  catch (error) {
110
- if (error instanceof http_1.CliHttpError) {
111
- const reason = extractHttpReason(error);
112
- if (reason === "not_project_member") {
113
- return {
114
- status: "failed",
115
- reason,
116
- suggestedNextAction: "use an API key/agent that is a member of this project, or add this agent to the project.",
117
- };
118
- }
119
- if (reason === "unauthorized") {
120
- return {
121
- status: "failed",
122
- reason,
123
- suggestedNextAction: "verify AGENTBRIDGE_API_KEY is valid for this environment and has project read access.",
124
- };
186
+ if (error instanceof http_1.CliHttpError &&
187
+ error.status === 404 &&
188
+ isRouteMissingBody(error.body ?? "")) {
189
+ try {
190
+ const packet = await (0, http_1.getJson)(syncCtx, packetPath);
191
+ return { status: "ok", packet };
125
192
  }
126
- if (reason === "project_not_found") {
127
- return {
128
- status: "failed",
129
- reason,
130
- suggestedNextAction: "verify AGENTBRIDGE_PROJECT_ID points to an existing project in this API environment.",
131
- };
193
+ catch (packetError) {
194
+ return mapProjectAccessFailure(packetError);
132
195
  }
133
- return {
134
- status: "failed",
135
- reason,
136
- suggestedNextAction: "confirm project ID, API key, and base URL are correct and that this key has project read access.",
137
- };
138
196
  }
139
- const messageReason = error instanceof Error ? normalizeReasonCandidate(error.message) : undefined;
140
- return {
141
- status: "failed",
142
- reason: messageReason ?? "network_error",
143
- suggestedNextAction: "check network reachability to the API base URL and retry doctor.",
144
- };
197
+ return mapProjectAccessFailure(error);
145
198
  }
146
199
  }
147
200
  async function checkIdentityAccess(ctx) {
@@ -156,7 +209,8 @@ async function checkIdentityAccess(ctx) {
156
209
  }
157
210
  const helloUrl = `${ctx.apiBaseUrl}/v1/dev/projects/${ctx.projectId}/hello`;
158
211
  let identityModel = "unknown";
159
- let executionSurfaceId = null;
212
+ let helloExecutionSurfaceId = null;
213
+ let baselinePending = false;
160
214
  try {
161
215
  const helloRes = await fetch(helloUrl, {
162
216
  method: "POST",
@@ -168,18 +222,22 @@ async function checkIdentityAccess(ctx) {
168
222
  });
169
223
  if (helloRes.ok) {
170
224
  const hello = (await helloRes.json());
225
+ baselinePending = isRecoveryBaselinePendingHello(hello);
171
226
  if (hello.identity_model === "work_identity") {
172
227
  identityModel = "work_identity";
173
228
  }
174
229
  else if (hello.identity_model === "legacy") {
175
230
  identityModel = "legacy";
176
231
  }
177
- executionSurfaceId = hello.execution_surface?.id?.trim() || null;
232
+ helloExecutionSurfaceId = hello.execution_surface?.id?.trim() || null;
178
233
  }
179
234
  }
180
235
  catch {
181
236
  // Keep default unknown/null and continue with identity resolution checks.
182
237
  }
238
+ const configSurfaceId = ctx.configExecutionSurfaceId?.trim() || null;
239
+ const executionSurfaceId = helloExecutionSurfaceId || configSurfaceId;
240
+ const executionSurfaceSource = helloExecutionSurfaceId ? "hello" : configSurfaceId ? "config" : undefined;
183
241
  try {
184
242
  const syncCtx = {
185
243
  projectId: ctx.projectId,
@@ -192,18 +250,28 @@ async function checkIdentityAccess(ctx) {
192
250
  (0, server_sync_1.listWorkIdentities)(syncCtx),
193
251
  ]);
194
252
  const callerId = callerPacket?.work_identity?.id ?? null;
195
- const startCapable = Boolean(executionSurfaceId);
196
- if (callerId) {
197
- return { status: "ok", identityModel, executionSurfaceId, startCapable };
253
+ const callerResolvable = Boolean(callerId) || identities.length === 1;
254
+ if (identityModel === "unknown" &&
255
+ callerResolvable &&
256
+ (baselinePending || Boolean(configSurfaceId))) {
257
+ identityModel = "work_identity";
198
258
  }
199
- if (identities.length === 1) {
200
- return { status: "ok", identityModel, executionSurfaceId, startCapable };
259
+ const startCapable = Boolean(executionSurfaceId);
260
+ if (callerResolvable) {
261
+ return {
262
+ status: "ok",
263
+ identityModel,
264
+ executionSurfaceId,
265
+ executionSurfaceSource,
266
+ startCapable,
267
+ };
201
268
  }
202
269
  return {
203
270
  status: "failed",
204
271
  reason: "caller_identity_unresolved",
205
272
  identityModel,
206
273
  executionSurfaceId,
274
+ executionSurfaceSource,
207
275
  startCapable,
208
276
  };
209
277
  }
@@ -213,12 +281,14 @@ async function checkIdentityAccess(ctx) {
213
281
  reason: "caller_identity_unresolved",
214
282
  identityModel,
215
283
  executionSurfaceId,
284
+ executionSurfaceSource,
216
285
  startCapable: Boolean(executionSurfaceId),
217
286
  };
218
287
  }
219
288
  }
220
289
  async function runDoctor(cliRootOverride) {
221
290
  const cliRoot = cliRootOverride ?? cliRootFromCommandDir();
291
+ const workspaceRoot = process.cwd();
222
292
  const cfg = (0, config_1.readConfig)();
223
293
  const freshness = (0, dist_freshness_1.getDistFreshnessReport)(cliRoot);
224
294
  const configPath = cliRootOverride
@@ -238,6 +308,7 @@ async function runDoctor(cliRootOverride) {
238
308
  const projectConfigPresent = projectIdPresent && apiKeyPresent && baseUrlPresent;
239
309
  const activeSession = (0, session_state_1.readSessionState)();
240
310
  const hasActiveWork = Boolean(activeSession?.id || activeSession?.serverSessionId);
311
+ const governance = detectGovernanceSignals(workspaceRoot, resolvedProjectId ?? undefined);
241
312
  const envContributed = Boolean(process.env.AGENTBRIDGE_PROJECT_ID) ||
242
313
  Boolean(process.env.AGENTBRIDGE_API_KEY) ||
243
314
  Boolean(process.env.AGENTBRIDGE_BASE_URL) ||
@@ -271,18 +342,35 @@ async function runDoctor(cliRootOverride) {
271
342
  if (projectAccess.reason) {
272
343
  lines.push(`Project access reason: ${projectAccess.reason}`);
273
344
  }
345
+ lines.push(`API key accepted by server: ${projectAccess.status === "ok"
346
+ ? "yes"
347
+ : projectAccess.status === "skipped"
348
+ ? "skipped"
349
+ : "no"}`);
274
350
  const identityAccess = await checkIdentityAccess({
275
351
  projectId: resolvedProjectId,
276
352
  apiKey: resolvedApiKey,
277
353
  apiBaseUrl: resolvedBaseUrl,
278
- configComplete: projectConfigPresent && projectAccess.status === "ok",
354
+ configComplete: projectConfigPresent,
355
+ configExecutionSurfaceId: cfg.executionSurfaceId,
279
356
  });
280
- lines.push(`Caller identity access: ${identityAccess.status}`);
281
- if (identityAccess.reason) {
282
- lines.push(`Caller identity reason: ${identityAccess.reason}`);
357
+ lines.push(`Rules files present: ${governance.rulesFilesPresent ? "yes" : "no"}`);
358
+ lines.push(`Rules format: ${governance.rulesFormat}`);
359
+ if (governance.rulesProjectIdInRepo) {
360
+ lines.push(`Rules project ID: ${governance.rulesProjectIdInRepo}`);
361
+ }
362
+ if (governance.rulesProjectIdMatches !== null) {
363
+ lines.push(`Rules project ID match: ${governance.rulesProjectIdMatches ? "yes" : "no"}`);
364
+ }
365
+ lines.push(`Rules installed: ${governance.rulesInstalled ? "yes" : "no"}`);
366
+ lines.push(`MCP configured: ${governance.mcpConfigured ? "yes" : "no"}`);
367
+ lines.push(`Agent governance: ${governance.governanceStatus}`);
368
+ if (governance.rulesIssues.length > 0) {
369
+ for (const issue of governance.rulesIssues) {
370
+ lines.push(`Rules issue: ${issue}`);
371
+ }
372
+ lines.push("Rules fix: run `agentbridge install-rules`");
283
373
  }
284
- lines.push(`Caller identity model: ${identityAccess.identityModel}`);
285
- lines.push(`Execution surface present: ${identityAccess.executionSurfaceId ? "yes" : "no"}`);
286
374
  lines.push(`Start capable: ${identityAccess.startCapable ? "yes" : "no"}`);
287
375
  if (projectAccess.status === "failed" && projectAccess.reason) {
288
376
  const view = (0, error_catalog_1.catalogViewForDoctorReason)(projectAccess.reason, projectAccess.suggestedNextAction);
@@ -309,55 +397,132 @@ async function runDoctor(cliRootOverride) {
309
397
  productStatus = "active_work_found";
310
398
  }
311
399
  else {
312
- productStatus = recoveryRequiredByPacket(projectAccess.packet)
313
- ? "needs_recover"
314
- : "ready";
400
+ if ((0, recovery_reconcile_1.recoveryBaselineRequired)(projectAccess.packet)) {
401
+ productStatus = "needs_recover";
402
+ }
403
+ else if ((0, recovery_reconcile_1.recoveryIsBasicPacket)(projectAccess.packet)) {
404
+ productStatus = "ready_basic_recovery";
405
+ }
406
+ else {
407
+ productStatus = "ready";
408
+ }
315
409
  }
316
410
  }
411
+ const localSupervisionReady = true;
412
+ const cloudSyncReady = projectAccess.status === "ok";
413
+ const strictTrackedReady = projectAccess.status === "ok" && identityAccess.status === "ok" && identityAccess.startCapable;
414
+ lines.push("");
415
+ lines.push("Capability levels:");
416
+ lines.push(`- Local supervision: ${localSupervisionReady ? "ready" : "unavailable"}`);
417
+ lines.push(`- Cloud sync: ${cloudSyncReady ? "ready" : "unavailable"}`);
418
+ lines.push(`- Strict tracked work: ${strictTrackedReady ? "ready" : "unavailable"}`);
419
+ if (!cloudSyncReady && projectAccess.reason) {
420
+ lines.push(` Cloud sync note: ${projectAccess.reason}`);
421
+ }
422
+ if (!strictTrackedReady && identityAccess.reason) {
423
+ lines.push(` Strict tracked note: ${identityAccess.reason}`);
424
+ }
317
425
  lines.push("");
318
426
  lines.push("Product status:");
319
427
  if (productStatus === "ready") {
320
428
  lines.push("- Connection: ready");
429
+ lines.push("- Governance: " + governance.governanceStatus);
321
430
  lines.push("- Recovery: ready");
322
- lines.push("- Next: agentbridge start");
431
+ lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
432
+ lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
433
+ lines.push("- Next: run `agentbridge watch` beside Cursor for live supervision");
434
+ }
435
+ else if (productStatus === "ready_basic_recovery") {
436
+ lines.push("- Connection: ready");
437
+ lines.push("- Governance: " + governance.governanceStatus);
438
+ lines.push("- Recovery: basic");
439
+ lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
440
+ lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
441
+ lines.push("- Note: Project context exists, but domains are not fully mapped yet.");
442
+ lines.push("- Next: run `agentbridge recover --force` for a full domain rebuild, or `agentbridge watch` for live supervision");
323
443
  }
324
444
  else if (productStatus === "active_work_found") {
445
+ const recoveryBasic = (0, recovery_reconcile_1.recoveryIsBasicPacket)(projectAccess.packet);
325
446
  lines.push("- Connection: ready");
326
- lines.push("- Recovery: ready");
447
+ lines.push("- Governance: " + governance.governanceStatus);
448
+ lines.push("- Recovery: " + (recoveryBasic ? "basic" : "ready"));
449
+ lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
450
+ lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
451
+ if (recoveryBasic) {
452
+ lines.push("- Note: Project context exists, but domains are not fully mapped yet.");
453
+ }
327
454
  lines.push("- Active work: found");
328
- lines.push("- Next: agentbridge start");
455
+ lines.push("- Next: run `agentbridge watch` beside Cursor for live supervision");
329
456
  }
330
457
  else if (productStatus === "needs_recover") {
331
458
  lines.push("- Connection: ready");
459
+ lines.push("- Governance: " + governance.governanceStatus);
332
460
  lines.push("- Recovery: required");
461
+ lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
462
+ lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
333
463
  lines.push("- Next: agentbridge recover");
334
464
  }
335
465
  else {
336
466
  lines.push("- Connection: incomplete");
467
+ lines.push("- Governance: " + governance.governanceStatus);
337
468
  lines.push("- Recovery: pending");
469
+ lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
470
+ lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
338
471
  if (!projectConfigPresent) {
339
472
  lines.push("- Note: Connection details are missing. Add credentials, then rerun agentbridge doctor.");
340
473
  }
474
+ else if (projectAccess.status === "failed" &&
475
+ (projectAccess.reason === "unauthorized" ||
476
+ projectAccess.reason === "forbidden" ||
477
+ projectAccess.reason === "not_project_member")) {
478
+ lines.push("- Reason: API key rejected by server.");
479
+ lines.push("- Next: run `agentbridge room exit`, get a fresh key from the dashboard, then `agentbridge connect`.");
480
+ if (identityAccess.executionSurfaceId) {
481
+ lines.push("- Note: Config still has a saved execution surface, but the server rejected the stored API key.");
482
+ }
483
+ }
341
484
  else if (!identityAccess.startCapable) {
342
485
  lines.push("- Reason: execution surface missing.");
343
486
  lines.push("- Next: agentbridge connect");
344
487
  }
345
- else if (identityAccess.status !== "ok") {
346
- lines.push("- Note: Caller identity is unresolved. Run agentbridge identity list and set a valid active agent.");
347
- }
348
488
  else {
349
489
  lines.push("- Note: Connection check failed. Verify credentials/network, then rerun agentbridge doctor.");
350
490
  }
351
- if (identityAccess.startCapable) {
491
+ if (identityAccess.startCapable &&
492
+ projectAccess.status === "failed" &&
493
+ projectAccess.reason !== "unauthorized" &&
494
+ projectAccess.reason !== "forbidden" &&
495
+ projectAccess.reason !== "not_project_member") {
352
496
  lines.push("- Next: agentbridge doctor");
353
497
  }
354
498
  }
499
+ lines.push("");
500
+ lines.push("Advanced details:");
501
+ lines.push(`- Caller identity access: ${identityAccess.status}`);
502
+ if (identityAccess.reason) {
503
+ lines.push(`- Caller identity reason: ${identityAccess.reason}`);
504
+ }
505
+ lines.push(`- Caller identity model: ${identityAccess.identityModel}`);
506
+ lines.push(`- Execution surface present: ${identityAccess.executionSurfaceId ? "yes" : "no"}`);
507
+ if (identityAccess.executionSurfaceSource) {
508
+ lines.push(`- Execution surface source: ${identityAccess.executionSurfaceSource}`);
509
+ }
510
+ lines.push(`- Start capable (strict/session modes): ${identityAccess.startCapable ? "yes" : "no"}`);
511
+ if (identityAccess.status !== "ok") {
512
+ lines.push("- Note: internal identity mismatch affects strict/resume flows, not room-level inferred watch startup.");
513
+ }
514
+ if (governance.governanceStatus === "inactive") {
515
+ lines.push("");
516
+ lines.push("Governance note: AgentBridge can review in terminal, but your AI agent may not stop automatically until rules and MCP are both configured.");
517
+ }
518
+ else {
519
+ lines.push("");
520
+ lines.push("Governance note: AgentBridge rules are installed and MCP is configured. The AI agent should stop when AgentBridge flags blocked work.");
521
+ }
355
522
  process.stdout.write(`${lines.join("\n")}\n`);
356
523
  if (freshness.state === "stale")
357
524
  return 1;
358
525
  if (projectAccess.status === "failed")
359
526
  return 1;
360
- if (identityAccess.status === "failed")
361
- return 1;
362
527
  return 0;
363
528
  }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runInstallRules = runInstallRules;
4
+ const node_path_1 = require("node:path");
5
+ const node_process_1 = require("node:process");
6
+ const config_1 = require("../config");
7
+ const errors_1 = require("../errors");
8
+ const http_1 = require("../http");
9
+ const rules_sync_1 = require("../rules-sync");
10
+ function resolveNetworkContext(overrides) {
11
+ const cfg = (0, config_1.readConfig)();
12
+ const projectId = overrides.projectId ?? process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "";
13
+ const apiKey = overrides.apiKey ?? process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
14
+ const apiBaseUrl = overrides.apiBaseUrl ??
15
+ process.env.AGENTBRIDGE_BASE_URL ??
16
+ cfg.apiBaseUrl ??
17
+ "https://agentauth-api-production.up.railway.app";
18
+ if (!projectId || !apiKey) {
19
+ throw (0, errors_1.catalogCliError)("CONFIG_INCOMPLETE");
20
+ }
21
+ return { projectId, apiKey, apiBaseUrl };
22
+ }
23
+ async function runInstallRules(opts = {}) {
24
+ const ctx = resolveNetworkContext(opts);
25
+ const workspaceRoot = (0, node_process_1.cwd)();
26
+ let rules;
27
+ try {
28
+ rules = await (0, rules_sync_1.fetchProjectRules)(ctx);
29
+ }
30
+ catch (error) {
31
+ if ((0, http_1.isCliHttpError)(error)) {
32
+ throw new errors_1.SafeCliError(`Could not fetch AgentBridge rules for project ${ctx.projectId} (${error.status}).`);
33
+ }
34
+ throw error;
35
+ }
36
+ if (!Array.isArray(rules.files) || rules.files.length === 0) {
37
+ throw new errors_1.SafeCliError("AgentBridge rules response did not include any files to install.");
38
+ }
39
+ (0, rules_sync_1.writeRulesFiles)(workspaceRoot, rules.files);
40
+ let installedAt = null;
41
+ try {
42
+ const marked = await (0, rules_sync_1.markProjectRulesInstalled)(ctx);
43
+ installedAt = marked.rules_installed_at ?? null;
44
+ }
45
+ catch (error) {
46
+ if ((0, http_1.isCliHttpError)(error)) {
47
+ throw new errors_1.SafeCliError(`Wrote rules files locally, but could not mark them installed on the server (${error.status}).`);
48
+ }
49
+ throw error;
50
+ }
51
+ const projectName = (0, rules_sync_1.extractProjectNameFromRulesResponse)(rules.files);
52
+ const lines = [
53
+ "Installed AgentBridge protocol rules:",
54
+ ` Project: ${projectName ?? "(unknown name)"} (${ctx.projectId})`,
55
+ ` Wrote: ${(0, node_path_1.resolve)(workspaceRoot, "AGENTBRIDGE.md")}`,
56
+ ` Wrote: ${(0, node_path_1.resolve)(workspaceRoot, ".cursor", "rules", "agentbridge.mdc")}`,
57
+ ];
58
+ if (installedAt) {
59
+ lines.push(` Server marked installed at: ${installedAt}`);
60
+ }
61
+ lines.push("");
62
+ lines.push("Next: run `agentbridge doctor` to verify rules and MCP configuration.");
63
+ process.stdout.write(`${lines.join("\n")}\n`);
64
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runProofGuidance = runProofGuidance;
4
+ const config_1 = require("../config");
5
+ const errors_1 = require("../errors");
6
+ const server_sync_1 = require("../server-sync");
7
+ function resolveNetworkContext() {
8
+ const cfg = (0, config_1.readConfig)();
9
+ const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
10
+ const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
11
+ const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ?? cfg.apiBaseUrl ?? "https://agentauth-api-production.up.railway.app";
12
+ if (!projectId) {
13
+ throw new errors_1.SafeCliError("Missing AGENTBRIDGE_PROJECT_ID. Set AGENTBRIDGE_PROJECT_ID (or run `agentbridge init --project ...`).");
14
+ }
15
+ if (!apiKey) {
16
+ throw new errors_1.SafeCliError("Missing AGENTBRIDGE_API_KEY. Provide --api-key, set AGENTBRIDGE_API_KEY, or save apiKey in .agentbridge/config.json.");
17
+ }
18
+ return { projectId, apiKey, apiBaseUrl };
19
+ }
20
+ async function runProofGuidance(options = {}) {
21
+ const ctx = resolveNetworkContext();
22
+ const guidance = await (0, server_sync_1.fetchAgentProofGuidance)(ctx, {
23
+ workSessionId: options.workSessionId,
24
+ changeRequestId: options.changeRequestId,
25
+ rolloutProofTooWeak: options.rolloutProofTooWeak,
26
+ rolloutProofNotRelevant: options.rolloutProofNotRelevant,
27
+ rolloutImpactCoverageGap: options.rolloutImpactCoverageGap,
28
+ });
29
+ process.stdout.write(`${JSON.stringify(guidance, null, 2)}\n`);
30
+ }