@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.
Files changed (69) hide show
  1. package/bin/agentbridge.js +11 -0
  2. package/dist/acceptance-block.js +21 -0
  3. package/dist/acceptance-preflight.js +91 -0
  4. package/dist/api-client.js +6 -0
  5. package/dist/authority-request.js +25 -0
  6. package/dist/briefing.js +26 -0
  7. package/dist/bug-registry.js +350 -0
  8. package/dist/build-info.json +6 -0
  9. package/dist/canonical-state.js +11 -0
  10. package/dist/claimed-paths.js +42 -0
  11. package/dist/cli-failure-log.js +34 -0
  12. package/dist/commands/accept.js +241 -0
  13. package/dist/commands/attention.js +85 -0
  14. package/dist/commands/autopilot.js +93 -0
  15. package/dist/commands/bug.js +106 -0
  16. package/dist/commands/check.js +283 -0
  17. package/dist/commands/connect.js +159 -0
  18. package/dist/commands/dist-freshness.js +105 -0
  19. package/dist/commands/doctor.js +300 -0
  20. package/dist/commands/done.js +292 -0
  21. package/dist/commands/handoff.js +189 -0
  22. package/dist/commands/handshake.js +78 -0
  23. package/dist/commands/health.js +154 -0
  24. package/dist/commands/identity.js +57 -0
  25. package/dist/commands/init.js +5 -0
  26. package/dist/commands/memory.js +400 -0
  27. package/dist/commands/next.js +21 -0
  28. package/dist/commands/precommit-check.js +17 -0
  29. package/dist/commands/recover.js +116 -0
  30. package/dist/commands/session.js +229 -0
  31. package/dist/commands/setup-mcp.js +56 -0
  32. package/dist/commands/start.js +626 -0
  33. package/dist/commands/status.js +486 -0
  34. package/dist/commands/use.js +13 -0
  35. package/dist/commands/verify.js +264 -0
  36. package/dist/commands/version.js +32 -0
  37. package/dist/commands/watch.js +1718 -0
  38. package/dist/config.js +55 -0
  39. package/dist/domain-resolution.js +63 -0
  40. package/dist/error-catalog.js +494 -0
  41. package/dist/errors.js +276 -0
  42. package/dist/file-fingerprints.js +45 -0
  43. package/dist/gates.js +200 -0
  44. package/dist/git-evidence.js +285 -0
  45. package/dist/git-status.js +81 -0
  46. package/dist/http.js +151 -0
  47. package/dist/index.js +622 -0
  48. package/dist/init.js +458 -0
  49. package/dist/memory-context-render.js +51 -0
  50. package/dist/operator-snapshot.js +99 -0
  51. package/dist/precommit.js +72 -0
  52. package/dist/preflight-changed-files.js +109 -0
  53. package/dist/proof-guidance.js +110 -0
  54. package/dist/redact-secrets.js +15 -0
  55. package/dist/revert-crossing.js +73 -0
  56. package/dist/server-sync.js +433 -0
  57. package/dist/session-state.js +138 -0
  58. package/dist/session.js +89 -0
  59. package/dist/supervision.js +212 -0
  60. package/dist/terminal-ui.js +18 -0
  61. package/dist/test-runner.js +62 -0
  62. package/dist/types.js +2 -0
  63. package/dist/verification-conditions.js +185 -0
  64. package/dist/watch-core.js +208 -0
  65. package/dist/watch-packet-handshake.js +71 -0
  66. package/dist/watcher.js +62 -0
  67. package/dist/work-context-resolver.js +412 -0
  68. package/dist/work-contract.js +110 -0
  69. package/package.json +44 -0
