@bridge_gpt/mcp-server 0.2.66 → 0.2.68

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 (171) hide show
  1. package/README.md +421 -83
  2. package/build/agent-capabilities/probes.js +15 -5
  3. package/build/agent-launchers/claude-executor-adapter.js +70 -16
  4. package/build/agent-launchers/executor-adapter.js +7 -4
  5. package/build/agents.generated.js +22 -2
  6. package/build/bitbucket-workspace-remote.js +136 -0
  7. package/build/bootstrap-project-identity.js +24 -0
  8. package/build/bounded-wait.js +67 -10
  9. package/build/bridge-permissions.js +829 -0
  10. package/build/claude-settings.js +18 -0
  11. package/build/cli-help.js +21 -0
  12. package/build/command-assets-doctor.js +24 -70
  13. package/build/command-provisioning.js +29 -5
  14. package/build/commands.generated.js +12 -12
  15. package/build/conductor/bridge-api-client.js +857 -1
  16. package/build/conductor/bring-up-facts.js +1 -1
  17. package/build/conductor/command-drift-production.js +92 -0
  18. package/build/conductor/command-drift.js +89 -0
  19. package/build/conductor/doctor.js +72 -29
  20. package/build/conductor/epic-branch-ci-inspection.js +1375 -0
  21. package/build/conductor/epic-implementer-cli.js +98 -28
  22. package/build/conductor/errors.js +4 -3
  23. package/build/conductor/gate-discovery.js +890 -0
  24. package/build/conductor/guided-repair.js +6 -2
  25. package/build/conductor/hook-runtime-qualification.js +1 -1
  26. package/build/conductor/install-doctor.js +15 -3
  27. package/build/conductor/json-output.js +63 -0
  28. package/build/conductor/merge-execution-contract.js +27 -8
  29. package/build/conductor/merge-execution-eligibility.js +3 -2
  30. package/build/conductor/pr-ci-producer.js +1 -1
  31. package/build/conductor/readiness-cli.js +113 -12
  32. package/build/conductor/readiness-sections.js +410 -9
  33. package/build/conductor/readiness.js +388 -33
  34. package/build/conductor/recovery-cli.js +310 -12
  35. package/build/conductor/recovery-operations.js +167 -3
  36. package/build/conductor/repair-contract.js +54 -3
  37. package/build/conductor/repository-workflow-remedy.js +125 -0
  38. package/build/conductor/tools.js +2 -2
  39. package/build/conductor-bundle-artifacts.js +8 -0
  40. package/build/connect-bitbucket-api.js +41 -6
  41. package/build/connect-bitbucket.js +106 -33
  42. package/build/credential-store.js +207 -47
  43. package/build/docs.generated.js +62 -3
  44. package/build/doctor.js +92 -1
  45. package/build/drive-epic-key.js +6 -5
  46. package/build/drive-epic.js +129 -61
  47. package/build/epic-coherence-input.js +2 -1
  48. package/build/epic-coherence-input.test-fixtures.js +4 -3
  49. package/build/epic-implementer-bin.js +1379 -28
  50. package/build/epic-implementer-bundle-cli.js +2 -2
  51. package/build/epic-workarounds-path.js +39 -0
  52. package/build/executor/cli.js +33 -2
  53. package/build/executor/completion-contract.js +66 -10
  54. package/build/executor/completion-supervision.js +4 -0
  55. package/build/executor/deps.js +4 -1
  56. package/build/executor/env.js +19 -0
  57. package/build/executor/gate-qualification-job.js +499 -0
  58. package/build/executor/guarded-fast-forward-push.js +129 -0
  59. package/build/executor/heartbeat.js +1 -1
  60. package/build/executor/http-client.js +20 -0
  61. package/build/executor/integration-job.js +122 -8
  62. package/build/executor/job-errors.js +33 -1
  63. package/build/executor/job-runner.js +813 -87
  64. package/build/executor/likely-tests.js +290 -0
  65. package/build/executor/live-worker-registry.js +1 -1
  66. package/build/executor/observation.js +37 -3
  67. package/build/executor/packaged-recipe.js +106 -0
  68. package/build/executor/permissions.js +115 -28
  69. package/build/executor/platform.js +1 -1
  70. package/build/executor/preflight.js +112 -26
  71. package/build/executor/process-containment.js +36 -12
  72. package/build/executor/process.js +15 -7
  73. package/build/executor/prompt-spec.js +33 -1
  74. package/build/executor/recently-failed-tests-file.js +71 -0
  75. package/build/executor/reconcile-overlap-job.js +41 -23
  76. package/build/executor/required-verification.js +1 -1
  77. package/build/executor/required-work-ledger.js +111 -18
  78. package/build/executor/resume-pre-spawn.js +2 -0
  79. package/build/executor/retirement.js +69 -0
  80. package/build/executor/runner.js +122 -13
  81. package/build/executor/service-unit.js +7 -1
  82. package/build/executor/test-clock.js +15 -0
  83. package/build/executor/types.js +32 -0
  84. package/build/executor/viewer-tabs.js +58 -8
  85. package/build/executor/worker-command.js +23 -7
  86. package/build/executor/worker-diagnostics.js +37 -0
  87. package/build/executor/worker-finalization.js +113 -34
  88. package/build/executor/worker-guard-hook.js +316 -58
  89. package/build/executor/worker-log.js +4 -3
  90. package/build/executor/worker-verification-guidance.js +37 -0
  91. package/build/executor/worktree.js +166 -8
  92. package/build/first-build-advisory.js +97 -0
  93. package/build/generated-assets-advisory.js +14 -0
  94. package/build/generated-assets-catalog.js +66 -0
  95. package/build/generated-assets-context.js +46 -0
  96. package/build/generated-assets-dependencies.js +26 -0
  97. package/build/generated-assets-doctor.js +50 -0
  98. package/build/generated-assets-health.js +65 -0
  99. package/build/generated-assets-host.js +17 -0
  100. package/build/generated-assets-inventory.js +17 -0
  101. package/build/generated-assets-paths.js +60 -0
  102. package/build/generated-assets-publisher.js +133 -0
  103. package/build/generated-assets-remedy.js +25 -0
  104. package/build/generated-assets-repair.js +72 -0
  105. package/build/generated-assets-session.js +71 -0
  106. package/build/generated-assets-test-support.js +35 -0
  107. package/build/index.js +1224 -1054
  108. package/build/init.js +54 -177
  109. package/build/install-bridge-conductor-gate.js +1372 -0
  110. package/build/install-bridge-conductor.js +296 -41
  111. package/build/install-bridge.js +547 -40
  112. package/build/mcp-install-state.js +50 -4
  113. package/build/merge-workflow-install.js +3 -4
  114. package/build/phase-context-git-probe.js +68 -0
  115. package/build/phase-result-artifacts.js +173 -5
  116. package/build/pipeline-utils.js +6 -2
  117. package/build/pipelines.generated.js +34 -160
  118. package/build/plan-execution-ledger.js +2 -32
  119. package/build/plane/alembic-head.js +12 -3
  120. package/build/plane/base-worktree-guard.js +147 -0
  121. package/build/plane/cli.js +217 -17
  122. package/build/plane/code-snapshot.js +468 -0
  123. package/build/plane/defaults.js +48 -3
  124. package/build/plane/endpoint.js +41 -0
  125. package/build/plane/manifest.js +136 -2
  126. package/build/plane/member-roster.js +94 -19
  127. package/build/plane/preflight.js +83 -2
  128. package/build/plane/process-cwd.js +67 -0
  129. package/build/plane/restart.js +542 -0
  130. package/build/plane/shutdown.js +31 -0
  131. package/build/plane/status.js +143 -8
  132. package/build/plane/supervisor.js +586 -179
  133. package/build/plane/types.js +54 -2
  134. package/build/printed-remedy-commands.js +52 -0
  135. package/build/readiness-check.js +1 -1
  136. package/build/readme.generated.js +1 -1
  137. package/build/repair-assets.js +93 -0
  138. package/build/review-generation.js +22 -0
  139. package/build/run-unit-tests-launcher.js +130 -49
  140. package/build/secret-redaction.js +33 -0
  141. package/build/setup-epic.js +152 -22
  142. package/build/sfcc/config.js +9 -0
  143. package/build/sfcc/credentials.js +100 -38
  144. package/build/sfcc/hostname.js +67 -0
  145. package/build/sfcc/permissions.js +17 -13
  146. package/build/sfcc/register.js +1 -1
  147. package/build/sfcc/tool-wrapper.js +39 -43
  148. package/build/sfcc/write-grants.js +17 -11
  149. package/build/sfcc/write-result.js +4 -3
  150. package/build/sfcc/writes-site-preference.js +20 -8
  151. package/build/start-tickets-prereqs.js +70 -16
  152. package/build/start-tickets.js +208 -36
  153. package/build/tool-error-envelope.js +61 -0
  154. package/build/tool-surface-gating.js +36 -0
  155. package/build/upgrade-cli.js +55 -1
  156. package/build/version.generated.js +3 -3
  157. package/build/visual-diff.js +22 -1
  158. package/build/worker-guard-hook-bin.js +4 -6
  159. package/build/worker-guard-hook-main.js +47 -0
  160. package/build/worktree-core.js +145 -6
  161. package/docs/EPIC-IMPLEMENTER-INSTALL.md +867 -0
  162. package/docs/EPIC-IMPLEMENTER.md +728 -0
  163. package/docs/install/mcp-tool-integrations.md +24 -15
  164. package/docs/install/sfcc-integration.md +12 -4
  165. package/package.json +3 -3
  166. package/pipelines/greenfield-setup.json +4 -128
  167. package/pipelines/implement-ticket.json +3 -2
  168. package/pipelines/plan-epic.json +0 -5
  169. package/pipelines/review-ticket.json +1 -1
  170. package/docs/CONDUCTOR.md +0 -605
  171. package/pipelines/idea-to-pr.json +0 -49
