@agentbridge1/cli 0.0.4 → 0.0.6
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/dist/build-info.json +4 -4
- package/dist/commands/accept.js +4 -4
- package/dist/commands/check.js +10 -1
- package/dist/commands/connect.js +192 -13
- package/dist/commands/doctor.js +163 -29
- package/dist/commands/proof-guidance.js +30 -0
- package/dist/commands/recover.js +171 -22
- package/dist/commands/setup-mcp.js +22 -1
- package/dist/commands/start.js +57 -63
- package/dist/commands/verify.js +124 -91
- package/dist/commands/watch.js +428 -113
- package/dist/error-catalog.js +57 -16
- package/dist/gates.js +3 -3
- package/dist/git-evidence.js +2 -0
- package/dist/http.js +29 -0
- package/dist/index.js +47 -30
- package/dist/init.js +204 -30
- package/dist/local-memory.js +33 -0
- package/dist/local-proof.js +158 -0
- package/dist/local-session-mirror.js +247 -0
- package/dist/local-supervision.js +250 -0
- package/dist/mcp/agentbridge-mcp.js +22947 -0
- package/dist/mcp/agentbridge-mcp.js.map +7 -0
- package/dist/mcp-runtime.js +31 -0
- package/dist/preflight-changed-files.js +24 -17
- package/dist/proof-obligations.js +155 -0
- package/dist/recovery-reconcile.js +183 -0
- package/dist/server-sync.js +36 -0
- package/dist/session-state.js +119 -21
- package/dist/session.js +9 -2
- package/dist/supervision.js +100 -6
- package/package.json +5 -2
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"builtAt": "2026-06-
|
|
3
|
-
"gitHead": "
|
|
4
|
-
"sourceLatestMtime": "2026-06-
|
|
5
|
-
"sourceLatestFile": "src/commands/
|
|
2
|
+
"builtAt": "2026-06-06T12:05:27.957Z",
|
|
3
|
+
"gitHead": "ec17ba8",
|
|
4
|
+
"sourceLatestMtime": "2026-06-06T11:59:41.649Z",
|
|
5
|
+
"sourceLatestFile": "src/commands/watch.ts"
|
|
6
6
|
}
|
package/dist/commands/accept.js
CHANGED
|
@@ -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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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) {
|
package/dist/commands/check.js
CHANGED
|
@@ -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
|
-
|
|
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.");
|
package/dist/commands/connect.js
CHANGED
|
@@ -84,6 +84,113 @@ async function listAgents(projectId, apiKey, apiBaseUrl) {
|
|
|
84
84
|
const body = (await res.json());
|
|
85
85
|
return Array.isArray(body.agents) ? body.agents : [];
|
|
86
86
|
}
|
|
87
|
+
async function resolveExecutionSurfaceFromHello(projectId, apiKey, apiBaseUrl) {
|
|
88
|
+
const url = `${apiBaseUrl}/v1/dev/projects/${projectId}/hello`;
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetch(url, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Bearer ${apiKey}`,
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify({ tool_type: "cli" }),
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
return {
|
|
100
|
+
executionSurfaceId: null,
|
|
101
|
+
identityModel: "unknown",
|
|
102
|
+
status: `http_${res.status}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const body = (await res.json());
|
|
106
|
+
if (body.identity_model !== "work_identity") {
|
|
107
|
+
if (body.identity_model === "legacy") {
|
|
108
|
+
return {
|
|
109
|
+
executionSurfaceId: null,
|
|
110
|
+
identityModel: "legacy",
|
|
111
|
+
status: "legacy_identity",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
executionSurfaceId: null,
|
|
116
|
+
identityModel: "unknown",
|
|
117
|
+
status: "unknown_identity_model",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const surfaceId = body.execution_surface?.id?.trim();
|
|
121
|
+
return {
|
|
122
|
+
executionSurfaceId: surfaceId || null,
|
|
123
|
+
identityModel: "work_identity",
|
|
124
|
+
status: surfaceId ? "ok" : "missing_execution_surface",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return {
|
|
129
|
+
executionSurfaceId: null,
|
|
130
|
+
identityModel: "unknown",
|
|
131
|
+
status: "network_error",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function bootstrapDefaultConnection(projectId, apiKey, apiBaseUrl) {
|
|
136
|
+
const url = `${apiBaseUrl}/v1/dev/projects/${projectId}/connections/bootstrap-default`;
|
|
137
|
+
try {
|
|
138
|
+
const res = await fetch(url, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: `Bearer ${apiKey}`,
|
|
142
|
+
"Content-Type": "application/json",
|
|
143
|
+
},
|
|
144
|
+
body: JSON.stringify({}),
|
|
145
|
+
});
|
|
146
|
+
if (!res.ok)
|
|
147
|
+
return { ok: false, status: res.status, reason: `http_${res.status}` };
|
|
148
|
+
const body = (await res.json());
|
|
149
|
+
const nextApiKey = body.api_key?.trim();
|
|
150
|
+
const executionSurfaceId = body.execution_surface_id?.trim();
|
|
151
|
+
if (!nextApiKey || !executionSurfaceId) {
|
|
152
|
+
return { ok: false, status: 200, reason: "invalid_payload" };
|
|
153
|
+
}
|
|
154
|
+
return { ok: true, apiKey: nextApiKey, executionSurfaceId };
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return { ok: false, status: 0, reason: "network_error" };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function rotateActiveConnectionKey(projectId, apiKey, apiBaseUrl) {
|
|
161
|
+
const listUrl = `${apiBaseUrl}/v1/dev/projects/${projectId}/connections`;
|
|
162
|
+
try {
|
|
163
|
+
const listRes = await fetch(listUrl, {
|
|
164
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
165
|
+
});
|
|
166
|
+
if (!listRes.ok)
|
|
167
|
+
return { ok: false, reason: `list_http_${listRes.status}` };
|
|
168
|
+
const listBody = (await listRes.json());
|
|
169
|
+
const activeConnection = (listBody.connections ?? []).find((connection) => connection?.id && connection?.status === "active");
|
|
170
|
+
if (!activeConnection?.id)
|
|
171
|
+
return { ok: false, reason: "no_active_connection" };
|
|
172
|
+
const rotateUrl = `${apiBaseUrl}/v1/dev/projects/${projectId}/connections/${activeConnection.id}/rotate-key`;
|
|
173
|
+
const rotateRes = await fetch(rotateUrl, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
headers: {
|
|
176
|
+
Authorization: `Bearer ${apiKey}`,
|
|
177
|
+
"Content-Type": "application/json",
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify({}),
|
|
180
|
+
});
|
|
181
|
+
if (!rotateRes.ok)
|
|
182
|
+
return { ok: false, reason: `rotate_http_${rotateRes.status}` };
|
|
183
|
+
const rotateBody = (await rotateRes.json());
|
|
184
|
+
const rotatedApiKey = rotateBody.api_key?.trim();
|
|
185
|
+
const executionSurfaceId = rotateBody.connection?.execution_surface?.id?.trim();
|
|
186
|
+
if (!rotatedApiKey || !executionSurfaceId)
|
|
187
|
+
return { ok: false, reason: "invalid_payload" };
|
|
188
|
+
return { ok: true, apiKey: rotatedApiKey, executionSurfaceId };
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return { ok: false, reason: "network_error" };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
87
194
|
async function runConnect(options = {}) {
|
|
88
195
|
process.stdout.write("AgentBridge connect\n");
|
|
89
196
|
process.stdout.write("─────────────────────────────────────────\n");
|
|
@@ -142,13 +249,86 @@ async function runConnect(options = {}) {
|
|
|
142
249
|
throw err;
|
|
143
250
|
}
|
|
144
251
|
process.stdout.write("OK\n");
|
|
252
|
+
let effectiveApiKey = apiKey;
|
|
253
|
+
const diagnostics = {
|
|
254
|
+
helloIdentityModel: "unknown",
|
|
255
|
+
helloStatus: "not_attempted",
|
|
256
|
+
bootstrapStatus: "not_attempted",
|
|
257
|
+
rotateStatus: "not_attempted",
|
|
258
|
+
};
|
|
259
|
+
const helloResolution = await resolveExecutionSurfaceFromHello(projectId, effectiveApiKey, apiBaseUrl);
|
|
260
|
+
diagnostics.helloIdentityModel = helloResolution.identityModel;
|
|
261
|
+
diagnostics.helloStatus = helloResolution.status;
|
|
262
|
+
let executionSurfaceId = helloResolution.executionSurfaceId;
|
|
263
|
+
let connectionUpgraded = false;
|
|
264
|
+
if (!executionSurfaceId) {
|
|
265
|
+
diagnostics.bootstrapStatus = "attempted";
|
|
266
|
+
const bootstrapAttempt = await bootstrapDefaultConnection(projectId, effectiveApiKey, apiBaseUrl);
|
|
267
|
+
if (bootstrapAttempt.ok) {
|
|
268
|
+
effectiveApiKey = bootstrapAttempt.apiKey;
|
|
269
|
+
executionSurfaceId = bootstrapAttempt.executionSurfaceId;
|
|
270
|
+
diagnostics.bootstrapStatus = "ok";
|
|
271
|
+
diagnostics.rotateStatus = "skipped";
|
|
272
|
+
connectionUpgraded = true;
|
|
273
|
+
}
|
|
274
|
+
else if (bootstrapAttempt.status === 409) {
|
|
275
|
+
diagnostics.bootstrapStatus = "http_409_existing_connection";
|
|
276
|
+
const rotated = await rotateActiveConnectionKey(projectId, effectiveApiKey, apiBaseUrl);
|
|
277
|
+
if (rotated.ok) {
|
|
278
|
+
diagnostics.rotateStatus = "ok";
|
|
279
|
+
effectiveApiKey = rotated.apiKey;
|
|
280
|
+
executionSurfaceId = rotated.executionSurfaceId;
|
|
281
|
+
connectionUpgraded = true;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
diagnostics.rotateStatus = rotated.reason;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
diagnostics.bootstrapStatus = bootstrapAttempt.reason;
|
|
289
|
+
diagnostics.rotateStatus = "skipped";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
diagnostics.bootstrapStatus = "skipped";
|
|
294
|
+
diagnostics.rotateStatus = "skipped";
|
|
295
|
+
}
|
|
296
|
+
if (!executionSurfaceId) {
|
|
297
|
+
(0, config_1.updateConfig)({
|
|
298
|
+
projectId,
|
|
299
|
+
apiKey: effectiveApiKey,
|
|
300
|
+
apiBaseUrl,
|
|
301
|
+
});
|
|
302
|
+
throw new errors_1.SafeCliError([
|
|
303
|
+
"Connection incomplete.",
|
|
304
|
+
"Project access was verified, but AgentBridge could not create or resolve an execution surface.",
|
|
305
|
+
"Tracked work cannot start yet.",
|
|
306
|
+
"",
|
|
307
|
+
`hello identity model: ${diagnostics.helloIdentityModel}`,
|
|
308
|
+
`hello status: ${diagnostics.helloStatus}`,
|
|
309
|
+
`bootstrap-default status: ${diagnostics.bootstrapStatus}`,
|
|
310
|
+
`rotate-key status: ${diagnostics.rotateStatus}`,
|
|
311
|
+
`backend URL: ${apiBaseUrl}`,
|
|
312
|
+
].join("\n"));
|
|
313
|
+
}
|
|
145
314
|
// Persist credentials
|
|
146
|
-
(0, config_1.updateConfig)({
|
|
315
|
+
(0, config_1.updateConfig)({
|
|
316
|
+
projectId,
|
|
317
|
+
apiKey: effectiveApiKey,
|
|
318
|
+
apiBaseUrl,
|
|
319
|
+
...(executionSurfaceId ? { executionSurfaceId } : {}),
|
|
320
|
+
});
|
|
147
321
|
process.stdout.write("Credentials saved to .agentbridge/config.json\n");
|
|
322
|
+
if (connectionUpgraded) {
|
|
323
|
+
process.stdout.write("Auto-configured an AgentConnection key and execution surface for this project.\n");
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
process.stdout.write(`Execution surface: ${executionSurfaceId}\n`);
|
|
327
|
+
}
|
|
148
328
|
// Pick or auto-select an agent identity
|
|
149
329
|
let activeAgentId = options.agentId ?? cfg.activeAgentId;
|
|
150
330
|
if (!activeAgentId) {
|
|
151
|
-
const agents = await listAgents(projectId,
|
|
331
|
+
const agents = await listAgents(projectId, effectiveApiKey, apiBaseUrl);
|
|
152
332
|
if (agents.length === 1 && agents[0]) {
|
|
153
333
|
activeAgentId = agents[0].id;
|
|
154
334
|
(0, config_1.updateConfig)({ activeAgentId });
|
|
@@ -159,7 +339,7 @@ async function runConnect(options = {}) {
|
|
|
159
339
|
for (const a of agents) {
|
|
160
340
|
process.stdout.write(` ${a.id} ${a.name ?? ""} ${a.role ?? ""}\n`.trimEnd() + "\n");
|
|
161
341
|
}
|
|
162
|
-
process.stdout.write('\nRun `agentbridge use <agent-id>` to select one
|
|
342
|
+
process.stdout.write('\nRun `agentbridge use <agent-id>` to select one.\n');
|
|
163
343
|
}
|
|
164
344
|
}
|
|
165
345
|
else {
|
|
@@ -169,24 +349,23 @@ async function runConnect(options = {}) {
|
|
|
169
349
|
process.stdout.write("\n");
|
|
170
350
|
process.stdout.write(`Project: ${projectName}\n`);
|
|
171
351
|
process.stdout.write(`Agents: ${agentCount}\n`);
|
|
352
|
+
process.stdout.write(`Execution surface: ${executionSurfaceId}\n`);
|
|
172
353
|
process.stdout.write(`Server: ${apiBaseUrl}\n`);
|
|
173
354
|
process.stdout.write("\n");
|
|
174
355
|
if (activeAgentId) {
|
|
175
|
-
process.stdout.write("✓ Connected
|
|
356
|
+
process.stdout.write("✓ Connected and ready.\n");
|
|
176
357
|
process.stdout.write([
|
|
177
358
|
"",
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"",
|
|
181
|
-
" 2. Run the watcher (keep it running in a terminal):",
|
|
182
|
-
" agentbridge watch",
|
|
183
|
-
"",
|
|
184
|
-
" 3. Code normally — AgentBridge watches in the background.",
|
|
185
|
-
" Approvals surface when you cross domain boundaries.",
|
|
359
|
+
"Next:",
|
|
360
|
+
" agentbridge doctor",
|
|
361
|
+
" agentbridge watch",
|
|
186
362
|
"",
|
|
187
363
|
].join("\n"));
|
|
188
364
|
}
|
|
189
365
|
else {
|
|
190
|
-
process.stdout.write("✓ Connected
|
|
366
|
+
process.stdout.write("✓ Connected.\n");
|
|
367
|
+
process.stdout.write("Run `agentbridge use <agent-id>` and then:\n");
|
|
368
|
+
process.stdout.write(" agentbridge doctor\n");
|
|
369
|
+
process.stdout.write(" agentbridge watch\n");
|
|
191
370
|
}
|
|
192
371
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -10,6 +10,7 @@ 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");
|
|
13
14
|
function cliRootFromCommandDir() {
|
|
14
15
|
return (0, node_path_1.resolve)(__dirname, "..", "..");
|
|
15
16
|
}
|
|
@@ -86,11 +87,27 @@ function extractHttpReason(error) {
|
|
|
86
87
|
}
|
|
87
88
|
return `http_${error.status}`;
|
|
88
89
|
}
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
90
|
+
function detectGovernanceSignals(workspaceRoot) {
|
|
91
|
+
const rulesMdcPath = (0, node_path_1.resolve)(workspaceRoot, ".cursor", "rules", "agentbridge.mdc");
|
|
92
|
+
const rulesMarkdownPath = (0, node_path_1.resolve)(workspaceRoot, "AGENTBRIDGE.md");
|
|
93
|
+
const mcpConfigPath = (0, node_path_1.resolve)(workspaceRoot, ".cursor", "mcp.json");
|
|
94
|
+
const rulesInstalled = (0, node_fs_1.existsSync)(rulesMdcPath) && (0, node_fs_1.existsSync)(rulesMarkdownPath);
|
|
95
|
+
let mcpConfigured = false;
|
|
96
|
+
if ((0, node_fs_1.existsSync)(mcpConfigPath)) {
|
|
97
|
+
try {
|
|
98
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(mcpConfigPath, "utf8"));
|
|
99
|
+
mcpConfigured = Boolean(parsed?.mcpServers &&
|
|
100
|
+
(parsed.mcpServers["agentbridge"] || parsed.mcpServers["agentbridge-mcp"]));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
mcpConfigured = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
rulesInstalled,
|
|
108
|
+
mcpConfigured,
|
|
109
|
+
governanceStatus: rulesInstalled && mcpConfigured ? "active" : "inactive",
|
|
110
|
+
};
|
|
94
111
|
}
|
|
95
112
|
async function checkProjectAccess(ctx) {
|
|
96
113
|
if (!ctx.configComplete) {
|
|
@@ -146,7 +163,39 @@ async function checkProjectAccess(ctx) {
|
|
|
146
163
|
}
|
|
147
164
|
async function checkIdentityAccess(ctx) {
|
|
148
165
|
if (!ctx.configComplete) {
|
|
149
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
status: "skipped",
|
|
168
|
+
reason: "config_incomplete",
|
|
169
|
+
identityModel: "unknown",
|
|
170
|
+
executionSurfaceId: null,
|
|
171
|
+
startCapable: false,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const helloUrl = `${ctx.apiBaseUrl}/v1/dev/projects/${ctx.projectId}/hello`;
|
|
175
|
+
let identityModel = "unknown";
|
|
176
|
+
let executionSurfaceId = null;
|
|
177
|
+
try {
|
|
178
|
+
const helloRes = await fetch(helloUrl, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: {
|
|
181
|
+
Authorization: `Bearer ${ctx.apiKey}`,
|
|
182
|
+
"Content-Type": "application/json",
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify({ tool_type: "cli" }),
|
|
185
|
+
});
|
|
186
|
+
if (helloRes.ok) {
|
|
187
|
+
const hello = (await helloRes.json());
|
|
188
|
+
if (hello.identity_model === "work_identity") {
|
|
189
|
+
identityModel = "work_identity";
|
|
190
|
+
}
|
|
191
|
+
else if (hello.identity_model === "legacy") {
|
|
192
|
+
identityModel = "legacy";
|
|
193
|
+
}
|
|
194
|
+
executionSurfaceId = hello.execution_surface?.id?.trim() || null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Keep default unknown/null and continue with identity resolution checks.
|
|
150
199
|
}
|
|
151
200
|
try {
|
|
152
201
|
const syncCtx = {
|
|
@@ -160,18 +209,34 @@ async function checkIdentityAccess(ctx) {
|
|
|
160
209
|
(0, server_sync_1.listWorkIdentities)(syncCtx),
|
|
161
210
|
]);
|
|
162
211
|
const callerId = callerPacket?.work_identity?.id ?? null;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
212
|
+
const startCapable = Boolean(executionSurfaceId);
|
|
213
|
+
if (callerId) {
|
|
214
|
+
return { status: "ok", identityModel, executionSurfaceId, startCapable };
|
|
215
|
+
}
|
|
216
|
+
if (identities.length === 1) {
|
|
217
|
+
return { status: "ok", identityModel, executionSurfaceId, startCapable };
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
status: "failed",
|
|
221
|
+
reason: "caller_identity_unresolved",
|
|
222
|
+
identityModel,
|
|
223
|
+
executionSurfaceId,
|
|
224
|
+
startCapable,
|
|
225
|
+
};
|
|
168
226
|
}
|
|
169
227
|
catch {
|
|
170
|
-
return {
|
|
228
|
+
return {
|
|
229
|
+
status: "failed",
|
|
230
|
+
reason: "caller_identity_unresolved",
|
|
231
|
+
identityModel,
|
|
232
|
+
executionSurfaceId,
|
|
233
|
+
startCapable: Boolean(executionSurfaceId),
|
|
234
|
+
};
|
|
171
235
|
}
|
|
172
236
|
}
|
|
173
237
|
async function runDoctor(cliRootOverride) {
|
|
174
238
|
const cliRoot = cliRootOverride ?? cliRootFromCommandDir();
|
|
239
|
+
const workspaceRoot = process.cwd();
|
|
175
240
|
const cfg = (0, config_1.readConfig)();
|
|
176
241
|
const freshness = (0, dist_freshness_1.getDistFreshnessReport)(cliRoot);
|
|
177
242
|
const configPath = cliRootOverride
|
|
@@ -191,6 +256,7 @@ async function runDoctor(cliRootOverride) {
|
|
|
191
256
|
const projectConfigPresent = projectIdPresent && apiKeyPresent && baseUrlPresent;
|
|
192
257
|
const activeSession = (0, session_state_1.readSessionState)();
|
|
193
258
|
const hasActiveWork = Boolean(activeSession?.id || activeSession?.serverSessionId);
|
|
259
|
+
const governance = detectGovernanceSignals(workspaceRoot);
|
|
194
260
|
const envContributed = Boolean(process.env.AGENTBRIDGE_PROJECT_ID) ||
|
|
195
261
|
Boolean(process.env.AGENTBRIDGE_API_KEY) ||
|
|
196
262
|
Boolean(process.env.AGENTBRIDGE_BASE_URL) ||
|
|
@@ -230,10 +296,10 @@ async function runDoctor(cliRootOverride) {
|
|
|
230
296
|
apiBaseUrl: resolvedBaseUrl,
|
|
231
297
|
configComplete: projectConfigPresent && projectAccess.status === "ok",
|
|
232
298
|
});
|
|
233
|
-
lines.push(`
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
299
|
+
lines.push(`Rules installed: ${governance.rulesInstalled ? "yes" : "no"}`);
|
|
300
|
+
lines.push(`MCP configured: ${governance.mcpConfigured ? "yes" : "no"}`);
|
|
301
|
+
lines.push(`Agent governance: ${governance.governanceStatus}`);
|
|
302
|
+
lines.push(`Start capable: ${identityAccess.startCapable ? "yes" : "no"}`);
|
|
237
303
|
if (projectAccess.status === "failed" && projectAccess.reason) {
|
|
238
304
|
const view = (0, error_catalog_1.catalogViewForDoctorReason)(projectAccess.reason, projectAccess.suggestedNextAction);
|
|
239
305
|
lines.push("");
|
|
@@ -252,54 +318,122 @@ async function runDoctor(cliRootOverride) {
|
|
|
252
318
|
lines.push("Suggested next action: run npm run dogfood:check before external dogfood.");
|
|
253
319
|
}
|
|
254
320
|
let productStatus = "not_ready";
|
|
255
|
-
if (projectAccess.status === "ok" &&
|
|
321
|
+
if (projectAccess.status === "ok" &&
|
|
322
|
+
identityAccess.status === "ok" &&
|
|
323
|
+
identityAccess.startCapable) {
|
|
256
324
|
if (hasActiveWork) {
|
|
257
325
|
productStatus = "active_work_found";
|
|
258
326
|
}
|
|
259
327
|
else {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
328
|
+
if ((0, recovery_reconcile_1.recoveryBaselineRequired)(projectAccess.packet)) {
|
|
329
|
+
productStatus = "needs_recover";
|
|
330
|
+
}
|
|
331
|
+
else if ((0, recovery_reconcile_1.recoveryIsBasicPacket)(projectAccess.packet)) {
|
|
332
|
+
productStatus = "ready_basic_recovery";
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
productStatus = "ready";
|
|
336
|
+
}
|
|
263
337
|
}
|
|
264
338
|
}
|
|
339
|
+
const localSupervisionReady = true;
|
|
340
|
+
const cloudSyncReady = projectAccess.status === "ok";
|
|
341
|
+
const strictTrackedReady = projectAccess.status === "ok" && identityAccess.status === "ok" && identityAccess.startCapable;
|
|
342
|
+
lines.push("");
|
|
343
|
+
lines.push("Capability levels:");
|
|
344
|
+
lines.push(`- Local supervision: ${localSupervisionReady ? "ready" : "unavailable"}`);
|
|
345
|
+
lines.push(`- Cloud sync: ${cloudSyncReady ? "ready" : "unavailable"}`);
|
|
346
|
+
lines.push(`- Strict tracked work: ${strictTrackedReady ? "ready" : "unavailable"}`);
|
|
347
|
+
if (!cloudSyncReady && projectAccess.reason) {
|
|
348
|
+
lines.push(` Cloud sync note: ${projectAccess.reason}`);
|
|
349
|
+
}
|
|
350
|
+
if (!strictTrackedReady && identityAccess.reason) {
|
|
351
|
+
lines.push(` Strict tracked note: ${identityAccess.reason}`);
|
|
352
|
+
}
|
|
265
353
|
lines.push("");
|
|
266
354
|
lines.push("Product status:");
|
|
267
355
|
if (productStatus === "ready") {
|
|
268
356
|
lines.push("- Connection: ready");
|
|
357
|
+
lines.push("- Governance: " + governance.governanceStatus);
|
|
269
358
|
lines.push("- Recovery: ready");
|
|
270
|
-
lines.push(
|
|
359
|
+
lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
|
|
360
|
+
lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
|
|
361
|
+
lines.push("- Next: run `agentbridge watch` beside Cursor for live supervision");
|
|
362
|
+
}
|
|
363
|
+
else if (productStatus === "ready_basic_recovery") {
|
|
364
|
+
lines.push("- Connection: ready");
|
|
365
|
+
lines.push("- Governance: " + governance.governanceStatus);
|
|
366
|
+
lines.push("- Recovery: basic");
|
|
367
|
+
lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
|
|
368
|
+
lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
|
|
369
|
+
lines.push("- Note: Project context exists, but domains are not fully mapped yet.");
|
|
370
|
+
lines.push("- Next: run `agent recover --force` for a full domain rebuild, or `agentbridge watch` for live supervision");
|
|
271
371
|
}
|
|
272
372
|
else if (productStatus === "active_work_found") {
|
|
373
|
+
const recoveryBasic = (0, recovery_reconcile_1.recoveryIsBasicPacket)(projectAccess.packet);
|
|
273
374
|
lines.push("- Connection: ready");
|
|
274
|
-
lines.push("-
|
|
375
|
+
lines.push("- Governance: " + governance.governanceStatus);
|
|
376
|
+
lines.push("- Recovery: " + (recoveryBasic ? "basic" : "ready"));
|
|
377
|
+
lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
|
|
378
|
+
lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
|
|
379
|
+
if (recoveryBasic) {
|
|
380
|
+
lines.push("- Note: Project context exists, but domains are not fully mapped yet.");
|
|
381
|
+
}
|
|
275
382
|
lines.push("- Active work: found");
|
|
276
|
-
lines.push("- Next: agentbridge
|
|
383
|
+
lines.push("- Next: run `agentbridge watch` beside Cursor for live supervision");
|
|
277
384
|
}
|
|
278
385
|
else if (productStatus === "needs_recover") {
|
|
279
386
|
lines.push("- Connection: ready");
|
|
387
|
+
lines.push("- Governance: " + governance.governanceStatus);
|
|
280
388
|
lines.push("- Recovery: required");
|
|
389
|
+
lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
|
|
390
|
+
lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
|
|
281
391
|
lines.push("- Next: agentbridge recover");
|
|
282
392
|
}
|
|
283
393
|
else {
|
|
284
|
-
lines.push("- Connection:
|
|
394
|
+
lines.push("- Connection: incomplete");
|
|
395
|
+
lines.push("- Governance: " + governance.governanceStatus);
|
|
285
396
|
lines.push("- Recovery: pending");
|
|
397
|
+
lines.push(`- Rules: ${governance.rulesInstalled ? "installed" : "missing"}`);
|
|
398
|
+
lines.push(`- MCP: ${governance.mcpConfigured ? "configured" : "missing"}`);
|
|
286
399
|
if (!projectConfigPresent) {
|
|
287
400
|
lines.push("- Note: Connection details are missing. Add credentials, then rerun agentbridge doctor.");
|
|
288
401
|
}
|
|
289
|
-
else if (identityAccess.
|
|
290
|
-
lines.push("-
|
|
402
|
+
else if (!identityAccess.startCapable) {
|
|
403
|
+
lines.push("- Reason: execution surface missing.");
|
|
404
|
+
lines.push("- Next: agentbridge connect");
|
|
291
405
|
}
|
|
292
406
|
else {
|
|
293
407
|
lines.push("- Note: Connection check failed. Verify credentials/network, then rerun agentbridge doctor.");
|
|
294
408
|
}
|
|
295
|
-
|
|
409
|
+
if (identityAccess.startCapable) {
|
|
410
|
+
lines.push("- Next: agentbridge doctor");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
lines.push("");
|
|
414
|
+
lines.push("Advanced details:");
|
|
415
|
+
lines.push(`- Caller identity access: ${identityAccess.status}`);
|
|
416
|
+
if (identityAccess.reason) {
|
|
417
|
+
lines.push(`- Caller identity reason: ${identityAccess.reason}`);
|
|
418
|
+
}
|
|
419
|
+
lines.push(`- Caller identity model: ${identityAccess.identityModel}`);
|
|
420
|
+
lines.push(`- Execution surface present: ${identityAccess.executionSurfaceId ? "yes" : "no"}`);
|
|
421
|
+
lines.push(`- Start capable (strict/session modes): ${identityAccess.startCapable ? "yes" : "no"}`);
|
|
422
|
+
if (identityAccess.status !== "ok") {
|
|
423
|
+
lines.push("- Note: internal identity mismatch affects strict/resume flows, not room-level inferred watch startup.");
|
|
424
|
+
}
|
|
425
|
+
if (governance.governanceStatus === "inactive") {
|
|
426
|
+
lines.push("");
|
|
427
|
+
lines.push("Governance note: AgentBridge can review in terminal, but your AI agent may not stop automatically until rules and MCP are both configured.");
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
lines.push("");
|
|
431
|
+
lines.push("Governance note: AgentBridge rules are installed and MCP is configured. The AI agent should stop when AgentBridge flags blocked work.");
|
|
296
432
|
}
|
|
297
433
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
298
434
|
if (freshness.state === "stale")
|
|
299
435
|
return 1;
|
|
300
436
|
if (projectAccess.status === "failed")
|
|
301
437
|
return 1;
|
|
302
|
-
if (identityAccess.status === "failed")
|
|
303
|
-
return 1;
|
|
304
438
|
return 0;
|
|
305
439
|
}
|
|
@@ -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
|
+
}
|