@bridge_gpt/mcp-server 0.2.62 → 0.2.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +66 -15
  2. package/build/agent-launchers/claude-executor-adapter.js +145 -20
  3. package/build/agent-launchers/executor-adapter.js +81 -2
  4. package/build/agents.generated.js +10 -1
  5. package/build/bounded-wait.js +32 -1
  6. package/build/bridge-config.js +104 -0
  7. package/build/codex-bridge-profile.js +10 -1
  8. package/build/commands.generated.js +7 -6
  9. package/build/conductor/bridge-api-client.js +565 -32
  10. package/build/conductor/bring-up-facts.js +3 -1
  11. package/build/conductor/doctor.js +23 -14
  12. package/build/conductor/epic-child-continuation.js +351 -0
  13. package/build/conductor/epic-implementer-cli.js +154 -17
  14. package/build/conductor/git-hooks.js +529 -118
  15. package/build/conductor/guided-repair.js +323 -0
  16. package/build/conductor/hook-runtime-qualification.js +340 -0
  17. package/build/conductor/readiness-cli.js +30 -9
  18. package/build/conductor/readiness-sections.js +5 -4
  19. package/build/conductor/readiness.js +45 -12
  20. package/build/conductor/recovery-cli.js +859 -27
  21. package/build/conductor/recovery-operations.js +574 -5
  22. package/build/conductor/repair-contract.js +69 -3
  23. package/build/conductor-bundle-artifacts.js +1 -0
  24. package/build/credential-store.js +52 -13
  25. package/build/diagnostic-text.js +36 -0
  26. package/build/docs.generated.js +3 -2
  27. package/build/doctor.js +147 -21
  28. package/build/drive-epic-key.js +12 -0
  29. package/build/drive-epic.js +1537 -125
  30. package/build/epic-coherence-input-cli.js +137 -0
  31. package/build/epic-coherence-input.js +920 -0
  32. package/build/epic-coherence-input.test-fixtures.js +175 -0
  33. package/build/epic-implementer-bin.js +41 -33
  34. package/build/epic-implementer-bundle-cli.js +14 -1
  35. package/build/epic-launch-diagnostic.js +31 -0
  36. package/build/epic-launch-profile.js +58 -19
  37. package/build/epic-run-status.js +5 -0
  38. package/build/epic-shared/bridge-client.js +46 -4
  39. package/build/executor/cli.js +39 -0
  40. package/build/executor/completion-contract.js +423 -0
  41. package/build/executor/completion-supervision.js +291 -0
  42. package/build/executor/correction-dispatch.js +60 -0
  43. package/build/executor/credentials.js +3 -1
  44. package/build/executor/deps.js +65 -1
  45. package/build/executor/env.js +12 -0
  46. package/build/executor/heartbeat.js +13 -3
  47. package/build/executor/http-client.js +91 -4
  48. package/build/executor/integration-job.js +6 -1
  49. package/build/executor/job-errors.js +61 -4
  50. package/build/executor/job-log-registry.js +340 -73
  51. package/build/executor/job-runner.js +1550 -55
  52. package/build/executor/job-types.js +9 -6
  53. package/build/executor/preflight.js +189 -1
  54. package/build/executor/process-containment.js +756 -0
  55. package/build/executor/process.js +235 -5
  56. package/build/executor/prompt-spec.js +366 -1
  57. package/build/executor/provider-checks.js +69 -0
  58. package/build/executor/rebase-finalization.js +351 -0
  59. package/build/executor/reconcile-overlap-job.js +77 -84
  60. package/build/executor/required-verification.js +313 -0
  61. package/build/executor/required-work-ledger.js +1121 -0
  62. package/build/executor/results.js +142 -0
  63. package/build/executor/resume-pre-spawn.js +87 -4
  64. package/build/executor/runner.js +168 -0
  65. package/build/executor/stale-artifacts.js +5 -4
  66. package/build/executor/test-declaration.js +20 -0
  67. package/build/executor/types.js +13 -0
  68. package/build/executor/watch-cli.js +35 -8
  69. package/build/executor/worker-command.js +70 -34
  70. package/build/executor/worker-finalization.js +168 -26
  71. package/build/executor/worker-guard-hook.js +75 -14
  72. package/build/executor/worker-log.js +137 -70
  73. package/build/executor/worktree-gc.js +30 -6
  74. package/build/executor/worktree.js +13 -0
  75. package/build/executor-launch.js +658 -0
  76. package/build/index.js +594 -1152
  77. package/build/init.js +107 -4
  78. package/build/install-bridge-conductor.js +231 -41
  79. package/build/install-bridge.js +284 -20
  80. package/build/install-doctor.js +172 -30
  81. package/build/install-reexec.js +69 -7
  82. package/build/macos-terminal-permission-guidance.js +16 -0
  83. package/build/merge-pull-request.js +1 -1
  84. package/build/model-thresholds-tool.js +185 -0
  85. package/build/pipelines.generated.js +9 -8
  86. package/build/plan-discovery.js +137 -0
  87. package/build/plan-epic-implementer-eligibility.js +2 -2
  88. package/build/plane/cli.js +37 -3
  89. package/build/plane/member-logs.js +3 -0
  90. package/build/plane/member-roster.js +7 -1
  91. package/build/plane/shutdown.js +59 -1
  92. package/build/plane/status.js +4 -0
  93. package/build/plane/supervisor.js +146 -0
  94. package/build/plane/worker-exit-code.js +2 -0
  95. package/build/project-root.js +99 -0
  96. package/build/readme.generated.js +1 -1
  97. package/build/review-tickets.js +156 -13
  98. package/build/scripts/executor-protocol-contract-driver.js +13 -3
  99. package/build/setup-epic.js +208 -125
  100. package/build/sfcc/setup-status.js +2 -0
  101. package/build/sfcc/tool-wrapper.js +2 -0
  102. package/build/sfcc/tools-configured.js +96 -0
  103. package/build/start-tickets.js +163 -58
  104. package/build/upgrade-cli.js +109 -24
  105. package/build/version.generated.js +3 -3
  106. package/build/windows-npm-entry.js +103 -0
  107. package/build/worker-guard-hook-bin.js +5 -4
  108. package/build/worktree-core.js +6 -5
  109. package/docs/CONDUCTOR.md +116 -2
  110. package/docs/install/mcp-tool-integrations.md +1 -0
  111. package/docs/install/sfcc-integration.md +12 -7
  112. package/package.json +2 -1
  113. package/pipelines/implement-ticket.json +1 -1
