@bridge_gpt/mcp-server 0.2.66 → 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.
- package/README.md +252 -77
- package/build/agent-capabilities/probes.js +15 -5
- package/build/agent-launchers/claude-executor-adapter.js +43 -16
- package/build/agent-launchers/executor-adapter.js +7 -4
- package/build/agents.generated.js +1 -1
- package/build/bounded-wait.js +67 -10
- package/build/commands.generated.js +11 -11
- package/build/conductor/bridge-api-client.js +143 -1
- package/build/conductor/bring-up-facts.js +1 -1
- package/build/conductor/doctor.js +3 -3
- package/build/conductor/epic-implementer-cli.js +22 -6
- package/build/conductor/errors.js +4 -3
- package/build/conductor/guided-repair.js +6 -2
- package/build/conductor/hook-runtime-qualification.js +1 -1
- package/build/conductor/merge-execution-contract.js +27 -8
- package/build/conductor/merge-execution-eligibility.js +3 -2
- package/build/conductor/pr-ci-producer.js +1 -1
- package/build/conductor/readiness-cli.js +18 -2
- package/build/conductor/readiness-sections.js +41 -6
- package/build/conductor/readiness.js +181 -29
- package/build/conductor/recovery-cli.js +200 -8
- package/build/conductor/recovery-operations.js +69 -3
- package/build/conductor/repair-contract.js +54 -3
- package/build/conductor/repository-workflow-remedy.js +125 -0
- package/build/conductor/tools.js +2 -2
- package/build/conductor-bundle-artifacts.js +8 -0
- package/build/docs.generated.js +8 -3
- package/build/drive-epic-key.js +6 -5
- package/build/drive-epic.js +85 -54
- package/build/epic-coherence-input.js +2 -1
- package/build/epic-implementer-bin.js +22 -20
- package/build/epic-implementer-bundle-cli.js +2 -2
- package/build/executor/cli.js +3 -2
- package/build/executor/completion-contract.js +48 -5
- package/build/executor/completion-supervision.js +4 -0
- package/build/executor/env.js +19 -0
- package/build/executor/heartbeat.js +1 -1
- package/build/executor/http-client.js +20 -0
- package/build/executor/job-errors.js +25 -0
- package/build/executor/job-runner.js +225 -41
- package/build/executor/observation.js +6 -1
- package/build/executor/preflight.js +51 -14
- package/build/executor/required-work-ledger.js +6 -1
- package/build/executor/resume-pre-spawn.js +2 -0
- package/build/executor/runner.js +8 -2
- package/build/executor/service-unit.js +7 -1
- package/build/executor/worker-finalization.js +82 -29
- package/build/executor/worker-guard-hook.js +137 -33
- package/build/executor/worktree.js +82 -1
- package/build/index.js +403 -429
- package/build/install-bridge-conductor.js +8 -6
- package/build/install-bridge.js +3 -3
- package/build/phase-context-git-probe.js +68 -0
- package/build/phase-result-artifacts.js +173 -5
- package/build/pipelines.generated.js +18 -24
- package/build/plane/alembic-head.js +12 -3
- package/build/plane/base-worktree-guard.js +147 -0
- package/build/plane/cli.js +217 -17
- package/build/plane/code-snapshot.js +468 -0
- package/build/plane/defaults.js +48 -3
- package/build/plane/endpoint.js +41 -0
- package/build/plane/manifest.js +120 -1
- package/build/plane/member-roster.js +94 -19
- package/build/plane/preflight.js +30 -2
- package/build/plane/process-cwd.js +67 -0
- package/build/plane/restart.js +542 -0
- package/build/plane/shutdown.js +31 -0
- package/build/plane/status.js +143 -8
- package/build/plane/supervisor.js +586 -179
- package/build/plane/types.js +54 -2
- package/build/printed-remedy-commands.js +37 -0
- package/build/readiness-check.js +1 -1
- package/build/readme.generated.js +1 -1
- package/build/review-generation.js +22 -0
- package/build/setup-epic.js +44 -19
- package/build/sfcc/config.js +9 -0
- package/build/sfcc/credentials.js +100 -38
- package/build/sfcc/hostname.js +67 -0
- package/build/sfcc/permissions.js +17 -13
- package/build/sfcc/register.js +1 -1
- package/build/sfcc/tool-wrapper.js +39 -43
- package/build/sfcc/write-grants.js +17 -11
- package/build/sfcc/write-result.js +4 -3
- package/build/sfcc/writes-site-preference.js +20 -8
- package/build/start-tickets.js +179 -31
- package/build/tool-error-envelope.js +61 -0
- package/build/version.generated.js +3 -3
- package/build/visual-diff.js +22 -1
- package/build/worker-guard-hook-bin.js +3 -6
- package/build/worker-guard-hook-main.js +47 -0
- package/build/worktree-core.js +130 -4
- package/docs/EPIC-IMPLEMENTER-INSTALL.md +849 -0
- package/docs/EPIC-IMPLEMENTER.md +662 -0
- package/docs/install/mcp-tool-integrations.md +24 -15
- package/docs/install/sfcc-integration.md +12 -4
- package/package.json +1 -1
- package/pipelines/plan-epic.json +0 -5
- package/pipelines/review-ticket.json +1 -1
- package/docs/CONDUCTOR.md +0 -605
- package/pipelines/idea-to-pr.json +0 -49
package/build/plane/status.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
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
11
|
import { WORKER_STALE_EXIT_CODE } from "./worker-exit-code.js";
|
|
12
12
|
/** Read the manifest and probe every recorded pid. Strictly read-only. */
|
|
13
13
|
export async function getPlaneStatus(repoRoot, deps) {
|
|
@@ -35,6 +35,8 @@ export async function getPlaneStatus(repoRoot, deps) {
|
|
|
35
35
|
unrecognizedMemberNames: read.unrecognizedMemberNames,
|
|
36
36
|
lifecycle: planeManifestLifecycle(manifest),
|
|
37
37
|
epicRunId: manifest.epicRunId ?? null,
|
|
38
|
+
snapshot: planeManifestSnapshot(manifest),
|
|
39
|
+
restartSupported: manifest.schemaVersion >= PLANE_RESTART_MIN_SCHEMA_VERSION,
|
|
38
40
|
createdAt: manifest.createdAt,
|
|
39
41
|
updatedAt: manifest.updatedAt,
|
|
40
42
|
members: probeManifestMembers(manifest, deps.proc).map((probe) => ({
|
|
@@ -45,6 +47,10 @@ export async function getPlaneStatus(repoRoot, deps) {
|
|
|
45
47
|
exitCode: probe.member.exitCode,
|
|
46
48
|
exitSignal: probe.member.exitSignal,
|
|
47
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
|
+
: {}),
|
|
48
54
|
})),
|
|
49
55
|
};
|
|
50
56
|
}
|
|
@@ -78,7 +84,19 @@ function describeLifecycle(phase) {
|
|
|
78
84
|
"left running; nothing is claiming jobs. Wind it down with `plane down`.");
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
|
-
/**
|
|
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
|
+
*/
|
|
82
100
|
export function formatPlaneStatus(result) {
|
|
83
101
|
if (!result.ok)
|
|
84
102
|
return `plane status FAILED: ${result.error}`;
|
|
@@ -93,10 +111,22 @@ export function formatPlaneStatus(result) {
|
|
|
93
111
|
` started ${result.createdAt}`,
|
|
94
112
|
` updated ${result.updatedAt}`,
|
|
95
113
|
"",
|
|
114
|
+
"Code snapshot",
|
|
115
|
+
...describeSnapshot(result.snapshot, result.restartSupported),
|
|
116
|
+
"",
|
|
117
|
+
"Members",
|
|
96
118
|
];
|
|
119
|
+
const context = {
|
|
120
|
+
supervisorLiveness: result.supervisorLiveness,
|
|
121
|
+
restartSupported: result.restartSupported,
|
|
122
|
+
...(result.snapshot.kind === "pinned" ? { pinnedSha: result.snapshot.snapshot.sha } : {}),
|
|
123
|
+
};
|
|
97
124
|
for (const member of result.members) {
|
|
98
125
|
lines.push(` ${member.name.padEnd(12)} ${describeMemberState(member, result.supervisorLiveness)} ` +
|
|
99
126
|
`${member.logPath}`);
|
|
127
|
+
const next = describeMemberNextAction(member, context);
|
|
128
|
+
if (next !== null)
|
|
129
|
+
lines.push(` next: ${next}`);
|
|
100
130
|
}
|
|
101
131
|
if (result.unrecognizedMemberNames.length > 0) {
|
|
102
132
|
// Never a silent omission. The plane really has more members than the list
|
|
@@ -121,14 +151,53 @@ export function formatPlaneStatus(result) {
|
|
|
121
151
|
// Members that genuinely ran and exited keep the original no-restart warning;
|
|
122
152
|
// one that never started was not restarted for an entirely different reason,
|
|
123
153
|
// and telling the operator to "read the log above" would be a dead end.
|
|
124
|
-
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");
|
|
125
155
|
if (holes.length > 0) {
|
|
126
156
|
lines.push("");
|
|
127
157
|
lines.push(`${holes.length} member(s) are not running. They are NOT restarted automatically — ` +
|
|
128
|
-
"read the log(s) above, then
|
|
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
|
+
}
|
|
129
167
|
}
|
|
130
168
|
return lines.join("\n");
|
|
131
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
|
+
}
|
|
132
201
|
/**
|
|
133
202
|
* True for a member the manifest still records as pre-spawn.
|
|
134
203
|
*
|
|
@@ -140,19 +209,33 @@ function isPreStart(member) {
|
|
|
140
209
|
return member.state === "spawning" && member.pid === null;
|
|
141
210
|
}
|
|
142
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
|
+
}
|
|
143
222
|
// Precedence below is unchanged and load-bearing: a live pid, then a recorded
|
|
144
223
|
// signal, then a recorded code, then unverifiable liveness. The pre-start
|
|
145
224
|
// cases are appended after all four, so they can only ever claim a member
|
|
146
225
|
// about which nothing else is known.
|
|
147
226
|
if (member.liveness === "alive") {
|
|
148
|
-
|
|
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);
|
|
149
231
|
}
|
|
150
232
|
if (member.exitSignal !== null) {
|
|
151
233
|
return `exited (signal ${member.exitSignal})`.padEnd(34);
|
|
152
234
|
}
|
|
153
235
|
if (member.exitCode !== null) {
|
|
154
|
-
if ((member.name === "worker" || member.name === "observer") &&
|
|
155
|
-
|
|
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);
|
|
156
239
|
}
|
|
157
240
|
return `exited (code ${member.exitCode})`.padEnd(34);
|
|
158
241
|
}
|
|
@@ -172,3 +255,55 @@ export function describeMemberState(member, supervisorLiveness) {
|
|
|
172
255
|
}
|
|
173
256
|
return `exited (no recorded exit status)`.padEnd(34);
|
|
174
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
|
+
}
|