@bridge_gpt/mcp-server 0.2.16 → 0.2.19

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 (103) hide show
  1. package/CONDUCTOR.md +75 -0
  2. package/README.md +2 -2
  3. package/build/agent-capabilities/probe-context.js +13 -3
  4. package/build/agent-capabilities/probes.js +262 -11
  5. package/build/agent-capabilities/reporter.js +1 -0
  6. package/build/agents.generated.js +3 -3
  7. package/build/backend-warnings.js +44 -0
  8. package/build/claude-settings.js +129 -0
  9. package/build/commands.generated.js +7 -6
  10. package/build/conductor/bridge-api-client.js +198 -18
  11. package/build/conductor/claude-hook.js +22 -4
  12. package/build/conductor/cli.js +76 -25
  13. package/build/conductor/deny-enforcement-preflight.js +96 -0
  14. package/build/conductor/doctor.js +183 -2
  15. package/build/conductor/done-gate.js +5 -0
  16. package/build/conductor/epic-reconcile.js +71 -14
  17. package/build/conductor/epic-runtime.js +839 -67
  18. package/build/conductor/epic-state.js +524 -63
  19. package/build/conductor/errors.js +156 -3
  20. package/build/conductor/event-accessors.js +252 -0
  21. package/build/conductor/file-scope-guard.js +201 -0
  22. package/build/conductor/github-mergeability.js +85 -0
  23. package/build/conductor/local-merge.js +47 -1
  24. package/build/conductor/merge-identity.js +41 -0
  25. package/build/conductor/merge-ledger.js +19 -72
  26. package/build/conductor/plan.js +12 -2
  27. package/build/conductor/pr-ci-producer.js +17 -2
  28. package/build/conductor/pr-discovery.js +11 -1
  29. package/build/conductor/producer-ledger.js +1 -1
  30. package/build/conductor/store.js +161 -18
  31. package/build/conductor/supervisor-config.js +4 -39
  32. package/build/conductor/supervisor-escalation.js +10 -26
  33. package/build/conductor/supervisor-ledger.js +5 -12
  34. package/build/conductor/supervisor-merge.js +32 -5
  35. package/build/conductor/supervisor-message-relay.js +2 -5
  36. package/build/conductor/supervisor-notification.js +1 -1
  37. package/build/conductor/supervisor-runtime.js +12 -54
  38. package/build/conductor/supervisor-state.js +4 -18
  39. package/build/conductor/supervisor-types.js +2 -2
  40. package/build/conductor/taxonomy.js +12 -0
  41. package/build/conductor/tools.js +28 -6
  42. package/build/conductor/worker-ledger-cli.js +244 -0
  43. package/build/conductor-bin.js +1800 -5166
  44. package/build/conductor-claude-hook-bin.js +4 -2
  45. package/build/doctor.js +40 -0
  46. package/build/executor/cli.js +229 -0
  47. package/build/executor/credentials.js +65 -0
  48. package/build/executor/deps.js +117 -0
  49. package/build/executor/env.js +79 -0
  50. package/build/executor/heartbeat.js +59 -0
  51. package/build/executor/http-client.js +131 -0
  52. package/build/executor/index.js +10 -0
  53. package/build/executor/job-errors.js +55 -0
  54. package/build/executor/job-log-registry.js +110 -0
  55. package/build/executor/job-runner.js +688 -0
  56. package/build/executor/job-types.js +60 -0
  57. package/build/executor/merge-job.js +155 -0
  58. package/build/executor/observation.js +123 -0
  59. package/build/executor/permissions.js +79 -0
  60. package/build/executor/preflight.js +144 -0
  61. package/build/executor/process.js +81 -0
  62. package/build/executor/prompt-spec.js +235 -0
  63. package/build/executor/results.js +134 -0
  64. package/build/executor/resume-pre-spawn.js +179 -0
  65. package/build/executor/runner.js +98 -0
  66. package/build/executor/terminal-mutation.js +34 -0
  67. package/build/executor/test-clock.js +109 -0
  68. package/build/executor/types.js +18 -0
  69. package/build/executor/verdict-artifact.js +53 -0
  70. package/build/executor/viewer-tabs.js +78 -0
  71. package/build/executor/watch-cli.js +113 -0
  72. package/build/executor/worker-command.js +106 -0
  73. package/build/executor/worker-finalization.js +97 -0
  74. package/build/executor/worker-log.js +92 -0
  75. package/build/executor/worktree-gc.js +134 -0
  76. package/build/executor/worktree-inspection.js +86 -0
  77. package/build/executor/worktree.js +103 -0
  78. package/build/index.js +13950 -9669
  79. package/build/install-bridge.js +25 -8
  80. package/build/install-doctor.js +387 -0
  81. package/build/mcp-invoke.js +19 -3
  82. package/build/mcp-provisioning.js +31 -25
  83. package/build/mcp-registration-doctor.js +27 -7
  84. package/build/mcp-server-invocation.js +152 -0
  85. package/build/pipelines.generated.js +31 -6
  86. package/build/readme.generated.js +1 -1
  87. package/build/regression-check.js +53 -1
  88. package/build/review-tickets.js +175 -21
  89. package/build/sfcc/reads-site-preference.js +52 -19
  90. package/build/start-tickets-conductor.js +47 -99
  91. package/build/start-tickets-prereqs.js +185 -4
  92. package/build/start-tickets.js +218 -180
  93. package/build/version.generated.js +1 -1
  94. package/build/visual-diff-worker.js +313 -0
  95. package/build/visual-diff.js +632 -0
  96. package/build/worktree-core.js +202 -0
  97. package/package.json +10 -6
  98. package/pipelines/review-ticket.json +24 -2
  99. package/public/css/main.min.css +3311 -1
  100. package/public/css/main.min.css.map +1 -1
  101. package/public/js/main.min.js +7924 -1
  102. package/public/js/main.min.js.map +1 -1
  103. package/smoke-test/SMOKE-TEST.md +5 -2
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Worker-side conductor-ledger subprocess boundary (BAPI-527, durable execution).
3
+ *
4
+ * CORE INVARIANT: only the CAPTURED CONDUCTOR NODE touches the `better-sqlite3`
5
+ * native binary. A dispatched worker's Node process must NEVER import or load it.
6
+ * Every worker-facing ledger operation (`check_messages`, and the
7
+ * `wait_for_done_gate` event emit) therefore runs through this module, which
8
+ * shells out to the packaged `conductor-bin.js` CLI executed by the conductor
9
+ * Node runtime captured at dispatch time in `CONDUCTOR_NODE_PATH`. Conductor-OWNED
10
+ * processes (the CLI itself, the supervisor/epic runtimes) keep calling
11
+ * `store.ts` directly — they legitimately own the native load.
12
+ *
13
+ * Hard-fail contract: when `CONDUCTOR_NODE_PATH` is missing/invalid or
14
+ * `BAPI_CONDUCTOR_CLI_FILE` is absent, this boundary throws a typed
15
+ * {@link ConductorLedgerSubprocessRuntimeError} rather than silently falling back
16
+ * to the worker's own `process.execPath`. Falling back would re-introduce the
17
+ * native load into the worker Node — the exact failure mode this slice removes.
18
+ *
19
+ * Security: argv is always a fixed LIST (`execFile`, never `shell: true`, never a
20
+ * command string). Event JSON payloads cross via STDIN (`--data-json-stdin`), so
21
+ * raw payloads/secrets never enter the process argument list. Every failure is
22
+ * converted to a sanitized typed error — no raw caught error, path, argv, stdout,
23
+ * stderr, or credential value is ever attached.
24
+ */
25
+ import * as nodeChildProcess from "node:child_process";
26
+ import { isAbsolute as pathIsAbsolute } from "node:path";
27
+ import { ConductorLedgerSubprocessRuntimeError, } from "./errors.js";
28
+ import { makeProducerDedupeKey, makeStableProducerEventId, } from "./producer-ledger.js";
29
+ /** The env key that carries the captured conductor Node executable path. */
30
+ export const CONDUCTOR_NODE_PATH_ENV = "CONDUCTOR_NODE_PATH";
31
+ /** The (pre-existing) env key that carries the packaged `conductor-bin.js` path. */
32
+ export const BAPI_CONDUCTOR_CLI_FILE_ENV = "BAPI_CONDUCTOR_CLI_FILE";
33
+ /**
34
+ * Bounded stdout buffer for a conductor CLI response. Conductor JSON responses
35
+ * (message batches / emit summaries) are small; 8 MiB is generous headroom while
36
+ * still capping a runaway subprocess.
37
+ */
38
+ export const WORKER_LEDGER_CLI_MAX_BUFFER = 8 * 1024 * 1024;
39
+ /**
40
+ * Hard wall-clock cap for a single conductor CLI subprocess. A hung
41
+ * `conductor-bin.js` must never hang `check_messages` / `wait_for_done_gate`
42
+ * indefinitely; `execFile`'s `timeout` kills the child and surfaces the callback
43
+ * error (mapped to a sanitized `spawn_failed`). Generous relative to a fast local
44
+ * ledger read/write, but bounded.
45
+ */
46
+ export const WORKER_LEDGER_CLI_TIMEOUT_MS = 30_000;
47
+ const defaultExecFile = (file, args, options, callback) =>
48
+ // The narrowed signature (utf-8 string stdout/stderr + list argv, no shell) is a
49
+ // safe structural subset of Node's execFile overloads.
50
+ nodeChildProcess.execFile(file, args, options, callback);
51
+ function nonEmpty(value) {
52
+ return typeof value === "string" && value.trim().length > 0;
53
+ }
54
+ /**
55
+ * Validate and resolve the worker-ledger subprocess runtime from the environment.
56
+ *
57
+ * `CONDUCTOR_NODE_PATH` must be set, non-empty, and an ABSOLUTE path (a relative
58
+ * value like `node` / `./node` is rejected as `invalid` — it must never resolve
59
+ * against `PATH` or the worker cwd). `BAPI_CONDUCTOR_CLI_FILE` must be set and
60
+ * non-empty. On any failure this throws a typed
61
+ * {@link ConductorLedgerSubprocessRuntimeError}; it NEVER falls back to
62
+ * `process.execPath`.
63
+ */
64
+ export function resolveWorkerLedgerCliRuntime(deps = {}) {
65
+ const env = deps.env ?? process.env;
66
+ const isAbsolute = deps.isAbsolute ?? pathIsAbsolute;
67
+ const nodePathRaw = env[CONDUCTOR_NODE_PATH_ENV];
68
+ if (!nonEmpty(nodePathRaw)) {
69
+ throw new ConductorLedgerSubprocessRuntimeError("missing", CONDUCTOR_NODE_PATH_ENV);
70
+ }
71
+ const nodePath = nodePathRaw.trim();
72
+ if (!isAbsolute(nodePath)) {
73
+ throw new ConductorLedgerSubprocessRuntimeError("invalid", CONDUCTOR_NODE_PATH_ENV);
74
+ }
75
+ const cliFileRaw = env[BAPI_CONDUCTOR_CLI_FILE_ENV];
76
+ if (!nonEmpty(cliFileRaw)) {
77
+ throw new ConductorLedgerSubprocessRuntimeError("cli_missing", BAPI_CONDUCTOR_CLI_FILE_ENV);
78
+ }
79
+ return { nodePath, cliFile: cliFileRaw.trim() };
80
+ }
81
+ /**
82
+ * Execute one conductor CLI subcommand under the captured conductor Node and
83
+ * resolve its raw stdout. argv is a fixed LIST — `[cliFile, ...subcommandArgs]` —
84
+ * spawned via `execFile` with `shell` disabled. An optional `stdin` payload is
85
+ * written to the child's stdin (used for `--data-json-stdin`) so raw payloads
86
+ * never enter argv. Any spawn error or abnormal exit is converted to a sanitized
87
+ * {@link ConductorLedgerSubprocessRuntimeError} — the raw error, stderr, and
88
+ * stdout are discarded so no path/secret leaks.
89
+ */
90
+ export function execConductorCli(subcommandArgs, stdin, deps = {}) {
91
+ const runtime = resolveWorkerLedgerCliRuntime(deps);
92
+ const execFile = deps.execFile ?? defaultExecFile;
93
+ const maxBuffer = deps.maxBuffer ?? WORKER_LEDGER_CLI_MAX_BUFFER;
94
+ const timeout = deps.timeout ?? WORKER_LEDGER_CLI_TIMEOUT_MS;
95
+ const argv = [runtime.cliFile, ...subcommandArgs];
96
+ return new Promise((resolve, reject) => {
97
+ let child;
98
+ try {
99
+ child = execFile(runtime.nodePath, argv,
100
+ // A `timeout` bounds a hung child; the kill surfaces as the callback error
101
+ // (mapped below to a sanitized spawn_failed) rather than an infinite hang.
102
+ { maxBuffer, encoding: "utf8", timeout }, (error, stdout) => {
103
+ if (error) {
104
+ // A non-zero exit, spawn failure, or timeout kill — never surface the
105
+ // raw error text (it can carry paths/secrets). Fixed reason only.
106
+ reject(new ConductorLedgerSubprocessRuntimeError("spawn_failed", CONDUCTOR_NODE_PATH_ENV));
107
+ return;
108
+ }
109
+ resolve(stdout);
110
+ });
111
+ }
112
+ catch {
113
+ reject(new ConductorLedgerSubprocessRuntimeError("spawn_failed", CONDUCTOR_NODE_PATH_ENV));
114
+ return;
115
+ }
116
+ if (stdin !== undefined) {
117
+ // A writable-stream 'error' (e.g. EPIPE when the child exits early) is emitted
118
+ // ASYNCHRONOUSLY and, without a listener, becomes an uncaught exception that
119
+ // crashes the whole worker process. Attach a no-op handler so the failure is
120
+ // absorbed here; the exec callback still surfaces the underlying failure as a
121
+ // sanitized spawn_failed. Never echo the raw error.
122
+ child.stdin?.on("error", () => {
123
+ /* swallowed: the exec callback owns the failure signal */
124
+ });
125
+ try {
126
+ child.stdin?.write(stdin);
127
+ child.stdin?.end();
128
+ }
129
+ catch {
130
+ // A synchronous write failure surfaces through the exec callback as a spawn
131
+ // error; do not throw here (and do not echo the raw failure).
132
+ }
133
+ }
134
+ });
135
+ }
136
+ /**
137
+ * Parse compact CLI JSON from stdout. Malformed output becomes a sanitized typed
138
+ * {@link ConductorLedgerSubprocessRuntimeError} (`malformed_stdout`) — the raw
139
+ * stdout is never attached to the thrown error.
140
+ */
141
+ export function parseCliJsonStdout(stdout) {
142
+ try {
143
+ return JSON.parse(stdout);
144
+ }
145
+ catch {
146
+ throw new ConductorLedgerSubprocessRuntimeError("malformed_stdout", CONDUCTOR_NODE_PATH_ENV);
147
+ }
148
+ }
149
+ /**
150
+ * Read + ACK a worker's pending relay messages through the conductor CLI, i.e.
151
+ * `conductor-bin.js check-messages --run-id <id> --worker-id <id> [--limit <n>] --json`.
152
+ * Returns the parsed {@link CheckWorkerMessagesResult}. Never touches the local
153
+ * SQLite store from the worker Node.
154
+ */
155
+ export async function checkWorkerMessagesViaCli(input, deps = {}) {
156
+ const args = ["check-messages", "--run-id", input.runId, "--worker-id", input.workerId];
157
+ if (input.limit !== undefined) {
158
+ args.push("--limit", String(input.limit));
159
+ }
160
+ args.push("--json");
161
+ const stdout = await execConductorCli(args, undefined, deps);
162
+ return parseCliJsonStdout(stdout);
163
+ }
164
+ /**
165
+ * Build the `emit-event` envelope argv (everything EXCEPT the normalized `data`
166
+ * object, which crosses via stdin through `--data-json-stdin`). Mirrors the
167
+ * claude-hook emit contract so raw payloads/secrets never reach the argument list.
168
+ */
169
+ export function buildEmitEventArgs(event) {
170
+ const args = ["emit-event", "--type", event.type, "--source", event.source];
171
+ // Forward the deterministic event id so the conductor process dedups server-side
172
+ // on the `events.id` UNIQUE constraint — this is what lets the worker skip the
173
+ // in-process `eventAlreadyExists` poll (which would load better-sqlite3).
174
+ if (nonEmpty(event.id ?? undefined))
175
+ args.push("--id", event.id);
176
+ if (nonEmpty(event.subject ?? undefined))
177
+ args.push("--subject", event.subject);
178
+ if (nonEmpty(event.run_id ?? undefined))
179
+ args.push("--run-id", event.run_id);
180
+ if (nonEmpty(event.worker_id ?? undefined))
181
+ args.push("--worker-id", event.worker_id);
182
+ if (nonEmpty(event.producer ?? undefined))
183
+ args.push("--producer", event.producer);
184
+ if (nonEmpty(event.observed_via ?? undefined)) {
185
+ args.push("--observed-via", event.observed_via);
186
+ }
187
+ if (event.schema_version !== undefined) {
188
+ args.push("--schema-version", String(event.schema_version));
189
+ }
190
+ if (nonEmpty(event.time ?? undefined))
191
+ args.push("--time", event.time);
192
+ if (typeof event.confidence === "number") {
193
+ args.push("--confidence", String(event.confidence));
194
+ }
195
+ args.push("--data-json-stdin", "--json");
196
+ return args;
197
+ }
198
+ /**
199
+ * Emit one conductor event through the CLI, i.e.
200
+ * `conductor-bin.js emit-event ... --data-json-stdin --json`, passing the
201
+ * normalized `data` object over STDIN rather than argv. Returns the parsed CLI
202
+ * JSON result. Never touches the local SQLite store from the worker Node.
203
+ */
204
+ export async function emitConductorEventViaCli(event, deps = {}) {
205
+ const args = buildEmitEventArgs(event);
206
+ const stdinPayload = JSON.stringify(event.data ?? {});
207
+ const stdout = await execConductorCli(args, stdinPayload, deps);
208
+ return parseCliJsonStdout(stdout);
209
+ }
210
+ /**
211
+ * Dedup-aware event emit through the CLI, with NO in-process ledger access.
212
+ *
213
+ * This is the worker gate path's replacement for the in-process
214
+ * {@link emitConductorEventIfNew}: the dedupe key + deterministic event id are
215
+ * derived PURELY (hashing only — no store read), the id is forwarded to the CLI
216
+ * (`emit-event --id`), and the conductor process performs the dedup server-side on
217
+ * the `events.id` UNIQUE constraint. Because the pre-check `eventAlreadyExists`
218
+ * poll is gone, a dispatched worker calling `wait_for_done_gate` never loads
219
+ * `better-sqlite3` — closing the exact gap BAPI-527 targets. A conductor-side
220
+ * duplicate is reported back as `{ ok: false, reason: "duplicate" }`.
221
+ */
222
+ export async function emitConductorEventIfNewViaCli(input, dimensions, deps = {}) {
223
+ const dedupeKey = makeProducerDedupeKey(dimensions);
224
+ const eventId = makeStableProducerEventId(dedupeKey);
225
+ // Embed the dedupe key under data.details (mirrors emitConductorEventIfNew) so a
226
+ // later ledger scan can still recognize the event, without disturbing other
227
+ // normalized details the caller supplied.
228
+ const existingData = input.data ?? {};
229
+ const existingDetails = existingData.details && typeof existingData.details === "object" && !Array.isArray(existingData.details)
230
+ ? existingData.details
231
+ : {};
232
+ const data = {
233
+ ...existingData,
234
+ details: { ...existingDetails, dedupe_key: dedupeKey },
235
+ };
236
+ const result = (await emitConductorEventViaCli({ ...input, id: eventId, data }, deps));
237
+ // The conductor CLI reports a UNIQUE-constraint collision as a structured
238
+ // duplicate rather than an error — treat that as a no-op dedup, everything else
239
+ // as a successful emit of the deterministic id.
240
+ if (result && result.ok === false && result.reason === "duplicate") {
241
+ return { emitted: false, reason: "duplicate" };
242
+ }
243
+ return { emitted: true, event_id: eventId };
244
+ }