@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
@@ -4,8 +4,8 @@
4
4
  * Single source of truth for which claimed job types the executor spawns and
5
5
  * which of those are RECOVERY jobs. Recovery jobs (`remediate`/`ci_fix`/`rebase`/
6
6
  * `reconcile_overlap`) resume the ticket's existing branch/PR rather than cutting
7
- * a fresh branch off base — the first three through the `/implement-ticket <KEY>
8
- * --auto` correction loop, `reconcile_overlap` through its own job body. Dispatch
7
+ * a fresh branch off base. Each recovery worker requires a versioned focused
8
+ * correction intent; `ci_fix` also uses its focused prompt spec. Dispatch
9
9
  * (`job-runner.ts` `runClaimedJob`), prompt synthesis (`worker-command.ts`
10
10
  * `resolveExecutorPrompt`), and worktree reuse (`job-runner.ts` `prepareSpawn` →
11
11
  * `worktree.ts` `ensureExecutorWorktree`) all read from here so the recovery /
@@ -22,10 +22,13 @@
22
22
  * `reconcile_overlap`). They work on the ticket's EXISTING branch/PR, so the
23
23
  * executor reuses that branch instead of cutting a fresh one off base.
24
24
  *
25
- * BAPI-1152: `reconcile_overlap` is a recovery job for worktree reuse and prompt
26
- * resolution, but it does NOT re-enter `/implement-ticket`: it always carries an
27
- * explicit server-rendered `payload.prompt`, which wins over the synthesis in
28
- * `worker-command.ts`, and `job-runner.ts` dispatches it to its own body.
25
+ * `ci_fix` stays a recovery job for branch reuse, the worktree lock, and
26
+ * finalization. `job-runner.ts` renders its server-authored focused prompt spec
27
+ * after the correction intent is validated.
28
+ *
29
+ * `reconcile_overlap` is a recovery job for worktree reuse and prompt
30
+ * resolution. Its server-rendered focused prompt is available only after
31
+ * validating the correction intent, and `job-runner.ts` dispatches its body.
29
32
  *
30
33
  * BAPI-1160: `ci_rerun` is DELIBERATELY ABSENT from this set and from
31
34
  * `SPAWN_JOB_TYPES` below. It is a deterministic actuator — one bounded
@@ -1,8 +1,17 @@
1
1
  import { DEFAULT_PROBE_TIMEOUT_MS } from "../agent-capabilities/types.js";
2
2
  import { inspectExecutorAgentAdapter, inspectionForFailedResolution, } from "../agent-launchers/executor-adapter-inspection.js";
3
3
  import { resolveExecutorAgentAdapter } from "../agent-launchers/executor-adapter-registry.js";
4
+ import { resolveCompletionEvidenceCapability } from "../agent-launchers/executor-adapter.js";
5
+ import { COMPLETION_EVIDENCE_CAPABILITY, REQUIRED_VERIFICATION_CAPABILITY, runtimeMatchesSupported, } from "./completion-contract.js";
4
6
  import { resolveExecutorAgentId } from "./agent-identity.js";
7
+ import { mkdtemp, rm } from "node:fs/promises";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { spawnSync } from "node:child_process";
11
+ import { defaultResolveBinPath } from "../start-tickets-conductor.js";
12
+ import { CORRECTION_INTENT_CAPABILITY } from "./correction-dispatch.js";
5
13
  import { resolveAllExecutorApiAccess, resolveBaseUrl, EXECUTOR_BASE_URL_REQUIRED_MESSAGE, } from "./credentials.js";
