@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,13 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runRecover = runRecover;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const node_process_1 = require("node:process");
4
7
  const config_1 = require("../config");
5
8
  const errors_1 = require("../errors");
6
- const server_sync_1 = require("../server-sync");
7
- const node_process_1 = require("node:process");
8
9
  const gates_1 = require("../gates");
9
- const init_1 = require("../init");
10
10
  const http_1 = require("../http");
11
+ const init_1 = require("../init");
12
+ const recovery_reconcile_1 = require("../recovery-reconcile");
13
+ const server_sync_1 = require("../server-sync");
11
14
  function resolveNetworkContext() {
12
15
  const cfg = (0, config_1.readConfig)();
13
16
  const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "";
@@ -20,9 +23,14 @@ function resolveNetworkContext() {
20
23
  }
21
24
  return { projectId, apiKey, apiBaseUrl };
22
25
  }
26
+ function rulesInstalled(repoRoot) {
27
+ return ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, "AGENTBRIDGE.md")) &&
28
+ (0, node_fs_1.existsSync)((0, node_path_1.resolve)(repoRoot, ".cursor", "rules", "agentbridge.mdc")));
29
+ }
23
30
  function renderRecoverOutput(packet) {
24
31
  const lines = [];
25
- const domainCount = packet.domains_summary.length;
32
+ const activeDomains = (packet.domains_summary ?? []).filter((d) => d.state !== "retired");
33
+ const domainCount = activeDomains.length;
26
34
  const ruleCount = packet.global_rules?.length ?? 0;
27
35
  const hasCharterContext = Boolean(packet.charter_summary?.purpose);
28
36
  lines.push("Project recovered.");
@@ -36,7 +44,7 @@ function renderRecoverOutput(packet) {
36
44
  if (domainCount > 0) {
37
45
  lines.push("");
38
46
  lines.push("Domains found:");
39
- for (const domain of packet.domains_summary) {
47
+ for (const domain of activeDomains) {
40
48
  const pathNote = domain.owned_path_count > 0 ? `${domain.owned_path_count} path(s)` : "paths pending";
41
49
  lines.push(`- ${domain.domain_name} — ${pathNote}`);
42
50
  }
@@ -55,18 +63,56 @@ function renderRecoverOutput(packet) {
55
63
  }
56
64
  lines.push("");
57
65
  lines.push("Next:");
58
- lines.push(" agentbridge start");
66
+ lines.push(" agentbridge watch");
59
67
  lines.push("");
60
68
  return lines.join("\n");
61
69
  }
62
70
  function recoveryStatusLabel(packet) {
63
71
  return packet.recovery_status ?? "unknown";
64
72
  }
65
- function baselineRequired(packet) {
66
- const status = packet.recovery_status ?? null;
67
- if (packet.project_mode !== "recovery")
68
- return false;
69
- return status === "baseline_required" || status === "pending" || status === null;
73
+ function formatDomainLines(refs) {
74
+ if (refs.length === 0)
75
+ return " (none)";
76
+ return refs.map((d) => `- ${d.name}`).join("\n");
77
+ }
78
+ function renderReconcileReport(input) {
79
+ const { plan, applied, qualityAfter } = input;
80
+ const lines = [""];
81
+ if (applied) {
82
+ lines.push("AgentBridge checked recovery.");
83
+ lines.push(`Recovery quality: ${qualityAfter}`);
84
+ if (plan.toAdd.length > 0) {
85
+ lines.push("");
86
+ lines.push("Added:");
87
+ lines.push(formatDomainLines(plan.toAdd));
88
+ }
89
+ if (plan.toPreserve.length > 0) {
90
+ lines.push("");
91
+ lines.push("Existing domains preserved:");
92
+ lines.push(formatDomainLines(plan.toPreserve));
93
+ }
94
+ if (plan.toRetire.length > 0) {
95
+ lines.push("");
96
+ lines.push("Retired:");
97
+ lines.push(formatDomainLines(plan.toRetire));
98
+ }
99
+ }
100
+ else {
101
+ lines.push("AgentBridge checked recovery.");
102
+ lines.push("No changes needed.");
103
+ lines.push("Recovery is up to date.");
104
+ lines.push(`Recovery quality: ${qualityAfter}`);
105
+ }
106
+ return lines.join("\n") + "\n";
107
+ }
108
+ function renderBasicHint() {
109
+ return [
110
+ "",
111
+ "Recovery: basic",
112
+ "AgentBridge found only a generic project area.",
113
+ "Run `agentbridge recover --force` to rebuild the domain map.",
114
+ "",
115
+ ].join("\n");
70
116
  }
71
117
  function renderRecoveryStatusBlock(input) {
72
118
  const lines = [];
@@ -100,7 +146,18 @@ function normalizeBootstrapError(error) {
100
146
  return (0, errors_1.catalogCliError)("CONFIG_INCOMPLETE", {
101
147
  what: `Recovery bootstrap payload was rejected by server validation${detailText}.`,
102
148
  why: "The server cannot activate recovery until required bootstrap fields pass validation.",
103
- next: "Retry `agentbridge recover`. If it fails again, run with AGENTBRIDGE_DEBUG=1 and share output.",
149
+ next: "Retry `agentbridge recover`. If it fails again, run with AGENTBRIDGE_DEBUG_HTTP=1 and share output.",
150
+ });
151
+ }
152
+ if ((0, http_1.isCliHttpError)(error) && error.status >= 500) {
153
+ const parsed = (0, http_1.parseCliHttpErrorBody)(error);
154
+ const serverDetail = (0, http_1.extractHttpErrorCode)(parsed) ||
155
+ error.body.trim().slice(0, 240) ||
156
+ "no response body";
157
+ return (0, errors_1.catalogCliError)("SERVER_ERROR", {
158
+ what: `Recovery bootstrap failed with HTTP ${error.status}.`,
159
+ why: "The server errored while applying recovery baseline at POST /v1/dev/projects/{id}/bootstrap.",
160
+ next: `Retry agentbridge recover. For full request/response traces, run with AGENTBRIDGE_DEBUG_HTTP=1. Server detail: ${serverDetail}`,
104
161
  });
105
162
  }
106
163
  if (error instanceof Error) {
@@ -175,15 +232,42 @@ async function runRecover(options = {}) {
175
232
  return;
176
233
  }
177
234
  const beforePacket = packet;
178
- const needsRecovery = baselineRequired(beforePacket);
179
- let actionTaken = "baseline already exists; no rebuild needed";
180
- if (needsRecovery || options.force) {
181
- actionTaken = needsRecovery
235
+ const cfg = (0, config_1.readConfig)();
236
+ const repoRoot = (0, node_process_1.cwd)();
237
+ const rulesOk = rulesInstalled(repoRoot);
238
+ let scan;
239
+ try {
240
+ process.stdout.write("Scanning repository layout...\n");
241
+ scan = await (0, init_1.scanRecoveryFromRepo)(ctx);
242
+ }
243
+ catch (error) {
244
+ process.stderr.write(`${(0, errors_1.renderCliError)(normalizeBootstrapError(error))}\n`);
245
+ process.exitCode = 1;
246
+ return;
247
+ }
248
+ const existingActive = (0, recovery_reconcile_1.packetDomainsToRefs)(beforePacket, cfg.domains ?? []);
249
+ const plan = (0, recovery_reconcile_1.buildReconcilePlan)({
250
+ existingActive,
251
+ candidates: scan.candidateRefs,
252
+ mode: options.force ? "force" : "safe",
253
+ packet: beforePacket,
254
+ rulesInstalled: rulesOk,
255
+ });
256
+ const needsBaseline = (0, recovery_reconcile_1.recoveryBaselineRequired)(beforePacket);
257
+ const shouldApply = needsBaseline || options.force || plan.hasChanges;
258
+ let actionTaken = "reconciliation check only; no changes needed";
259
+ if (shouldApply) {
260
+ actionTaken = needsBaseline
182
261
  ? "build recovery baseline from repository evidence"
183
- : "force-refresh recovery baseline from repository evidence";
184
- process.stdout.write("Building recovery baseline now...\n");
262
+ : options.force
263
+ ? "force-refresh recovery baseline from repository evidence"
264
+ : "reconcile recovery with repository evidence";
265
+ process.stdout.write("Applying recovery changes...\n");
185
266
  try {
186
- await (0, init_1.runBootstrapRecovery)(ctx);
267
+ await (0, init_1.runBootstrapRecovery)(ctx, {
268
+ reconcilePlan: plan,
269
+ scan,
270
+ });
187
271
  packet = await (0, server_sync_1.fetchProjectPacket)(ctx);
188
272
  }
189
273
  catch (error) {
@@ -193,7 +277,19 @@ async function runRecover(options = {}) {
193
277
  }
194
278
  }
195
279
  const afterPacket = packet;
196
- if (baselineRequired(afterPacket)) {
280
+ const qualityAfter = (0, recovery_reconcile_1.recoveryQualityLabel)((0, recovery_reconcile_1.buildReconcilePlan)({
281
+ existingActive: (0, recovery_reconcile_1.packetDomainsToRefs)(afterPacket, cfg.domains ?? []),
282
+ candidates: scan.candidateRefs,
283
+ mode: options.force ? "force" : "safe",
284
+ packet: afterPacket,
285
+ rulesInstalled: rulesOk,
286
+ }).quality);
287
+ process.stdout.write(renderReconcileReport({
288
+ plan,
289
+ applied: shouldApply,
290
+ qualityAfter,
291
+ }));
292
+ if ((0, recovery_reconcile_1.recoveryBaselineRequired)(afterPacket)) {
197
293
  process.stderr.write([
198
294
  "Recovery could not complete: baseline still required.",
199
295
  "",
@@ -208,7 +304,6 @@ async function runRecover(options = {}) {
208
304
  process.exitCode = 1;
209
305
  return;
210
306
  }
211
- const repoRoot = (0, node_process_1.cwd)();
212
307
  (0, gates_1.ensureGitignoreSessionEntry)(repoRoot);
213
308
  (0, gates_1.ensureGatesFile)(repoRoot);
214
309
  process.stdout.write(renderRecoveryStatusBlock({
@@ -216,7 +311,10 @@ async function runRecover(options = {}) {
216
311
  before: beforePacket,
217
312
  after: afterPacket,
218
313
  action: actionTaken,
219
- next: "agentbridge start",
314
+ next: "agentbridge watch",
220
315
  }));
221
- process.stdout.write(renderRecoverOutput(packet));
316
+ process.stdout.write(renderRecoverOutput(afterPacket));
317
+ if ((0, recovery_reconcile_1.recoveryIsBasicPacket)(afterPacket)) {
318
+ process.stdout.write(renderBasicHint());
319
+ }
222
320
  }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runRoomExit = runRoomExit;
4
+ const config_1 = require("../config");
5
+ const session_state_1 = require("../session-state");
6
+ function envOverridesConfig() {
7
+ const overrides = [];
8
+ if (process.env.AGENTBRIDGE_PROJECT_ID?.trim()) {
9
+ overrides.push("AGENTBRIDGE_PROJECT_ID");
10
+ }
11
+ if (process.env.AGENTBRIDGE_API_KEY?.trim()) {
12
+ overrides.push("AGENTBRIDGE_API_KEY");
13
+ }
14
+ if (process.env.AGENTBRIDGE_BASE_URL?.trim()) {
15
+ overrides.push("AGENTBRIDGE_BASE_URL");
16
+ }
17
+ return overrides;
18
+ }
19
+ function shouldClearLocalSession(keepSession) {
20
+ if (keepSession)
21
+ return false;
22
+ const state = (0, session_state_1.readSessionState)();
23
+ if (!state)
24
+ return false;
25
+ return state.status === "active" || state.status === "blocked";
26
+ }
27
+ function runRoomExit(options = {}) {
28
+ const before = (0, config_1.readConfig)();
29
+ const hadConnection = Boolean(before.projectId || before.apiKey || before.executionSurfaceId || before.activeAgentId);
30
+ const result = (0, config_1.clearRoomConnection)();
31
+ const clearedSession = shouldClearLocalSession(Boolean(options.keepSession));
32
+ if (clearedSession) {
33
+ (0, session_state_1.clearSessionState)();
34
+ }
35
+ const envOverrides = envOverridesConfig();
36
+ if (options.json) {
37
+ process.stdout.write(`${JSON.stringify({
38
+ action: "room_exit",
39
+ config_path: config_1.CONFIG_PATH,
40
+ had_connection: hadConnection,
41
+ cleared_keys: result.clearedKeys,
42
+ previous_project_id: result.previousProjectId ?? null,
43
+ had_api_key: result.hadApiKey,
44
+ cleared_local_session: clearedSession,
45
+ env_overrides: envOverrides,
46
+ preserved: ["domains", "apiBaseUrl", "precommitHookInstalled", "cliPath"],
47
+ }, null, 2)}\n`);
48
+ return;
49
+ }
50
+ process.stdout.write("AgentBridge room exit\n");
51
+ process.stdout.write("─────────────────────────────────────────\n");
52
+ if (!hadConnection && result.clearedKeys.length === 0) {
53
+ process.stdout.write("No saved room connection in .agentbridge/config.json.\n");
54
+ }
55
+ else {
56
+ process.stdout.write("Cleared saved room connection from .agentbridge/config.json.\n");
57
+ if (result.previousProjectId) {
58
+ process.stdout.write(` Project: ${result.previousProjectId}\n`);
59
+ }
60
+ if (result.hadApiKey) {
61
+ process.stdout.write(" API key: removed from config\n");
62
+ }
63
+ if (result.clearedKeys.includes("executionSurfaceId")) {
64
+ process.stdout.write(" Execution surface: removed from config\n");
65
+ }
66
+ if (result.clearedKeys.includes("activeAgentId")) {
67
+ process.stdout.write(" Active agent: removed from config\n");
68
+ }
69
+ }
70
+ if (clearedSession) {
71
+ process.stdout.write("Cleared active local supervision session (.agentbridge/session.json).\n");
72
+ }
73
+ process.stdout.write("\nPreserved: domain map and other recovery data from init/recover.\n");
74
+ process.stdout.write("Server rules and MCP config on disk are unchanged.\n");
75
+ if (envOverrides.length > 0) {
76
+ process.stdout.write(`\nNote: ${envOverrides.join(", ")} still set in your shell — they override config until unset.\n`);
77
+ }
78
+ process.stdout.write("\nNext:\n");
79
+ process.stdout.write(" 1. Get a fresh API key at https://agentbridge.dev/dashboard\n");
80
+ process.stdout.write(" 2. agentbridge connect --project <id> --api-key <key>\n");
81
+ process.stdout.write(" 3. agentbridge doctor\n");
82
+ }
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runSetupMcp = runSetupMcp;
4
+ const node_path_1 = require("node:path");
4
5
  const config_1 = require("../config");
6
+ const mcp_runtime_1 = require("../mcp-runtime");
5
7
  const MCP_SERVER_NAME = "agentbridge";
6
8
  function standardSnippet(projectId, apiKey, apiBaseUrl) {
7
9
  const serverConfig = {
@@ -47,8 +49,27 @@ async function runSetupMcp(options = {}) {
47
49
  else {
48
50
  process.stdout.write("\n✓ Credentials filled from .agentbridge/config.json\n");
49
51
  }
52
+ const cliDistDir = (0, node_path_1.resolve)(__dirname, "..");
53
+ if (!(0, mcp_runtime_1.isMcpRuntimeAvailable)(cliDistDir)) {
54
+ process.stdout.write([
55
+ "",
56
+ "⚠ MCP runtime is missing from this CLI install.",
57
+ " `agentbridge mcp` will exit until you reinstall:",
58
+ " npm install -g @agentbridge1/cli@latest",
59
+ "",
60
+ " Or point mcp.json at a repo build:",
61
+ " node /path/to/AuthAgent/cli/dist/mcp/agentbridge-mcp.js",
62
+ "",
63
+ ].join("\n"));
64
+ }
65
+ else {
66
+ process.stdout.write([
67
+ "",
68
+ "✓ MCP runtime is bundled with this CLI (`agentbridge mcp` is ready).",
69
+ "",
70
+ ].join("\n"));
71
+ }
50
72
  process.stdout.write([
51
- "",
52
73
  "After saving the config, restart your editor to activate the MCP server.",
53
74
  "The MCP server lets your AI assistant call tools like agent_hello, check AgentBridge status, and trigger approvals.",
54
75
  "",
@@ -39,9 +39,8 @@ const domain_resolution_1 = require("../domain-resolution");
39
39
  const errors_1 = require("../errors");
40
40
  const error_catalog_1 = require("../error-catalog");
41
41
  const http_1 = require("../http");
42
- const git_status_1 = require("../git-status");
43
42
  const session_1 = require("../session");
44
- const work_contract_1 = require("../work-contract");
43
+ const session_state_1 = require("../session-state");
45
44
  const server_sync_1 = require("../server-sync");
46
45
  const work_context_resolver_1 = require("../work-context-resolver");
47
46
  const PROMOTION_PLAN = {
@@ -567,84 +566,55 @@ async function executeStartWorkSession(opts) {
567
566
  otherSessionIds: [...new Set(otherSessionIds)],
568
567
  };
569
568
  }
570
- async function runSmartStart(opts = {}) {
571
- const cfg = (0, config_1.readConfig)();
572
- await ensureProjectAccess();
573
- const ctx = (0, config_1.contextFromConfig)();
574
- const explicitAgentId = opts.agentId?.trim();
575
- const configuredActiveAgentId = cfg.activeAgentId?.trim();
576
- if (!explicitAgentId && !configuredActiveAgentId) {
577
- throw (0, errors_1.catalogCliError)("START_MISSING_ACTIVE_AGENT");
578
- }
579
- const executionSurfaceId = await resolveExecutionSurfaceIdForStart(ctx, opts, cfg.executionSurfaceId);
580
- if (!executionSurfaceId) {
581
- throw (0, errors_1.catalogCliError)("START_EXECUTION_SURFACE_REQUIRED");
582
- }
583
- const resolution = await (0, work_context_resolver_1.resolveWorkContext)(ctx, {
584
- allowServerCurrentForCr: true,
585
- includeOtherActiveSessions: true,
586
- });
587
- if (resolution.state === "current_session_resolved") {
588
- process.stdout.write("Active work session found - entering watch mode.\n");
589
- if (!opts.skipWatch) {
590
- const { runWatch } = await Promise.resolve().then(() => __importStar(require("./watch")));
591
- await runWatch({ allowDirty: true });
592
- }
593
- return;
594
- }
595
- if (resolution.state === "ambiguous_active_sessions") {
596
- process.stdout.write(`${(0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n")}\n`);
597
- throw (0, errors_1.catalogCliError)((0, error_catalog_1.workContextStateToCode)(resolution.state));
598
- }
599
- if (resolution.state === "mismatch" || resolution.state === "stale_orphan_session_detected") {
600
- process.stdout.write(`${(0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n")}\n`);
601
- throw (0, errors_1.catalogCliError)((0, error_catalog_1.workContextStateToCode)(resolution.state));
602
- }
603
- const inferred = (0, work_contract_1.inferWorkContract)({
569
+ function hasActiveLocalRun() {
570
+ const local = (0, session_state_1.readSessionState)();
571
+ if (!local)
572
+ return false;
573
+ if (local.status !== "active" && local.status !== "blocked")
574
+ return false;
575
+ if (!local.id || local.id === "none")
576
+ return false;
577
+ return true;
578
+ }
579
+ async function runDefaultStart(opts = {}) {
580
+ const { runLocalSupervision } = await Promise.resolve().then(() => __importStar(require("../local-supervision")));
581
+ await runLocalSupervision({
604
582
  prompt: opts.prompt,
605
- branchName: (0, git_status_1.getBranchName)(),
606
- dirtyFiles: (0, git_status_1.getDirtyWorkingTreeFiles)(),
607
- activeChangeRequestId: cfg.activeChangeRequestId ?? null,
608
- });
609
- const draft = {
610
- summary: inferred.summary,
611
- scope: opts.scope?.trim() || inferred.scope,
612
- };
613
- const confirmed = await (0, work_contract_1.confirmWorkContract)(draft, {
614
- nonInteractive: !process.stdin.isTTY,
615
- });
616
- if (!confirmed) {
617
- process.stdout.write("Cancelled.\n");
618
- return;
619
- }
620
- await executeStartWorkSession({
621
- ...opts,
622
- summary: confirmed.summary,
623
- scope: confirmed.scope,
583
+ details: opts.details,
584
+ confirmClose: opts.confirmClose,
624
585
  });
625
- process.stdout.write("Work session started. Entering watch mode...\n");
626
- if (!opts.skipWatch) {
627
- const { runWatch } = await Promise.resolve().then(() => __importStar(require("./watch")));
628
- await runWatch({ allowDirty: true });
629
- }
586
+ }
587
+ function isStrictTrackedStartRequest(opts) {
588
+ if (opts.resume === true)
589
+ return true;
590
+ if (opts.changeRequestId?.trim())
591
+ return true;
592
+ const explicitSummaryFlag = opts.summaryFlagProvided === true;
593
+ const explicitScopeFlag = opts.scopeFlagProvided === true;
594
+ const explicitInputProvided = opts.summary !== undefined || opts.scope !== undefined;
595
+ return explicitSummaryFlag || explicitScopeFlag || explicitInputProvided;
630
596
  }
631
597
  async function runStart(opts = {}) {
598
+ const strictTrackedStart = isStrictTrackedStartRequest(opts);
632
599
  const explicitSummaryFlag = opts.summaryFlagProvided === true;
633
600
  const explicitScopeFlag = opts.scopeFlagProvided === true;
634
601
  const explicitInputProvided = opts.summary !== undefined || opts.scope !== undefined;
635
602
  const explicitModeRequested = explicitSummaryFlag || explicitScopeFlag || explicitInputProvided;
636
603
  const explicitSummary = opts.summary?.trim();
637
604
  const explicitScope = opts.scope?.trim();
638
- if (explicitModeRequested && explicitSummary && explicitScope) {
605
+ if (strictTrackedStart && explicitSummary && explicitScope) {
639
606
  await executeStartWorkSession({ ...opts, summary: explicitSummary, scope: explicitScope });
640
607
  if (!opts.skipWatch) {
641
608
  const { runWatch } = await Promise.resolve().then(() => __importStar(require("./watch")));
642
- await runWatch({ allowDirty: true });
609
+ await runWatch({ allowDirty: true, details: opts.details });
643
610
  }
644
611
  return;
645
612
  }
613
+ if (strictTrackedStart) {
614
+ throw (0, errors_1.catalogCliError)("START_EXPLICIT_PAIR_REQUIRED");
615
+ }
646
616
  if (explicitModeRequested) {
647
617
  throw (0, errors_1.catalogCliError)("START_EXPLICIT_PAIR_REQUIRED");
648
618
  }
649
- await runSmartStart(opts);
619
+ await runDefaultStart(opts);
650
620
  }