@agentbridge1/cli 0.0.6 → 0.0.8

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.
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runInstallRules = runInstallRules;
4
+ const node_path_1 = require("node:path");
5
+ const node_process_1 = require("node:process");
6
+ const config_1 = require("../config");
7
+ const errors_1 = require("../errors");
8
+ const http_1 = require("../http");
9
+ const rules_sync_1 = require("../rules-sync");
10
+ function resolveNetworkContext(overrides) {
11
+ const cfg = (0, config_1.readConfig)();
12
+ const projectId = overrides.projectId ?? process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "";
13
+ const apiKey = overrides.apiKey ?? process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
14
+ const apiBaseUrl = overrides.apiBaseUrl ??
15
+ process.env.AGENTBRIDGE_BASE_URL ??
16
+ cfg.apiBaseUrl ??
17
+ "https://agentauth-api-production.up.railway.app";
18
+ if (!projectId || !apiKey) {
19
+ throw (0, errors_1.catalogCliError)("CONFIG_INCOMPLETE");
20
+ }
21
+ return { projectId, apiKey, apiBaseUrl };
22
+ }
23
+ async function runInstallRules(opts = {}) {
24
+ const ctx = resolveNetworkContext(opts);
25
+ const workspaceRoot = (0, node_process_1.cwd)();
26
+ let rules;
27
+ try {
28
+ rules = await (0, rules_sync_1.fetchProjectRules)(ctx);
29
+ }
30
+ catch (error) {
31
+ if ((0, http_1.isCliHttpError)(error)) {
32
+ throw new errors_1.SafeCliError(`Could not fetch AgentBridge rules for project ${ctx.projectId} (${error.status}).`);
33
+ }
34
+ throw error;
35
+ }
36
+ if (!Array.isArray(rules.files) || rules.files.length === 0) {
37
+ throw new errors_1.SafeCliError("AgentBridge rules response did not include any files to install.");
38
+ }
39
+ (0, rules_sync_1.writeRulesFiles)(workspaceRoot, rules.files);
40
+ let installedAt = null;
41
+ try {
42
+ const marked = await (0, rules_sync_1.markProjectRulesInstalled)(ctx);
43
+ installedAt = marked.rules_installed_at ?? null;
44
+ }
45
+ catch (error) {
46
+ if ((0, http_1.isCliHttpError)(error)) {
47
+ throw new errors_1.SafeCliError(`Wrote rules files locally, but could not mark them installed on the server (${error.status}).`);
48
+ }
49
+ throw error;
50
+ }
51
+ const projectName = (0, rules_sync_1.extractProjectNameFromRulesResponse)(rules.files);
52
+ const lines = [
53
+ "Installed AgentBridge protocol rules:",
54
+ ` Project: ${projectName ?? "(unknown name)"} (${ctx.projectId})`,
55
+ ` Wrote: ${(0, node_path_1.resolve)(workspaceRoot, "AGENTBRIDGE.md")}`,
56
+ ` Wrote: ${(0, node_path_1.resolve)(workspaceRoot, ".cursor", "rules", "agentbridge.mdc")}`,
57
+ ];
58
+ if (installedAt) {
59
+ lines.push(` Server marked installed at: ${installedAt}`);
60
+ }
61
+ lines.push("");
62
+ lines.push("Next: run `agentbridge doctor` to verify rules and MCP configuration.");
63
+ process.stdout.write(`${lines.join("\n")}\n`);
64
+ }
@@ -110,7 +110,7 @@ function renderBasicHint() {
110
110
  "",
111
111
  "Recovery: basic",
112
112
  "AgentBridge found only a generic project area.",
113
- "Run `agent recover --force` to rebuild the domain map.",
113
+ "Run `agentbridge recover --force` to rebuild the domain map.",
114
114
  "",
115
115
  ].join("\n");
116
116
  }
