@bridge_gpt/mcp-server 0.2.34 → 0.2.37

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 (109) hide show
  1. package/README.md +490 -366
  2. package/build/agent-capabilities/probe-context.js +8 -1
  3. package/build/agent-capabilities/probes.js +7 -1
  4. package/build/agents.generated.js +1 -1
  5. package/build/base-url.js +79 -0
  6. package/build/bridge-api-urls.js +9 -0
  7. package/build/chain-orchestrator.js +93 -15
  8. package/build/claude-review-workflow.js +264 -0
  9. package/build/claude-user-config-doctor.js +317 -0
  10. package/build/cli-release.js +53 -0
  11. package/build/commands.generated.js +6 -5
  12. package/build/conductor/bridge-api-client.js +393 -4
  13. package/build/conductor/deny-enforcement-preflight.js +1 -0
  14. package/build/conductor/done-gate.js +44 -5
  15. package/build/conductor/epic-reconcile.js +6 -0
  16. package/build/conductor/install-doctor.js +462 -0
  17. package/build/conductor-bin.js +3 -3
  18. package/build/conductor-bundle-artifacts.js +37 -15
  19. package/build/credential-store.js +205 -4
  20. package/build/direct-ticket-tools.js +70 -0
  21. package/build/doctor.js +473 -81
  22. package/build/executor/cli.js +83 -6
  23. package/build/executor/credentials.js +39 -11
  24. package/build/executor/deps.js +32 -1
  25. package/build/executor/env.js +71 -28
  26. package/build/executor/heartbeat.js +138 -17
  27. package/build/executor/http-client.js +49 -8
  28. package/build/executor/index.js +4 -0
  29. package/build/executor/job-errors.js +4 -0
  30. package/build/executor/job-runner.js +530 -20
  31. package/build/executor/observation.js +130 -0
  32. package/build/executor/permissions.js +114 -8
  33. package/build/executor/preflight.js +127 -8
  34. package/build/executor/prompt-spec.js +51 -0
  35. package/build/executor/runner.js +23 -2
  36. package/build/executor/service-unit.js +876 -0
  37. package/build/executor/test-clock.js +75 -3
  38. package/build/executor/types.js +4 -18
  39. package/build/executor/worker-command.js +73 -12
  40. package/build/executor/worker-config-isolation.js +287 -0
  41. package/build/executor/worker-finalization.js +68 -14
  42. package/build/executor/worktree.js +46 -4
  43. package/build/index.js +1039 -237
  44. package/build/init.js +503 -111
  45. package/build/install-bridge-conductor.js +491 -0
  46. package/build/install-bridge.js +1188 -247
  47. package/build/install-reexec.js +233 -0
  48. package/build/launcher-config-inspection.js +351 -0
  49. package/build/mcp-host-config.js +11 -1
  50. package/build/mcp-install-state.js +32 -0
  51. package/build/mcp-invoke.js +49 -6
  52. package/build/mcp-provisioning.js +52 -13
  53. package/build/mcp-registration-doctor.js +14 -5
  54. package/build/notifications.js +553 -0
  55. package/build/pipeline-orchestrator.js +146 -4
  56. package/build/pipeline-utils.js +3 -0
  57. package/build/pipelines.generated.js +32 -13
  58. package/build/plan-execution-ledger.js +550 -0
  59. package/build/plan-phase-routing.js +272 -0
  60. package/build/plane/alembic-head.js +110 -0
  61. package/build/plane/build-freshness.js +167 -0
  62. package/build/plane/cli.js +480 -0
  63. package/build/plane/defaults.js +266 -0
  64. package/build/plane/manifest.js +377 -0
  65. package/build/plane/member-logs.js +147 -0
  66. package/build/plane/member-roster.js +147 -0
  67. package/build/plane/preflight.js +289 -0
  68. package/build/plane/shutdown.js +195 -0
  69. package/build/plane/status.js +125 -0
  70. package/build/plane/supervisor.js +569 -0
  71. package/build/plane/test-fakes.js +156 -0
  72. package/build/plane/types.js +75 -0
  73. package/build/readme.generated.js +1 -1
  74. package/build/run-unit-tests-launcher.js +259 -0
  75. package/build/setup-epic.js +772 -28
  76. package/build/sfcc/log-gate.js +38 -11
  77. package/build/sfcc/log-query.js +55 -15
  78. package/build/sfcc/ocapi-shape.js +51 -14
  79. package/build/sfcc/output.js +41 -11
  80. package/build/sfcc/permissions.js +24 -2
  81. package/build/sfcc/read-projection.js +181 -0
  82. package/build/sfcc/read-result.js +158 -0
  83. package/build/sfcc/reads-custom-object-def.js +29 -18
  84. package/build/sfcc/reads-site-preference.js +75 -29
  85. package/build/sfcc/reads-system-object.js +40 -34
  86. package/build/sfcc/sfcc-result.js +106 -0
  87. package/build/sfcc/tool-wrapper.js +56 -13
  88. package/build/sfcc/write-grants.js +45 -22
  89. package/build/sfcc/write-guard.js +21 -13
  90. package/build/sfcc/write-result.js +61 -14
  91. package/build/sfcc/write-tool-common.js +126 -32
  92. package/build/sfcc/writes-system-object.js +11 -50
  93. package/build/start-tickets-prereqs.js +129 -0
  94. package/build/start-tickets.js +17 -13
  95. package/build/ticket-backend-metadata.js +59 -0
  96. package/build/ticket-key-utils.js +92 -0
  97. package/build/tool-error-envelope.js +71 -0
  98. package/build/tool-surface-gating.js +72 -0
  99. package/build/update-status.js +102 -0
  100. package/build/upgrade-advice.js +47 -0
  101. package/build/upgrade-cli.js +412 -110
  102. package/build/version.generated.js +1 -1
  103. package/build/worktree-core.js +73 -0
  104. package/docs/CONDUCTOR.md +132 -6
  105. package/docs/install/mcp-tool-integrations.md +29 -21
  106. package/package.json +9 -6
  107. package/pipelines/implement-ticket.json +19 -4
  108. package/build/conductor/supervisor-judgment-python.js +0 -141
  109. package/build/conductor/supervisor-judgment.js +0 -215
