@bridge_gpt/mcp-server 0.2.65 → 0.2.67

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 (132) hide show
  1. package/README.md +269 -82
  2. package/build/agent-capabilities/probes.js +15 -5
  3. package/build/agent-launchers/claude-executor-adapter.js +55 -34
  4. package/build/agent-launchers/executor-adapter.js +34 -4
  5. package/build/agents.generated.js +1 -1
  6. package/build/bounded-wait.js +67 -10
  7. package/build/bridge-config.js +104 -0
  8. package/build/codex-bridge-profile.js +10 -1
  9. package/build/commands.generated.js +12 -12
  10. package/build/conductor/bridge-api-client.js +372 -10
  11. package/build/conductor/bring-up-facts.js +1 -1
  12. package/build/conductor/doctor.js +3 -3
  13. package/build/conductor/epic-child-continuation.js +61 -34
  14. package/build/conductor/epic-implementer-cli.js +34 -6
  15. package/build/conductor/errors.js +4 -3
  16. package/build/conductor/guided-repair.js +327 -0
  17. package/build/conductor/hook-runtime-qualification.js +1 -1
  18. package/build/conductor/merge-execution-contract.js +27 -8
  19. package/build/conductor/merge-execution-eligibility.js +3 -2
  20. package/build/conductor/pr-ci-producer.js +1 -1
  21. package/build/conductor/readiness-cli.js +46 -9
  22. package/build/conductor/readiness-sections.js +41 -6
  23. package/build/conductor/readiness.js +204 -30
  24. package/build/conductor/recovery-cli.js +703 -20
  25. package/build/conductor/recovery-operations.js +392 -3
  26. package/build/conductor/repair-contract.js +112 -3
  27. package/build/conductor/repository-workflow-remedy.js +125 -0
  28. package/build/conductor/tools.js +2 -2
  29. package/build/conductor-bundle-artifacts.js +8 -0
  30. package/build/credential-store.js +5 -4
  31. package/build/diagnostic-text.js +36 -0
  32. package/build/docs.generated.js +8 -3
  33. package/build/doctor.js +70 -10
  34. package/build/drive-epic-key.js +6 -5
  35. package/build/drive-epic.js +479 -131
  36. package/build/epic-coherence-input.js +2 -1
  37. package/build/epic-implementer-bin.js +30 -26
  38. package/build/epic-implementer-bundle-cli.js +2 -2
  39. package/build/epic-launch-diagnostic.js +31 -0
  40. package/build/epic-launch-profile.js +44 -14
  41. package/build/executor/cli.js +3 -2
  42. package/build/executor/completion-contract.js +48 -5
  43. package/build/executor/completion-supervision.js +9 -0
  44. package/build/executor/correction-dispatch.js +60 -0
  45. package/build/executor/env.js +25 -0
  46. package/build/executor/heartbeat.js +1 -1
  47. package/build/executor/http-client.js +35 -0
  48. package/build/executor/integration-job.js +6 -1
  49. package/build/executor/job-errors.js +38 -4
  50. package/build/executor/job-log-registry.js +340 -73
  51. package/build/executor/job-runner.js +485 -74
  52. package/build/executor/job-types.js +8 -13
  53. package/build/executor/observation.js +6 -1
  54. package/build/executor/preflight.js +136 -10
  55. package/build/executor/prompt-spec.js +113 -9
  56. package/build/executor/required-work-ledger.js +6 -1
  57. package/build/executor/resume-pre-spawn.js +2 -0
  58. package/build/executor/runner.js +31 -2
  59. package/build/executor/service-unit.js +7 -1
  60. package/build/executor/stale-artifacts.js +5 -4
  61. package/build/executor/types.js +1 -0
  62. package/build/executor/watch-cli.js +35 -8
  63. package/build/executor/worker-command.js +43 -43
  64. package/build/executor/worker-finalization.js +161 -43
  65. package/build/executor/worker-guard-hook.js +152 -12
  66. package/build/executor/worker-log.js +137 -70
  67. package/build/executor/worktree-gc.js +30 -6
  68. package/build/executor/worktree.js +82 -1
  69. package/build/index.js +482 -660
  70. package/build/init.js +107 -4
  71. package/build/install-bridge-conductor.js +8 -6
  72. package/build/install-bridge.js +287 -23
  73. package/build/install-doctor.js +172 -30
  74. package/build/install-reexec.js +69 -7
  75. package/build/macos-terminal-permission-guidance.js +16 -0
  76. package/build/model-thresholds-tool.js +185 -0
  77. package/build/phase-context-git-probe.js +68 -0
  78. package/build/phase-result-artifacts.js +173 -5
  79. package/build/pipelines.generated.js +19 -25
  80. package/build/plane/alembic-head.js +12 -3
  81. package/build/plane/base-worktree-guard.js +147 -0
  82. package/build/plane/cli.js +217 -17
  83. package/build/plane/code-snapshot.js +468 -0
  84. package/build/plane/defaults.js +48 -3
  85. package/build/plane/endpoint.js +41 -0
  86. package/build/plane/manifest.js +120 -1
  87. package/build/plane/member-roster.js +94 -19
  88. package/build/plane/preflight.js +30 -2
  89. package/build/plane/process-cwd.js +67 -0
  90. package/build/plane/restart.js +542 -0
  91. package/build/plane/shutdown.js +31 -0
  92. package/build/plane/status.js +145 -6
  93. package/build/plane/supervisor.js +588 -177
  94. package/build/plane/types.js +54 -2
  95. package/build/plane/worker-exit-code.js +2 -0
  96. package/build/printed-remedy-commands.js +37 -0
  97. package/build/project-root.js +99 -0
  98. package/build/readiness-check.js +1 -1
  99. package/build/readme.generated.js +1 -1
  100. package/build/review-generation.js +22 -0
  101. package/build/review-tickets.js +156 -13
  102. package/build/setup-epic.js +224 -127
  103. package/build/sfcc/config.js +9 -0
  104. package/build/sfcc/credentials.js +100 -38
  105. package/build/sfcc/hostname.js +67 -0
  106. package/build/sfcc/permissions.js +17 -13
  107. package/build/sfcc/register.js +1 -1
  108. package/build/sfcc/setup-status.js +2 -0
  109. package/build/sfcc/tool-wrapper.js +41 -43
  110. package/build/sfcc/tools-configured.js +96 -0
  111. package/build/sfcc/write-grants.js +17 -11
  112. package/build/sfcc/write-result.js +4 -3
  113. package/build/sfcc/writes-site-preference.js +20 -8
  114. package/build/start-tickets.js +332 -79
  115. package/build/tool-error-envelope.js +61 -0
  116. package/build/upgrade-cli.js +109 -24
  117. package/build/version.generated.js +3 -3
  118. package/build/visual-diff.js +22 -1
  119. package/build/windows-npm-entry.js +103 -0
  120. package/build/worker-guard-hook-bin.js +3 -5
  121. package/build/worker-guard-hook-main.js +47 -0
  122. package/build/worktree-core.js +136 -9
  123. package/docs/EPIC-IMPLEMENTER-INSTALL.md +849 -0
  124. package/docs/EPIC-IMPLEMENTER.md +662 -0
  125. package/docs/install/mcp-tool-integrations.md +25 -15
  126. package/docs/install/sfcc-integration.md +21 -8
  127. package/package.json +1 -1
  128. package/pipelines/implement-ticket.json +1 -1
  129. package/pipelines/plan-epic.json +0 -5
  130. package/pipelines/review-ticket.json +1 -1
  131. package/docs/CONDUCTOR.md +0 -605
  132. package/pipelines/idea-to-pr.json +0 -49
