@agentbridge1/cli 0.0.1
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/bin/agentbridge.js +11 -0
- package/dist/acceptance-block.js +21 -0
- package/dist/acceptance-preflight.js +91 -0
- package/dist/api-client.js +6 -0
- package/dist/authority-request.js +25 -0
- package/dist/briefing.js +26 -0
- package/dist/bug-registry.js +350 -0
- package/dist/build-info.json +6 -0
- package/dist/canonical-state.js +11 -0
- package/dist/claimed-paths.js +42 -0
- package/dist/cli-failure-log.js +34 -0
- package/dist/commands/accept.js +241 -0
- package/dist/commands/attention.js +85 -0
- package/dist/commands/autopilot.js +93 -0
- package/dist/commands/bug.js +106 -0
- package/dist/commands/check.js +283 -0
- package/dist/commands/connect.js +159 -0
- package/dist/commands/dist-freshness.js +105 -0
- package/dist/commands/doctor.js +300 -0
- package/dist/commands/done.js +292 -0
- package/dist/commands/handoff.js +189 -0
- package/dist/commands/handshake.js +78 -0
- package/dist/commands/health.js +154 -0
- package/dist/commands/identity.js +57 -0
- package/dist/commands/init.js +5 -0
- package/dist/commands/memory.js +400 -0
- package/dist/commands/next.js +21 -0
- package/dist/commands/precommit-check.js +17 -0
- package/dist/commands/recover.js +116 -0
- package/dist/commands/session.js +229 -0
- package/dist/commands/setup-mcp.js +56 -0
- package/dist/commands/start.js +626 -0
- package/dist/commands/status.js +486 -0
- package/dist/commands/use.js +13 -0
- package/dist/commands/verify.js +264 -0
- package/dist/commands/version.js +32 -0
- package/dist/commands/watch.js +1718 -0
- package/dist/config.js +55 -0
- package/dist/domain-resolution.js +63 -0
- package/dist/error-catalog.js +494 -0
- package/dist/errors.js +276 -0
- package/dist/file-fingerprints.js +45 -0
- package/dist/gates.js +200 -0
- package/dist/git-evidence.js +285 -0
- package/dist/git-status.js +81 -0
- package/dist/http.js +151 -0
- package/dist/index.js +622 -0
- package/dist/init.js +458 -0
- package/dist/memory-context-render.js +51 -0
- package/dist/operator-snapshot.js +99 -0
- package/dist/precommit.js +72 -0
- package/dist/preflight-changed-files.js +109 -0
- package/dist/proof-guidance.js +110 -0
- package/dist/redact-secrets.js +15 -0
- package/dist/revert-crossing.js +73 -0
- package/dist/server-sync.js +433 -0
- package/dist/session-state.js +138 -0
- package/dist/session.js +89 -0
- package/dist/supervision.js +212 -0
- package/dist/terminal-ui.js +18 -0
- package/dist/test-runner.js +62 -0
- package/dist/types.js +2 -0
- package/dist/verification-conditions.js +185 -0
- package/dist/watch-core.js +208 -0
- package/dist/watch-packet-handshake.js +71 -0
- package/dist/watcher.js +62 -0
- package/dist/work-context-resolver.js +412 -0
- package/dist/work-contract.js +110 -0
- package/package.json +44 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDoctor = runDoctor;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const config_1 = require("../config");
|
|
7
|
+
const error_catalog_1 = require("../error-catalog");
|
|
8
|
+
const errors_1 = require("../errors");
|
|
9
|
+
const http_1 = require("../http");
|
|
10
|
+
const dist_freshness_1 = require("./dist-freshness");
|
|
11
|
+
const session_state_1 = require("../session-state");
|
|
12
|
+
const server_sync_1 = require("../server-sync");
|
|
13
|
+
function cliRootFromCommandDir() {
|
|
14
|
+
return (0, node_path_1.resolve)(__dirname, "..", "..");
|
|
15
|
+
}
|
|
16
|
+
function normalizeReasonCandidate(value) {
|
|
17
|
+
if (!value)
|
|
18
|
+
return undefined;
|
|
19
|
+
const trimmed = value.trim();
|
|
20
|
+
if (!trimmed)
|
|
21
|
+
return undefined;
|
|
22
|
+
const lowered = trimmed.toLowerCase();
|
|
23
|
+
if (lowered.includes("not_project_member"))
|
|
24
|
+
return "not_project_member";
|
|
25
|
+
if (lowered.includes("unauthorized") || lowered.includes("invalid_api_key"))
|
|
26
|
+
return "unauthorized";
|
|
27
|
+
if (lowered.includes("forbidden"))
|
|
28
|
+
return "forbidden";
|
|
29
|
+
if (lowered.includes("project_not_found"))
|
|
30
|
+
return "project_not_found";
|
|
31
|
+
if (lowered.includes("not_found") && lowered.includes("project"))
|
|
32
|
+
return "project_not_found";
|
|
33
|
+
if (lowered.includes("too_many_requests") || lowered.includes("rate_limit"))
|
|
34
|
+
return "rate_limited";
|
|
35
|
+
if (lowered.includes("timed_out") || lowered.includes("timeout"))
|
|
36
|
+
return "request_timeout";
|
|
37
|
+
if (lowered.includes("network_error") ||
|
|
38
|
+
lowered.includes("fetch failed") ||
|
|
39
|
+
lowered.includes("econnrefused") ||
|
|
40
|
+
lowered.includes("econnreset") ||
|
|
41
|
+
lowered.includes("enotfound")) {
|
|
42
|
+
return "network_error";
|
|
43
|
+
}
|
|
44
|
+
const normalized = lowered.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
45
|
+
if (normalized.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (normalized.length <= 64)
|
|
48
|
+
return normalized;
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function extractHttpReason(error) {
|
|
52
|
+
const rawBodyReason = normalizeReasonCandidate(error.body);
|
|
53
|
+
if (rawBodyReason) {
|
|
54
|
+
return rawBodyReason;
|
|
55
|
+
}
|
|
56
|
+
if (error.body) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(error.body);
|
|
59
|
+
const code = parsed.error?.code ?? parsed.code;
|
|
60
|
+
const codeReason = normalizeReasonCandidate(code);
|
|
61
|
+
if (codeReason)
|
|
62
|
+
return codeReason;
|
|
63
|
+
const message = parsed.error?.message ?? parsed.message;
|
|
64
|
+
const messageReason = normalizeReasonCandidate(message);
|
|
65
|
+
if (messageReason)
|
|
66
|
+
return messageReason;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// fall through to status/body fallback
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (error.status === 404) {
|
|
73
|
+
return "project_not_found";
|
|
74
|
+
}
|
|
75
|
+
if (error.status === 429) {
|
|
76
|
+
return "rate_limited";
|
|
77
|
+
}
|
|
78
|
+
if (error.status === 403) {
|
|
79
|
+
return "forbidden";
|
|
80
|
+
}
|
|
81
|
+
if (error.status === 401) {
|
|
82
|
+
return "unauthorized";
|
|
83
|
+
}
|
|
84
|
+
if (error.status >= 500) {
|
|
85
|
+
return "server_error";
|
|
86
|
+
}
|
|
87
|
+
return `http_${error.status}`;
|
|
88
|
+
}
|
|
89
|
+
async function checkProjectAccess(ctx) {
|
|
90
|
+
if (!ctx.configComplete) {
|
|
91
|
+
return {
|
|
92
|
+
status: "skipped",
|
|
93
|
+
reason: "config_incomplete",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const projectId = ctx.projectId;
|
|
97
|
+
const apiKey = ctx.apiKey;
|
|
98
|
+
const apiBaseUrl = ctx.apiBaseUrl;
|
|
99
|
+
try {
|
|
100
|
+
await (0, http_1.getJson)({ projectId, apiKey, apiBaseUrl, apiKeySource: "config" }, `/v1/dev/projects/${encodeURIComponent(projectId)}/packet`);
|
|
101
|
+
return { status: "ok" };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (error instanceof http_1.CliHttpError) {
|
|
105
|
+
const reason = extractHttpReason(error);
|
|
106
|
+
if (reason === "not_project_member") {
|
|
107
|
+
return {
|
|
108
|
+
status: "failed",
|
|
109
|
+
reason,
|
|
110
|
+
suggestedNextAction: "use an API key/agent that is a member of this project, or add this agent to the project.",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (reason === "unauthorized") {
|
|
114
|
+
return {
|
|
115
|
+
status: "failed",
|
|
116
|
+
reason,
|
|
117
|
+
suggestedNextAction: "verify AGENTBRIDGE_API_KEY is valid for this environment and has project read access.",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (reason === "project_not_found") {
|
|
121
|
+
return {
|
|
122
|
+
status: "failed",
|
|
123
|
+
reason,
|
|
124
|
+
suggestedNextAction: "verify AGENTBRIDGE_PROJECT_ID points to an existing project in this API environment.",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
status: "failed",
|
|
129
|
+
reason,
|
|
130
|
+
suggestedNextAction: "confirm project ID, API key, and base URL are correct and that this key has project read access.",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const messageReason = error instanceof Error ? normalizeReasonCandidate(error.message) : undefined;
|
|
134
|
+
return {
|
|
135
|
+
status: "failed",
|
|
136
|
+
reason: messageReason ?? "network_error",
|
|
137
|
+
suggestedNextAction: "check network reachability to the API base URL and retry doctor.",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function checkIdentityAccess(ctx) {
|
|
142
|
+
if (!ctx.configComplete) {
|
|
143
|
+
return { status: "skipped", reason: "config_incomplete" };
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const syncCtx = {
|
|
147
|
+
projectId: ctx.projectId,
|
|
148
|
+
apiKey: ctx.apiKey,
|
|
149
|
+
apiBaseUrl: ctx.apiBaseUrl,
|
|
150
|
+
apiKeySource: "config",
|
|
151
|
+
};
|
|
152
|
+
const [callerPacket, identities] = await Promise.all([
|
|
153
|
+
(0, server_sync_1.fetchCallerIdentityPacket)(syncCtx),
|
|
154
|
+
(0, server_sync_1.listWorkIdentities)(syncCtx),
|
|
155
|
+
]);
|
|
156
|
+
const callerId = callerPacket?.work_identity?.id ?? null;
|
|
157
|
+
if (callerId)
|
|
158
|
+
return { status: "ok" };
|
|
159
|
+
if (identities.length === 1)
|
|
160
|
+
return { status: "ok" };
|
|
161
|
+
return { status: "failed", reason: "caller_identity_unresolved" };
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return { status: "failed", reason: "caller_identity_unresolved" };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function runDoctor(cliRootOverride) {
|
|
168
|
+
const cliRoot = cliRootOverride ?? cliRootFromCommandDir();
|
|
169
|
+
const cfg = (0, config_1.readConfig)();
|
|
170
|
+
const freshness = (0, dist_freshness_1.getDistFreshnessReport)(cliRoot);
|
|
171
|
+
const configPath = cliRootOverride
|
|
172
|
+
? (0, node_path_1.resolve)(cliRoot, "..", ".agentbridge", "config.json")
|
|
173
|
+
: config_1.CONFIG_PATH;
|
|
174
|
+
const projectConfigFilePresent = (0, node_fs_1.existsSync)(configPath);
|
|
175
|
+
const resolvedProjectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
|
|
176
|
+
const resolvedApiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey;
|
|
177
|
+
const resolvedBaseUrl = process.env.AGENTBRIDGE_BASE_URL ??
|
|
178
|
+
cfg.apiBaseUrl ??
|
|
179
|
+
"https://agentauth-api-production.up.railway.app";
|
|
180
|
+
const resolvedAgentId = process.env.AGENTBRIDGE_AGENT_ID ?? cfg.activeAgentId;
|
|
181
|
+
const projectIdPresent = Boolean(resolvedProjectId);
|
|
182
|
+
const apiKeyPresent = Boolean(resolvedApiKey);
|
|
183
|
+
const baseUrlPresent = Boolean(resolvedBaseUrl);
|
|
184
|
+
const agentIdPresent = Boolean(resolvedAgentId);
|
|
185
|
+
const projectConfigPresent = projectIdPresent && apiKeyPresent && baseUrlPresent;
|
|
186
|
+
const activeSession = (0, session_state_1.readSessionState)();
|
|
187
|
+
const hasActiveWork = Boolean(activeSession?.id || activeSession?.serverSessionId);
|
|
188
|
+
const envContributed = Boolean(process.env.AGENTBRIDGE_PROJECT_ID) ||
|
|
189
|
+
Boolean(process.env.AGENTBRIDGE_API_KEY) ||
|
|
190
|
+
Boolean(process.env.AGENTBRIDGE_BASE_URL) ||
|
|
191
|
+
Boolean(process.env.AGENTBRIDGE_AGENT_ID);
|
|
192
|
+
const fileContributed = Boolean(cfg.projectId) || Boolean(cfg.apiKey) || Boolean(cfg.apiBaseUrl) || Boolean(cfg.activeAgentId);
|
|
193
|
+
const configSource = envContributed && fileContributed ? "mixed" : envContributed ? "env" : fileContributed ? "file" : "missing";
|
|
194
|
+
const lines = [];
|
|
195
|
+
lines.push("AgentBridge CLI doctor");
|
|
196
|
+
lines.push(`CLI dist: ${freshness.state}`);
|
|
197
|
+
lines.push(`Build timestamp: ${freshness.builtAt ?? "unknown"}`);
|
|
198
|
+
lines.push(`Git head: ${freshness.gitHead ?? "unknown"}`);
|
|
199
|
+
lines.push(`Source newer than dist: ${freshness.sourceNewerThanDist}`);
|
|
200
|
+
if (freshness.reason) {
|
|
201
|
+
lines.push(`Dist reason: ${freshness.reason}`);
|
|
202
|
+
}
|
|
203
|
+
lines.push(`Project config present: ${projectConfigPresent ? "yes" : "no"}`);
|
|
204
|
+
lines.push(`Project config file present: ${projectConfigFilePresent ? "yes" : "no"}`);
|
|
205
|
+
lines.push(`Project ID present: ${projectIdPresent ? "yes" : "no"}`);
|
|
206
|
+
lines.push(`Base URL present: ${baseUrlPresent ? "yes" : "no"}`);
|
|
207
|
+
lines.push(`API key present: ${apiKeyPresent ? "yes" : "no"}`);
|
|
208
|
+
lines.push(`Agent ID present: ${agentIdPresent ? "yes" : "no"}`);
|
|
209
|
+
lines.push(`Config source: ${configSource}`);
|
|
210
|
+
lines.push(`Active work state: ${hasActiveWork ? "found" : "none"}`);
|
|
211
|
+
const projectAccess = await checkProjectAccess({
|
|
212
|
+
projectId: resolvedProjectId,
|
|
213
|
+
apiKey: resolvedApiKey,
|
|
214
|
+
apiBaseUrl: resolvedBaseUrl,
|
|
215
|
+
configComplete: projectConfigPresent,
|
|
216
|
+
});
|
|
217
|
+
lines.push(`Project access: ${projectAccess.status}`);
|
|
218
|
+
if (projectAccess.reason) {
|
|
219
|
+
lines.push(`Project access reason: ${projectAccess.reason}`);
|
|
220
|
+
}
|
|
221
|
+
const identityAccess = await checkIdentityAccess({
|
|
222
|
+
projectId: resolvedProjectId,
|
|
223
|
+
apiKey: resolvedApiKey,
|
|
224
|
+
apiBaseUrl: resolvedBaseUrl,
|
|
225
|
+
configComplete: projectConfigPresent && projectAccess.status === "ok",
|
|
226
|
+
});
|
|
227
|
+
lines.push(`Caller identity access: ${identityAccess.status}`);
|
|
228
|
+
if (identityAccess.reason) {
|
|
229
|
+
lines.push(`Caller identity reason: ${identityAccess.reason}`);
|
|
230
|
+
}
|
|
231
|
+
if (projectAccess.status === "failed" && projectAccess.reason) {
|
|
232
|
+
const view = (0, error_catalog_1.catalogViewForDoctorReason)(projectAccess.reason, projectAccess.suggestedNextAction);
|
|
233
|
+
lines.push("");
|
|
234
|
+
lines.push((0, errors_1.renderCliErrorView)(view));
|
|
235
|
+
}
|
|
236
|
+
else if (projectAccess.status === "failed" && projectAccess.suggestedNextAction) {
|
|
237
|
+
lines.push(`Suggested next action: ${projectAccess.suggestedNextAction}`);
|
|
238
|
+
}
|
|
239
|
+
else if (freshness.state === "stale") {
|
|
240
|
+
lines.push("Suggested next action: run npm run build:cli, then rerun doctor.");
|
|
241
|
+
}
|
|
242
|
+
else if (freshness.state === "unknown") {
|
|
243
|
+
lines.push("Suggested next action: run npm run build:cli to generate dist metadata.");
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
lines.push("Suggested next action: run npm run dogfood:check before external dogfood.");
|
|
247
|
+
}
|
|
248
|
+
let productStatus = "not_ready";
|
|
249
|
+
if (projectAccess.status === "ok" && identityAccess.status === "ok") {
|
|
250
|
+
if (hasActiveWork) {
|
|
251
|
+
productStatus = "active_work_found";
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
productStatus =
|
|
255
|
+
cfg.domains && cfg.domains.length > 0
|
|
256
|
+
? "ready"
|
|
257
|
+
: "needs_recover";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
lines.push("");
|
|
261
|
+
lines.push("Product status:");
|
|
262
|
+
if (productStatus === "ready") {
|
|
263
|
+
lines.push("- Connection: ready");
|
|
264
|
+
lines.push("- Recovery: ready");
|
|
265
|
+
lines.push("- Next: agentbridge start");
|
|
266
|
+
}
|
|
267
|
+
else if (productStatus === "active_work_found") {
|
|
268
|
+
lines.push("- Connection: ready");
|
|
269
|
+
lines.push("- Recovery: ready");
|
|
270
|
+
lines.push("- Active work: found");
|
|
271
|
+
lines.push("- Next: agentbridge start");
|
|
272
|
+
}
|
|
273
|
+
else if (productStatus === "needs_recover") {
|
|
274
|
+
lines.push("- Connection: ready");
|
|
275
|
+
lines.push("- Recovery: required");
|
|
276
|
+
lines.push("- Next: agentbridge recover");
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
lines.push("- Connection: required");
|
|
280
|
+
lines.push("- Recovery: pending");
|
|
281
|
+
if (!projectConfigPresent) {
|
|
282
|
+
lines.push("- Note: Connection details are missing. Add credentials, then rerun agentbridge doctor.");
|
|
283
|
+
}
|
|
284
|
+
else if (identityAccess.status !== "ok") {
|
|
285
|
+
lines.push("- Note: Caller identity is unresolved. Run agentbridge identity list and set a valid active agent.");
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
lines.push("- Note: Connection check failed. Verify credentials/network, then rerun agentbridge doctor.");
|
|
289
|
+
}
|
|
290
|
+
lines.push("- Next: agentbridge doctor");
|
|
291
|
+
}
|
|
292
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
293
|
+
if (freshness.state === "stale")
|
|
294
|
+
return 1;
|
|
295
|
+
if (projectAccess.status === "failed")
|
|
296
|
+
return 1;
|
|
297
|
+
if (identityAccess.status === "failed")
|
|
298
|
+
return 1;
|
|
299
|
+
return 0;
|
|
300
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__doneInternals = void 0;
|
|
4
|
+
exports.runDone = runDone;
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const acceptance_preflight_1 = require("../acceptance-preflight");
|
|
8
|
+
const acceptance_block_1 = require("../acceptance-block");
|
|
9
|
+
const work_context_resolver_1 = require("../work-context-resolver");
|
|
10
|
+
const operator_snapshot_1 = require("../operator-snapshot");
|
|
11
|
+
const operator_snapshot_2 = require("../operator-snapshot");
|
|
12
|
+
const proof_guidance_1 = require("../proof-guidance");
|
|
13
|
+
const memory_context_render_1 = require("../memory-context-render");
|
|
14
|
+
const check_1 = require("./check");
|
|
15
|
+
function resolveNetworkContext() {
|
|
16
|
+
const cfg = (0, config_1.readConfig)();
|
|
17
|
+
const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
|
|
18
|
+
const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
|
|
19
|
+
const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ?? cfg.apiBaseUrl ?? "https://agentauth-api-production.up.railway.app";
|
|
20
|
+
if (!projectId) {
|
|
21
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_PROJECT_ID. Set AGENTBRIDGE_PROJECT_ID (or run `agentbridge init --project ...`).");
|
|
22
|
+
}
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_API_KEY. Provide --api-key, set AGENTBRIDGE_API_KEY, or save apiKey in .agentbridge/config.json.");
|
|
25
|
+
}
|
|
26
|
+
return { projectId, apiKey, apiBaseUrl };
|
|
27
|
+
}
|
|
28
|
+
function normalizeChangedFiles(files) {
|
|
29
|
+
return [...new Set(files.map((file) => file.trim()).filter((file) => file.length > 0))].sort();
|
|
30
|
+
}
|
|
31
|
+
function resolveHandoffStatus(report) {
|
|
32
|
+
return report.handoff.status === "posted" ? "present" : "missing";
|
|
33
|
+
}
|
|
34
|
+
function renderNoActive(ctx) {
|
|
35
|
+
const cfg = (0, config_1.readConfig)();
|
|
36
|
+
const lines = [];
|
|
37
|
+
if (cfg.lastAcceptedSessionId) {
|
|
38
|
+
lines.push(`Status: no_current_session (${operator_snapshot_2.COMPLETION_STATE_LABELS.no_current_session})`);
|
|
39
|
+
lines.push("Error code: WORK_CONTEXT_NO_CURRENT_SESSION");
|
|
40
|
+
lines.push("What happened: No active tracked work session is currently resolved.");
|
|
41
|
+
lines.push("Why it matters: Done/acceptance gates cannot evaluate without a current session.");
|
|
42
|
+
lines.push(`Last accepted session: ${cfg.lastAcceptedSessionId}`);
|
|
43
|
+
lines.push("Next: agentbridge watch");
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
46
|
+
lines.push("Status: no_current_session (No current tracked work session)");
|
|
47
|
+
lines.push("Error code: WORK_CONTEXT_NO_CURRENT_SESSION");
|
|
48
|
+
lines.push("What happened: No active tracked work session found.");
|
|
49
|
+
lines.push("Why it matters: Done/acceptance gates cannot evaluate without a current session.");
|
|
50
|
+
lines.push("Next: agentbridge watch");
|
|
51
|
+
return lines.join("\n");
|
|
52
|
+
}
|
|
53
|
+
function renderList(title, values) {
|
|
54
|
+
if (values.length === 0)
|
|
55
|
+
return [title, "- none"];
|
|
56
|
+
return [title, ...values.map((value, index) => `${index + 1}. ${value}`)];
|
|
57
|
+
}
|
|
58
|
+
function renderEvidenceSummary(report) {
|
|
59
|
+
if (report.verification_runs.length === 0)
|
|
60
|
+
return "none";
|
|
61
|
+
const fresh = report.verification_runs.filter((run) => !run.stale);
|
|
62
|
+
const stale = report.verification_runs.filter((run) => run.stale);
|
|
63
|
+
const freshText = fresh.length > 0 ? fresh.map((run) => `[${run.status}] ${run.command}`).join(" | ") : "none";
|
|
64
|
+
const staleText = stale.length > 0 ? stale.map((run) => `[${run.status}] ${run.command} (stale)`).join(" | ") : "none";
|
|
65
|
+
return `Fresh: ${freshText}; Stale: ${staleText}`;
|
|
66
|
+
}
|
|
67
|
+
function suggestVerifyCommand(report, changedFiles) {
|
|
68
|
+
const detailSuggestion = (0, proof_guidance_1.getMissingProofDetails)(report)
|
|
69
|
+
.map((detail) => detail.suggested_verify?.trim())
|
|
70
|
+
.find((value) => Boolean(value && value.length > 0));
|
|
71
|
+
if (detailSuggestion)
|
|
72
|
+
return detailSuggestion;
|
|
73
|
+
const candidates = (0, proof_guidance_1.suggestVerifyCommands)([...changedFiles, ...report.changed_files], report.detected_work_type);
|
|
74
|
+
return candidates[0] ?? "agentbridge verify -- <command>";
|
|
75
|
+
}
|
|
76
|
+
function buildNeedsProofPrompt(report, verifyCommand, missingDetails = (0, proof_guidance_1.getMissingProofDetails)(report)) {
|
|
77
|
+
const numbered = (missingDetails.length > 0
|
|
78
|
+
? missingDetails.map((detail) => `${detail.message}\n Why: ${detail.why}\n Source/rule: ${detail.source_rule}\n Recipe: ${detail.proof_recipe}`)
|
|
79
|
+
: ["(no explicit missing proof listed)"])
|
|
80
|
+
.map((item, idx) => `${idx + 1}. ${item}`)
|
|
81
|
+
.join("\n");
|
|
82
|
+
return (`"Before this work can be accepted, complete the following proof items:\n` +
|
|
83
|
+
`${numbered}\n` +
|
|
84
|
+
`Run the relevant verification commands.\n` +
|
|
85
|
+
`Suggested first command: ${verifyCommand}\n` +
|
|
86
|
+
`Return exact outputs.\n` +
|
|
87
|
+
`Do not modify unrelated files."`);
|
|
88
|
+
}
|
|
89
|
+
function buildFailedPrompt(report) {
|
|
90
|
+
const failed = report.verification_runs
|
|
91
|
+
.filter((run) => run.status === "failed")
|
|
92
|
+
.map((run) => run.command);
|
|
93
|
+
const reasons = failed.length > 0 ? failed : report.next_required_action;
|
|
94
|
+
const numbered = (reasons.length > 0 ? reasons : ["(no explicit failure reason listed)"])
|
|
95
|
+
.map((item, idx) => `${idx + 1}. ${item}`)
|
|
96
|
+
.join("\n");
|
|
97
|
+
return (`"This work failed acceptance because:\n` +
|
|
98
|
+
`${numbered}\n` +
|
|
99
|
+
`Investigate only the changed files and failed evidence.\n` +
|
|
100
|
+
`Do not broaden scope."`);
|
|
101
|
+
}
|
|
102
|
+
function buildNeedsReviewPrompt(report) {
|
|
103
|
+
const scopeDriftReasons = (report.out_of_scope_files ?? []).length > 0
|
|
104
|
+
? (report.out_of_scope_files ?? []).map((file, idx) => `${idx + 1}. out-of-scope file: ${file}`)
|
|
105
|
+
: [];
|
|
106
|
+
const fallbackReasons = report.next_required_action.length > 0
|
|
107
|
+
? report.next_required_action.map((item, idx) => `${idx + 1}. ${item}`)
|
|
108
|
+
: ["1. (no explicit review reason listed)"];
|
|
109
|
+
const reasons = [...scopeDriftReasons, ...fallbackReasons].join("\n");
|
|
110
|
+
return (`"This work needs review due to scope/boundary constraints:\n` +
|
|
111
|
+
`${reasons}\n` +
|
|
112
|
+
`Revert/remove out-of-scope files, rerun agentbridge check, then continue.\n` +
|
|
113
|
+
`Do not broaden implementation."`);
|
|
114
|
+
}
|
|
115
|
+
function renderAcceptanceSweep(report, preSyncedChangedFiles) {
|
|
116
|
+
const lines = [];
|
|
117
|
+
const handoffStatus = resolveHandoffStatus(report);
|
|
118
|
+
const changedUnion = normalizeChangedFiles([...preSyncedChangedFiles, ...report.changed_files]);
|
|
119
|
+
const changedFiles = changedUnion.length > 0 ? changedUnion.join(", ") : "none";
|
|
120
|
+
const evidenceSummary = renderEvidenceSummary(report);
|
|
121
|
+
const missingDetails = (0, proof_guidance_1.getMissingProofDetails)(report);
|
|
122
|
+
const verifyCommand = suggestVerifyCommand(report, changedUnion);
|
|
123
|
+
let statusState = "no_current_session";
|
|
124
|
+
let exactNextAction = "agentbridge check";
|
|
125
|
+
let next = `Next: ${exactNextAction}`;
|
|
126
|
+
const completionState = report.completion.state;
|
|
127
|
+
if (completionState === "needs_proof") {
|
|
128
|
+
statusState = "needs_proof";
|
|
129
|
+
exactNextAction = verifyCommand;
|
|
130
|
+
next = "Next: agentbridge verify -- <command>";
|
|
131
|
+
}
|
|
132
|
+
else if (completionState === "stale_evidence") {
|
|
133
|
+
statusState = "stale_evidence";
|
|
134
|
+
exactNextAction = verifyCommand;
|
|
135
|
+
next = "Next: agentbridge verify -- <command> (re-verify after file change)";
|
|
136
|
+
}
|
|
137
|
+
else if (completionState === "failed") {
|
|
138
|
+
statusState = "failed";
|
|
139
|
+
exactNextAction = "investigate failed evidence in changed files only";
|
|
140
|
+
next = "Next: investigate failed evidence in changed files only";
|
|
141
|
+
}
|
|
142
|
+
else if (completionState === "needs_review") {
|
|
143
|
+
statusState = "needs_review";
|
|
144
|
+
if ((report.out_of_scope_files ?? []).length > 0) {
|
|
145
|
+
exactNextAction = "revert/remove out-of-scope files, then rerun agentbridge check";
|
|
146
|
+
next = "Next: revert/remove out-of-scope files, then rerun agentbridge check";
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
exactNextAction = "request approval / handoff / update scope";
|
|
150
|
+
next = "Next: request approval / handoff / update scope";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (completionState === "ready_for_handoff") {
|
|
154
|
+
statusState = "ready_for_handoff";
|
|
155
|
+
exactNextAction = 'agentbridge handoff --summary "<what changed>"';
|
|
156
|
+
next = 'Next: agentbridge handoff --summary "<what changed>"';
|
|
157
|
+
}
|
|
158
|
+
else if (completionState === "ready_to_accept") {
|
|
159
|
+
statusState = "ready_to_accept";
|
|
160
|
+
exactNextAction = "agentbridge accept";
|
|
161
|
+
next = "Next: agentbridge accept";
|
|
162
|
+
}
|
|
163
|
+
else if (completionState === "accepted") {
|
|
164
|
+
statusState = "accepted";
|
|
165
|
+
exactNextAction = "agentbridge watch";
|
|
166
|
+
next = "Next: agentbridge watch";
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
statusState = "no_current_session";
|
|
170
|
+
exactNextAction = "agentbridge watch";
|
|
171
|
+
next = "Next: agentbridge watch";
|
|
172
|
+
}
|
|
173
|
+
lines.push("ACCEPTANCE SWEEP");
|
|
174
|
+
lines.push(`Status: ${statusState} (${operator_snapshot_2.COMPLETION_STATE_LABELS[statusState]})`);
|
|
175
|
+
lines.push(`Current CR/session: ${report.change_request_id ?? "none"} / ${report.work_session_id}`);
|
|
176
|
+
lines.push(`Changed files: ${changedFiles}`);
|
|
177
|
+
lines.push(`Evidence summary: ${evidenceSummary}`);
|
|
178
|
+
if (report.proof_quality) {
|
|
179
|
+
lines.push(`Proof confidence: ${report.proof_quality.confidence_level}`);
|
|
180
|
+
if (report.proof_quality.missing_robustness.length > 0) {
|
|
181
|
+
lines.push(`Missing robustness: ${report.proof_quality.missing_robustness.join(" | ")}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const memoryContextLines = (0, memory_context_render_1.renderMemoryContextLines)(report.memory_context);
|
|
185
|
+
if (memoryContextLines.length > 0) {
|
|
186
|
+
lines.push("");
|
|
187
|
+
lines.push(...memoryContextLines);
|
|
188
|
+
}
|
|
189
|
+
lines.push(`Missing proof: ${missingDetails.length > 0 ? missingDetails.map((detail) => detail.message).join(" | ") : "none"}`);
|
|
190
|
+
lines.push(`Risks remaining: ${report.risks_remaining.length > 0 ? report.risks_remaining.join(" | ") : "none"}`);
|
|
191
|
+
lines.push(`Protocol warnings: ${report.protocol_warnings.length > 0
|
|
192
|
+
? report.protocol_warnings.map((warning) => `${warning.code}: ${warning.message}`).join(" | ")
|
|
193
|
+
: "none"}`);
|
|
194
|
+
lines.push(`Handoff status: ${handoffStatus}`);
|
|
195
|
+
lines.push(`Acceptance decision: ${report.decision}`);
|
|
196
|
+
lines.push(`Exact next action: ${exactNextAction}`);
|
|
197
|
+
lines.push(next);
|
|
198
|
+
if (completionState === "needs_proof") {
|
|
199
|
+
lines.push("");
|
|
200
|
+
lines.push("Missing proof list:");
|
|
201
|
+
if (missingDetails.length === 0) {
|
|
202
|
+
lines.push("1. (no explicit missing proof listed)");
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
for (const [index, detail] of missingDetails.entries()) {
|
|
206
|
+
lines.push(`${index + 1}. ${detail.message}`);
|
|
207
|
+
lines.push(` Why: ${detail.why}`);
|
|
208
|
+
lines.push(` Source/rule: ${detail.source_rule}`);
|
|
209
|
+
lines.push(` Recipe: ${detail.proof_recipe}`);
|
|
210
|
+
if (detail.suggested_verify) {
|
|
211
|
+
lines.push(` Suggested verify: ${detail.suggested_verify}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
lines.push("Copy this back to the agent:");
|
|
216
|
+
lines.push(buildNeedsProofPrompt(report, verifyCommand, missingDetails));
|
|
217
|
+
}
|
|
218
|
+
else if (completionState === "stale_evidence") {
|
|
219
|
+
lines.push("");
|
|
220
|
+
lines.push("Stale evidence (PROOF_STALE_AFTER_CHANGE):");
|
|
221
|
+
if ((report.stale_files ?? []).length > 0) {
|
|
222
|
+
lines.push(...renderList("Files needing re-verification:", report.stale_files ?? []));
|
|
223
|
+
}
|
|
224
|
+
lines.push("Copy this back to the agent:");
|
|
225
|
+
lines.push((0, check_1.buildStaleProofPrompt)(report));
|
|
226
|
+
}
|
|
227
|
+
else if (completionState === "failed") {
|
|
228
|
+
const failedEvidence = report.verification_runs
|
|
229
|
+
.filter((run) => run.status === "failed")
|
|
230
|
+
.map((run) => run.command);
|
|
231
|
+
lines.push("");
|
|
232
|
+
lines.push(...renderList("Failed evidence/reasons:", failedEvidence.length > 0 ? failedEvidence : report.next_required_action));
|
|
233
|
+
lines.push("Copy this back to the agent:");
|
|
234
|
+
lines.push(buildFailedPrompt(report));
|
|
235
|
+
}
|
|
236
|
+
else if (completionState === "needs_review") {
|
|
237
|
+
lines.push("");
|
|
238
|
+
if ((report.out_of_scope_files ?? []).length > 0) {
|
|
239
|
+
lines.push("Scope drift (SCOPE_DRIFT_OUT_OF_SCOPE_FILE):");
|
|
240
|
+
lines.push(...(report.out_of_scope_files ?? []).map((file) => `- ${file}`));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
lines.push(...renderList("Scope/boundary reasons:", report.next_required_action));
|
|
244
|
+
}
|
|
245
|
+
lines.push("Copy this back to the agent:");
|
|
246
|
+
lines.push(buildNeedsReviewPrompt(report));
|
|
247
|
+
}
|
|
248
|
+
if (report.protocol_warnings.length > 0) {
|
|
249
|
+
lines.push("");
|
|
250
|
+
lines.push("Protocol warnings:");
|
|
251
|
+
for (const warning of report.protocol_warnings) {
|
|
252
|
+
lines.push(`- ${warning.code}: ${warning.message}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return lines.join("\n");
|
|
256
|
+
}
|
|
257
|
+
async function runDone(options = {}) {
|
|
258
|
+
const ctx = resolveNetworkContext();
|
|
259
|
+
const { resolution, preflight, report } = await (0, acceptance_preflight_1.resolveAcceptanceWorkContext)(ctx);
|
|
260
|
+
const snapshot = (0, operator_snapshot_1.buildOperatorSnapshot)(resolution);
|
|
261
|
+
const preSyncedChangedFiles = preflight.observedFiles;
|
|
262
|
+
if (resolution.state !== "current_session_resolved" || !report) {
|
|
263
|
+
if (options.json) {
|
|
264
|
+
process.stdout.write(`${JSON.stringify({ snapshot }, null, 2)}\n`);
|
|
265
|
+
process.exitCode = 1;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const body = resolution.state === "no_current_session"
|
|
269
|
+
? `${renderNoActive(ctx)}\n\n${(0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n")}`
|
|
270
|
+
: (0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n");
|
|
271
|
+
process.stdout.write(`${body}\n`);
|
|
272
|
+
process.exitCode = 1;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (options.json) {
|
|
276
|
+
process.stdout.write(`${JSON.stringify({ snapshot, acceptance_report: report }, null, 2)}\n`);
|
|
277
|
+
if ((0, acceptance_block_1.shouldBlockAcceptanceAction)(report)) {
|
|
278
|
+
process.exitCode = 1;
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const rendered = renderAcceptanceSweep(report, preSyncedChangedFiles);
|
|
283
|
+
process.stdout.write(`${rendered}\n`);
|
|
284
|
+
if ((0, acceptance_block_1.shouldBlockAcceptanceAction)(report)) {
|
|
285
|
+
process.exitCode = 1;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
exports.__doneInternals = {
|
|
289
|
+
renderAcceptanceSweep,
|
|
290
|
+
resolveHandoffStatus,
|
|
291
|
+
renderNoActive,
|
|
292
|
+
};
|