@@ -22,8 +22,20 @@
22
22
  * an existence-only check. The check instead compares the authoritative origin
23
23
  * branch tip SHA against the worker's own HEAD commit (`headSha`, from git
24
24
  * telemetry) whenever that comparison is available.
25
+ *
26
+ * BAPI-762: the authoritative origin-tip-vs-HEAD comparison runs regardless of
27
+ * whether the completion result carries a `pr_url`. The pipeline guarantees a PR
28
+ * URL for essentially every implement job, so a PR-presence short-circuit ABOVE
29
+ * this comparison could never catch an unpushed correction commit — a run could
30
+ * report `clean_exit`/`succeeded` with a PR open and a commit that never reached
31
+ * origin. When the origin tip exists but does not match the worker's own HEAD,
32
+ * that is positive proof of a DIFFERENT failure shape than "no evidence any work
33
+ * reached origin": `WorkerFinalizationSavedButUnfinalized` names it distinctly so
34
+ * the terminal-disposition classifier (`terminal_disposition.py`) can route it as
35
+ * a resumable, deterministic cause instead of laundering it into a generic crash
36
+ * that gets retried as a transient upstream failure.
25
37
  */
26
- import { secretFreeErrorMessage, WorkerFinalizationMissingRemoteBranchAndPr, WorkerFinalizationPrBaseMismatch, } from "./job-errors.js";
38
+ import { secretFreeErrorMessage, WorkerFinalizationMissingRemoteBranchAndPr, WorkerFinalizationPrBaseMismatch, WorkerFinalizationSavedButUnfinalized, } from "./job-errors.js";
27
39
  import { isImplementationStyleJobType } from "./job-types.js";
28
40
  /** Bounded settling re-check defaults for the authoritative origin-tip lookup. */
29
41
  const DEFAULT_ORIGIN_FINALIZATION_ATTEMPTS = 3;
@@ -171,18 +183,51 @@ function prBaseMismatchFailure(job, prNumber, expectedBase, actualBase) {
171
183
  classification: "crashed",
172
184
  };
173
185
  }
