@agentbridge1/cli 0.0.7 → 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.
@@ -21058,6 +21058,20 @@ function computeFileFingerprints(paths) {
21058
21058
  }
21059
21059
 
21060
21060
  // src/local-proof.ts
21061
+ function normalizePath2(path) {
21062
+ return path.trim().replaceAll("\\", "/");
21063
+ }
21064
+ function isProofNoiseFile(file) {
21065
+ const normalized = normalizePath2(file);
21066
+ const lower = normalized.toLowerCase();
21067
+ if (lower === "agentbridge.md" || lower === ".cursor" || lower.startsWith(".cursor/")) {
21068
+ return true;
21069
+ }
21070
+ if (/\.timestamp-\d+-[a-z0-9]+\.mjs$/i.test(normalized)) {
21071
+ return true;
21072
+ }
21073
+ return false;
21074
+ }
21061
21075
  function isLocalVerificationRun(value) {
21062
21076
  if (typeof value !== "object" || value === null) return false;
21063
21077
  const row = value;
@@ -21080,6 +21094,12 @@ function isLocalVerificationRun(value) {
21080
21094
  }
21081
21095
 
21082
21096
  // src/session-state.ts
21097
+ function isActiveLocalSession(state) {
21098
+ if (!state) return false;
21099
+ if (state.status === "closed") return false;
21100
+ if (!state.id || state.id === "none") return false;
21101
+ return true;
21102
+ }
21083
21103
  function resolveRepoRoot() {
21084
21104
  return process.env.AGENTBRIDGE_REPO_ROOT?.trim() || process.cwd();
21085
21105
  }
@@ -21226,11 +21246,11 @@ function writeSessionState(state) {
21226
21246
 
21227
21247
  // src/git-status.ts
21228
21248
  var import_node_child_process = require("node:child_process");
21229
- function normalizePath2(path) {
21249
+ function normalizePath3(path) {
21230
21250
  return path.trim().replaceAll("\\", "/");
21231
21251
  }
21232
21252
  function isAgentbridgeLocalPath(path) {
21233
- const normalized = normalizePath2(path);
21253
+ const normalized = normalizePath3(path);
21234
21254
  return normalized === ".agentbridge" || normalized.startsWith(".agentbridge/");
21235
21255
  }
21236
21256
  function isRenameOrCopy(xy) {
@@ -21246,25 +21266,28 @@ function parseGitStatusPorcelainZ(raw) {
21246
21266
  const payload = token.slice(3);
21247
21267
  if (!payload) continue;
21248
21268
  if (isRenameOrCopy(xy)) {
21249
- const originalPath = normalizePath2(payload);
21250
- const renamedTo = normalizePath2(tokens[idx + 1] ?? "");
21269
+ const originalPath = normalizePath3(payload);
21270
+ const renamedTo = normalizePath3(tokens[idx + 1] ?? "");
21251
21271
  if (renamedTo.length > 0) {
21252
21272
  entries.push({ xy, path: renamedTo, originalPath });
21253
21273
  }
21254
21274
  idx += 1;
21255
21275
  continue;
21256
21276
  }
21257
- entries.push({ xy, path: normalizePath2(payload) });
21277
+ entries.push({ xy, path: normalizePath3(payload) });
21258
21278
  }
21259
21279
  return entries;
21260
21280
  }
21281
+ function isSupervisionRelevantPath(path) {
21282
+ return !isAgentbridgeLocalPath(path) && !isProofNoiseFile(path);
21283
+ }
21261
21284
  function collectChangedFilesFromStatusEntries(entries) {
21262
21285
  const files = /* @__PURE__ */ new Set();
21263
21286
  for (const entry of entries) {
21264
- if (entry.path && !isAgentbridgeLocalPath(entry.path)) {
21287
+ if (entry.path && isSupervisionRelevantPath(entry.path)) {
21265
21288
  files.add(entry.path);
21266
21289
  }
21267
- if (entry.originalPath && !isAgentbridgeLocalPath(entry.originalPath)) {
21290
+ if (entry.originalPath && isSupervisionRelevantPath(entry.originalPath)) {
21268
21291
  files.add(entry.originalPath);
21269
21292
  }
21270
21293
  }
@@ -21313,6 +21336,36 @@ function captureLocalSessionBaseline() {
21313
21336
  fingerprintsAtStart
21314
21337
  };
21315
21338
  }
21339
+ function openLocalSession(input) {
21340
+ const claimedPaths = [...new Set((input.claimedPaths ?? []).map((path) => path.trim()).filter(Boolean))];
21341
+ const baseline = captureLocalSessionBaseline();
21342
+ const now = baseline.startedAt;
21343
+ const state = {
21344
+ id: `local_${Date.now().toString(36)}`,
21345
+ agentId: input.agentId?.trim() || "local",
21346
+ laneDomain: input.laneDomain,
21347
+ intent: input.intent?.trim() || void 0,
21348
+ mode: input.mode,
21349
+ changeRequestId: input.changeRequestId,
21350
+ claimedPaths,
21351
+ status: "active",
21352
+ changedFiles: [],
21353
+ crossings: [],
21354
+ approvals: [],
21355
+ domains: input.domains,
21356
+ serverSessionId: input.serverSessionId,
21357
+ pendingHandoffToAgent: input.pendingHandoffToAgent,
21358
+ pendingHandoffDomain: input.pendingHandoffDomain,
21359
+ createdAt: now,
21360
+ updatedAt: now,
21361
+ startedAt: baseline.startedAt,
21362
+ gitHead: baseline.gitHead,
21363
+ dirtyFilesAtStart: baseline.dirtyFilesAtStart,
21364
+ fingerprintsAtStart: baseline.fingerprintsAtStart
21365
+ };
21366
+ writeSessionState(state);
21367
+ return state;
21368
+ }
21316
21369
 
21317
21370
  // src/local-session-mirror.ts
21318
21371
  function uniquePaths(paths) {
@@ -21523,6 +21576,475 @@ function mirrorMcpToolSuccess(toolName, args, json) {
21523
21576
  mirrorMcpLifecycleEvent(patch);
21524
21577
  }
21525
21578
 
21579
+ // src/error-catalog.ts
21580
+ var CATALOG = {
21581
+ PROJECT_ACCESS_NOT_MEMBER: {
21582
+ code: "PROJECT_ACCESS_NOT_MEMBER",
21583
+ category: "PROJECT_ACCESS_ERROR",
21584
+ title: "Project access denied.",
21585
+ what: "This API key is valid but the agent is not a member of this project.",
21586
+ why: "AgentBridge cannot read or mutate work state without project membership.",
21587
+ next: "Use a key for this project or add this agent to the room."
21588
+ },
21589
+ PROJECT_ACCESS_UNAUTHORIZED: {
21590
+ code: "PROJECT_ACCESS_UNAUTHORIZED",
21591
+ category: "AUTH_ERROR",
21592
+ title: "Authentication failed.",
21593
+ what: "The API key was missing, invalid, or rejected by the server.",
21594
+ why: "AgentBridge cannot reach project APIs without valid credentials.",
21595
+ next: "Run `agentbridge room exit`, set a fresh AGENTBRIDGE_API_KEY, then `agentbridge connect`."
21596
+ },
21597
+ PROJECT_ACCESS_NOT_FOUND: {
21598
+ code: "PROJECT_ACCESS_NOT_FOUND",
21599
+ category: "PROJECT_ACCESS_ERROR",
21600
+ title: "Project not found.",
21601
+ what: "The configured project ID does not exist in this API environment.",
21602
+ why: "Commands target the wrong room or environment.",
21603
+ next: "Verify AGENTBRIDGE_PROJECT_ID and rerun `agentbridge init --project <id>`."
21604
+ },
21605
+ CONNECT_EXECUTION_SURFACE_MISSING: {
21606
+ code: "CONNECT_EXECUTION_SURFACE_MISSING",
21607
+ category: "IDENTITY_ERROR",
21608
+ title: "Connection incomplete.",
21609
+ what: "Project access was verified, but this key is not bound to an AgentConnection execution surface.",
21610
+ why: "Connect requires a room connection key that resolves to work_identity on /hello.",
21611
+ next: [
21612
+ "In the AgentBridge dashboard, open this room and rotate the API key (or create a new room).",
21613
+ "Update AGENTBRIDGE_API_KEY or .agentbridge/config.json with the new key.",
21614
+ "Run: agentbridge connect --project <project-id> --api-key <new-key>",
21615
+ "Connect does not create or rotate keys automatically."
21616
+ ].join("\n")
21617
+ },
21618
+ IDENTITY_ACTIVE_AGENT_STALE: {
21619
+ code: "IDENTITY_ACTIVE_AGENT_STALE",
21620
+ category: "IDENTITY_ERROR",
21621
+ title: "Active agent could not be resolved.",
21622
+ what: "Configured activeAgentId could not be resolved in this project.",
21623
+ why: "Start and watch need a WorkIdentity that exists in the current room.",
21624
+ next: "Run `agentbridge identity list` and update with `agentbridge use <agent-id>`."
21625
+ },
21626
+ WORK_CONTEXT_NO_CURRENT_SESSION: {
21627
+ code: "WORK_CONTEXT_NO_CURRENT_SESSION",
21628
+ category: "WORK_CONTEXT_ERROR",
21629
+ title: "No active tracked work session.",
21630
+ what: "No active tracked work session was found for this command.",
21631
+ why: "Proof, verify, accept, and handoff require a bound work session.",
21632
+ next: "Run `agentbridge watch` beside Cursor for live supervision, or `agentbridge verify -- <test command>` to record proof.",
21633
+ blocksAcceptance: true
21634
+ },
21635
+ WORK_CONTEXT_BINDING_REQUIRED: {
21636
+ code: "WORK_CONTEXT_BINDING_REQUIRED",
21637
+ category: "WORK_CONTEXT_ERROR",
21638
+ title: "Work session binding required.",
21639
+ what: "This command needs a linked local/server work session.",
21640
+ why: "The CLI and server must agree on the active change request and session.",
21641
+ next: 'Run `agentbridge watch --allow-dirty` for default review, or `agentbridge watch --task "<task>" --scope "<path>"` for strict mode.',
21642
+ blocksAcceptance: true
21643
+ },
21644
+ PROOF_STALE_AFTER_CHANGE: {
21645
+ code: "PROOF_STALE_AFTER_CHANGE",
21646
+ category: "PROOF_STALE_ERROR",
21647
+ title: "Proof is stale.",
21648
+ what: "Verification passed earlier, but scoped files changed afterward.",
21649
+ why: "Acceptance requires proof that matches the current tree.",
21650
+ next: "Rerun `agentbridge verify -- <command>`.",
21651
+ blocksAcceptance: true
21652
+ },
21653
+ SCOPE_DRIFT_OUT_OF_SCOPE_FILE: {
21654
+ code: "SCOPE_DRIFT_OUT_OF_SCOPE_FILE",
21655
+ category: "SCOPE_DRIFT_ERROR",
21656
+ title: "Scope drift detected.",
21657
+ what: "The agent changed a file outside the declared scope.",
21658
+ why: "Out-of-scope edits are not safe to trust until reviewed or rescoped.",
21659
+ next: 'Options: (1) revert the out-of-scope file, (2) widen strict scope via `agentbridge watch --task "<work>" --scope "<wider-path>"`, or (3) split into a separate task.',
21660
+ blocksAcceptance: true
21661
+ },
21662
+ HANDOFF_REQUIRED: {
21663
+ code: "HANDOFF_REQUIRED",
21664
+ category: "HANDOFF_ERROR",
21665
+ title: "Handoff required.",
21666
+ what: "Acceptance is blocked until a handoff is recorded for this session.",
21667
+ why: "Cross-boundary work must be explicitly handed off before close.",
21668
+ next: "Run `agentbridge handoff` with a summary, then retry accept.",
21669
+ blocksAcceptance: true
21670
+ },
21671
+ ACCEPTANCE_BLOCKED: {
21672
+ code: "ACCEPTANCE_BLOCKED",
21673
+ category: "ACCEPTANCE_ERROR",
21674
+ title: "Acceptance blocked by protocol rules.",
21675
+ what: "Server checks rejected acceptance due to missing handoff, proof, or scope alignment.",
21676
+ why: "The acceptance contract was not fully satisfied.",
21677
+ next: "Run `agentbridge watch --once` to see current blocking issues, resolve each one, then retry `agentbridge accept`.",
21678
+ blocksAcceptance: true
21679
+ },
21680
+ MEMORY_SUGGEST_NO_SESSION: {
21681
+ code: "MEMORY_SUGGEST_NO_SESSION",
21682
+ category: "MEMORY_ERROR",
21683
+ title: "No accepted session for memory suggest.",
21684
+ what: "Memory suggest could not find an accepted session to summarize.",
21685
+ why: "Memory packets are generated from completed, accepted work.",
21686
+ next: "Complete and accept a session first, then rerun `agentbridge memory suggest`."
21687
+ },
21688
+ CONFIG_INCOMPLETE: {
21689
+ code: "CONFIG_INCOMPLETE",
21690
+ category: "CONFIG_ERROR",
21691
+ title: "Configuration incomplete.",
21692
+ what: "Project ID, API key, or base URL is missing from config and environment.",
21693
+ why: "AgentBridge cannot call the server without connection settings.",
21694
+ next: "Run `agentbridge init` or set AGENTBRIDGE_PROJECT_ID / AGENTBRIDGE_API_KEY."
21695
+ },
21696
+ IDENTITY_NO_ACTIVE_AGENT: {
21697
+ code: "IDENTITY_NO_ACTIVE_AGENT",
21698
+ category: "IDENTITY_ERROR",
21699
+ title: "No active agent configured.",
21700
+ what: "activeAgentId is not set in .agentbridge/config.json.",
21701
+ why: "Watch and start need a WorkIdentity selected for this repo.",
21702
+ next: "Run `agentbridge identity list` then `agentbridge use <agent-id>`."
21703
+ },
21704
+ CONFIG_NO_DOMAIN_MAP: {
21705
+ code: "CONFIG_NO_DOMAIN_MAP",
21706
+ category: "CONFIG_ERROR",
21707
+ title: "Domain map missing.",
21708
+ what: "No recovered domain map was found in .agentbridge/config.json.",
21709
+ why: "Watch uses domain boundaries to enforce scoped file tracking.",
21710
+ next: "Run `agentbridge init` to recover domains for this repo."
21711
+ },
21712
+ AUTH_LOGIN_FAILED: {
21713
+ code: "AUTH_LOGIN_FAILED",
21714
+ category: "AUTH_ERROR",
21715
+ title: "Sign in failed.",
21716
+ what: "Authentication could not be completed.",
21717
+ why: "You cannot open rooms without a valid session.",
21718
+ next: "Return to login and try again, or contact your admin if auth is disabled."
21719
+ },
21720
+ NETWORK_UNREACHABLE: {
21721
+ code: "NETWORK_UNREACHABLE",
21722
+ category: "NETWORK_ERROR",
21723
+ title: "Network error.",
21724
+ what: "The CLI could not reach the AgentBridge API.",
21725
+ why: "Without network access, local commands cannot sync work state.",
21726
+ next: "Check AGENTBRIDGE_BASE_URL and network connectivity, then rerun `agentbridge doctor`."
21727
+ },
21728
+ SERVER_ERROR: {
21729
+ code: "SERVER_ERROR",
21730
+ category: "SERVER_ERROR",
21731
+ title: "Server error.",
21732
+ what: "The AgentBridge server failed while handling the request.",
21733
+ why: "The action could not complete until the server recovers.",
21734
+ next: "Retry shortly. If it persists, run `agentbridge doctor` and check server logs."
21735
+ },
21736
+ UNKNOWN_RUNTIME_ERROR: {
21737
+ code: "UNKNOWN_RUNTIME_ERROR",
21738
+ category: "UNKNOWN_ERROR",
21739
+ title: "Command failed.",
21740
+ what: "The command could not be completed due to an unexpected local/runtime error.",
21741
+ why: "AgentBridge could not classify this failure.",
21742
+ next: "Run `agentbridge doctor` with AGENTBRIDGE_DEBUG=1 and retry."
21743
+ },
21744
+ START_SUMMARY_REQUIRED: {
21745
+ code: "START_SUMMARY_REQUIRED",
21746
+ category: "START_ERROR",
21747
+ title: "Summary required.",
21748
+ what: "Start requires a non-empty --summary describing the work.",
21749
+ why: "Change requests and work sessions need a human-readable intent.",
21750
+ next: 'Run `agentbridge start --summary "<work>" --scope "<path>"`.'
21751
+ },
21752
+ START_SCOPE_REQUIRED: {
21753
+ code: "START_SCOPE_REQUIRED",
21754
+ category: "START_ERROR",
21755
+ title: "Scope required.",
21756
+ what: "Start requires a non-empty --scope path or glob.",
21757
+ why: "Scoped work must declare which files this session may touch.",
21758
+ next: 'Run `agentbridge start --summary "<work>" --scope "<path>"`.'
21759
+ },
21760
+ START_MISSING_ACTIVE_AGENT: {
21761
+ code: "START_MISSING_ACTIVE_AGENT",
21762
+ category: "IDENTITY_ERROR",
21763
+ title: "No active agent configured.",
21764
+ what: "Neither activeAgentId nor --agent was provided for strict tracked start.",
21765
+ why: "Strict tracked work (--summary/--scope, --resume, or --change-request) must bind to a WorkIdentity in this project.",
21766
+ next: [
21767
+ "For strict tracked work: run `agentbridge identity list` then `agentbridge use <agent-id>`, or pass --agent.",
21768
+ "For room-level watching only: run `agentbridge start` with no strict flags."
21769
+ ].join("\n")
21770
+ },
21771
+ START_EXECUTION_SURFACE_REQUIRED: {
21772
+ code: "START_EXECUTION_SURFACE_REQUIRED",
21773
+ category: "CONFIG_ERROR",
21774
+ title: "Execution surface missing.",
21775
+ what: "No executionSurfaceId is saved in .agentbridge/config.json.",
21776
+ why: "The server needs a stable execution surface to open a tracked session.",
21777
+ next: [
21778
+ "Run:",
21779
+ " agentbridge connect --project <project-id> --api-key <key> --api-base-url <url>",
21780
+ "Then:",
21781
+ " agentbridge doctor",
21782
+ "If this continues, AgentBridge could not create an AgentConnection/execution surface for this project."
21783
+ ].join("\n")
21784
+ },
21785
+ START_AGENT_INVALID: {
21786
+ code: "START_AGENT_INVALID",
21787
+ category: "IDENTITY_ERROR",
21788
+ title: "Agent could not be resolved.",
21789
+ what: "The --agent value does not match any WorkIdentity in this project.",
21790
+ why: "Start cannot open scoped work without a valid project agent.",
21791
+ next: 'Run `agentbridge identity list` and retry with `--agent "<valid-agent-id>"`.'
21792
+ },
21793
+ START_IDENTITY_MISMATCH: {
21794
+ code: "START_IDENTITY_MISMATCH",
21795
+ category: "IDENTITY_ERROR",
21796
+ title: "Agent identity mismatch.",
21797
+ what: "The resolved agent is not authorized for this API key's WorkIdentity.",
21798
+ why: "Start must run under the same WorkIdentity as the API key.",
21799
+ next: "Use an API key bound to that agent, or pick an agent your key owns."
21800
+ },
21801
+ START_CALLER_IDENTITY_UNRESOLVED: {
21802
+ code: "START_CALLER_IDENTITY_UNRESOLVED",
21803
+ category: "IDENTITY_ERROR",
21804
+ title: "Caller identity unresolved.",
21805
+ what: "The API key could not be mapped to a WorkIdentity in this project.",
21806
+ why: "Start requires a resolvable caller WorkIdentity from the server.",
21807
+ next: "Run `agentbridge doctor` and verify this key is an AgentConnection key."
21808
+ },
21809
+ START_DOMAIN_UNRESOLVED: {
21810
+ code: "START_DOMAIN_UNRESOLVED",
21811
+ category: "START_ERROR",
21812
+ title: "Domain could not be inferred.",
21813
+ what: "No domain could be inferred from scope or active identity.",
21814
+ why: "Scoped work must target a recovered domain lane.",
21815
+ next: 'Pass `--domain "<domain>"` with start, or run `agentbridge init`.'
21816
+ },
21817
+ START_LANE_CLAIM_CONFIRM_REQUIRED: {
21818
+ code: "START_LANE_CLAIM_CONFIRM_REQUIRED",
21819
+ category: "START_ERROR",
21820
+ title: "Lane claim needs explicit confirmation.",
21821
+ what: "Start inferred a domain with medium confidence.",
21822
+ why: "Production-safe lane claim requires explicit confirmation when scope-to-domain mapping is ambiguous.",
21823
+ next: 'Rerun with `--confirm-domain` or pass an explicit `--domain "<domain>"`.'
21824
+ },
21825
+ START_LANE_CLAIM_LOW_CONFIDENCE: {
21826
+ code: "START_LANE_CLAIM_LOW_CONFIDENCE",
21827
+ category: "START_ERROR",
21828
+ title: "Lane claim confidence too low.",
21829
+ what: "AgentBridge could not confidently bind this work to a single domain lane.",
21830
+ why: "A wrong lane claim undermines scope enforcement and ownership attribution.",
21831
+ next: 'Pass explicit `--domain "<domain>"` and tighter `--scope "<path>"`, then rerun start.'
21832
+ },
21833
+ START_OWNER_UNRESOLVED: {
21834
+ code: "START_OWNER_UNRESOLVED",
21835
+ category: "START_ERROR",
21836
+ title: "Domain owner unresolved.",
21837
+ what: "The change request or session policy requires an owner WorkIdentity that is not assigned.",
21838
+ why: "The server will not open a tracked session without domain ownership.",
21839
+ next: "Ensure this project has a domain owner for the scope, or pass --domain."
21840
+ },
21841
+ START_CR_OWNERSHIP_MISMATCH: {
21842
+ code: "START_CR_OWNERSHIP_MISMATCH",
21843
+ category: "START_ERROR",
21844
+ title: "Tracked task belongs to another connected agent.",
21845
+ what: "AgentBridge found an old tracked task owned by a different connected agent.",
21846
+ why: "AgentBridge will not let one connected agent automatically take over another agent's tracked work.",
21847
+ next: "Run `agentbridge watch` for live supervision, or switch back to the original connected agent if you intend to resume old tracked work."
21848
+ },
21849
+ START_CR_NOT_EXECUTABLE: {
21850
+ code: "START_CR_NOT_EXECUTABLE",
21851
+ category: "START_ERROR",
21852
+ title: "Change request not executable.",
21853
+ what: "The change request is in a terminal or incompatible lifecycle state.",
21854
+ why: "Only draft/scoped/assigned/ready_for_session CRs can start scoped work.",
21855
+ next: "Pick another change request or create a new one with start."
21856
+ },
21857
+ START_SESSION_OPEN_FAILED: {
21858
+ code: "START_SESSION_OPEN_FAILED",
21859
+ category: "START_ERROR",
21860
+ title: "Session could not be opened.",
21861
+ what: "A change request was prepared but no work session could be opened.",
21862
+ why: "Watch and verify require a server-backed session linked to the CR.",
21863
+ next: "Run `agentbridge watch --change-request <id>` or inspect `agentbridge session list`."
21864
+ },
21865
+ START_LOCAL_SESSION_WRITE_FAILED: {
21866
+ code: "START_LOCAL_SESSION_WRITE_FAILED",
21867
+ category: "START_ERROR",
21868
+ title: "Local session write failed.",
21869
+ what: "The server session opened but local session state could not be saved.",
21870
+ why: "Watch and verify rely on .agentbridge/session state on disk.",
21871
+ next: "Check repo permissions under .agentbridge/ and retry start."
21872
+ },
21873
+ VERIFY_COMMAND_REQUIRED: {
21874
+ code: "VERIFY_COMMAND_REQUIRED",
21875
+ category: "PROOF_ERROR",
21876
+ title: "Verification command required.",
21877
+ what: "Verify requires a shell command after `--`.",
21878
+ why: "Proof must record the output of a concrete verification command.",
21879
+ next: "Run `agentbridge verify -- npm test` (or your project command).",
21880
+ blocksAcceptance: true
21881
+ },
21882
+ VERIFY_COMMAND_FAILED: {
21883
+ code: "VERIFY_COMMAND_FAILED",
21884
+ category: "PROOF_ERROR",
21885
+ title: "Verification command failed.",
21886
+ what: "The verification command exited with a non-zero status.",
21887
+ why: "Failed proof blocks acceptance until tests or checks pass.",
21888
+ next: "Fix the command failure, then rerun `agentbridge verify -- <command>`.",
21889
+ blocksAcceptance: true
21890
+ },
21891
+ PROOF_MISSING: {
21892
+ code: "PROOF_MISSING",
21893
+ category: "PROOF_ERROR",
21894
+ title: "Required proof missing.",
21895
+ what: "Acceptance checks report missing verification evidence.",
21896
+ why: "Acceptance requires recorded proof for this work session.",
21897
+ next: "Run `agentbridge verify -- <command>` then `agentbridge check`.",
21898
+ blocksAcceptance: true
21899
+ },
21900
+ PROOF_TOO_WEAK: {
21901
+ code: "PROOF_TOO_WEAK",
21902
+ category: "PROOF_ERROR",
21903
+ title: "Proof too weak.",
21904
+ what: "Verification ran, but proof strength is below what this change requires.",
21905
+ why: "High-risk or source changes need stronger proof than file-existence checks.",
21906
+ next: "Rerun with a stronger command from proof guidance (e.g. `agentbridge verify -- npm test`).",
21907
+ blocksAcceptance: true
21908
+ },
21909
+ PROOF_NOT_RELEVANT: {
21910
+ code: "PROOF_NOT_RELEVANT",
21911
+ category: "PROOF_ERROR",
21912
+ title: "Proof not relevant.",
21913
+ what: "Recorded proof does not cover the files or impact of this change.",
21914
+ why: "Proof must match the changed files \u2014 unrelated passing tests do not count.",
21915
+ next: "Rerun verification scoped to the changed files listed in the acceptance report.",
21916
+ blocksAcceptance: true
21917
+ },
21918
+ PROOF_IMPACT_COVERAGE_GAP: {
21919
+ code: "PROOF_IMPACT_COVERAGE_GAP",
21920
+ category: "PROOF_ERROR",
21921
+ title: "Proof impact coverage gap.",
21922
+ what: "Proof exists but does not cover required impact areas for this work type.",
21923
+ why: "Some change profiles require broader verification than a single lightweight check.",
21924
+ next: "Run the minimum commands listed under proof guidance in `agentbridge check`.",
21925
+ blocksAcceptance: true
21926
+ },
21927
+ PROOF_EVIDENCE_NOT_RECORDED: {
21928
+ code: "PROOF_EVIDENCE_NOT_RECORDED",
21929
+ category: "PROOF_ERROR",
21930
+ title: "Proof not recorded.",
21931
+ what: "Verification could not be recorded on the server.",
21932
+ why: "Without a verification run, acceptance cannot proceed.",
21933
+ next: "Retry verify after confirming network access and session binding.",
21934
+ blocksAcceptance: true
21935
+ },
21936
+ SESSION_ID_REQUIRED: {
21937
+ code: "SESSION_ID_REQUIRED",
21938
+ category: "WORK_CONTEXT_ERROR",
21939
+ title: "Session id required.",
21940
+ what: "Session inspect requires a work session id argument.",
21941
+ why: "The command must know which server session to load.",
21942
+ next: "Run `agentbridge session inspect <work-session-id>`."
21943
+ },
21944
+ SESSION_ABANDON_REASON_REQUIRED: {
21945
+ code: "SESSION_ABANDON_REASON_REQUIRED",
21946
+ category: "WORK_CONTEXT_ERROR",
21947
+ title: "Abandon reason too short.",
21948
+ what: "Session abandon requires --reason with at least 8 characters.",
21949
+ why: "Abandon is audited and must explain why the session stopped.",
21950
+ next: 'Run `agentbridge session abandon --reason "<why stopping>"`.'
21951
+ },
21952
+ SESSION_NO_TARGET: {
21953
+ code: "SESSION_NO_TARGET",
21954
+ category: "WORK_CONTEXT_ERROR",
21955
+ title: "No session to abandon.",
21956
+ what: "No --session id was passed and no local session is linked.",
21957
+ why: "Abandon must target a specific work session.",
21958
+ next: "Pass --session <id> or link a session via `agentbridge watch`."
21959
+ },
21960
+ WORK_CONTEXT_SESSION_ALREADY_TERMINAL: {
21961
+ code: "WORK_CONTEXT_SESSION_ALREADY_TERMINAL",
21962
+ category: "WORK_CONTEXT_ERROR",
21963
+ title: "Session already closed.",
21964
+ what: "The linked work session is closed or terminal.",
21965
+ why: "Proof and acceptance cannot attach to a finished session.",
21966
+ next: 'Run `agentbridge session abandon --reason "session closed"` and start fresh.',
21967
+ blocksAcceptance: true
21968
+ },
21969
+ ACCEPTANCE_ALREADY_CLOSED: {
21970
+ code: "ACCEPTANCE_ALREADY_CLOSED",
21971
+ category: "ACCEPTANCE_ERROR",
21972
+ title: "Work already closed.",
21973
+ what: "This change request or session is already in a terminal acceptance state.",
21974
+ why: "Accept and verify cannot mutate closed work.",
21975
+ next: "Run `agentbridge watch --allow-dirty` to review new coding work.",
21976
+ blocksAcceptance: true
21977
+ },
21978
+ WORK_CONTEXT_SESSION_CR_MISMATCH: {
21979
+ code: "WORK_CONTEXT_SESSION_CR_MISMATCH",
21980
+ category: "WORK_CONTEXT_ERROR",
21981
+ title: "Session change-request mismatch.",
21982
+ what: "Local session points at a different change request than requested.",
21983
+ why: "Proof or acceptance could attach to the wrong work.",
21984
+ next: "Fix activeChangeRequestId or abandon the stale local session.",
21985
+ blocksAcceptance: true
21986
+ },
21987
+ WORK_CONTEXT_STALE_LOCAL_SESSION: {
21988
+ code: "WORK_CONTEXT_STALE_LOCAL_SESSION",
21989
+ category: "WORK_CONTEXT_ERROR",
21990
+ title: "Stale local session.",
21991
+ what: "Local session id no longer exists on the server.",
21992
+ why: "Watch and verify would track orphaned state.",
21993
+ next: "Local session state has been cleared. Run `agentbridge watch --allow-dirty` to review current work.",
21994
+ blocksAcceptance: true
21995
+ },
21996
+ WORK_CONTEXT_SCOPE_MISMATCH: {
21997
+ code: "WORK_CONTEXT_SCOPE_MISMATCH",
21998
+ category: "WORK_CONTEXT_ERROR",
21999
+ title: "Session scope or task mismatch.",
22000
+ what: "The active session was started with a different task or scope than requested.",
22001
+ why: "Resuming the wrong session would silently corrupt proof and scope boundaries.",
22002
+ next: 'Finish or abandon the current session (`agentbridge session abandon --reason "..."`) then rerun `agentbridge watch --task "<task>" --scope "<path>"`.',
22003
+ blocksAcceptance: true
22004
+ },
22005
+ WORK_CONTEXT_AMBIGUOUS_SESSIONS: {
22006
+ code: "WORK_CONTEXT_AMBIGUOUS_SESSIONS",
22007
+ category: "WORK_CONTEXT_ERROR",
22008
+ title: "Ambiguous active sessions.",
22009
+ what: "Multiple active sessions match this change request.",
22010
+ why: "The CLI cannot pick a single current session safely.",
22011
+ next: 'Run `agentbridge session abandon --session <id> --reason "duplicate"`.',
22012
+ blocksAcceptance: true
22013
+ },
22014
+ WORK_CONTEXT_OTHER_ACTIVE_SESSIONS: {
22015
+ code: "WORK_CONTEXT_OTHER_ACTIVE_SESSIONS",
22016
+ category: "WORK_CONTEXT_ERROR",
22017
+ title: "Other active sessions exist.",
22018
+ what: "No current session is bound, but other active sessions exist on the server.",
22019
+ why: "Verify and accept must not attach to the wrong session silently.",
22020
+ next: "Run `agentbridge session list --active` to identify the correct session, then `agentbridge watch --change-request <cr-id>` to bind it explicitly.",
22021
+ blocksAcceptance: true
22022
+ },
22023
+ SESSION_SERVER_MISSING: {
22024
+ code: "SESSION_SERVER_MISSING",
22025
+ category: "WORK_CONTEXT_ERROR",
22026
+ title: "Session not found on server.",
22027
+ what: "The requested work session id does not exist in this project.",
22028
+ why: "Inspect and abandon require a valid server session.",
22029
+ next: "Run `agentbridge session list` and pick a current id."
22030
+ }
22031
+ };
22032
+
22033
+ // src/intent-validation.ts
22034
+ var VAGUE_PHRASES = [
22035
+ "working on project",
22036
+ "making changes",
22037
+ "updating files",
22038
+ "fix stuff",
22039
+ "general work"
22040
+ ];
22041
+ function isVagueIntent(intent) {
22042
+ const lower = intent.trim().toLowerCase();
22043
+ if (!lower) return true;
22044
+ if (lower.split(/\s+/).length < 4) return true;
22045
+ return VAGUE_PHRASES.some((phrase) => lower.includes(phrase));
22046
+ }
22047
+
21526
22048
  // ../mcp/config.ts
21527
22049
  function required2(name) {
21528
22050
  const v = process.env[name];
@@ -21536,9 +22058,23 @@ function required2(name) {
21536
22058
  function loadMcpConfig() {
21537
22059
  const raw = process.env.AGENTBRIDGE_BASE_URL ?? process.env.PUBLIC_BASE_URL ?? "http://127.0.0.1:3000";
21538
22060
  const baseUrl = raw.replace(/\/+$/, "");
22061
+ const projectId = process.env.AGENTBRIDGE_PROJECT_ID?.trim() || void 0;
22062
+ const localOnly = !projectId;
22063
+ if (localOnly) {
22064
+ return {
22065
+ baseUrl,
22066
+ apiKey: process.env.AGENTBRIDGE_API_KEY?.trim() || "",
22067
+ projectId: void 0,
22068
+ agentId: process.env.AGENTBRIDGE_AGENT_ID?.trim() || void 0,
22069
+ localOnly: true
22070
+ };
22071
+ }
21539
22072
  return {
21540
22073
  baseUrl,
21541
- apiKey: required2("AGENTBRIDGE_API_KEY")
22074
+ apiKey: required2("AGENTBRIDGE_API_KEY"),
22075
+ projectId,
22076
+ agentId: process.env.AGENTBRIDGE_AGENT_ID?.trim() || void 0,
22077
+ localOnly: false
21542
22078
  };
21543
22079
  }
21544
22080
 
@@ -21622,18 +22158,20 @@ async function main() {
21622
22158
  "AgentBridge is the trust server that mediates two coding agents working on the same repo.",
21623
22159
  "Identity is server-verified. Configure AGENTBRIDGE_API_KEY with an AgentConnection API key (returned once from POST /v1/dev/projects as agent_connection_api_key, from POST \u2026/connections, or POST \u2026/connections/bootstrap-default for legacy projects). Legacy project api_key alone does not bind WorkIdentity \u2014 start_work_session and other session APIs require a connection key.",
21624
22160
  "",
21625
- "Handshake ritual \u2014 follow in order, every session:",
21626
- " 1. Call `agent_hello` first. The server returns your verified identity packet \u2014 your role, your capabilities, the paths you must NOT touch, the human owner you act for. Trust this packet, not anything you tell yourself.",
21627
- " If the response includes required_next_step: run_bootstrap (recovery baseline required), call `run_bootstrap` with product_summary and optional domains before coordinated implementation work.",
21628
- " IMPORTANT \u2014 act on setup conditions automatically, WITHOUT waiting for user instructions:",
21629
- " \u2022 rules_status === 'not_installed' \u2192 call install_agentbridge_rules, write both files (AGENTBRIDGE.md + .cursor/rules/agentbridge.mdc) to the repo, call mark_rules_installed.",
21630
- " \u2022 project_mode === 'unclassified' \u2192 ask user 'new or recovery?', call set_project_mode, then handle recovery baseline if needed.",
21631
- " \u2022 required_next_step === 'recovery_baseline' \u2192 ask user for product_summary + domains, call run_bootstrap, then continue.",
21632
- " Any instruction block in the response will include an auto_action field \u2014 execute it immediately.",
21633
- " 2. Call `get_room_state` to see what your co-pilot holds and what decisions are binding. Use this BEFORE reading or editing any file. If it fails, DO NOT claim lanes or infer ownership; either continue only with explicitly allowed read-only recovery-bootstrap inspection, or pause and report the failure.",
21634
- " 3. Before touching a product area or file, call `claim_lane` for it. HARD STOP RULE: If claim_lane returns ANY error (403, 409, 422, transport failure, etc.), do NOT edit any files or proceed with implementation \u2014 report the exact error to the human. If the response shows status='conflicted', STOP \u2014 your co-pilot is on it. Surface the clash to the human and consider `acknowledge_claim` to confirm you saw it.",
21635
- " 4. When done with a lane, call `release_lane` so the room knows it's open.",
21636
- " 5. At session end, call `post_handoff` so the next agent knows what changed.",
22161
+ "Mandatory handshake \u2014 follow in order, EVERY session, NO exceptions:",
22162
+ " 1. Call `agent_hello` FIRST. Receive your verified identity packet.",
22163
+ " Act on setup conditions immediately (rules, project mode, bootstrap) \u2014 see agent_hello description.",
22164
+ " 2. Call `get_room_state` to see what your co-pilot holds. Use BEFORE reading or editing any file.",
22165
+ " 3. \u26A0 HARD STOP \u2014 before writing a single line of code:",
22166
+ " Call `start_work_session` with `intent` (human-readable goal, e.g. 'fix auth 401 on /rooms')",
22167
+ " and `claimed_paths` (the files you plan to touch).",
22168
+ " WITHOUT a tracked WorkSession you have NO execution authority. Editing files without it is",
22169
+ " a protocol violation \u2014 AgentBridge watch will flag the work as unverified and the human",
22170
+ " will see '(no intent declared)' with no scope, no trust.",
22171
+ " 4. Call `generate_authority_packet` to receive your full execution surface.",
22172
+ " 5. Call `claim_lane` for every file/area before touching it.",
22173
+ " 6. Call `release_lane` when done with each lane.",
22174
+ " 7. Call `post_handoff` at session end.",
21637
22175
  "",
21638
22176
  "Use `get_live_wire` any time to read the project's chronological event log.",
21639
22177
  "Use `request_context` to ask your co-pilot a question. Use `reserve_file` to request an approval-gated lock.",
@@ -21654,9 +22192,11 @@ async function main() {
21654
22192
  server.registerTool(
21655
22193
  "agent_hello",
21656
22194
  {
21657
- description: "Identify yourself to the trust server and receive your verified identity packet.\n\nOPERATING LOOP (Phase 5.5 \u2014 read this carefully):\n 1. Call agent_hello FIRST every session.\n 2. Inspect the response's `active_sessions` array:\n \u2022 0 sessions \u2192 there is no active tracked job (internal WorkSession) for this connection. Stop and ask the human to start a job before issuing any controlled call.\n \u2022 1 session \u2192 that is your active tracked job. Use its work_session_id for everything below.\n \u2022 2+ sessions \u2192 DO NOT GUESS. The response sets selected_session_required=true. Ask the human which session to use, or call select_work_session to confirm.\n 3. Call generate_authority_packet(project_id, work_session_id) to receive the full tracked-job authority packet (WorkIdentity, ExecutionSurface, allowed/blocked domains, scope_snapshot, out_of_scope_snapshot, risk_level).\n 4. Pass work_session_id on EVERY controlled call: claim_lane, release_lane, post_handoff, close_work_session, check_close_readiness.\n 5. Respect `session_required_for_implementation=true` (a tracked job is required before this agent can edit files). If `active_sessions` is empty, do not perform implementation edits.\n\nAUTHORITY MODEL:\n \u2022 Cursor / Claude Code / etc. are ExecutionSurfaces. They are NOT the agent identity.\n \u2022 The accountable identity is the WorkIdentity (e.g. 'Auth Agent').\n \u2022 A WorkIdentity is granted only by an active tracked job (WorkSession record) bound to your AgentConnection.\n \u2022 You cannot self-declare authority. The server resolves your role from that WorkSession.\n\nIdentity packet shapes:\n \u2022 NEW (AgentConnection key): `work_identity` packet with WorkIdentity, ExecutionSurface, domain, capabilities, blocked_domains.\n \u2022 LEGACY (Agent API key): `verified` packet with role, capabilities, blocked_paths.\n\nRECOVERY MODE \u2014 when you're working on an existing unstructured codebase:\n \u2022 If the project's `project_mode` is 'recovery' and `recoveryStatus` is 'active' or 'stabilising',\n the response includes a `recovery_brief` block.\n \u2022 If you are NEW to this project (no prior completed sessions), `recovery_brief` includes:\n - `product_summary`: what the codebase does\n - `known_domains`: list of domain names with trap counts\n - `known_traps`: flat list of ALL traps across domains \u2014 READ BEFORE TOUCHING ANYTHING\n - `recommended_first_action`: what to do first\n - `warning`: 'This is a recovery project. Treat all domain boundaries as fragile.'\n \u2022 If you have prior sessions, `recovery_brief` is abbreviated with `recommended_first_action: 'continue_with_memory'`.\n \u2022 If `recoveryStatus === 'archived'`, the response signals `recovery_archived: true` \u2014 treat as a normal V1 project.\n \u2022 If `required_next_step` is `run_bootstrap` (or `recovery_status` is `baseline_required`), call `run_bootstrap` with `product_summary` and optional `domains` \u2014 same payload as POST /v1/dev/projects/:id/bootstrap.\n\nAUTOMATIC SETUP \u2014 do not wait for user instructions when any of these apply:\n \u2022 `rules_status === 'not_installed'` \u2192 call install_agentbridge_rules, write AGENTBRIDGE.md and .cursor/rules/agentbridge.mdc to the repo, call mark_rules_installed.\n \u2022 `project_mode === 'unclassified'` or `required_next_step === 'classify_project_mode'` \u2192 ask user new/recovery, call set_project_mode.\n \u2022 `required_next_step === 'recovery_baseline'` \u2192 ask user for summary + domains, call run_bootstrap.\n When setup is required, the instruction block includes an `auto_action` string \u2014 execute it immediately.\n\nSTARTUP FLOW \u2014 call in order on every new chat:\n 1. agent_hello \u2192 receive identity + check for setup conditions\n 2. get_project_packet \u2192 receive compact project context (product summary, domain counts, charter, risks)\n 3. resolve_work_context \u2192 structured next step from durable state (sessions, approvals, CRs, paths, LIP); NL classifier is last resort only\n 4. get_domain_packet \u2192 load detailed domain context for the resolved domain(s) (traps, risks, owned paths)\n 5. get_last_implementation_packet \u2192 durable post-close implementation memory (what changed, files, risks, learned_after)\n 6. inspect repo files targeted to those domains / the packet\n 7. start_work_session + generate_authority_packet ONLY before editing files\n\nagent_hello does NOT return full product memory \u2014 call get_project_packet for startup context.\nPrefer resolve_work_context before classify_task_domain when the user's intent is vague or continuation-style.\nFor regressions after recent work, do not begin by summarising chat history. Load the Last Implementation Packet first (get_last_implementation_packet).",
22195
+ description: "Call agent_hello at the start of every session.\n\nLOCAL MODE (no AGENTBRIDGE_PROJECT_ID configured):\n - If a contract already exists: returns it. No arguments needed.\n - If no contract exists: pass intent with what you are about to do.\n agent_hello({ intent: \"Fix auth 401 on /rooms endpoint\" })\n - agentbridge watch in the terminal tracks the contract and prints a verdict.\n - Do not call start_work_session, claim_lane, or generate_authority_packet in local mode.\n\nSERVER MODE (AGENTBRIDGE_PROJECT_ID configured):\nIdentify yourself to the trust server and receive your verified identity packet.\n\nOPERATING LOOP (Phase 5.5 \u2014 read this carefully):\n 1. Call agent_hello FIRST every session.\n 2. Inspect the response's `active_sessions` array:\n \u2022 0 sessions \u2192 \u26A0 HARD STOP. You have NO execution authority.\n DO NOT read files, DO NOT write code, DO NOT run commands.\n You MUST call `start_work_session` NOW with:\n - `intent`: a human-readable description of what the user asked for\n (e.g. 'fix the 401 auth error on /rooms', 'add dark mode toggle')\n - `claimed_paths`: the files/directories you plan to touch\n Without this, AgentBridge watch will report '(no intent declared)' and\n flag all your changes as UNVERIFIED. The human loses all trust visibility.\n \u2022 1 session \u2192 that is your active tracked job. Use its work_session_id for everything below.\n \u2022 2+ sessions \u2192 DO NOT GUESS. The response sets selected_session_required=true. Ask the human which session to use, or call select_work_session to confirm.\n 3. Call generate_authority_packet(project_id, work_session_id) to receive the full tracked-job authority packet (WorkIdentity, ExecutionSurface, allowed/blocked domains, scope_snapshot, out_of_scope_snapshot, risk_level).\n 4. Pass work_session_id on EVERY controlled call: claim_lane, release_lane, post_handoff, close_work_session, check_close_readiness.\n 5. Respect `session_required_for_implementation=true` (a tracked job is required before this agent can edit files). If `active_sessions` is empty, do not perform implementation edits.\n\nAUTHORITY MODEL:\n \u2022 Cursor / Claude Code / etc. are ExecutionSurfaces. They are NOT the agent identity.\n \u2022 The accountable identity is the WorkIdentity (e.g. 'Auth Agent').\n \u2022 A WorkIdentity is granted only by an active tracked job (WorkSession record) bound to your AgentConnection.\n \u2022 You cannot self-declare authority. The server resolves your role from that WorkSession.\n\nIdentity packet shapes:\n \u2022 NEW (AgentConnection key): `work_identity` packet with WorkIdentity, ExecutionSurface, domain, capabilities, blocked_domains.\n \u2022 LEGACY (Agent API key): `verified` packet with role, capabilities, blocked_paths.\n\nRECOVERY MODE \u2014 when you're working on an existing unstructured codebase:\n \u2022 If the project's `project_mode` is 'recovery' and `recoveryStatus` is 'active' or 'stabilising',\n the response includes a `recovery_brief` block.\n \u2022 If you are NEW to this project (no prior completed sessions), `recovery_brief` includes:\n - `product_summary`: what the codebase does\n - `known_domains`: list of domain names with trap counts\n - `known_traps`: flat list of ALL traps across domains \u2014 READ BEFORE TOUCHING ANYTHING\n - `recommended_first_action`: what to do first\n - `warning`: 'This is a recovery project. Treat all domain boundaries as fragile.'\n \u2022 If you have prior sessions, `recovery_brief` is abbreviated with `recommended_first_action: 'continue_with_memory'`.\n \u2022 If `recoveryStatus === 'archived'`, the response signals `recovery_archived: true` \u2014 treat as a normal V1 project.\n \u2022 If `required_next_step` is `run_bootstrap` (or `recovery_status` is `baseline_required`), call `run_bootstrap` with `product_summary` and optional `domains` \u2014 same payload as POST /v1/dev/projects/:id/bootstrap.\n\nAUTOMATIC SETUP \u2014 do not wait for user instructions when any of these apply:\n \u2022 `rules_status === 'not_installed'` \u2192 call install_agentbridge_rules, write AGENTBRIDGE.md and .cursor/rules/agentbridge.mdc to the repo, call mark_rules_installed.\n \u2022 `project_mode === 'unclassified'` or `required_next_step === 'classify_project_mode'` \u2192 ask user new/recovery, call set_project_mode.\n \u2022 `required_next_step === 'recovery_baseline'` \u2192 ask user for summary + domains, call run_bootstrap.\n When setup is required, the instruction block includes an `auto_action` string \u2014 execute it immediately.\n\nSTARTUP FLOW \u2014 call in order on every new chat:\n 1. agent_hello \u2192 receive identity + check for setup conditions\n 2. get_project_packet \u2192 receive compact project context (product summary, domain counts, charter, risks)\n 3. resolve_work_context \u2192 structured next step from durable state (sessions, approvals, CRs, paths, LIP); NL classifier is last resort only\n 4. get_domain_packet \u2192 load detailed domain context for the resolved domain(s)\n 5. get_last_implementation_packet \u2192 durable post-close implementation memory\n 6. \u26A0 start_work_session \u2192 REQUIRED before ANY file edit. Declare intent + claimed_paths.\n This is NOT optional. Without it, agentbridge watch cannot verify\n your work and will report all changes as UNVERIFIED SCOPE UNKNOWN.\n intent = the user's goal in plain English (copy it verbatim if possible)\n claimed_paths = the files/dirs you plan to modify\n 7. generate_authority_packet \u2192 receive full execution authority\n 8. inspect + implement\n\nagent_hello does NOT return full product memory \u2014 call get_project_packet for startup context.\nPrefer resolve_work_context before classify_task_domain when the user's intent is vague or continuation-style.\nFor regressions after recent work, do not begin by summarising chat history. Load the Last Implementation Packet first (get_last_implementation_packet).",
21658
22196
  inputSchema: {
21659
- project_id: external_exports.string().min(1).describe("Project / handshake id (hnd_\u2026)"),
22197
+ project_id: external_exports.string().min(1).optional().describe(
22198
+ "Project / handshake id (hnd_\u2026). Optional when AGENTBRIDGE_PROJECT_ID env var is set \u2014 the server uses it automatically."
22199
+ ),
21660
22200
  tool_type: external_exports.enum([
21661
22201
  "cursor",
21662
22202
  "claude_code",
@@ -21678,11 +22218,50 @@ async function main() {
21678
22218
  ),
21679
22219
  work_session_id: external_exports.string().optional().describe(
21680
22220
  "Phase 5: if you have an active tracked job (ws_\u2026), pass it here. The response will include an active_session block with brief_summary and next_action hint. Follow up with generate_authority_packet to receive the full authority packet."
22221
+ ),
22222
+ intent: external_exports.string().max(500).optional().describe(
22223
+ "LOCAL MODE: declare the work contract before editing files (e.g. 'Fix auth 401 on /rooms endpoint'). Required when no active contract exists."
21681
22224
  )
21682
22225
  }
21683
22226
  },
21684
22227
  async (args) => {
21685
- const path = `/v1/dev/projects/${encodeURIComponent(args.project_id)}/hello`;
22228
+ if (cfg.localOnly) {
22229
+ const existing = readSessionState();
22230
+ if (isActiveLocalSession(existing)) {
22231
+ return toolJson({
22232
+ mode: "local",
22233
+ action: "reuse",
22234
+ contract: existing,
22235
+ message: "Reusing active local work contract."
22236
+ });
22237
+ }
22238
+ const declaredIntent = args.intent?.trim() || args.note?.trim();
22239
+ if (!declaredIntent || isVagueIntent(declaredIntent)) {
22240
+ return toolError(
22241
+ 'No active AgentBridge contract.\n\nDeclare what you are about to do before editing files:\n agent_hello({ intent: "Fix auth 401 on /rooms endpoint" })\n\nOr run in a terminal: agentbridge start "Fix auth 401 on /rooms endpoint"'
22242
+ );
22243
+ }
22244
+ const session = openLocalSession({
22245
+ agentId: "mcp",
22246
+ laneDomain: null,
22247
+ intent: declaredIntent,
22248
+ domains: [],
22249
+ mode: "local_supervision"
22250
+ });
22251
+ return toolJson({
22252
+ mode: "local",
22253
+ action: "created",
22254
+ contract: session,
22255
+ message: "Local work contract created."
22256
+ });
22257
+ }
22258
+ const resolvedProjectId = args.project_id ?? cfg.projectId;
22259
+ if (!resolvedProjectId) {
22260
+ return toolError(
22261
+ "project_id is required. Pass it as an argument or set AGENTBRIDGE_PROJECT_ID in the MCP server environment."
22262
+ );
22263
+ }
22264
+ const path = `/v1/dev/projects/${encodeURIComponent(resolvedProjectId)}/hello`;
21686
22265
  const body = {};
21687
22266
  if (args.tool_type !== void 0) body.tool_type = args.tool_type;
21688
22267
  if (args.capabilities_advert !== void 0)