@@ -22,17 +22,60 @@ function isCapacityEvidenceRefusal(status, bodyText) {
22
22
  return true;
23
23
  if (status !== 409)
24
24
  return false;
25
+ return readDetailErrorCode(bodyText) === UNSUPPORTED_TERMINAL_CAPACITY_ERROR_CODE;
26
+ }
27
+ /**
28
+ * BAPI-1301 (D4a) — the server's stable `error_code` when a covered `/complete`
29
+ * carries an envelope that does not prove the attempt finished its required
30
+ * work. The job is still claimed; the executor must report `/fail` (with the
31
+ * same envelope) instead.
32
+ */
33
+ export const COMPLETION_EVIDENCE_REFUSES_SUCCESS_ERROR_CODE = "COMPLETION_EVIDENCE_REFUSES_SUCCESS";
34
+ /**
35
+ * Read the stable `detail.error_code` token from an error body, or null. Only
36
+ * that one closed token is inspected; nothing else in the body is retained.
37
+ */
38
+ function readDetailErrorCode(bodyText) {
25
39
  try {
26
40
  const parsed = JSON.parse(bodyText);
27
41
  const detail = parsed && typeof parsed === "object" ? parsed.detail : undefined;
28
- return (!!detail &&
29
- typeof detail === "object" &&
30
- detail.error_code === UNSUPPORTED_TERMINAL_CAPACITY_ERROR_CODE);
42
+ if (!detail || typeof detail !== "object")
43
+ return null;
44
+ const code = detail.error_code;
45
+ return typeof code === "string" ? code : null;
31
46
  }
32
47
  catch {
33
- return false;
48
+ return null;
34
49
  }
35
50
  }
51
+ /**
52
+ * BAPI-1301 (D4a) — whether a `/complete` response refused SUCCESS for a covered
53
+ * job because its completion evidence cannot support it: a 409 whose
54
+ * `error_code` is exactly {@link COMPLETION_EVIDENCE_REFUSES_SUCCESS_ERROR_CODE}.
55
+ *
56
+ * Mirrors {@link isCapacityEvidenceRefusal}'s shape, but is exported and NOT
57
+ * wired into `mapMutationResponse`: the mutation mapping stays unchanged (a 409
58
+ * still maps to `stale_claim` for every caller that does not ask), and the job
59
+ * runner — which holds the envelope — decides to re-report as `/fail`. A 409
60
+ * `STALE_CLAIM` is never a refusal: the claim is gone and a re-send cannot help.
61
+ */
62
+ export function isCompletionEvidenceRefusal(status, bodyText) {
63
+ if (status !== 409)
64
+ return false;
65
+ return readDetailErrorCode(bodyText) === COMPLETION_EVIDENCE_REFUSES_SUCCESS_ERROR_CODE;
66
+ }
67
+ /**
68
+ * BAPI-1301 (D4a) — normalize a claim response's `required_capabilities`. Only an
69
+ * array of strings is admitted; anything else (absent on an older server, null,
70
+ * malformed) reads as `[]` — "no requirement", which is exactly what an older
71
+ * server's rows mean. A malformed value can never manufacture a requirement the
72
+ * executor would then refuse to run.
73
+ */
74
+ export function normalizeRequiredCapabilities(value) {
75
+ if (!Array.isArray(value))
76
+ return [];
77
+ return value.every((entry) => typeof entry === "string") ? [...value] : [];
78
+ }
36
79
  /** Bound a server-provided diagnostic snippet included in error strings. */