@@ -146,7 +146,18 @@ function normalizeBootstrapError(error) {
146
146
  return (0, errors_1.catalogCliError)("CONFIG_INCOMPLETE", {
147
147
  what: `Recovery bootstrap payload was rejected by server validation${detailText}.`,
148
148
  why: "The server cannot activate recovery until required bootstrap fields pass validation.",
149
- 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}`,
150
161
  });
151
162
  }
152
163
  if (error instanceof Error) {
@@ -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
+ }
@@ -3,72 +3,82 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runSetupMcp = runSetupMcp;
4
4
  const node_path_1 = require("node:path");
5
5
  const config_1 = require("../config");
6
+ const mcp_config_1 = require("../mcp-config");
6
7
  const mcp_runtime_1 = require("../mcp-runtime");
7
8
  const MCP_SERVER_NAME = "agentbridge";
8
- function standardSnippet(projectId, apiKey, apiBaseUrl) {
9
- const serverConfig = {
10
- command: "agentbridge",
11
- args: ["mcp"],
12
- env: {
13
- AGENTBRIDGE_PROJECT_ID: projectId,
14
- AGENTBRIDGE_API_KEY: apiKey,
15
- AGENTBRIDGE_BASE_URL: apiBaseUrl,
16
- },
17
- };
18
- return JSON.stringify({ [MCP_SERVER_NAME]: serverConfig }, null, 2);
19
- }
20
- async function runSetupMcp(options = {}) {
21
- const cfg = (0, config_1.readConfig)();
22
- const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "<your-project-id>";
23
- const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "<your-api-key>";
24
- const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ??
25
- cfg.apiBaseUrl ??
26
- "https://agentauth-api-production.up.railway.app";
27
- const editor = options.editor ?? "cursor";
28
- process.stdout.write("\nAgentBridge MCP Setup\n");
29
- process.stdout.write("─────────────────────────────────────────\n\n");
9
+ function editorConfigHint(editor) {
30
10
  if (editor === "cursor") {
31
- process.stdout.write("Add this to your ~/.cursor/mcp.json (or project-level .cursor/mcp.json):\n\n");
32
- }
33
- else if (editor === "windsurf") {
34
- process.stdout.write("Add this to your ~/.codeium/windsurf/mcp_config.json:\n\n");
35
- }
36
- else if (editor === "vscode") {
37
- process.stdout.write("Add this to your .vscode/mcp.json:\n\n");
38
- }
39
- else {
40
- process.stdout.write(`Add this to your ${editor} MCP config:\n\n`);
11
+ return "Add this to your ~/.cursor/mcp.json (or project-level .cursor/mcp.json):\n\n";
41
12
  }
42
- process.stdout.write("Recommended config:\n\n");
43
- process.stdout.write(JSON.stringify({
44
- mcpServers: JSON.parse(standardSnippet(projectId, apiKey, apiBaseUrl)),
45
- }, null, 2) + "\n");
46
- if (projectId === "<your-project-id>" || apiKey === "<your-api-key>") {
47
- process.stdout.write("\n⚠ Credentials not found. Run `agentbridge connect` first to save your project ID and API key.\n");
13
+ if (editor === "windsurf") {
14
+ return "Add this to your ~/.codeium/windsurf/mcp_config.json:\n\n";
48
15
  }
49
- else {
50
- process.stdout.write("\n✓ Credentials filled from .agentbridge/config.json\n");
16
+ if (editor === "vscode") {
17
+ return "Add this to your .vscode/mcp.json:\n\n";
51
18
  }
52
- const cliDistDir = (0, node_path_1.resolve)(__dirname, "..");
19
+ return "Add this to your " + editor + " MCP config:\n\n";
20
+ }
21
+ function printRuntimeStatus(cliDistDir) {
53
22
  if (!(0, mcp_runtime_1.isMcpRuntimeAvailable)(cliDistDir)) {
54
23
  process.stdout.write([
55
24
  "",
56
25
  "⚠ MCP runtime is missing from this CLI install.",
57
- " `agentbridge mcp` will exit until you reinstall:",
26
+ " agentbridge mcp will exit until you reinstall:",
58
27
  " npm install -g @agentbridge1/cli@latest",
59
28
  "",
60
29
  " Or point mcp.json at a repo build:",
61
30
  " node /path/to/AuthAgent/cli/dist/mcp/agentbridge-mcp.js",
62
31
  "",
63
32
  ].join("\n"));
33
+ return;
64
34
  }
65
- else {
35
+ process.stdout.write(["", "✓ MCP runtime is bundled with this CLI (agentbridge mcp is ready).", ""].join("\n"));
36
+ }
37
+ async function runSetupMcp(options = {}) {
38
+ const cliDistDir = (0, node_path_1.resolve)(__dirname, "..");
39
+ const editor = options.editor ?? "cursor";
40
+ process.stdout.write("\nAgentBridge MCP Setup\n");
41
+ process.stdout.write("─────────────────────────────────────────\n\n");
42
+ if (options.local) {
43
+ const entry = (0, mcp_config_1.buildLocalMcpServerEntry)(cliDistDir);
44
+ const mcpPath = (0, mcp_config_1.writeLocalMcpConfig)(cliDistDir);
45
+ process.stdout.write("Mode: local-first (no project ID or API key required)\n\n");
46
+ process.stdout.write("MCP config written: " + mcpPath + "\n\n");
47
+ process.stdout.write("Configured entry:\n\n");
48
+ process.stdout.write(JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: entry } }, null, 2) + "\n");
49
+ process.stdout.write("\nLocal mode: agent_hello creates work contracts on disk.\n" +
50
+ " Run agentbridge watch in this repo, then restart Cursor.\n");
51
+ printRuntimeStatus(cliDistDir);
66
52
  process.stdout.write([
67
53
  "",
68
- "✓ MCP runtime is bundled with this CLI (`agentbridge mcp` is ready).",
54
+ "Next:",
55
+ " 1. Restart Cursor to load MCP.",
56
+ " 2. agentbridge watch",
57
+ " 3. In chat: agent_hello({ intent: \"what you are about to do\" })",
69
58
  "",
70
59
  ].join("\n"));
60
+ return;
61
+ }
62
+ const cfg = (0, config_1.readConfig)();
63
+ const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId ?? "<your-project-id>";
64
+ const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "<your-api-key>";
65
+ const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ??
66
+ cfg.apiBaseUrl ??
67
+ "https://agentauth-api-production.up.railway.app";
68
+ process.stdout.write(editorConfigHint(editor));
69
+ process.stdout.write("Recommended config:\n\n");
70
+ const serverEntry = (0, mcp_config_1.buildServerMcpServerEntry)(projectId, apiKey, apiBaseUrl);
71
+ process.stdout.write(JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: serverEntry } }, null, 2) + "\n");
72
+ if (projectId === "<your-project-id>" || apiKey === "<your-api-key>") {
73
+ process.stdout.write("\n⚠ Credentials not found. Run agentbridge connect first to save your project ID and API key.\n" +
74
+ " Or use local mode: agentbridge setup-mcp --local\n");
75
+ }
76
+ else {
77
+ const mcpPath = (0, mcp_config_1.mergeAgentbridgeIntoCursorMcp)(serverEntry);
78
+ process.stdout.write("\nMCP config written: " + mcpPath + "\n");
79
+ process.stdout.write("\n✓ Credentials filled from .agentbridge/config.json\n");
71
80
  }
81
+ printRuntimeStatus(cliDistDir);
72
82
  process.stdout.write([
73
83
  "After saving the config, restart your editor to activate the MCP server.",
74
84
  "The MCP server lets your AI assistant call tools like agent_hello, check AgentBridge status, and trigger approvals.",
@@ -33,12 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runLocalStart = runLocalStart;
36
37
  exports.runStart = runStart;
37
38
  const config_1 = require("../config");
38
39
  const domain_resolution_1 = require("../domain-resolution");
39
40
  const errors_1 = require("../errors");
40
41
  const error_catalog_1 = require("../error-catalog");
41
42
  const http_1 = require("../http");
43
+ const intent_validation_1 = require("../intent-validation");
42
44
  const session_1 = require("../session");
43
45
  const session_state_1 = require("../session-state");
44
46
  const server_sync_1 = require("../server-sync");
@@ -300,10 +302,19 @@ async function resolveStartOwnership(input) {
300
302
  projectId: ctx.projectId,
301
303
  identities,
302
304
  });
303
- let resolvedDomain = input.explicitDomain?.trim() ||
304
- (0, domain_resolution_1.inferLaneFromFiles)([input.scope], input.configuredDomains).laneDomain ||
305
+ const explicitDomain = input.explicitDomain?.trim();
306
+ const inferredScopeDomain = (0, domain_resolution_1.inferLaneFromFiles)([input.scope], input.configuredDomains).laneDomain;
307
+ let resolvedDomain = explicitDomain ||
308
+ inferredScopeDomain ||
305
309
  callerIdentity.domainName ||
306
310
  undefined;
311
+ let laneClaimSource = explicitDomain
312
+ ? "explicit_domain"
313
+ : inferredScopeDomain
314
+ ? "scope_pattern"
315
+ : callerIdentity.domainName
316
+ ? "caller_identity_domain"
317
+ : "unresolved";
307
318
  let packetDomainOwner = null;
308
319
  let packetDomainName = null;
309
320
  try {
@@ -315,6 +326,7 @@ async function resolveStartOwnership(input) {
315
326
  const first = domainPacket.domains[0];
316
327
  if (!resolvedDomain && first?.domain_name) {
317
328
  resolvedDomain = first.domain_name;
329
+ laneClaimSource = "domain_packet";
318
330
  }
319
331
  packetDomainOwner = first?.owner_work_identity_id ?? null;
320
332
  packetDomainName = first?.domain_name ?? null;
@@ -325,6 +337,11 @@ async function resolveStartOwnership(input) {
325
337
  if (!resolvedDomain) {
326
338
  throw (0, errors_1.catalogCliError)("START_DOMAIN_UNRESOLVED");
327
339
  }
340
+ const laneClaimConfidence = laneClaimSource === "explicit_domain" || laneClaimSource === "scope_pattern"
341
+ ? "high"
342
+ : laneClaimSource === "domain_packet" || laneClaimSource === "caller_identity_domain"
343
+ ? "medium"
344
+ : "low";
328
345
  const projectDomain = projectPacket.domains_summary.find((domain) => equalsIgnoreCase(domain.domain_name, resolvedDomain));
329
346
  const ownerFromProjectPacket = projectDomain?.owner_work_identity_id ?? null;
330
347
  const ownerFromPacket = packetDomainOwner;
@@ -343,6 +360,8 @@ async function resolveStartOwnership(input) {
343
360
  identitySource: resolvedIdentity.source,
344
361
  identityWarning: resolvedIdentity.warning,
345
362
  suggestedActiveAgentId: resolvedIdentity.suggestedActiveAgentId,
363
+ laneClaimConfidence,
364
+ laneClaimSource,
346
365
  };
347
366
  }
348
367
  async function ensureChangeRequestReady(changeRequestId, ownerWorkIdentityId, resolvedDomain, scope) {
@@ -441,6 +460,14 @@ async function executeStartWorkSession(opts) {
441
460
  });
442
461
  const resolvedDomain = ownership.resolvedDomain;
443
462
  const activeAgentId = ownership.resolvedAgentId;
463
+ if (ownership.laneClaimConfidence === "low") {
464
+ throw (0, errors_1.catalogCliError)("START_LANE_CLAIM_LOW_CONFIDENCE");
465
+ }
466
+ if (ownership.laneClaimConfidence === "medium" && opts.confirmDomain !== true) {
467
+ throw (0, errors_1.catalogCliError)("START_LANE_CLAIM_CONFIRM_REQUIRED", {
468
+ what: `Lane claim is medium confidence (${ownership.laneClaimSource}) for domain "${resolvedDomain}".`,
469
+ });
470
+ }
444
471
  const explicitResume = opts.resume === true;
445
472
  const explicitCrId = opts.changeRequestId?.trim() || undefined;
446
473
  const existingCrId = explicitCrId ?? (explicitResume ? cfg.activeChangeRequestId?.trim() || undefined : undefined);
@@ -545,18 +572,31 @@ async function executeStartWorkSession(opts) {
545
572
  }
546
573
  (0, config_1.updateConfig)({ activeChangeRequestId: changeRequest.id });
547
574
  const output = [
548
- "AgentBridge work started",
549
- `Project: ${ctx.projectId}`,
550
- `Change request: ${changeRequest.id}`,
551
- `Work session: ${workSessionId}`,
552
- "Scope:",
553
- `- ${scope}`,
554
- ...(activeAgentId ? [`Agent: ${activeAgentId}`] : []),
555
- `Work Identity: ${ownership.ownerWorkIdentityId}`,
556
- `Identity source: ${ownership.identitySource}`,
557
- ...(resolvedDomain ? [`Domain: ${resolvedDomain}`] : []),
558
- ...(ownership.identityWarning ? [`Warning:\n${ownership.identityWarning}`] : []),
559
- "Next: supervision is now active.",
575
+ "AgentBridge start",
576
+ "",
577
+ "1) Actions performed",
578
+ `- Started tracked work for scope: ${scope}`,
579
+ `- Linked task ${changeRequest.id} to run ${workSessionId}`,
580
+ `- Work session: ${workSessionId}`,
581
+ ...(activeAgentId ? [`- Agent: ${activeAgentId}`] : []),
582
+ ...(resolvedDomain ? [`- Domain: ${resolvedDomain}`] : []),
583
+ "",
584
+ "2) Proof present / missing",
585
+ "- Present: task + run are active and linked",
586
+ "- Missing: verification proof for this change (tests/checks not recorded yet)",
587
+ `- Identity source: ${ownership.identitySource}`,
588
+ `- Lane claim confidence: ${ownership.laneClaimConfidence} (${ownership.laneClaimSource})`,
589
+ ...(ownership.identityWarning
590
+ ? [
591
+ "- Warning: identity config mismatch detected (using caller identity fallback)",
592
+ ownership.identityWarning,
593
+ ]
594
+ : []),
595
+ "",
596
+ "3) Next move",
597
+ "- Keep supervision running with `agentbridge watch`",
598
+ "- After changes, run `agentbridge verify -- <command>`",
599
+ "- Re-run `agentbridge watch` to confirm proof and boundaries",
560
600
  ];
561
601
  process.stdout.write(`${renderOtherSessions(output, [...new Set(otherSessionIds)]).join("\n")}\n`);
562
602
  return {
@@ -567,14 +607,31 @@ async function executeStartWorkSession(opts) {
567
607
  };
568
608
  }
569
609
  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;
610
+ return (0, session_state_1.isActiveLocalSession)((0, session_state_1.readSessionState)());
611
+ }
612
+ async function runLocalStart(intent) {
613
+ const validatedIntent = (0, intent_validation_1.validateIntent)(intent);
614
+ const existing = (0, session_state_1.readSessionState)();
615
+ if ((0, session_state_1.isActiveLocalSession)(existing)) {
616
+ if (existing.intent?.trim() === validatedIntent) {
617
+ process.stdout.write(`Contract already active: ${validatedIntent}\n`);
618
+ return existing;
619
+ }
620
+ throw (0, errors_1.catalogCliError)("START_EXPLICIT_PAIR_REQUIRED", {
621
+ what: "A different AgentBridge contract is already active.",
622
+ why: `Current contract: ${existing.intent ?? "(unknown)"}`,
623
+ next: "Finish the current contract in watch, or close it before starting a new one.",
624
+ });
625
+ }
626
+ const session = (0, session_1.openLocalSession)({
627
+ agentId: "local",
628
+ laneDomain: null,
629
+ intent: validatedIntent,
630
+ domains: [],
631
+ mode: "local_supervision",
632
+ });
633
+ process.stdout.write(`Contract created: ${validatedIntent}\n`);
634
+ return session;
578
635
  }
579
636
  async function runDefaultStart(opts = {}) {
580
637
  const { runLocalSupervision } = await Promise.resolve().then(() => __importStar(require("../local-supervision")));
@@ -595,6 +652,12 @@ function isStrictTrackedStartRequest(opts) {
595
652
  return explicitSummaryFlag || explicitScopeFlag || explicitInputProvided;
596
653
  }
597
654
  async function runStart(opts = {}) {
655
+ const cfg = (0, config_1.readConfig)();
656
+ const localIntent = opts.prompt?.trim() || opts.summary?.trim();
657
+ if (!cfg.projectId?.trim() && localIntent) {
658
+ await runLocalStart(localIntent);
659
+ return;
660
+ }
598
661
  const strictTrackedStart = isStrictTrackedStartRequest(opts);
599
662
  const explicitSummaryFlag = opts.summaryFlagProvided === true;
600
663
  const explicitScopeFlag = opts.scopeFlagProvided === true;