@@ -6,8 +6,9 @@
6
6
  * a hole in the roster (a member that crashed and was deliberately not
7
7
  * restarted) is precisely what this command exists to *show*.
8
8
  */
9
- import { planeManifestLifecycle, probeManifestMembers, readPlaneManifest, } from "./manifest.js";
10
- import { PLANE_RUNTIME_DIR, PLANE_RUNTIME_LOG_PATH, } from "./types.js";
9
+ import { planeManifestLifecycle, planeManifestSnapshot, probeManifestMembers, readPlaneManifest, } from "./manifest.js";
10
+ import { PLANE_RESTART_MIN_SCHEMA_VERSION, PLANE_RUNTIME_DIR, PLANE_RUNTIME_LOG_PATH, } from "./types.js";
11
+ import { WORKER_STALE_EXIT_CODE } from "./worker-exit-code.js";
11
12
  /** Read the manifest and probe every recorded pid. Strictly read-only. */
12
13
  export async function getPlaneStatus(repoRoot, deps) {
13
14
  const read = await readPlaneManifest(repoRoot, deps.fs);
@@ -34,6 +35,8 @@ export async function getPlaneStatus(repoRoot, deps) {
34
35
  unrecognizedMemberNames: read.unrecognizedMemberNames,
35
36
  lifecycle: planeManifestLifecycle(manifest),
36
37
  epicRunId: manifest.epicRunId ?? null,
38
+ snapshot: planeManifestSnapshot(manifest),
39
+ restartSupported: manifest.schemaVersion >= PLANE_RESTART_MIN_SCHEMA_VERSION,
37
40
  createdAt: manifest.createdAt,
38
41
  updatedAt: manifest.updatedAt,
39
42
  members: probeManifestMembers(manifest, deps.proc).map((probe) => ({
@@ -44,6 +47,10 @@ export async function getPlaneStatus(repoRoot, deps) {
44
47
  exitCode: probe.member.exitCode,
45
48
  exitSignal: probe.member.exitSignal,
46
49
  logPath: probe.member.logPath,
50
+ ...(probe.member.cwd !== undefined ? { cwd: probe.member.cwd } : {}),
51
+ ...(probe.member.restartFailure !== undefined
52
+ ? { restartFailure: probe.member.restartFailure }
53
+ : {}),
47
54
  })),
48
55
  };
49
56
  }
@@ -77,7 +84,19 @@ function describeLifecycle(phase) {
77
84
  "left running; nothing is claiming jobs. Wind it down with `plane down`.");
78
85
  }