37
80
  function boundedDetail(text) {
38
81
  const trimmed = (text ?? "").trim();
@@ -142,6 +185,22 @@ function toConductorGetFetch(fetchLike) {
142
185
  };
143
186
  };
144
187
  }
188
+ /**
189
+ * BAPI-1301 (D4a) — the completion-contract fields of a terminal report, each
190
+ * present only when set. Omitting an undefined key (rather than sending it as
191
+ * `undefined`/`null`) keeps a legacy terminal body byte-identical, which an
192
+ * older server's strict `extra="forbid"` schema depends on.
193
+ */
194
+ function completionContractFields(report) {
195
+ return {
196
+ ...(report.completion_contract !== undefined
197
+ ? { completion_contract: report.completion_contract }
198
+ : {}),
199
+ ...(report.completion_evidence !== undefined
200
+ ? { completion_evidence: report.completion_evidence }
201
+ : {}),
202
+ };
203
+ }
145
204
  export function createExecutorHttpClient(config) {
146
205
  const base = config.baseUrl.replace(/\/+$/, "") + "/executor/jobs";
147
206
  function keyForRepo(repoName) {
@@ -206,6 +265,12 @@ export function createExecutorHttpClient(config) {
206
265
  if (!job || typeof job !== "object" || typeof job.claim_token !== "string") {
207
266
  return { kind: "fatal", error: "claim returned a malformed job payload" };
208
267
  }
268
+ // BAPI-1301 (D4a): the requirement is normalized in place only when
269
+ // the server sent the key, so an older server's claim keeps its exact
270
+ // shape; a present-but-malformed value reads as "no requirement".
271
+ if ("required_capabilities" in job) {
272
+ job.required_capabilities = normalizeRequiredCapabilities(job.required_capabilities);
273
+ }
209
274
  return { kind: "claimed", job, reconcilerLiveness };
210
275
  }
211
276
  catch {
@@ -229,6 +294,18 @@ export function createExecutorHttpClient(config) {
229
294
  // 5xx and any other unexpected status are retryable.
230
295
  return { kind: "retryable", error: `claim failed (HTTP ${status}): ${boundedDetail(text)}` };
231
296
  },
297
+ async scopeReadiness(job) {
298
+ const { status, text } = await post(`/${job.id}/scope-readiness`, { repo_name: job.repo_name, claim_token: job.claim_token }, job.repo_name);
299
+ if (status !== 200)
300
+ throw new Error(`scope readiness HTTP ${status}`);
301
+ const parsed = JSON.parse(text);
302
+ if (!parsed || typeof parsed !== "object" ||
303
+ !("decision" in parsed) ||
304
+ !["ready", "waiting", "blocked"].includes(String(parsed.decision))) {
305
+ throw new Error("scope readiness response malformed");
306
+ }
307
+ return parsed;
308
+ },
232
309
  // Heartbeat does NOT go through `mutate()`: it is the one mutation whose
233
310
  // response BODY carries information beyond the outcome (the BAPI-731 stop
234
311
  // request), so it maps the response itself instead of discarding the body.
@@ -242,6 +319,11 @@ export function createExecutorHttpClient(config) {
242
319
  local_commit_count: payload.local_commit_count,
243
320
  last_commit_sha: payload.last_commit_sha,
244
321
  telemetry: payload.telemetry,
322
+ // BAPI-1301 (D4a): the key is added only when present, so a legacy
323
+ // heartbeat body is byte-identical for an older server.
324
+ ...(payload.ownership_context !== undefined
325
+ ? { ownership_context: payload.ownership_context }
326
+ : {}),
245
327
  };
246
328
  const res = await post(`/${job.id}/heartbeat`, body, job.repo_name);
247
329
  status = res.status;
@@ -290,6 +372,7 @@ export function createExecutorHttpClient(config) {
290
372
  local_commit_count: completion.local_commit_count,
291
373
  last_commit_sha: completion.last_commit_sha,
292
374
  telemetry: completion.telemetry,
375
+ ...completionContractFields(completion),
293
376
  };
294
377
  return mutate(`/${job.id}/complete`, body, true, job.repo_name);
295
378
  },
@@ -300,9 +383,13 @@ export function createExecutorHttpClient(config) {
300
383
  error_kind: failure.error_kind,
301
384
  error_message: failure.error_message,
302
385
  classification: failure.classification,
386
+ // BAPI-1330: the observed process exit, only when the runner has one —
387
+ // a failure without it keeps its exact pre-BAPI-1330 body.
388
+ ...(failure.exit_code !== undefined ? { exit_code: failure.exit_code } : {}),
303
389
  local_commit_count: failure.local_commit_count,
304
390
  last_commit_sha: failure.last_commit_sha,
305
391
  telemetry: failure.telemetry,
392
+ ...completionContractFields(failure),
306
393
  };
307
394
  if (failure.capacity_evidence === undefined) {
308
395
  return mutate(`/${job.id}/fail`, body, false, job.repo_name);
@@ -703,13 +703,18 @@ export function buildIntegrationCorrectionJob(action, timeoutSeconds) {
703
703
  job_type: "rebase",
704
704
  ticket_key: action.epic_key,
705
705
  epic_run_id: action.epic_run_id,
706
- payload: { prompt: action.correction_prompt ?? "", base_branch: action.base_branch },
706
+ payload: {
707
+ prompt: action.correction_prompt ?? "", base_branch: action.base_branch,
708
+ correction_intent: action.correction_intent ?? null,
709
+ integration_action_id: action.action_id,
710
+ },
707
711
  expected_branch: action.epic_branch,
708
712
  expected_head_sha: action.expected_epic_head_sha,
709
713
  lease_expires_at: action.lease_expires_at,
710
714
  attempt_count: 1,
711
715
  max_attempts: 1,
712
716
  timeout_seconds: timeoutSeconds,
717
+ required_capabilities: ["correction_intent.v1"],
713
718
  };
714
719
  }
715
720
  /**
@@ -13,6 +13,10 @@
13
13
  * never pushed, so there is nothing to recreate from (TDD §7).
14
14
  * - `BranchMismatch` — a `resume` worktree is on the wrong branch; working there
15
15
  * would corrupt an unrelated branch, so abort rather than proceed (TDD §7).
16
+ * - `ContinuationWorktreeMissing` / `ContinuationLineageMismatch` — a parked-child
17
+ * continuation (BAPI-1300) could not prove its retained work: the worktree is
18
+ * gone, or its HEAD does not descend from the authorized head. Refused before
19
+ * any local mutation; never recreated, reset, or cleaned.
16
20
  * - `WorkerFinalizationMissingRemoteBranchAndPr` — an implementation-style job
17
21
  * (BAPI-551) exited cleanly but produced neither a PR URL nor a pushed origin
18
22
  * branch, stranding the implement gate; see `worker-finalization.ts`.
@@ -24,10 +28,11 @@
24
28
  * exited cleanly and its exact HEAD is durable on origin, but no usable pull
25
29
  * request exists for that branch: none is visible, its URL is blank, its
26
30
  * description is blank (BAPI-824 folded in), or it does not yet carry the
27
- * pushed head. The work is COMPLETE and PUSHED — only the attachment is
28
- * missing — so this kind is deliberately distinct from every other
29
- * finalization failure, and its guidance names attachment and warns against
30
- * deleting or rebasing the branch; see `worker-finalization.ts`.
31
+ * pushed head. The commits are PUSHED and the attachment is missing; whether
32
+ * the required work is finished or its checks passed is NOT established by
33
+ * this kind (BAPI-1330). It stays distinct from every other finalization
34
+ * failure, and its guidance names attachment and warns against deleting or
35
+ * rebasing the branch; see `worker-finalization.ts`.
31
36
  * - `WorkerFinalizationSavedButUnfinalized` — an implementation-style job
32
37
  * (BAPI-762) exited cleanly, and an origin branch exists at an authoritative
33
38
  * tip that does NOT match the worker's own HEAD — durable work exists on
@@ -112,10 +117,30 @@ import { normalizeMcpServerNames } from "./observation.js";
112
117
  export const MissingVerdictArtifact = "MissingVerdictArtifact";
113
118
  export const WorktreeLostBeforePush = "WorktreeLostBeforePush";
114
119
  export const BranchMismatch = "BranchMismatch";
120
+ /**
121
+ * BAPI-1300: a parked-child CONTINUATION found no retained worktree for its
122
+ * branch. A continuation never recreates one from origin — that would silently
123
+ * drop unpushed work the continuation exists to carry — so it refuses instead.
124
+ */
125
+ export const ContinuationWorktreeMissing = "ContinuationWorktreeMissing";
126
+ /**
127
+ * BAPI-1300: the retained worktree's HEAD does not descend from the head the
128
+ * continuation was authorized against. Checked BEFORE the WIP checkpoint, so an
129
+ * unrelated history is never committed onto and never adopted as the new head.
130
+ */
131
+ export const ContinuationLineageMismatch = "ContinuationLineageMismatch";
115
132
  export const WorkerFinalizationMissingRemoteBranchAndPr = "WorkerFinalizationMissingRemoteBranchAndPr";
116
133
  export const WorkerFinalizationPrBaseMismatch = "WorkerFinalizationPrBaseMismatch";
117
134
  export const WorkerFinalizationPrNotAttached = "WorkerFinalizationPrNotAttached";
118
135
  export const WorkerFinalizationSavedButUnfinalized = "WorkerFinalizationSavedButUnfinalized";
136
+ /**
137
+ * BAPI-1330: a COVERED attempt's publication could not be proven — the worker's
138
+ * full HEAD was unknown, or the pull request reported no head commit. Distinct
139
+ * from `WorkerFinalizationPrNotAttached` because nothing here was observed to be
140
+ * missing: the facts needed to decide were unavailable, so the finalization
141
+ * verdict is `unknown`, never `unmet` and never `ok`.
142
+ */
143
+ export const WorkerFinalizationPublicationUnverified = "WorkerFinalizationPublicationUnverified";
119
144
  export const WorkerConfigIsolation = "ContractError.WorkerConfigIsolation";
120
145
  export const PreSpawnVerification = "ContractError.PreSpawnVerification";
121
146
  export const BridgeCredentialUnavailable = "ContractError.BridgeCredentialUnavailable";
@@ -139,6 +164,38 @@ export const StaleArtifactCleanupFailed = "ContractError.StaleArtifactCleanupFai
139
164
  * than proceeding on an unverified premise.
140
165
  */
141
166
  export const WorkerEnvFilePresent = "ContractError.WorkerEnvFilePresent";
167
+ /**
168
+ * BAPI-1296: a `ci_fix` job could not be run as a FOCUSED repair. Raised before
169
+ * any worktree effect when the payload's focused contract is missing, malformed,
170
+ * or carries an explicit prompt (a legacy full-recipe prompt included), and under
171
+ * the worktree lock when the prepared checkout's repository, branch, or HEAD does
172
+ * not match the dispatched CI observation. The message carries a fixed
173
+ * `reason=<code>` token and never ticket, check, or log text. The job is refused
174
+ * rather than downgraded to `/implement-ticket`: re-running the whole recipe to
175
+ * fix one check is the cost this contract removes.
176
+ */
177
+ export const CiFixContext = "ContractError.CiFixContext";
178
+ /**
179
+ * BAPI-1311: a `rebase` job carrying a `payload.focused_rebase` context could not
180
+ * be run as a FOCUSED merge-stage repair — an unsupported context version, a
181
+ * malformed or missing field, a blank server prompt, an identity that does not
182
+ * match the claimed job, or a claim that lacks the focused capability. Raised
183
+ * before any worktree effect. The message carries a fixed `reason=<code>` token
184
+ * and never prompt, ticket, or payload text. The job is refused rather than
185
+ * reinterpreted as a legacy rebase or downgraded to `/implement-ticket`.
186
+ */
187
+ export const FocusedRebaseContext = "ContractError.FocusedRebaseContext";
188
+ /**
189
+ * BAPI-1311: a focused rebase pushed its repair but the post-push wait PROVED it
190
+ * cannot succeed — a required check concluded red at the pushed head, the pull
191
+ * request closed or reads unmergeable, or the bound pull request / head / head
192
+ * branch / base changed. The SAME kind the server records when its completion
193
+ * verifier rejects a rebase (`REBASE_CONTRACT_ERROR_KIND` in
194
+ * `api/library/epic_implementer/rebase_completion_contract.py`), so an executor-
195
+ * observed and a server-observed contract miss read as one state. Unavailable
196
+ * evidence at the deadline is NOT this kind; it is the ordinary `Timeout`.
197
+ */
198
+ export const RebaseNotVerified = "ContractError.RebaseNotVerified";
142
199
  /**
143
200
  * BAPI-1152 — `reconcile_overlap` failure kinds. Each names ONE way the
144
201
  * wrapper's merge-into-child could not reach a verified push, so an operator