@@ -0,0 +1,400 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runMemorySuggest = runMemorySuggest;
4
+ exports.runMemoryApply = runMemoryApply;
5
+ exports.runMemoryReject = runMemoryReject;
6
+ exports.runMemoryDefer = runMemoryDefer;
7
+ exports.runMemoryIntakeEscapedBug = runMemoryIntakeEscapedBug;
8
+ exports.runMemoryRevert = runMemoryRevert;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const config_1 = require("../config");
12
+ const server_sync_1 = require("../server-sync");
13
+ const http_1 = require("../http");
14
+ const errors_1 = require("../errors");
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({
22
+ code: "CONFIG_INCOMPLETE",
23
+ category: "CONFIG_ERROR",
24
+ what: "Missing AGENTBRIDGE_PROJECT_ID.",
25
+ why: "Memory commands cannot reach the server without a project ID.",
26
+ next: "Set AGENTBRIDGE_PROJECT_ID or run `agentbridge init --project <id>`.",
27
+ });
28
+ }
29
+ if (!apiKey) {
30
+ throw new errors_1.SafeCliError({
31
+ code: "CONFIG_INCOMPLETE",
32
+ category: "CONFIG_ERROR",
33
+ what: "Missing AGENTBRIDGE_API_KEY.",
34
+ why: "Memory commands cannot authenticate without an API key.",
35
+ next: "Provide --api-key, set AGENTBRIDGE_API_KEY, or save apiKey in .agentbridge/config.json.",
36
+ });
37
+ }
38
+ return { projectId, apiKey, apiBaseUrl };
39
+ }
40
+ function isSecretLike(text) {
41
+ return /(api[_-]?key|bearer\s|sk-[a-z0-9]{10,}|password\s*[:=])/i.test(text);
42
+ }
43
+ function formatList(title, items) {
44
+ if (items.length === 0)
45
+ return [];
46
+ return [title, ...items.map((item) => ` - ${item}`)];
47
+ }
48
+ function firstTopItem(candidate) {
49
+ return (candidate.invariants[0] ??
50
+ candidate.known_traps[0] ??
51
+ candidate.future_proof_requirements[0] ??
52
+ candidate.accepted_lessons[0] ??
53
+ null);
54
+ }
55
+ function renderSuggestion(candidate, compact) {
56
+ const lines = [];
57
+ const rationale = candidate.reason ?? candidate.signal.reason;
58
+ lines.push(`Memory suggest: ${candidate.decision}`);
59
+ lines.push(`Rationale: ${rationale}`);
60
+ lines.push(`Signal durability: ${candidate.signal.durability} (${candidate.signal.reason})`);
61
+ lines.push(candidate.accepted_summary);
62
+ if (candidate.work_session_id) {
63
+ lines.push(`Work session: ${candidate.work_session_id}`);
64
+ }
65
+ if (candidate.change_request_id) {
66
+ lines.push(`Change request: ${candidate.change_request_id}`);
67
+ }
68
+ if (compact) {
69
+ const topItem = firstTopItem(candidate);
70
+ if (topItem)
71
+ lines.push(`Top item: ${topItem}`);
72
+ lines.push(`Evidence refs: ${candidate.evidence_refs.length}`);
73
+ if (candidate.omitted_low_signal_items?.length) {
74
+ lines.push(`Filtered items: ${candidate.omitted_low_signal_items.length}`);
75
+ }
76
+ if (candidate.excluded_audit_facts.length > 0) {
77
+ lines.push(`Excluded noise: ${candidate.excluded_audit_facts.length}`);
78
+ }
79
+ }
80
+ else {
81
+ lines.push(`Suggested scope: ${candidate.suggested_scope}`);
82
+ if (candidate.domain)
83
+ lines.push(`Domain: ${candidate.domain}`);
84
+ if (candidate.signal.detectors_triggered.length > 0) {
85
+ lines.push(`Detectors: ${candidate.signal.detectors_triggered.join(", ")}`);
86
+ }
87
+ lines.push(...formatList("Invariants:", candidate.invariants));
88
+ lines.push(...formatList("Known traps:", candidate.known_traps));
89
+ lines.push(...formatList("Future proof requirements:", candidate.future_proof_requirements));
90
+ lines.push(...formatList("Accepted lessons:", candidate.accepted_lessons));
91
+ if (candidate.evidence_refs.length > 0) {
92
+ lines.push("Evidence refs:");
93
+ for (const ref of candidate.evidence_refs) {
94
+ const note = ref.note ? ` (${ref.note})` : "";
95
+ lines.push(` - ${ref.type}:${ref.id}${note}`);
96
+ }
97
+ }
98
+ if (candidate.excluded_audit_facts.length > 0) {
99
+ lines.push(...formatList("Excluded noise:", candidate.excluded_audit_facts));
100
+ }
101
+ if (candidate.omitted_low_signal_items?.length) {
102
+ lines.push(...formatList("Omitted low signal items:", candidate.omitted_low_signal_items));
103
+ }
104
+ if (candidate.duplicate_or_related_memory?.length) {
105
+ lines.push("Related memory:");
106
+ for (const dup of candidate.duplicate_or_related_memory) {
107
+ const domain = dup.domain ? ` domain=${dup.domain}` : "";
108
+ lines.push(` - [${dup.scope}${domain}] ${dup.reason} (${dup.matched_fields.join(", ")})`);
109
+ }
110
+ }
111
+ }
112
+ const output = lines.join("\n");
113
+ if (isSecretLike(output)) {
114
+ throw new Error("Refusing to print memory suggestion output that may contain secrets.");
115
+ }
116
+ process.stdout.write(`${output}\n`);
117
+ }
118
+ async function runMemorySuggest(options) {
119
+ const ctx = resolveNetworkContext();
120
+ try {
121
+ const candidate = await (0, server_sync_1.fetchMemorySuggestion)(ctx, {
122
+ workSessionId: options.workSessionId,
123
+ changeRequestId: options.changeRequestId,
124
+ domain: options.domain,
125
+ });
126
+ if (options.json) {
127
+ process.stdout.write(`${JSON.stringify({ suggestion: candidate }, null, 2)}\n`);
128
+ return;
129
+ }
130
+ renderSuggestion(candidate, options.compact === true);
131
+ }
132
+ catch (error) {
133
+ const status = error instanceof http_1.CliHttpError
134
+ ? error.status
135
+ : typeof error === "object" &&
136
+ error !== null &&
137
+ "status" in error &&
138
+ typeof error.status === "number"
139
+ ? error.status
140
+ : null;
141
+ if (status !== null) {
142
+ const detail = status === 404
143
+ ? "No matching or accepted work session found. Try --work-session <id> or accept a session first."
144
+ : status === 400 || status === 422
145
+ ? "Invalid memory suggest request. Check --work-session/--change-request values."
146
+ : "Memory suggest failed. Run `agentbridge doctor` and retry.";
147
+ const why = status === 404
148
+ ? "Memory suggestions require a resolvable accepted or active work session context."
149
+ : status === 400 || status === 422
150
+ ? "The request payload did not satisfy server validation."
151
+ : "The server could not process this request.";
152
+ process.stderr.write([
153
+ `What happened: Memory suggest failed. ${detail}`,
154
+ `Why it matters: ${why}`,
155
+ "Next action: Run `agentbridge status` to confirm current context, then retry.",
156
+ ].join("\n") + "\n");
157
+ return;
158
+ }
159
+ throw error;
160
+ }
161
+ }
162
+ // ── Phase 6B: apply / reject / defer / revert ────────────────────────────────
163
+ function parseItemsFlag(value) {
164
+ if (!value || value.trim().length === 0)
165
+ return undefined;
166
+ // Expected format: --items invariants,known_traps (apply all from those buckets)
167
+ const buckets = value
168
+ .split(",")
169
+ .map((s) => s.trim())
170
+ .filter((s) => s.length > 0);
171
+ if (buckets.length === 0)
172
+ return undefined;
173
+ const out = {};
174
+ for (const bucket of buckets) {
175
+ if (bucket === "invariants" ||
176
+ bucket === "known_traps" ||
177
+ bucket === "future_proof_requirements" ||
178
+ bucket === "accepted_lessons") {
179
+ out[bucket] = null; // placeholder; resolved at apply time using candidate
180
+ }
181
+ else {
182
+ throw new Error(`Unknown items bucket: ${bucket}. Allowed: invariants, known_traps, future_proof_requirements, accepted_lessons`);
183
+ }
184
+ }
185
+ return out;
186
+ }
187
+ function fetchAndValidateCandidate(ctx, options) {
188
+ return (0, server_sync_1.fetchMemorySuggestion)(ctx, options);
189
+ }
190
+ function ensureSuggestable(candidate) {
191
+ if (candidate.decision === "skip") {
192
+ throw new Error(`Candidate decision is "skip": ${candidate.signal.reason}. Nothing to apply.`);
193
+ }
194
+ }
195
+ function resolveAppliedItems(candidate, itemsFlag) {
196
+ if (!itemsFlag)
197
+ return undefined;
198
+ const out = {};
199
+ if (Object.prototype.hasOwnProperty.call(itemsFlag, "invariants")) {
200
+ out.invariants = candidate.invariants;
201
+ }
202
+ if (Object.prototype.hasOwnProperty.call(itemsFlag, "known_traps")) {
203
+ out.known_traps = candidate.known_traps;
204
+ }
205
+ if (Object.prototype.hasOwnProperty.call(itemsFlag, "future_proof_requirements")) {
206
+ out.future_proof_requirements = candidate.future_proof_requirements;
207
+ }
208
+ if (Object.prototype.hasOwnProperty.call(itemsFlag, "accepted_lessons")) {
209
+ out.accepted_lessons = candidate.accepted_lessons;
210
+ }
211
+ return out;
212
+ }
213
+ function handleApplyError(error, action) {
214
+ const view = (0, errors_1.formatCliError)(error);
215
+ const what = `Memory ${action} failed. ${view.what}`.trim();
216
+ process.stderr.write([
217
+ `What happened: ${what}`,
218
+ `Why it matters: ${view.why}`,
219
+ `Next action: ${view.next}`,
220
+ ].join("\n") + "\n");
221
+ }
222
+ async function runMemoryApply(options) {
223
+ const ctx = resolveNetworkContext();
224
+ try {
225
+ const candidate = await fetchAndValidateCandidate(ctx, {
226
+ workSessionId: options.workSessionId,
227
+ changeRequestId: options.changeRequestId,
228
+ domain: options.domain,
229
+ });
230
+ ensureSuggestable(candidate);
231
+ const scope = options.scope ?? candidate.suggested_scope;
232
+ const domain = options.domain ?? candidate.domain;
233
+ const itemsFlag = parseItemsFlag(options.items);
234
+ const resolvedItems = resolveAppliedItems(candidate, itemsFlag);
235
+ const result = await (0, server_sync_1.applyMemoryCandidateRequest)(ctx, {
236
+ scope,
237
+ domain,
238
+ items: resolvedItems,
239
+ reviewerNote: options.reviewerNote,
240
+ candidate,
241
+ });
242
+ const lines = [
243
+ `Memory applied: scope=${result.scope}${result.domain ? ` domain=${result.domain}` : ""}`,
244
+ `Approval audit_id: ${result.audit_id}`,
245
+ ];
246
+ if (result.pcs_id)
247
+ lines.push(`ProjectCurrentState id: ${result.pcs_id}`);
248
+ if (result.dm_id)
249
+ lines.push(`DomainMemory id: ${result.dm_id}`);
250
+ if (result.warnings.length > 0) {
251
+ lines.push(...formatList("Warnings:", result.warnings));
252
+ }
253
+ lines.push(`Revert with: agentbridge memory revert --approval-audit ${result.audit_id}`);
254
+ process.stdout.write(`${lines.join("\n")}\n`);
255
+ }
256
+ catch (error) {
257
+ handleApplyError(error, "apply");
258
+ }
259
+ }
260
+ async function runMemoryReject(options) {
261
+ const ctx = resolveNetworkContext();
262
+ try {
263
+ const candidate = await fetchAndValidateCandidate(ctx, {
264
+ workSessionId: options.workSessionId,
265
+ changeRequestId: options.changeRequestId,
266
+ domain: options.domain,
267
+ });
268
+ const result = await (0, server_sync_1.rejectMemoryCandidateRequest)(ctx, {
269
+ reviewerNote: options.reviewerNote,
270
+ candidate,
271
+ });
272
+ process.stdout.write(`Memory candidate rejected. Audit id: ${result.audit_id}\n`);
273
+ }
274
+ catch (error) {
275
+ handleApplyError(error, "reject");
276
+ }
277
+ }
278
+ async function runMemoryDefer(options) {
279
+ const ctx = resolveNetworkContext();
280
+ try {
281
+ const candidate = await fetchAndValidateCandidate(ctx, {
282
+ workSessionId: options.workSessionId,
283
+ changeRequestId: options.changeRequestId,
284
+ domain: options.domain,
285
+ });
286
+ const result = await (0, server_sync_1.deferMemoryCandidateRequest)(ctx, {
287
+ reviewerNote: options.reviewerNote,
288
+ candidate,
289
+ });
290
+ process.stdout.write(`Memory candidate deferred. Audit id: ${result.audit_id}\n`);
291
+ }
292
+ catch (error) {
293
+ handleApplyError(error, "defer");
294
+ }
295
+ }
296
+ // ── Phase 6E: escaped-bug intake ─────────────────────────────────────────────
297
+ function splitListFlag(value) {
298
+ if (!value)
299
+ return undefined;
300
+ const parts = value
301
+ .split("\n")
302
+ .map((s) => s.trim())
303
+ .filter((s) => s.length > 0);
304
+ return parts.length > 0 ? parts : undefined;
305
+ }
306
+ function loadFindingFromFile(path) {
307
+ const abs = (0, node_path_1.resolve)(process.cwd(), path);
308
+ let raw;
309
+ try {
310
+ raw = (0, node_fs_1.readFileSync)(abs, "utf8");
311
+ }
312
+ catch (err) {
313
+ throw new Error(`Failed to read escaped-bug finding file at ${abs}: ${err instanceof Error ? err.message : String(err)}`);
314
+ }
315
+ let parsed;
316
+ try {
317
+ parsed = JSON.parse(raw);
318
+ }
319
+ catch (err) {
320
+ throw new Error(`Invalid JSON in ${abs}: ${err instanceof Error ? err.message : String(err)}`);
321
+ }
322
+ if (!parsed || typeof parsed !== "object") {
323
+ throw new Error(`Escaped-bug finding file must be a JSON object: ${abs}`);
324
+ }
325
+ return parsed;
326
+ }
327
+ async function runMemoryIntakeEscapedBug(options) {
328
+ const ctx = resolveNetworkContext();
329
+ let finding;
330
+ if (options.fromFile && options.fromFile.trim().length > 0) {
331
+ finding = loadFindingFromFile(options.fromFile.trim());
332
+ // Allow flag overrides for convenience.
333
+ if (options.domain)
334
+ finding.domain = options.domain;
335
+ if (options.workSessionId)
336
+ finding.work_session_id = options.workSessionId;
337
+ if (options.changeRequestId)
338
+ finding.change_request_id = options.changeRequestId;
339
+ if (options.reviewerNote)
340
+ finding.reviewer_note = options.reviewerNote;
341
+ }
342
+ else {
343
+ if (!options.title || options.title.trim().length === 0) {
344
+ process.stderr.write("Missing --title \"<text>\" (or --from-file <path>). Escaped-bug findings require a title.\n");
345
+ return;
346
+ }
347
+ if (!options.summary || options.summary.trim().length === 0) {
348
+ process.stderr.write("Missing --summary \"<text>\" (or --from-file <path>). Escaped-bug findings require a summary.\n");
349
+ return;
350
+ }
351
+ finding = {
352
+ title: options.title.trim(),
353
+ summary: options.summary.trim(),
354
+ domain: options.domain,
355
+ work_session_id: options.workSessionId,
356
+ change_request_id: options.changeRequestId,
357
+ reviewer_note: options.reviewerNote,
358
+ invariants: splitListFlag(options.invariants),
359
+ known_traps: splitListFlag(options.knownTraps),
360
+ future_proof_requirements: splitListFlag(options.futureProofRequirements),
361
+ accepted_lessons: splitListFlag(options.acceptedLessons),
362
+ };
363
+ }
364
+ try {
365
+ const { candidate } = await (0, server_sync_1.intakeEscapedBugRequest)(ctx, finding);
366
+ process.stdout.write("Escaped bug recorded. Generated candidate:\n");
367
+ renderSuggestion(candidate, options.compact === true);
368
+ if (candidate.decision !== "skip") {
369
+ process.stdout.write("Apply with: agentbridge memory apply (after human review, use --work-session/--change-request to re-fetch the same candidate path if relevant)\n");
370
+ }
371
+ }
372
+ catch (error) {
373
+ handleApplyError(error, "intake-escaped-bug");
374
+ }
375
+ }
376
+ async function runMemoryRevert(options) {
377
+ if (!options.approvalAuditId || options.approvalAuditId.trim().length === 0) {
378
+ process.stderr.write("Missing --approval-audit <id>. Use the audit_id printed by `agentbridge memory apply`.\n");
379
+ return;
380
+ }
381
+ const ctx = resolveNetworkContext();
382
+ try {
383
+ const result = await (0, server_sync_1.revertMemoryCandidateRequest)(ctx, {
384
+ approvalAuditId: options.approvalAuditId,
385
+ reviewerNote: options.reviewerNote,
386
+ force: options.force,
387
+ });
388
+ const lines = [
389
+ `Memory reverted: approval=${result.approval_audit_id}`,
390
+ `Revert audit_id: ${result.revert_audit_id}`,
391
+ ];
392
+ if (result.warnings.length > 0) {
393
+ lines.push(...formatList("Warnings:", result.warnings));
394
+ }
395
+ process.stdout.write(`${lines.join("\n")}\n`);
396
+ }
397
+ catch (error) {
398
+ handleApplyError(error, "revert");
399
+ }
400
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runNext = runNext;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const operator_snapshot_1 = require("../operator-snapshot");
9
+ const health_1 = require("./health");
10
+ async function runNext(options) {
11
+ const summary = await (0, health_1.collectHealthSummary)({
12
+ includeOtherActiveSessions: true,
13
+ });
14
+ if (options.json) {
15
+ process.stdout.write(`${JSON.stringify({ snapshot: summary.snapshot, rollup: summary.rollup }, null, 2)}\n`);
16
+ return;
17
+ }
18
+ process.stdout.write(`${chalk_1.default.bold("AgentBridge Next")}\n`);
19
+ process.stdout.write(`${(0, operator_snapshot_1.renderOperatorSnapshotHuman)(summary.snapshot)}\n`);
20
+ process.stdout.write(`Signals: ${summary.rollup.overall_status} · next=${summary.rollup.next_action}\n`);
21
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runPrecommitCheckCommand = runPrecommitCheckCommand;
4
+ const precommit_1 = require("../precommit");
5
+ function runPrecommitCheckCommand() {
6
+ const staged = (0, precommit_1.stagedFilesFromGit)();
7
+ const result = (0, precommit_1.runPrecommitCheckFromSession)(staged);
8
+ if (!result.ok) {
9
+ process.stderr.write("Blocked commit due to unresolved protected boundary crossing(s):\n");
10
+ for (const file of result.blocked) {
11
+ process.stderr.write(`- ${file}\n`);
12
+ }
13
+ process.exitCode = 1;
14
+ return;
15
+ }
16
+ process.stdout.write("Pre-commit check passed.\n");
17
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runRecover = runRecover;
4
+ const config_1 = require("../config");
5
+ const errors_1 = require("../errors");
6
+ const server_sync_1 = require("../server-sync");
7
+ const node_process_1 = require("node:process");
8
+ const gates_1 = require("../gates");
9
+ const init_1 = require("../init");
10
+ function resolveNetworkContext() {
11
+ const cfg = (0, config_1.readConfig)();
12
+ const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "";
13
+ const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
14
+ const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ??
15
+ cfg.apiBaseUrl ??
16
+ "https://agentauth-api-production.up.railway.app";
17
+ if (!projectId || !apiKey) {
18
+ throw (0, errors_1.catalogCliError)("CONFIG_INCOMPLETE");
19
+ }
20
+ return { projectId, apiKey, apiBaseUrl };
21
+ }
22
+ function renderRecoverOutput(packet) {
23
+ const lines = [];
24
+ lines.push("Project recovered.");
25
+ lines.push("");
26
+ lines.push(`Project: ${packet.project_name ?? packet.project_id}`);
27
+ if (packet.domains_summary.length > 0) {
28
+ lines.push("");
29
+ lines.push("Domains found:");
30
+ for (const domain of packet.domains_summary) {
31
+ const pathNote = domain.owned_path_count > 0 ? `${domain.owned_path_count} path(s)` : "paths pending";
32
+ lines.push(`- ${domain.domain_name} — ${pathNote}`);
33
+ }
34
+ }
35
+ if (packet.charter_summary?.purpose) {
36
+ lines.push("");
37
+ lines.push("Known context:");
38
+ lines.push(`- ${packet.charter_summary.purpose}`);
39
+ }
40
+ if (packet.global_rules && packet.global_rules.length > 0) {
41
+ lines.push("");
42
+ lines.push("Project rules:");
43
+ for (const rule of packet.global_rules.slice(0, 3)) {
44
+ lines.push(`- ${rule}`);
45
+ }
46
+ }
47
+ lines.push("");
48
+ lines.push("Next:");
49
+ lines.push(" agentbridge start");
50
+ lines.push("");
51
+ return lines.join("\n");
52
+ }
53
+ async function runRecover(options = {}) {
54
+ process.exitCode = 0;
55
+ process.stdout.write([
56
+ "AgentBridge is recovering this project.",
57
+ "It will identify project context, domains, known traps, and memory for future agent work.",
58
+ "",
59
+ ].join("\n"));
60
+ let ctx;
61
+ try {
62
+ ctx = resolveNetworkContext();
63
+ }
64
+ catch (err) {
65
+ if (err instanceof errors_1.SafeCliError) {
66
+ process.stderr.write(`${(0, errors_1.renderCliError)(err)}\n`);
67
+ }
68
+ else {
69
+ process.stderr.write(`${(0, errors_1.renderCliError)((0, errors_1.catalogCliError)("CONFIG_INCOMPLETE"))}\n`);
70
+ }
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+ process.stdout.write("Verifying project access...\n");
75
+ let packet;
76
+ try {
77
+ packet = await (0, server_sync_1.fetchProjectPacket)(ctx);
78
+ }
79
+ catch (err) {
80
+ const errMsg = err instanceof Error ? err.message : String(err);
81
+ process.stderr.write([
82
+ "",
83
+ "Recovery could not complete.",
84
+ "",
85
+ "What happened: AgentBridge could not reach the project.",
86
+ "Why it matters: Project context is required before AI agents can work safely.",
87
+ `Next action: Run "agentbridge doctor" to diagnose the connection, then retry.`,
88
+ `Error: ${errMsg}`,
89
+ "",
90
+ ].join("\n"));
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+ const alreadyRecovered = (packet.domains_summary?.length ?? 0) > 0 ||
95
+ (packet.recovery_status !== null &&
96
+ packet.recovery_status !== undefined &&
97
+ packet.recovery_status !== "pending");
98
+ if (!options.force && alreadyRecovered) {
99
+ const repoRoot = (0, node_process_1.cwd)();
100
+ (0, gates_1.ensureGitignoreSessionEntry)(repoRoot);
101
+ (0, gates_1.ensureGatesFile)(repoRoot);
102
+ process.stdout.write("Project context already exists.\n\n");
103
+ process.stdout.write(renderRecoverOutput(packet));
104
+ return;
105
+ }
106
+ if (!alreadyRecovered) {
107
+ process.stdout.write("No baseline found. Building recovery baseline now...\n");
108
+ await (0, init_1.runBootstrapRecovery)(ctx);
109
+ packet = await (0, server_sync_1.fetchProjectPacket)(ctx);
110
+ }
111
+ // force mode or partial state: show current state
112
+ const repoRoot = (0, node_process_1.cwd)();
113
+ (0, gates_1.ensureGitignoreSessionEntry)(repoRoot);
114
+ (0, gates_1.ensureGatesFile)(repoRoot);
115
+ process.stdout.write(renderRecoverOutput(packet));
116
+ }