@@ -31,6 +31,8 @@ import { HOOK_RUNTIME_PROBE_ACTION, HOOK_RUNTIME_PROBE_MARKER } from "./hook-run
31
31
  import { runFileScopeGuardCli } from "./file-scope-guard.js";
32
32
  import { runPostCommitHookProducer, runReferenceTransactionHookProducer } from "./git-producer.js";
33
33
  import { buildConductorDoctorReport, formatConductorDoctorReport } from "./doctor.js";
34
+ import { createCommandDriftInspector } from "./command-drift-production.js";
35
+ import { writeJsonDocument } from "./json-output.js";
34
36
  import { resolveSupervisorConfig } from "./supervisor-config.js";
35
37
  import { VERSION } from "../version.generated.js";
36
38
  // `runSupervisor` is imported LAZILY inside runSuperviseCommand: it transitively
@@ -57,18 +59,21 @@ export function getConductorUsage() {
57
59
  return [
58
60
  "Usage: epic-implementer <command> [options]",
59
61
  "",
60
- "Local append-only event ledger for multi-agent coordination.",
61
- "Talks ONLY to the local SQLite store (~/.config/bridge/events.db); no Bridge API calls.",
62
+ "Local append-only event ledger for multi-agent coordination, plus run-control",
63
+ "commands. The ledger commands talk ONLY to the local SQLite store",
64
+ "(~/.config/bridge/events.db); the run-control commands (stop-run through",
65
+ "rerun-ci), epic-status, and readiness call the Bridge API.",
62
66
  "",
63
67
  "Commands:",
64
68
  " emit-event Append one semantic event to the ledger",
65
69
  " supervise --run-id <id> Run the foreground, run-scoped supervisor loop",
66
- " epic-tick Run one stateless reconciliation pass for an Epic",
70
+ " epic-tick RETIRED (v1): always exits 1 with EPIC_TICK_V1_FROZEN; the",
71
+ " server-side reconciler replaced it",
67
72
  " epic-status Print read-only health summary of an Epic Run",
68
73
  " send-message Enqueue ONE typed supervisor->worker relay message (idempotent)",
69
74
  " check-messages Read + ACK pending relay messages for a worker (no redelivery)",
70
75
  " doctor Read-only health/diagnostics report (ledger + git hooks)",
71
- " readiness Read-only ADVISORY report of every conductor prerequisite",
76
+ " readiness Read-only ADVISORY report of every Epic Implementer prerequisite",
72
77
  " (install + epic-implementer doctor + plane preflight + server),",
73
78
  " each with pass/warn/fail/skip and one named remediation.",
74
79
  " Remediations are NOT run automatically; always exits 0.",
@@ -77,6 +82,7 @@ export function getConductorUsage() {
77
82
  " git-hook post-commit Run the post-commit producer (invoked by the installed hook)",
78
83
  " git-hook reference-transaction --phase <p> --stdin-file <f>",
79
84
  " Run the reference-transaction producer (invoked by the hook)",
85
+ " likely-tests --base <sha> Local advisory test references for committed changes.",
80
86
  " file-scope-guard Warn-only: compare the branch diff against the declared",
81
87
  " touched-file set (always exits 0; never blocks a PR)",
82
88
  " stop-run Stop an epic run: block dispatch and cancel queued work",
@@ -91,6 +97,7 @@ export function getConductorUsage() {
91
97
  " scope-reparse --epic-run-id <id> --scope-id <scope>",
92
98
  " Re-drive the run's OWN index scope through retry-reparse",
93
99
  " and schedule its parse. Refused if the scope is not the run's.",
100
+ " escalate --epic-run-id <id> --ticket-key <key> --cause <cause> --action-needed <text>",
94
101
  " dispatch-remediation --epic-run-id <id> --ticket-key <key> --context-file <path>",
95
102
  ` Dispatch a remediation job carrying driver context (UTF-8,`,
96
103
  ` at most DRIVER_CONTEXT_MAX_BYTES = ${DRIVER_CONTEXT_MAX_BYTES} bytes; never truncated).`,
@@ -106,7 +113,8 @@ export function getConductorUsage() {
106
113
  " resume-run --epic-run-id <id> [--clear-quarantine] [--json]",
107
114
  " Resume a paused run (a quarantined one only with --clear-quarantine);",
108
115
  " activation is re-checked server-side. Active/no-control is a no-op.",
109
- " continue-child --epic-run-id <id> --ticket-key <key> [--reason <text>] [--json]",
116
+ " continue-child --epic-run-id <id> --ticket-key <key> [--reason <text> --worker-exit-proof exited|fenced] [--json]",
117
+ " grant-continuation --epic-run-id <id> --ticket-key <key> --reason <text> [--extra-continuations 1] [--extra-seconds <seconds>] [--json]",
110
118
  " Continue a parked child's CURRENT episode WITHOUT a reset: same attempt,",
111
119
  " retained work, only the allowance left. At most one dispatch per episode.",
112
120
  " continuation-receipt --epic-run-id <id> --ticket-key <key> [--request-id <id>] [--json]",
@@ -115,6 +123,10 @@ export function getConductorUsage() {
115
123
  " resume-ci --epic-run-id <id> --ticket-key <key> [--json]",
116
124
  " Resume a child parked on a qualified CI stop once CI is green: CI",
117
125
  " returns to evaluation with NO new wait, job, or repair allowance.",
126
+ " rerun-ci --epic-run-id <id> --ticket-key <key> --binding <token> [--json]",
127
+ " Ask CI to re-run a ticket's FAILED checks at its bound head (guided: copy",
128
+ " the command explain-run rendered). Charges NO allowance and never re-runs",
129
+ " claude-review. A re-run is not a verdict: after CI is green, use resume-ci.",
118
130
  "",
119
131
  "supervise options:",
120
132
  " --run-id <id> Run/session identifier to supervise (required)",
@@ -172,6 +184,9 @@ export function getConductorUsage() {
172
184
  " --no-deny-probe Accepted for parity with `doctor`; inert here — `readiness`",
173
185
  " never spawns the deny-enforcement probe, and reports that",
174
186
  " check as an explicit skip naming `epic-implementer doctor`",
187
+ " --epic-run-id <id> The epic run being attached; when the live plane is bound",
188
+ " to it, the plane port and existing-plane rows pass with",
189
+ " reason own_plane instead of failing",
175
190
  " --help Print the readiness usage message",
176
191
  " Note: advisory only. It blocks nothing and changes no exit code; `drive-epic`",
177
192
  " remains the sole route-selection gate and server-side admission the sole refusal.",
@@ -196,11 +211,11 @@ export function getConductorUsage() {
196
211
  " epic-implementer scope-catch-up --epic-run-id <id> --scope-id <scope>",
197
212
  " # a merge landed on epic/<KEY> that the scope never observed (unobserved_advance)",
198
213
  " epic-implementer patch-policy --epic-run-id <id> --patch-file required-checks.json",
199
- " # required_checks_empty_no_mode; the file holds {\"required_checks\":[\"conductor-ci / gate\"]}",
214
+ " # required_checks_empty_no_mode; the file holds {\"required_checks\":[\"epic-implementer-ci / gate\"]}",
200
215
  " epic-implementer resume-run --epic-run-id <id>",
201
216
  " # a cap_wall_clock pause whose cause is now cleared",
202
217
  "",
203
- "epic-tick options:",
218
+ "epic-tick options (retired; parsed by no live path):",
204
219
  " --epic-key <KEY> Epic key to supervise (required, non-empty)",
205
220
  " --scheduled-at <epoch> Epoch-seconds timestamp when this tick was scheduled (optional)",
206
221
  " --lease-ttl-seconds <n> Lease TTL in seconds (optional, default 120)",
@@ -259,6 +274,8 @@ export function getConductorUsage() {
259
274
  " epic-implementer continuation-receipt --epic-run-id 3f9c2b7e-... --ticket-key BAPI-852",
260
275
  " # CI finished green after the child parked on an expired CI wait:",
261
276
  " epic-implementer resume-ci --epic-run-id 3f9c2b7e-... --ticket-key BAPI-852",
277
+ " # CI failed on infrastructure: re-run it (never claude-review); then resume-ci once green:",
278
+ " epic-implementer rerun-ci --epic-run-id 3f9c2b7e-... --ticket-key BAPI-852 --binding <token>",
262
279
  ].join("\n");
263
280
  }
264
281
  /**
@@ -294,6 +311,7 @@ const VALID_COMMANDS = new Set([
294
311
  "install-git-hooks",
295
312
  "git-hook",
296
313
  "file-scope-guard",
314
+ "likely-tests",
297
315
  // BAPI-872: CLI-only operator recovery verbs — never registered as MCP tools.
298
316
  "stop-run",
299
317
  "abandon-run",
@@ -301,6 +319,7 @@ const VALID_COMMANDS = new Set([
301
319
  "adopt-current-head-and-unpark",
302
320
  // BAPI-1154: CLI-only run-addressed repair verbs — never registered as MCP tools.
303
321
  "scope-reparse",
322
+ "escalate",
304
323
  "dispatch-remediation",
305
324
  "merge-child",
306
325
  // BAPI-1176: CLI-only run-addressed repair verbs — never registered as MCP tools.
@@ -309,9 +328,12 @@ const VALID_COMMANDS = new Set([
309
328
  "resume-run",
310
329
  // BAPI-1300: CLI-only parked-child continuation pair — never registered as MCP tools.
311
330
  "continue-child",
331
+ "grant-continuation",
312
332
  "continuation-receipt",
313
333
  // BAPI-1326: CLI-only allowance-preserving CI resume — never an MCP tool.
314
334
  "resume-ci",
335
+ // BAPI-1388: CLI-only guided provider re-run of failed CI workflow runs — never an MCP tool.
336
+ "rerun-ci",
315
337
  // Private, and deliberately ABSENT from the usage text: `__hook-bin` exists as
316
338
  // the bundled-artifact regression guard for BAPI-772 (mirroring `plane
317
339
  // __entrypoint`), not as a supported operator workflow.
@@ -532,11 +554,9 @@ export async function runEmitEventCommand(argv, deps = {}) {
532
554
  throw error;
533
555
  }
534
556
  if (parsed.json) {
535
- console.log(JSON.stringify(result));
536
- }
537
- else {
538
- console.log(JSON.stringify(result, null, 2));
557
+ return (await writeJsonDocument(JSON.stringify(result))) ? 0 : 1;
539
558
  }
559
+ console.log(JSON.stringify(result, null, 2));
540
560
  return 0;
541
561
  }
542
562
  // ---------------------------------------------------------------------------
@@ -638,7 +658,8 @@ export async function runSendMessageCommand(argv, deps = {}) {
638
658
  }
639
659
  const result = await sendWorkerMessage(parsed.input);
640
660
  if (parsed.json) {
641
- console.log(JSON.stringify(result));
661
+ if (!(await writeJsonDocument(JSON.stringify(result))))
662
+ return 1;
642
663
  }
643
664
  else {
644
665
  console.log([
@@ -691,8 +712,7 @@ export async function runCheckMessagesCommand(argv) {
691
712
  }
692
713
  const result = await checkWorkerMessages(parsed.input);
693
714
  if (parsed.json) {
694
- console.log(JSON.stringify(result));
695
- return 0;
715
+ return (await writeJsonDocument(JSON.stringify(result))) ? 0 : 1;
696
716
  }
697
717
  const lines = [`Acknowledged ${result.acked_count} of ${result.count} message(s).`];
698
718
  for (const message of result.messages) {
@@ -717,10 +737,16 @@ export async function runDoctorCommand(argv, deps = {}) {
717
737
  return 0;
718
738
  }
719
739
  // A caller may inject deps (e.g. a fake deny inspector in tests) to stay hermetic.
720
- const report = await buildConductorDoctorReport(bools.has("--no-deny-probe") ? { ...deps, skipDenyProbe: true } : deps);
740
+ // BAPI-1392: the warn-only committed-command drift row is read-only; a caller's
741
+ // injected inspector wins so tests stay hermetic.
742
+ const doctorDeps = {
743
+ inspectCommandDrift: createCommandDriftInspector({ env: deps.env ?? process.env, cwd: process.cwd() }),
744
+ ...deps,
745
+ };
746
+ const report = await buildConductorDoctorReport(bools.has("--no-deny-probe") ? { ...doctorDeps, skipDenyProbe: true } : doctorDeps);
721
747
  if (bools.has("--json")) {
722
- console.log(JSON.stringify({ ...report.ledger, git_hooks: report.git_hooks, mcp_profile: report.mcp_profile, native_ledger: report.native_ledger, deny_enforcement: report.deny_enforcement }));
723
- return 0;
748
+ const written = await writeJsonDocument(JSON.stringify({ ...report.ledger, git_hooks: report.git_hooks, mcp_profile: report.mcp_profile, native_ledger: report.native_ledger, deny_enforcement: report.deny_enforcement, ...(report.command_drift ? { command_drift: report.command_drift } : {}) }));
749
+ return written ? 0 : 1;
724
750
  }
725
751
  console.log(formatConductorDoctorReport(report));
726
752
  return 0;
@@ -1092,7 +1118,7 @@ export async function runApprovePlanCommand(argv) {
1092
1118
  if (!accessResult.ok) {
1093
1119
  const envelope = { error: "CREDENTIALS_UNAVAILABLE", status: 401, message: accessResult.error };
1094
1120
  if (parsed.json) {
1095
- console.log(JSON.stringify({ ok: false, kind: "unauthorized", error: envelope.message }));
1121
+ await writeJsonDocument(JSON.stringify({ ok: false, kind: "unauthorized", error: envelope.message }));
1096
1122
  }
1097
1123
  else {
1098
1124
  console.error(`Error: ${accessResult.error}`);
@@ -1110,7 +1136,8 @@ export async function runApprovePlanCommand(argv) {
1110
1136
  `the current approved version and that the blob has been stored first.`);
1111
1137
  }
1112
1138
  if (parsed.json) {
1113
- console.log(JSON.stringify({ ok: true, plan_hash: result.plan_hash }));
1139
+ if (!(await writeJsonDocument(JSON.stringify({ ok: true, plan_hash: result.plan_hash }))))
1140
+ return 1;
1114
1141
  }
1115
1142
  else {
1116
1143
  console.log(`Plan approved atomically. ` +
@@ -1125,7 +1152,7 @@ export async function runApprovePlanCommand(argv) {
1125
1152
  // rather than distinguishing 5xx (2) from other failures.
1126
1153
  const envelope = toConductorErrorEnvelope(error);
1127
1154
  if (parsed.json) {
1128
- console.log(JSON.stringify(envelope));
1155
+ await writeJsonDocument(JSON.stringify(envelope));
1129
1156
  }
1130
1157
  else {
1131
1158
  console.error(`Error: ${formatConductorErrorLine(envelope)}`);
@@ -1179,7 +1206,7 @@ export async function runEpicStatusCommand(argv) {
1179
1206
  const accessResult = await resolveConductorBridgeApiAccess();
1180
1207
  if (!accessResult.ok) {
1181
1208
  if (parsed.json) {
1182
- console.log(JSON.stringify({ ok: false, kind: "unauthorized", error: accessResult.error }));
1209
+ await writeJsonDocument(JSON.stringify({ ok: false, kind: "unauthorized", error: accessResult.error }));
1183
1210
  }
1184
1211
  else {
1185
1212
  console.error(`Error: ${accessResult.error}`);
@@ -1189,8 +1216,7 @@ export async function runEpicStatusCommand(argv) {
1189
1216
  try {
1190
1217
  const state = await fetchEpicRunState(accessResult.access, parsed.epicKey);
1191
1218
  if (parsed.json) {
1192
- console.log(JSON.stringify(state));
1193
- return 0;
1219
+ return (await writeJsonDocument(JSON.stringify(state))) ? 0 : 1;
1194
1220
  }
1195
1221
  // Human-readable summary: structured status fields only, no raw payloads.
1196
1222
  const lines = [];
@@ -1220,7 +1246,9 @@ export async function runEpicStatusCommand(argv) {
1220
1246
  catch (error) {
1221
1247
  if (error instanceof BridgeApiError && error.status === 404) {
1222
1248
  if (parsed.json) {
1223
- console.log(JSON.stringify({ epic_key: parsed.epicKey, status: "unknown", state: null }));
1249
+ const written = await writeJsonDocument(JSON.stringify({ epic_key: parsed.epicKey, status: "unknown", state: null }));
1250
+ if (!written)
1251
+ return 1;
1224
1252
  }
1225
1253
  else {
1226
1254
  console.log("No such epic found.");
@@ -1231,7 +1259,7 @@ export async function runEpicStatusCommand(argv) {
1231
1259
  // rather than distinguishing 5xx (2) from other failures.
1232
1260
  const envelope = toConductorErrorEnvelope(error);
1233
1261
  if (parsed.json) {
1234
- console.log(JSON.stringify(envelope));
1262
+ await writeJsonDocument(JSON.stringify(envelope));
1235
1263
  }
1236
1264
  else {
1237
1265
  console.error(`Error: ${formatConductorErrorLine(envelope)}`);
@@ -1318,8 +1346,7 @@ export async function runPurgeCommand(argv) {
1318
1346
  }
1319
1347
  const result = await purgeConductorLedger();
1320
1348
  if (bools.has("--json")) {
1321
- console.log(JSON.stringify(result));
1322
- return 0;
1349
+ return (await writeJsonDocument(JSON.stringify(result))) ? 0 : 1;
1323
1350
  }
1324
1351
  console.log([
1325
1352
  `Conductor ledger purged (existed: ${result.existed}).`,
@@ -1329,6 +1356,32 @@ export async function runPurgeCommand(argv) {
1329
1356
  ].join("\n"));
1330
1357
  return 0;
1331
1358
  }
1359
+ export async function runLikelyTestsCommand(argv, deps = {}) {
1360
+ const { resolveLikelyTests, isFullCommitSha, validTestReference, DISCOVERY_NOTES } = await import("../executor/likely-tests.js");
1361
+ const stdout = deps.stdout ?? ((text) => { process.stdout.write(text); });
1362
+ const stderr = deps.stderr ?? ((text) => { process.stderr.write(text); });
1363
+ let base;
1364
+ if (argv.length === 2 && argv[0] === "--base")
1365
+ base = argv[1];
1366
+ if (argv.length === 1 && argv[0].startsWith("--base="))
1367
+ base = argv[0].slice(7);
1368
+ if (!base || !isFullCommitSha(base)) {
1369
+ stderr(DISCOVERY_NOTES.invalid_arguments + "\n");
1370
+ return 0;
1371
+ }
1372
+ try {
1373
+ const result = await (deps.resolve ?? resolveLikelyTests)({ cwd: deps.cwd ?? process.cwd(), comparisonSha: base });
1374
+ for (const reference of result.references)
1375
+ if (validTestReference(reference))
1376
+ stdout(reference + "\n");
1377
+ for (const diagnostic of result.diagnostics)
1378
+ stderr(DISCOVERY_NOTES[diagnostic] + "\n");
1379
+ }
1380
+ catch {
1381
+ stderr(DISCOVERY_NOTES.git_unavailable + "\n");
1382
+ }
1383
+ return 0;
1384
+ }
1332
1385
  /**
1333
1386
  * Dispatch the epic-implementer CLI. Returns (asynchronously) a process exit
1334
1387
  * code (non-zero for parser, validation, and storage failures). The dispatcher
@@ -1340,7 +1393,9 @@ export async function runPurgeCommand(argv) {
1340
1393
  * profile group this dispatcher sits alongside remain unrenamed until S5; this
1341
1394
  * S4 slice renames only the public entry point and CLI-facing text.
1342
1395
  */
1343
- export async function runEpicImplementerCli(argv) {
1396
+ export async function runEpicImplementerCli(argv, likelyTestsDeps) {
1397
+ if (argv[0] === "likely-tests")
1398
+ return runLikelyTestsCommand(argv.slice(1), likelyTestsDeps);
1344
1399
  const parsed = parseConductorArgs(argv);
1345
1400
  if (parsed.kind === "help") {
1346
1401
  console.log(getConductorUsage());
@@ -1389,6 +1444,8 @@ export async function runEpicImplementerCli(argv) {
1389
1444
  // Also dispatched before any MCP construction or store open: it only
1390
1445
  // imports the native binding, so it can answer on a host with no ledger.
1391
1446
  return await runHookRuntimeProbeCommand();
1447
+ case "likely-tests":
1448
+ return runLikelyTestsCommand(parsed.argv);
1392
1449
  case "file-scope-guard":
1393
1450
  // BAPI-507 (N-2): warn-only worker file-scope guard. Always exits 0.
1394
1451
  return runFileScopeGuardCli();
@@ -1416,6 +1473,10 @@ export async function runEpicImplementerCli(argv) {
1416
1473
  const { runScopeReparseCommand } = await import("./recovery-cli.js");
1417
1474
  return await runScopeReparseCommand(parsed.argv);
1418
1475
  }
1476
+ case "escalate": {
1477
+ const { runEscalateCommand } = await import("./recovery-cli.js");
1478
+ return await runEscalateCommand(parsed.argv);
1479
+ }
1419
1480
  case "dispatch-remediation": {
1420
1481
  const { runDispatchRemediationCommand } = await import("./recovery-cli.js");
1421
1482
  return await runDispatchRemediationCommand(parsed.argv);
@@ -1442,6 +1503,10 @@ export async function runEpicImplementerCli(argv) {
1442
1503
  const { runContinueChildCommand } = await import("./recovery-cli.js");
1443
1504
  return await runContinueChildCommand(parsed.argv);
1444
1505
  }
1506
+ case "grant-continuation": {
1507
+ const { runGrantContinuationCommand } = await import("./recovery-cli.js");
1508
+ return await runGrantContinuationCommand(parsed.argv);
1509
+ }
1445
1510
  case "continuation-receipt": {
1446
1511
  const { runContinuationReceiptCommand } = await import("./recovery-cli.js");
1447
1512
  return await runContinuationReceiptCommand(parsed.argv);
@@ -1451,6 +1516,11 @@ export async function runEpicImplementerCli(argv) {
1451
1516
  const { runResumeCiCommand } = await import("./recovery-cli.js");
1452
1517
  return await runResumeCiCommand(parsed.argv);
1453
1518
  }
1519
+ case "rerun-ci": {
1520
+ // BAPI-1388: delegates only to the guided, pinned rerun-ci operation.
1521
+ const { runRerunCiCommand } = await import("./recovery-cli.js");
1522
+ return await runRerunCiCommand(parsed.argv);
1523
+ }
1454
1524
  default:
1455
1525
  console.error('Error: Unknown command. Run "epic-implementer --help" for usage.');
1456
1526
  return 1;
@@ -70,9 +70,10 @@ export class ConductorStoreError extends Error {
70
70
  */
71
71
  export class ConductorEpicTickV1FrozenError extends Error {
72
72
  constructor() {
73
- super("The v1 `epic-implementer epic-tick` path is frozen (EPIC_TICK_V1_FROZEN). Epic " +
74
- "Conductor v2 replaces the local epic tick with a server-side reconciler " +
75
- "plus the local executor — run `mcp-server executor` instead.");
73
+ super("The v1 `epic-implementer epic-tick` path is frozen (EPIC_TICK_V1_FROZEN). The " +
74
+ "Epic Implementer replaced the local epic tick with a server-side reconciler " +
75
+ "plus the local executor — run `mcp-server executor --repo <name> " +
76
+ "--epic-run-id <run-id>` instead.");
76
77
  this.name = "ConductorEpicTickV1FrozenError";
77
78
  }
78
79
  }