174
- function missingBranchAndPrFailure(job, detail) {
186
+ /**
187
+ * `detail` describes a state with NO evidence any work reached origin (branch
188
+ * unresolved, branch absent from origin, or the origin lookup itself failed).
189
+ * `hasPrUrl` only changes the wording — a PR existing is never treated as
190
+ * evidence of a push, so the message must not claim "no PR URL" when one was
191
+ * actually present (that would be false and would mislead the operator reading
192
+ * it toward the wrong recovery step).
193
+ */
194
+ function missingBranchAndPrFailure(job, detail, hasPrUrl) {
175
195
  const label = job.ticket_key ? `${job.ticket_key} (job ${job.id})` : `job ${job.id}`;
196
+ const prefix = hasPrUrl ? "opened a PR, but" : "produced no PR URL and";
176
197
  return {
177
198
  error_kind: WorkerFinalizationMissingRemoteBranchAndPr,
178
- error_message: `${label} exited cleanly but ${detail}`,
199
+ error_message: `${label} exited cleanly but ${prefix} ${detail}`,
200
+ classification: "crashed",
201
+ };
202
+ }
203
+ /**
204
+ * BAPI-762: the origin branch exists at an authoritative tip that does not match
205
+ * the worker's own HEAD — durable work exists on origin, but not this worker's
206
+ * latest commit. Unlike {@link missingBranchAndPrFailure}, this state has positive
207
+ * evidence of something recoverable, so the message names the branch and the
208
+ * origin SHA an operator can resume/finalize from rather than re-running. The
209
+ * human-facing text truncates SHAs to 12 characters (matching the codebase's
210
+ * existing convention); the full 40-character origin SHA is carried in the
211
+ * structured `last_commit_sha` field so nothing has to re-derive it from prose.
212
+ */
213
+ function savedButUnfinalizedFailure(job, branch, originSha, workerHeadSha) {
214
+ const label = job.ticket_key ? `${job.ticket_key} (job ${job.id})` : `job ${job.id}`;
215
+ return {
216
+ error_kind: WorkerFinalizationSavedButUnfinalized,
217
+ error_message: `${label} exited cleanly, but origin branch '${branch}' is at ${originSha.slice(0, 12)}, ` +
218
+ `which does not match this worker's HEAD ${workerHeadSha.slice(0, 12)} — the worker's latest ` +
219
+ `commit was not pushed. Work already on origin at this SHA is recoverable: resume/finalize ` +
220
+ `from '${branch}' instead of re-running from scratch.`,
179
221
  classification: "crashed",
222
+ last_commit_sha: originSha,
180
223
  };
181
224
  }
182
225
  /**
183
- * Validate that an implementation-style job's clean exit actually produced a PR
184
- * or a pushed origin branch. Non-implementation-style jobs (verdict jobs) and
185
- * any result carrying a non-empty `pr_url` bypass the git check entirely.
226
+ * Validate that an implementation-style job's clean exit actually published its
227
+ * work to origin. Non-implementation-style jobs (verdict jobs) bypass the git
228
+ * check entirely. A `pr_url` on the completion result is NOT proof of a push
229
+ * (BAPI-762) — the authoritative origin-tip-vs-HEAD comparison below always runs,
230
+ * so an unpushed local commit is detected whether or not a pull request exists.
186
231
  */
187
232
  export async function validateWorkerFinalization(input) {
188
233
  const { job, branch, worktreePath, result, runCommand, headSha } = input;
@@ -216,14 +261,15 @@ export async function validateWorkerFinalization(input) {
216
261
  }
217
262
  }
218
263
  }
219
- if (extractPrUrl(result)) {
220
- return { ok: true };
221
- }
264
+ const hasPrUrl = Boolean(extractPrUrl(result));
265
+ // BAPI-762: `branch`/`headSha` are normalized once here and reused through the
266
+ // rest of the check — including by the diagnostics below — instead of being
267
+ // re-derived at each failure site.
222
268
  const trimmedBranch = typeof branch === "string" ? branch.trim() : "";
223
269
  if (!trimmedBranch) {
224
270
  return {
225
271
  ok: false,
226
- failure: missingBranchAndPrFailure(job, "produced no PR URL and no expected branch to verify on origin"),
272
+ failure: missingBranchAndPrFailure(job, "no expected branch to verify on origin", hasPrUrl),
227
273
  };
228
274
  }