79
86
  }
80
- /** One line per member: name, state, exit status where known, log path. */
87
+ /**
88
+ * Render a status result.
89
+ *
90
+ * The ORDER is the design (BAPI-1362): lifecycle and the bound run first, because
91
+ * they say whether touching the plane is safe at all; then the `Code snapshot`
92
+ * section, because what code the members run decides which recovery is safe; then
93
+ * the members, each with a text state and ONE next action. Nothing is carried by
94
+ * colour or by column alignment alone — every row starts with its member name and
95
+ * states its condition in words — so the output survives `TERM=dumb`, a pipe, a
96
+ * narrow terminal, and a screen reader. Long paths and commands are emitted whole
97
+ * on a line of their own rather than truncated, so the terminal wraps them and
98
+ * nothing the operator needs to copy is cut.
99
+ */
81
100
  export function formatPlaneStatus(result) {
82
101
  if (!result.ok)
83
102
  return `plane status FAILED: ${result.error}`;
@@ -92,10 +111,22 @@ export function formatPlaneStatus(result) {
92
111
  ` started ${result.createdAt}`,
93
112
  ` updated ${result.updatedAt}`,
94
113
  "",
114
+ "Code snapshot",
115
+ ...describeSnapshot(result.snapshot, result.restartSupported),
116
+ "",
117
+ "Members",
95
118
  ];
119
+ const context = {
120
+ supervisorLiveness: result.supervisorLiveness,
121
+ restartSupported: result.restartSupported,
122
+ ...(result.snapshot.kind === "pinned" ? { pinnedSha: result.snapshot.snapshot.sha } : {}),
123
+ };
96
124
  for (const member of result.members) {
97
125
  lines.push(` ${member.name.padEnd(12)} ${describeMemberState(member, result.supervisorLiveness)} ` +
98
126
  `${member.logPath}`);
127
+ const next = describeMemberNextAction(member, context);
128
+ if (next !== null)
129
+ lines.push(` next: ${next}`);
99
130
  }
100
131
  if (result.unrecognizedMemberNames.length > 0) {
101
132
  // Never a silent omission. The plane really has more members than the list
@@ -120,14 +151,53 @@ export function formatPlaneStatus(result) {
120
151
  // Members that genuinely ran and exited keep the original no-restart warning;
121
152
  // one that never started was not restarted for an entirely different reason,
122
153
  // and telling the operator to "read the log above" would be a dead end.
123
- const holes = result.members.filter((m) => m.liveness !== "alive" && !neverStarted.includes(m));
154
+ const holes = result.members.filter((m) => m.liveness !== "alive" && !neverStarted.includes(m) && m.state !== "restarting");
124
155
  if (holes.length > 0) {
125
156
  lines.push("");
126
157
  lines.push(`${holes.length} member(s) are not running. They are NOT restarted automatically — ` +
127
- "read the log(s) above, then `plane down` and `plane up` when you have a fix.");
158
+ "read the log(s) above, then use the `next:` action under each member.");
159
+ // A full wind-down is the remedy only when there is no live supervisor left to
160
+ // take a restart request. With one, every restartable member has a scoped fix
161
+ // and recommending `plane down` here would stop a bound run to repair one
162
+ // process.
163
+ if (result.supervisorLiveness !== "alive") {
164
+ lines.push("The supervisor is not running, so nothing can restart a member: wind the plane down " +
165
+ "with `plane down` (it stops the bound run first), then `plane up`.");
166
+ }
128
167
  }
129
168
  return lines.join("\n");
130
169
  }
170
+ /**
171
+ * The `Code snapshot` section's body lines (BAPI-1362).
172
+ *
173
+ * A pinned plane prints the FULL commit id and the complete path — never a
174
+ * shortened id, because this is the value an operator compares against `git
175
+ * rev-parse`. A legacy plane says so in exactly one recognizable phrase and
176
+ * invents nothing.
177
+ */
178
+ function describeSnapshot(snapshot, restartSupported) {
179
+ if (snapshot.kind === "pinned") {
180
+ return [
181
+ ` status Pinned`,
182
+ ` commit ${snapshot.snapshot.sha}`,
183
+ ` path ${snapshot.snapshot.path}`,
184
+ " note The server, worker, and observer run from this commit, so moving your",
185
+ " checkout does not change them. `plane restart <member>` reuses it.",
186
+ " `plane down && plane up` moves the plane to NEW code: use it between",
187
+ " runs, because it stops a bound run.",
188
+ ];
189
+ }
190
+ return [
191
+ " status Unpinned (legacy)",
192
+ " note This plane does not record a code snapshot, so its Python members were",
193
+ " launched from your checkout and follow it when it moves. No pinned",
194
+ " commit or path is reported because none exists.",
195
+ restartSupported
196
+ ? " `plane restart <member>` still works; it reuses each member's original launch."
197
+ : " It was started by an older build, so `plane restart` is unavailable for it.",
198
+ " To move it to new code, use `plane down && plane up` between runs (it stops a bound run).",
199
+ ];
200
+ }
131
201
  /**
132
202
  * True for a member the manifest still records as pre-spawn.
133
203
  *
@@ -139,17 +209,34 @@ function isPreStart(member) {
139
209
  return member.state === "spawning" && member.pid === null;
140
210
  }
141
211
  export function describeMemberState(member, supervisorLiveness) {
212
+ // A restart in progress or a failed restart is the operator's own action, not a
213
+ // crash, and is worded as such (BAPI-1362). Both are read BEFORE the exit
214
+ // branches below, because a failed restart may record an exit status too.
215
+ if (member.state === "restarting") {
216
+ return `restarting (replacing pid ${member.pid ?? "?"}; status may change shortly)`.padEnd(34);
217
+ }
218
+ if (member.restartFailure !== undefined) {
219
+ const process = member.liveness === "alive" ? `replacement pid ${member.pid ?? "?"} still running` : "no process running";
220
+ return `restart FAILED (${member.restartFailure}; ${process})`.padEnd(34);
221
+ }
142
222
  // Precedence below is unchanged and load-bearing: a live pid, then a recorded
143
223
  // signal, then a recorded code, then unverifiable liveness. The pre-start
144
224
  // cases are appended after all four, so they can only ever claim a member
145
225
  // about which nothing else is known.
146
226
  if (member.liveness === "alive") {
147
- return `running (pid ${member.pid ?? "?"})`.padEnd(34);
227
+ // `ready` is the manifest's record that the member passed its readiness gate;
228
+ // `running` alone means it was spawned and the gate was not (yet) confirmed.
229
+ const readiness = member.state === "ready" ? "ready" : "readiness not confirmed";
230
+ return `running (pid ${member.pid ?? "?"}, ${readiness})`.padEnd(34);
148
231
  }
149
232
  if (member.exitSignal !== null) {
150
233
  return `exited (signal ${member.exitSignal})`.padEnd(34);
151
234
  }
152
235
  if (member.exitCode !== null) {
236
+ if ((member.name === "worker" || member.name === "observer") &&
237
+ member.exitCode === WORKER_STALE_EXIT_CODE) {
238
+ return `exited (code 75: code on disk changed)`.padEnd(34);
239
+ }
153
240
  return `exited (code ${member.exitCode})`.padEnd(34);
154
241
  }
155
242
  if (member.liveness === "unknown") {
@@ -168,3 +255,55 @@ export function describeMemberState(member, supervisorLiveness) {
168
255
  }
169
256
  return `exited (no recorded exit status)`.padEnd(34);
170
257
  }
258
+ /**
259
+ * The single safest next action for one member, or null when none is needed
260
+ * (BAPI-1362).
261
+ *
262
+ * Scoped by design. A restartable member that is down gets `plane restart
263
+ * <member>` — which replaces only that member and leaves the pinned commit and
264
+ * the bound run alone. An executor lane gets run-level recovery, because
265
+ * per-member restart is unavailable for it and `plane restart executor-N` would
266
+ * be refused. `plane down && plane up` is named only where it is genuinely the
267
+ * remedy: no live supervisor to take a request, or a pinned snapshot that is gone.
268
+ *
269
+ * Pure, and built from fixed prose plus the member name, which `isPlaneMemberName`
270
+ * has already bounded — nothing here can carry a path or a credential.
271
+ */
272
+ export function describeMemberNextAction(member, context) {
273
+ const isExecutor = member.name.startsWith("executor-");
274
+ const down = member.liveness !== "alive" && member.state !== "restarting" && !isPreStart(member);
275
+ const keeps = context.pinnedSha !== undefined
276
+ ? `it keeps the pinned commit ${context.pinnedSha.slice(0, 12)} and the bound run`
277
+ : "it leaves the rest of the plane and the bound run running";
278
+ if (member.state === "restarting") {
279
+ return "a restart is in progress — run `plane status` again shortly; do not start another.";
280
+ }
281
+ if (isExecutor) {
282
+ return down
283
+ ? "per-member restart is unavailable for an executor lane — recover at the run level (re-attach with `drive-epic`)."
284
+ : null;
285
+ }
286
+ if (!down && member.restartFailure === undefined)
287
+ return null;
288
+ if (context.supervisorLiveness !== "alive") {
289
+ return "the supervisor is not running, so this member cannot be restarted — `plane down`, then `plane up`.";
290
+ }
291
+ if (!context.restartSupported) {
292
+ return ("this plane was started by an older build, so `plane restart` is unavailable — " +
293
+ "between runs, `plane down && plane up` moves it to new code (it stops a bound run).");
294
+ }
295
+ switch (member.restartFailure) {
296
+ case "stop-incomplete":
297
+ return `the old process would not exit — inspect ${member.logPath}, then \`plane restart ${member.name}\` again.`;
298
+ case "readiness":
299
+ return (`the replacement did not become ready — inspect ${member.logPath}, then ` +
300
+ `\`plane restart ${member.name}\` again (${keeps}).`);
301
+ case "snapshot":
302
+ return ("the pinned code could not be revalidated — restore it, or between runs " +
303
+ "`plane down && plane up` moves the plane to new code (it stops a bound run).");
304
+ case "spawn":
305
+ return `the replacement could not be started — inspect ${member.logPath}, then \`plane restart ${member.name}\` again.`;
306
+ default:
307
+ return `\`plane restart ${member.name}\` — ${keeps}.`;
308
+ }
309
+ }