14
+ import { FOCUSED_REBASE_CAPABILITY, SCOPE_WAIT_CAPABILITY } from "./types.js";
6
15
  /**
7
16
  * Environment override for the deny probe's headless timeout (BAPI-722).
8
17
  *
@@ -80,6 +89,63 @@ export function createDenyProbeCache() {
80
89
  },
81
90
  };
82
91
  }
92
+ /** Bound on a completion-evidence refusal reason (it is logged every cycle). */
93
+ const COMPLETION_REFUSAL_MAX_CHARS = 200;
94
+ /**
95
+ * BAPI-1301 (D4a) — decide whether this executor may advertise
96
+ * `completion_evidence.v1`.
97
+ *
98
+ * Probes the installed runtime through the adapter's declared probe and compares
99
+ * it with BOTH the adapter's declared identity and the approved identity the
100
+ * executor's lifecycle parser was measured against. Every mismatched field is
101
+ * named in the bounded reason; values are safe by construction (a parsed version
102
+ * or the `unrecognized` placeholder, closed platform ids, fixed schema names).
103
+ * Never throws and never produces a fatal finding.
104
+ */
105
+ export async function evaluateCompletionEvidenceQualification(adapter, deps) {
106
+ const bounded = (text) => text.slice(0, COMPLETION_REFUSAL_MAX_CHARS);
107
+ const capability = resolveCompletionEvidenceCapability(adapter);
108
+ if (!capability.supported) {
109
+ return { qualified: false, refusal: bounded(capability.reason), runtime: null };
110
+ }
111
+ let probed;
112
+ try {
113
+ probed = await capability.value.probeRuntime({
114
+ runCommand: deps.runCommand,
115
+ platform: deps.platform,
116
+ // Absent → the adapter's default (`process.arch`); injectable for tests.
117
+ ...(deps.arch !== undefined ? { arch: deps.arch } : {}),
118
+ });
119
+ }
120
+ catch {
121
+ probed = null;
122
+ }
123
+ if (probed === null) {
124
+ return { qualified: false, refusal: "runtime identity probe did not run", runtime: null };
125
+ }
126
+ const declared = capability.value.runtime;
127
+ const mismatches = [];
128
+ for (const key of ["adapter", "cli_version", "platform", "event_schema"]) {
129
+ if (probed[key] !== declared[key]) {
130
+ mismatches.push(`${key} ${String(probed[key]).slice(0, 40)} != ${declared[key]}`);
131
+ }
132
+ }
133
+ if (mismatches.length > 0) {
134
+ return {
135
+ qualified: false,
136
+ refusal: bounded(`probed runtime differs from the approved identity: ${mismatches.join("; ")}`),
137
+ runtime: probed,
138
+ };
139
+ }
140
+ if (!runtimeMatchesSupported(probed)) {
141
+ return {
142
+ qualified: false,
143
+ refusal: "adapter-declared runtime is not the approved completion-evidence runtime",
144
+ runtime: probed,
145
+ };
146
+ }
147
+ return { qualified: true, refusal: null, runtime: probed };
148
+ }
83
149
  /** Fail-fast report shape for a preflight that refused before probing. */