229
275
  // Recovery/resume jobs fetch `origin/<branch>` before the worker even starts,
@@ -233,7 +279,9 @@ export async function validateWorkerFinalization(input) {
233
279
  // fails loud instead of passing. When HEAD is unresolved (degraded telemetry),
234
280
  // fall back to the existence-only check rather than inventing a new failure
235
281
  // mode. The authoritative lookup is retried a few times so a push that settles
236
- // just after the worker exits still finalizes (BAPI-566 Bug A).
282
+ // just after the worker exits still finalizes (BAPI-566 Bug A). This lookup
283
+ // runs unconditionally — including when `hasPrUrl` is true (BAPI-762, AC-5): a
284
+ // PR being open is never accepted as proof this worker's own commit landed.
237
285
  const trimmedHeadSha = typeof headSha === "string" ? headSha.trim().toLowerCase() : "";
238
286
  const attempts = normalizeAttempts(input.originResolveAttempts);
239
287
  const retryDelayMs = normalizeRetryDelay(input.originResolveRetryDelayMs);
@@ -245,19 +293,25 @@ export async function validateWorkerFinalization(input) {
245
293
  catch (err) {
246
294
  return {
247
295
  ok: false,
248
- failure: missingBranchAndPrFailure(job, `produced no PR URL and branch '${trimmedBranch}' could not be verified on origin: ${secretFreeErrorMessage(err)}`),
296
+ failure: missingBranchAndPrFailure(job, `branch '${trimmedBranch}' could not be verified on origin: ${secretFreeErrorMessage(err)}`, hasPrUrl),
249
297
  };
250
298
  }
251
299
  if (remoteSha === null) {
252
300
  return {
253
301
  ok: false,
254
- failure: missingBranchAndPrFailure(job, `produced no PR URL and branch '${trimmedBranch}' is not on origin`),
302
+ failure: missingBranchAndPrFailure(job, `branch '${trimmedBranch}' is not on origin`, hasPrUrl),
255
303
  };
256
304
  }
305
+ // BAPI-762: an authoritative origin tip that does not match the worker's HEAD
306
+ // is positive evidence of RECOVERABLE work — distinct from the sub-cases above,
307
+ // which have no evidence any work reached origin at all. This is the only
308
+ // sub-case that produces `WorkerFinalizationSavedButUnfinalized`, and it fires
309
+ // identically whether or not a PR is open (AC-5) — the PR shortcut this ticket
310
+ // removes could otherwise conceal exactly this state.
257
311
  if (trimmedHeadSha && remoteSha !== trimmedHeadSha) {
258
312
  return {
259
313
  ok: false,
260
- failure: missingBranchAndPrFailure(job, `produced no PR URL and origin branch '${trimmedBranch}' is at ${remoteSha.slice(0, 12)}, which does not match this worker's HEAD ${trimmedHeadSha.slice(0, 12)} — the worker's commit was not pushed`),
314
+ failure: savedButUnfinalizedFailure(job, trimmedBranch, remoteSha, trimmedHeadSha),
261
315
  };
262
316
  }
263
317
  return { ok: true };
@@ -34,6 +34,10 @@ function toWorktreeCoreDeps(deps) {
34
34
  platform: deps.platform,
35
35
  env: deps.env,
36
36
  cwd: deps.cwd,
37
+ // BAPI-727: route path-only untracked-cleanup diagnostics to the executor's
38
+ // stderr logger. Shared `start-tickets` callers may keep omitting this — the
39
+ // primitive treats an absent callback as "do not report".
40
+ onCleanupDiagnostic: deps.errorLog,
37
41
  };
38
42
  }
39
43
  /** Build the command-provisioning boundary from the executor deps (BAPI-664). */
@@ -57,12 +61,35 @@ function toCommandProvisioningDeps(deps) {
57
61
  * preserved unchanged. Errors stay secret-free (no raw filesystem exception, Git
58
62
  * output, or command contents).
59
63
  */
60
- async function finalizeExecutorWorktree(worktreePath, branch, deps) {
64
+ async function finalizeExecutorWorktree(worktreePath, branch, expectedHeadSha, deps) {
61
65
  const provisioned = await provisionCommandsForWorktree(worktreePath, toCommandProvisioningDeps(deps));
62
66
  if (!provisioned.ok) {
63
67
  return { ok: false, error: provisioned.error };
64
68
  }
65
- return { ok: true, worktreePath, branch };
69
+ return { ok: true, worktreePath, branch, expectedHeadSha };
70
+ }
71
+ /** A full 40-character hex object name. */
72
+ const FULL_SHA_PATTERN = /^[0-9a-f]{40}$/i;
73
+ /**
74
+ * Resolve a ref to its immutable commit via `rev-parse <ref>^{commit}`.
75
+ *
76
+ * Returns `null` on any failure or malformed output. The caller turns that into
77
+ * a bounded worktree failure rather than inventing an expected SHA — a made-up
78
+ * expectation would make the pre-spawn assertion either vacuous or wrong.
79
+ */
80
+ async function resolveCommitSha(deps, worktreeCwd, ref) {
81
+ try {
82
+ const result = await deps.runCommand("git", ["rev-parse", `${ref}^{commit}`], {
83
+ cwd: worktreeCwd,
84
+ });
85
+ if (!commandSucceeded(result))
86
+ return null;
87
+ const sha = result.stdout.trim();
88
+ return FULL_SHA_PATTERN.test(sha) ? sha : null;
89
+ }
90
+ catch {
91
+ return null;
92
+ }
66
93
  }
67
94
  /**
68
95
  * Ensure the worktree for a job exists, delegating to the shared Worktrunk
@@ -115,13 +142,25 @@ export async function ensureExecutorWorktree(job, options, deps, policy = {}) {
115
142
  error: `git fetch origin ${branch} failed${reason ? `: ${reason}` : ""}`,
116
143
  };
117
144
  }
145
+ // BAPI-731: resolve the freshly fetched remote head to an immutable commit
146
+ // BEFORE creating the worktree, so the pre-spawn assertion has an
147
+ // authoritative expectation. Resolved here (right after the fetch) rather
148
+ // than after creation, so the expectation is independent of the worktree the
149
+ // assertion will later inspect.
150
+ const expectedHeadSha = await resolveCommitSha(deps, deps.cwd, originRef);
151
+ if (expectedHeadSha === null) {
152
+ return {
153
+ ok: false,
154
+ error: `failed to resolve '${originRef}' to a commit after fetching branch '${branch}'`,
155
+ };
156
+ }
118
157
  const row = await createWorktreeForTicket(toWorktreeCoreDeps(deps), key, { [key]: branch }, options.worktrunkBinary, baseStartPoint, guardStaleWorktree,
119
158
  // Hard-reset a reused existing local branch onto the freshly fetched
120
159
  // pushed head; a missing local branch is instead cut from `baseStartPoint`
121
160
  // (= `origin/<branch>`) inside the primitive, so both land at origin.
122
161
  { freshenFromOrigin: originRef });
123
162
  if (row.status === "created" && typeof row.path === "string") {
124
- return finalizeExecutorWorktree(row.path, branch, deps);
163
+ return finalizeExecutorWorktree(row.path, branch, expectedHeadSha, deps);
125
164
  }
126
165
  return { ok: false, error: row.error ?? `worktree creation failed for branch '${branch}'` };
127
166
  }
@@ -146,7 +185,10 @@ export async function ensureExecutorWorktree(job, options, deps, policy = {}) {
146
185
  const baseSha = resolvedBase.base_sha;
147
186
  const row = await createWorktreeForTicket(toWorktreeCoreDeps(deps), key, { [key]: branch }, options.worktrunkBinary, baseSha, guardStaleWorktree, { alignExistingBranchTo: baseSha, verifyHeadMatches: baseSha });
148
187
  if (row.status === "created" && typeof row.path === "string") {
149
- return finalizeExecutorWorktree(row.path, branch, deps);
188
+ // BAPI-731: `baseSha` is already the pinned immutable commit this fresh
189
+ // worktree was cut from and verified against (`verifyHeadMatches`), so it is
190
+ // the expectation — no extra resolution needed.
191
+ return finalizeExecutorWorktree(row.path, branch, baseSha, deps);
150
192
  }
151
193
  return { ok: false, error: row.error ?? `worktree creation failed for branch '${branch}'` };
152
194
  }