84
150
  function refusedPreflight(fatalFindings, warnings, adapter) {
85
151
  return {
@@ -94,6 +160,62 @@ function refusedPreflight(fatalFindings, warnings, adapter) {
94
160
  adapter,
95
161
  };
96
162
  }
163
+ const CORRECTION_HOOK_FIXTURE_ID = "correction-entry-nested-v1";
164
+ /** Exercise the packaged hook process, including a nested-agent entry attempt. */
165
+ export function probeInstalledCorrectionHook(worktreePath, binPath = defaultResolveBinPath("worker-guard-hook-bin.js")) {
166
+ const args = [binPath, "--worktree-root", worktreePath,
167
+ "--correction-intent-version", "1"];
168
+ const env = { ...process.env, BAPI_CORRECTION_INTENT_VERSION: "1" };
169
+ const fixtures = [
170
+ { payload: { tool_name: "Skill", tool_input: { skill: "bridge-implement-ticket" } }, status: 2 },
171
+ { payload: { tool_name: "Task", tool_input: { prompt: "/implement-ticket BAPI-1 --auto" } }, status: 2 },
172
+ { payload: { tool_name: "Read", tool_input: { file_path: "commands/src/implement-ticket.md" } }, status: 2 },
173
+ { payload: { tool_name: "mcp__bridge_api__request_plan_generation", tool_input: {} }, status: 2 },
174
+ { payload: { tool_name: "mcp__bridge_api__get_plan", tool_input: { ticket_number: "BAPI-1" } }, status: 0 },
175
+ ];
176
+ return fixtures.every(({ payload, status }) => {
177
+ const result = spawnSync(process.execPath, args, {
178
+ input: JSON.stringify(payload), encoding: "utf8", env, timeout: 5000,
179
+ });
180
+ return result.error === undefined && result.status === status;
181
+ });
182
+ }
183
+ export async function qualifyCorrectionIntentRuntime(adapter, deps, probeHook = probeInstalledCorrectionHook) {
184
+ if (adapter.identity.strategyId !== "claude-strict-mcp-v1" ||
185
+ adapter.denyEnforcement?.supported !== true || !deps.writeFile || !deps.mkdir) {
186
+ return { qualified: false, evidence: null };
187
+ }
188
+ const worktree = await (deps.mkdtemp ?? mkdtemp)(join((deps.tmpdir ?? tmpdir)(), "bridge-correction-hook-"));
189
+ try {
190
+ const bin = defaultResolveBinPath("worker-guard-hook-bin.js");
191
+ const installed = await adapter.denyEnforcement.value.provisionWorktreeDenyLayer({
192
+ worktreePath: worktree, baseBranch: "main", homedir: deps.homedir(),
193
+ workerBranch: "feature/probe", workerGuardHookBinPath: bin,
194
+ correctionIntentVersion: 1,
195
+ });
196
+ const settings = await deps.readFile(join(worktree, ".claude", "settings.local.json"));
197
+ const hookInstalled = installed.ok && settings.includes(bin) &&
198
+ settings.includes("--correction-intent-version 1") && settings.includes("PreToolUse");
199
+ const nestedDenial = hookInstalled && probeHook(worktree, bin);
200
+ return {
201
+ qualified: hookInstalled && nestedDenial,
202
+ evidence: {
203
+ version: 1, hook_installed: hookInstalled, nested_denial: nestedDenial,
204
+ fixture_id: CORRECTION_HOOK_FIXTURE_ID,
205
+ runtime: `${adapter.identity.adapterId}:${process.version}`,
206
+ },
207
+ };
208
+ }
209
+ catch {
210
+ return { qualified: false, evidence: null };
211
+ }
212
+ finally {
213
+ if (deps.rmRecursive)
214
+ await deps.rmRecursive(worktree);
215
+ else
216
+ await rm(worktree, { recursive: true, force: true });
217
+ }
218
+ }
97
219
  /**
98
220
  * Collect the executor preflight report. Populates the manifest fields and
99
221
  * accumulates fatal findings — the runner refuses to claim when any exist.
@@ -116,7 +238,15 @@ export async function collectExecutorPreflight(options, deps, seams = {}) {
116
238
  // preflight's own injected `readFile` keeps the inspection hermetic in
117
239
  // tests and read-only in production — the adapter never opens a file
118
240
  // handle this module did not hand it.
119
- claude: { readFile: deps.readFile },
241
+ claude: {
242
+ readFile: deps.readFile,
243
+ ...(deps.writeFile && deps.mkdir ? {
244
+ denyProvisioningDeps: {
245
+ readFile: deps.readFile, writeFile: deps.writeFile,
246
+ mkdir: deps.mkdir, homedir: deps.homedir,
247
+ },
248
+ } : {}),
249
+ },
120
250
  }));
121
251
  const resolution = resolveAdapter(agentId);
122
252
  if (!resolution.supported) {
@@ -346,6 +476,30 @@ export async function collectExecutorPreflight(options, deps, seams = {}) {
346
476
  }
347
477
  }
348
478
  warnings.push(...adapterInspection.inspection.warnings);
479
+ // --- Completion-evidence qualification (never fatal, BAPI-1301) --------
480
+ // Last, and outside `fatalFindings` on purpose: an executor that cannot
481
+ // supervise required work to completion is still a correct executor for every
482
+ // other job. It simply omits `completion_evidence.v1` from its claim manifest,
483
+ // and the server's claim filter keeps covered work away from it. One bounded
484
+ // line says why, so an operator expecting covered work can see the cause.
485
+ const completion = await evaluateCompletionEvidenceQualification(adapter, deps);
486
+ if (!completion.qualified && completion.refusal !== null) {
487
+ warnings.push(`completion evidence not advertised: ${completion.refusal}`);
488
+ }
489
+ let correction = {
490
+ qualified: false, evidence: null,
491
+ };
492
+ if (fatalFindings.length === 0) {
493
+ try {
494
+ correction = await qualifyCorrectionIntentRuntime(adapter, deps);
495
+ }
496
+ catch {
497
+ correction = { qualified: false, evidence: null };
498
+ }
499
+ }
500
+ if (!correction.qualified) {
501
+ warnings.push("correction intent not advertised: installed nested hook unverified");
502
+ }
349
503
  return {
350
504
  ok: fatalFindings.length === 0,
351
505
  fatalFindings,
@@ -356,6 +510,11 @@ export async function collectExecutorPreflight(options, deps, seams = {}) {
356
510
  ghAuthed,
357
511
  denyEnforced,
358
512
  adapter: adapterInspection.inspection,
513
+ completionEvidenceQualified: completion.qualified,
514
+ completionEvidenceRefusal: completion.refusal,
515
+ completionRuntime: completion.runtime,
516
+ correctionIntentQualified: correction.qualified,
517
+ correctionQualificationEvidence: correction.evidence,
359
518
  };
360
519
  }
361
520
  /**
@@ -379,6 +538,15 @@ export async function collectExecutorPreflight(options, deps, seams = {}) {
379
538
  * `undefined`-valued. For the same reason `repo_wide` is never serialized as
380
539
  * `false`: `false` is the server's default and means "not an opt-out", so
381
540
  * sending it would add a key that carries no information.
541
+ *
542
+ * BAPI-1301 (D4a) adds a third optional key, `capabilities`, under the same
543
+ * rule: `["completion_evidence.v1"]` only when preflight qualified the runtime.
544
+ *
545
+ * BAPI-1311 makes `capabilities` ADDITIVE: `focused_rebase.v1` is advertised by
546
+ * every executor this function builds a manifest for — a manifest is only built
547
+ * once ordinary preflight permits claiming — independently of completion-evidence
548
+ * qualification. The completion tokens keep their exact conditional behavior and
549
+ * order; the focused token is appended after them.
382
550
  */
383
551
  export function buildClaimManifest(report, options, freeSlots) {
384
552
  return {
@@ -392,5 +560,25 @@ export function buildClaimManifest(report, options, freeSlots) {
392
560
  disk_free_gb: report.diskFreeGb ?? 0,
393
561
  ...(options.epicRunIds !== undefined ? { epic_run_ids: options.epicRunIds } : {}),
394
562
  ...(options.repoWide === true ? { repo_wide: true } : {}),
563
+ // BAPI-1301 (D4a): advertised ONLY when preflight qualified the exact
564
+ // runtime; otherwise the key is absent (never `[]`), keeping the manifest's
565
+ // `Object.keys()` shape for every unqualified executor and older server.
566
+ // BAPI-1302 (D4c): a qualified executor also runs declared checks itself
567
+ // (`required-verification.ts`), so it advertises that it can claim a job
568
+ // carrying a required-verification declaration. An older server drops the
569
+ // unknown token (`normalize_declared_capabilities`), so it is safe to send.
570
+ // BAPI-1311: the focused-rebase token rides every claiming manifest, after
571
+ // any completion tokens. It is NOT a completion-evidence statement — rebase is
572
+ // not a covered job type — so it never waits on that qualification. An older
573
+ // server drops the unknown token (`normalize_declared_capabilities`).
574
+ capabilities: [
575
+ ...(report.completionEvidenceQualified === true
576
+ ? [COMPLETION_EVIDENCE_CAPABILITY, REQUIRED_VERIFICATION_CAPABILITY]
577
+ : []),
578
+ FOCUSED_REBASE_CAPABILITY,
579
+ SCOPE_WAIT_CAPABILITY,
580
+ ...(report.correctionIntentQualified === true ? [CORRECTION_INTENT_CAPABILITY] : []),
581
+ ...(report.correctionIntentQualified === true ? ["ci_evidence.v1"] : []),
582
+ ],
395
583
  };
396
584
  }