@bridge_gpt/mcp-server 0.2.41 → 0.2.43

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 (88) hide show
  1. package/README.md +330 -191
  2. package/build/agent-capabilities/cli.js +2 -1
  3. package/build/agent-launchers/claude-executor-adapter.js +17 -4
  4. package/build/agents.generated.js +2 -2
  5. package/build/claude-review-workflow.js +510 -45
  6. package/build/claude-user-config-doctor.js +42 -11
  7. package/build/cli-release.js +2 -1
  8. package/build/commands.generated.js +6 -5
  9. package/build/conduct-epic/bridge-client.js +354 -113
  10. package/build/conduct-epic/checkpoint-store.js +17 -0
  11. package/build/conduct-epic/cli.js +947 -99
  12. package/build/conduct-epic/cut-protocol.js +327 -0
  13. package/build/conduct-epic/spawn.js +14 -2
  14. package/build/conductor/bridge-api-client.js +148 -1
  15. package/build/conductor/cli.js +109 -1
  16. package/build/conductor/doctor.js +101 -16
  17. package/build/conductor/epic-reconcile.js +72 -19
  18. package/build/conductor/epic-runtime.js +15 -3
  19. package/build/conductor/errors.js +47 -0
  20. package/build/conductor/git-hooks.js +205 -11
  21. package/build/conductor/install-doctor.js +230 -1
  22. package/build/conductor/local-merge.js +130 -28
  23. package/build/conductor/recovery-cli.js +313 -0
  24. package/build/conductor/recovery-operations.js +219 -0
  25. package/build/conductor/tools.js +32 -3
  26. package/build/conductor/worker-ledger-cli.js +27 -1
  27. package/build/conductor-bin.js +20 -16
  28. package/build/credentials-cli.js +3 -2
  29. package/build/docs.generated.js +2 -1
  30. package/build/doctor.js +120 -44
  31. package/build/drive-epic.js +375 -0
  32. package/build/executor/cli.js +48 -1
  33. package/build/executor/env.js +21 -0
  34. package/build/executor/http-client.js +71 -3
  35. package/build/executor/index-scope.js +39 -0
  36. package/build/executor/job-errors.js +9 -0
  37. package/build/executor/job-log-registry.js +69 -0
  38. package/build/executor/job-runner.js +198 -29
  39. package/build/executor/live-worker-registry.js +83 -0
  40. package/build/executor/observation.js +259 -6
  41. package/build/executor/platform.js +147 -3
  42. package/build/executor/process.js +58 -14
  43. package/build/executor/runner.js +454 -48
  44. package/build/executor/test-clock.js +3 -2
  45. package/build/executor/worker-finalization.js +233 -56
  46. package/build/executor/worktree.js +8 -1
  47. package/build/index-scope-contract.js +96 -0
  48. package/build/index.js +2277 -270
  49. package/build/init.js +83 -22
  50. package/build/install-bridge-conductor.js +323 -14
  51. package/build/install-bridge.js +225 -47
  52. package/build/install-doctor.js +23 -9
  53. package/build/install-reexec.js +2 -1
  54. package/build/launcher-config-inspection.js +83 -22
  55. package/build/mcp-host-config.js +331 -67
  56. package/build/mcp-host-targets.js +45 -21
  57. package/build/mcp-identity.js +92 -0
  58. package/build/mcp-install-state.js +94 -1
  59. package/build/mcp-invoke.js +2 -1
  60. package/build/mcp-provisioning.js +45 -12
  61. package/build/mcp-registration-doctor.js +35 -13
  62. package/build/mcp-server-invocation.js +4 -2
  63. package/build/merge-pull-request.js +208 -9
  64. package/build/pipelines.generated.js +305 -15
  65. package/build/plane/cli.js +73 -7
  66. package/build/plane/defaults.js +18 -5
  67. package/build/plane/manifest.js +90 -0
  68. package/build/plane/preflight.js +100 -10
  69. package/build/plane/shutdown.js +71 -3
  70. package/build/plane/test-fakes.js +9 -1
  71. package/build/readme.generated.js +1 -1
  72. package/build/regression-check.js +3 -2
  73. package/build/review-tickets.js +8 -7
  74. package/build/run-unit-tests-launcher.js +149 -6
  75. package/build/schedule-run.js +3 -2
  76. package/build/setup-epic.js +531 -82
  77. package/build/sfcc/tool-wrapper.js +15 -0
  78. package/build/start-tickets-prereqs.js +11 -6
  79. package/build/start-tickets.js +91 -85
  80. package/build/update-check.js +3 -2
  81. package/build/upgrade-advice.js +2 -1
  82. package/build/upgrade-cli.js +50 -18
  83. package/build/version.generated.js +2 -1
  84. package/build/worktree-core.js +31 -17
  85. package/docs/CONDUCTOR.md +22 -0
  86. package/docs/install/mcp-tool-integrations.md +19 -3
  87. package/package.json +2 -2
  88. package/pipelines/greenfield-setup.json +286 -0
@@ -20,6 +20,20 @@ import { readdirSync } from "fs";
20
20
  import { spawnSync } from "child_process";
21
21
  import path from "path";
22
22
  const DEFAULT_BUILD_DIR = "build";
23
+ // BAPI-877 — the SECOND directory the unit lane discovers. `mcp_server/scripts/`
24
+ // holds hand-authored ESM (`"type": "module"`) that the build itself runs:
25
+ // bundle-version.js, sync-agent-mirrors.js, and friends. They are NOT tsc inputs
26
+ // (tsconfig.json is rootDir "src" / include "src/**/*.ts"), so they compile to
27
+ // nothing and a `*.test.js` beside them has no build/ counterpart to discover.
28
+ // Before this constant existed, such a file ran in NO lane at all: not `npm
29
+ // test` (which walked build/ only), not the integration lane, not the pre-push
30
+ // gate. sync-agent-mirrors.test.js sat unrun for months that way.
31
+ //
32
+ // Discovered from source rather than from build/ for that reason, and unioned
33
+ // into the "normal" group — a `scripts/…` path can never match the
34
+ // build/integration/ prefix, so it needs no filter change to land there.
35
+ const SCRIPT_TEST_DIR = "scripts";
36
+ export const SCRIPTS_DIR_PREFIX = "scripts/";
23
37
  // The Windows CreateProcess command-line limit is ~8191 characters. This
24
38
  // budget stays well under it (accounting for execPath + node options +
25
39
  // separators) so a single batch can never approach the real ceiling even on a
@@ -28,9 +42,9 @@ const DEFAULT_BUILD_DIR = "build";
28
42
  export const MAX_COMMAND_LENGTH = 6000;
29
43
  // Explicit manifest: only tests that call node:test's `mock.module()` API
30
44
  // need --experimental-test-module-mocks. Everything else discovered under
31
- // build/ is eligible for the "normal" group automatically — new tests do NOT
32
- // need to be registered anywhere else. Add an entry here only when a new test
33
- // needs module mocking.
45
+ // build/ OR scripts/ is eligible for the "normal" group automatically — new
46
+ // tests do NOT need to be registered anywhere else. Add an entry here only when
47
+ // a new test needs module mocking.
34
48
  export const MODULE_MOCK_MANIFEST = [
35
49
  "build/attachment-download.test.js",
36
50
  "build/attachment-upload.test.js",
@@ -40,6 +54,8 @@ export const MODULE_MOCK_MANIFEST = [
40
54
  "build/conductor/git-inspection.test.js",
41
55
  "build/conductor/paths.test.js",
42
56
  "build/conductor/pr-ci-producer-emit-seam.test.js",
57
+ "build/conductor/recovery-cli.test.js",
58
+ "build/conductor/recovery-operations.test.js",
43
59
  "build/conductor/security-regressions.test.js",
44
60
  "build/conductor/store-lifecycle.test.js",
45
61
  "build/conductor/store-queries.test.js",
@@ -57,6 +73,7 @@ export const MODULE_MOCK_MANIFEST = [
57
73
  "build/index-heavy-read-truncation.test.js",
58
74
  "build/index-output-path.test.js",
59
75
  "build/index.review-rounds.test.js",
76
+ "build/plane/cli.test.js",
60
77
  "build/recovery-formatting.test.js",
61
78
  "build/sfcc/client.test.js",
62
79
  "build/sfcc/permissions.test.js",
@@ -95,8 +112,24 @@ export const FORCE_EXIT_QUARANTINE = ["build/secret-safety.test.js"];
95
112
  // test:smoke`) — neither runs as part of `npm test`. `measure-tools.test.js`
96
113
  // is the one file under that directory that has always run as part of the
97
114
  // normal unit suite.
98
- const INTEGRATION_DIR_PREFIX = "build/integration/";
115
+ export const INTEGRATION_DIR_PREFIX = "build/integration/";
99
116
  const INTEGRATION_DIR_ALLOWLIST = new Set(["build/integration/measure-tools.test.js"]);
117
+ // BAPI-848 — files under build/integration/ that belong to a DIFFERENT lane and
118
+ // must therefore be excluded from integration discovery:
119
+ //
120
+ // * measure-tools.test.js runs in the normal unit lane (allowlisted above)
121
+ // * packaged-cli-smoke.test.js runs in `npm run test:smoke`
122
+ //
123
+ // This set is the entire registration surface for the integration lane. Adding a
124
+ // new build/integration/*.test.js requires editing NOTHING — which is the point:
125
+ // the old scripts.test:integration named every file explicitly on one line, so
126
+ // every ticket adding an integration test had to edit a line shared with every
127
+ // other integration test, and a file whose name was forgotten ran in no lane at
128
+ // all.
129
+ export const INTEGRATION_DISCOVERY_EXCLUSIONS = [
130
+ "build/integration/measure-tools.test.js",
131
+ "build/integration/packaged-cli-smoke.test.js",
132
+ ];
100
133
  // Compiled test files that live OUTSIDE build/integration/ but still belong to
101
134
  // the separately-invoked `npm run test:integration` lane, so the unit lane must
102
135
  // skip them. BAPI-683 originally introduced this set as
@@ -112,6 +145,10 @@ const INTEGRATION_DIR_ALLOWLIST = new Set(["build/integration/measure-tools.test
112
145
  // discovered into the unit lane automatically and needs no registration —
113
146
  // tests/pytest/mcp/test_mcp_server_test_registration_multicomponent.py fails if
114
147
  // a *.integration.test.ts ends up in neither lane.
148
+ //
149
+ // BAPI-877 — a `scripts/…` path must NEVER be listed here. This is not a style
150
+ // rule: `discoverIntegrationTestFiles` walks build/ only, so the entry would fail
151
+ // its own presence check below and throw on EVERY `npm run test:integration` run.
115
152
  export const INTEGRATION_LANE_ONLY = [
116
153
  "build/conductor/conductor-runtime.integration.test.js",
117
154
  ];
@@ -144,6 +181,55 @@ export function discoverTestFiles(options) {
144
181
  results.sort();
145
182
  return results;
146
183
  }
184
+ /**
185
+ * BAPI-877 — hand-authored `scripts/*.test.js`, sorted and package-relative.
186
+ *
187
+ * A thin delegation rather than a second walker: `buildDir` already generalizes
188
+ * (the walk is directory-agnostic and `path.relative(root, …)` yields
189
+ * `scripts/x.test.js` for free), and duplicating the ENOENT swallow, the sort,
190
+ * and the separator normalization would be three chances to diverge.
191
+ *
192
+ * Deliberately does NOT apply the empty-discovery guard — `discoverUnitTestFiles`
193
+ * owns that, so this stays a pure query usable in isolation.
194
+ */
195
+ export function discoverScriptTestFiles(options) {
196
+ return discoverTestFiles({ ...options, buildDir: SCRIPT_TEST_DIR });
197
+ }
198
+ /**
199
+ * BAPI-877 — everything the unit lane runs: compiled `build/**` plus authored
200
+ * `scripts/**`.
201
+ *
202
+ * WHY THE EMPTY-SCRIPTS GUARD IS SEPARATE. `selectTestGroup`'s "selected group
203
+ * is empty" refusal cannot fire for this: ~390 compiled files are always
204
+ * present, so a scripts-discovery regression would be masked and the lane would
205
+ * report green over zero scripts tests — the exact "coverage that exists only if
206
+ * someone runs it by hand" failure BAPI-877 exists to remove. Refusing here
207
+ * matches `runIntegrationLane` and `discoverIntegrationTestFiles`, which take the
208
+ * same posture for the same reason.
209
+ *
210
+ * The cost is deliberate: deleting every `scripts/*.test.js` breaks `npm test`
211
+ * until someone edits this file. Deleting all coverage for the build's version
212
+ * generator and agent-mirror synchronizer SHOULD require touching the line that
213
+ * says so, rather than silently shrinking the suite.
214
+ *
215
+ * WHY IT LIVES HERE and not in `runSelectedGroup`: the guard belongs on the
216
+ * production path only. Every test that injects its own `discoverFn` supplies a
217
+ * build-only fixture tree, and firing there would force `scripts/*` entries into
218
+ * BASELINE_NORMAL_FILES — falsifying the independent historical oracle this
219
+ * suite is built on.
220
+ */
221
+ export function discoverUnitTestFiles(options) {
222
+ const compiled = discoverTestFiles(options);
223
+ const authored = discoverScriptTestFiles(options);
224
+ if (authored.length === 0) {
225
+ throw new Error(`run-unit-tests: discovered zero ${SCRIPTS_DIR_PREFIX}*.test.js under ` +
226
+ `"${options.root}" — refusing to run. A scripts-lane discovery regression is ` +
227
+ `invisible beside the compiled tests that still ran, which is the failure ` +
228
+ `this lane exists to prevent (BAPI-877). If ${SCRIPTS_DIR_PREFIX} genuinely ` +
229
+ `has no test file any more, remove this guard deliberately.`);
230
+ }
231
+ return [...compiled, ...authored].sort();
232
+ }
147
233
  /** Throws if the module-mock, force-exit-quarantine, or integration-lane manifest has drifted from the discovered build output. */
148
234
  export function validateManifest(discovered) {
149
235
  const discoveredSet = new Set(discovered);
@@ -248,8 +334,8 @@ export function runSelectedGroup(mode, options) {
248
334
  if (mode !== "normal" && mode !== "module-mocks") {
249
335
  throw new Error(`run-unit-tests: unknown group "${mode}" (expected "normal" or "module-mocks")`);
250
336
  }
251
- const { root, execPath = process.execPath, spawnFn = spawnSync, discoverFn = (opts) => discoverTestFiles(opts), log = console.log, } = options;
252
- const discovered = discoverFn({ root });
337
+ const { root, execPath = process.execPath, spawnFn = spawnSync, discoverFn = (opts) => discoverUnitTestFiles(opts), fsImpl, log = console.log, } = options;
338
+ const discovered = discoverFn({ root, fsImpl });
253
339
  const selected = selectTestGroup(mode, discovered);
254
340
  // Split out the force-exit quarantine: those files run last, each as its own
255
341
  // single-file spawn WITH --test-force-exit (exact tally, prompt exit despite
@@ -284,3 +370,60 @@ export function runSelectedGroup(mode, options) {
284
370
  });
285
371
  return aggregateExit;
286
372
  }
373
+ /**
374
+ * Returns the integration lane's file list: every compiled `*.test.js` under
375
+ * `build/integration/` except the files belonging to another lane, plus the
376
+ * explicitly-registered files that live outside that directory
377
+ * (:data:`INTEGRATION_LANE_ONLY`). Sorted and package-relative.
378
+ *
379
+ * BAPI-848. Discovery replaced a hand-maintained enumeration in
380
+ * `scripts.test:integration`. A directory glob in the npm script itself was NOT
381
+ * viable: the MCP suite runs on Windows in CI, where npm runs scripts through
382
+ * cmd.exe and `*` is never expanded, so the script would have been silently
383
+ * handed a literal path and run zero tests.
384
+ */
385
+ export function discoverIntegrationTestFiles(options) {
386
+ const discovered = discoverTestFiles(options);
387
+ const excluded = new Set(INTEGRATION_DISCOVERY_EXCLUSIONS);
388
+ const fromDirectory = discovered.filter((file) => file.startsWith(INTEGRATION_DIR_PREFIX) && !excluded.has(file));
389
+ // The outside-directory entries stay explicit and are VALIDATED against the
390
+ // build output, so a renamed or deleted file fails loudly instead of silently
391
+ // dropping out of every lane.
392
+ const discoveredSet = new Set(discovered);
393
+ for (const entry of INTEGRATION_LANE_ONLY) {
394
+ if (!discoveredSet.has(entry)) {
395
+ throw new Error(`run-integration-tests: integration-lane entry not found in build output: ${entry} ` +
396
+ `(rebuild with 'npm run build', or remove it from INTEGRATION_LANE_ONLY if the file was deleted/renamed)`);
397
+ }
398
+ }
399
+ const selected = [...new Set([...fromDirectory, ...INTEGRATION_LANE_ONLY])];
400
+ selected.sort();
401
+ return selected;
402
+ }
403
+ /** Discovers, batches, and spawns the integration lane; returns an aggregate exit code. */
404
+ export function runIntegrationLane(options) {
405
+ const { root, execPath = process.execPath, spawnFn = spawnSync, discoverFn = (opts) => discoverIntegrationTestFiles(opts), log = console.log, } = options;
406
+ const selected = discoverFn({ root });
407
+ if (selected.length === 0) {
408
+ // Refusing beats reporting a green run over zero files — a discovery bug
409
+ // that silently selected nothing would look exactly like a passing suite.
410
+ throw new Error("run-integration-tests: discovered zero integration tests — refusing to run " +
411
+ "(did you forget 'npm run build'?)");
412
+ }
413
+ const nodeOptions = ["--test"];
414
+ const batches = partitionTestBatches(selected, { execPath, nodeOptions });
415
+ log(`run-integration-tests: files=${selected.length} batches=${batches.length}`);
416
+ let aggregateExit = 0;
417
+ batches.forEach((batch, index) => {
418
+ log(`run-integration-tests: batch ${index + 1}/${batches.length} (${batch.length} file(s))`);
419
+ const result = spawnFn(execPath, [...nodeOptions, ...batch], {
420
+ cwd: root,
421
+ stdio: "inherit",
422
+ shell: false,
423
+ });
424
+ if ((result.status ?? 1) !== 0) {
425
+ aggregateExit = 1;
426
+ }
427
+ });
428
+ return aggregateExit;
429
+ }
@@ -23,6 +23,7 @@ import { getAgentLauncher, formatValidAgentLauncherNames } from "./agent-launche
23
23
  import { resolveCommandOnPath } from "./agent-launchers/claude.js";
24
24
  import { discoverCommandCatalog, resolveSchedulableCommand, validateCommandArgv, } from "./command-catalog.js";
25
25
  import { buildTargetCommandLine } from "./scheduled-prompt.js";
26
+ import { MCP_PACKAGE_NAME } from "./mcp-identity.js";
26
27
  /**
27
28
  * Default deps backed by real subprocesses / process state. Subprocess execution
28
29
  * uses `execFile` (list-based, never `shell: true`) and supports
@@ -96,7 +97,7 @@ const SCHEDULE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
96
97
  export function getScheduleRunUsage() {
97
98
  return [
98
99
  "Usage:",
99
- " npx -y @bridge_gpt/mcp-server schedule-run <create|list|cancel|doctor> [flags]",
100
+ ` npx -y ${MCP_PACKAGE_NAME} schedule-run <create|list|cancel|doctor> [flags]`,
100
101
  "",
101
102
  "Schedules a local, one-shot run of ANY Bridge slash-command automation (from",
102
103
  "the repo's .claude/commands/*.md catalog) at a chosen time using an OS-native",
@@ -659,7 +660,7 @@ export async function resolveScheduleCreateInput(options, runAtIso, deps) {
659
660
  if (isTransientNpxEntryPath(cliEntryPath)) {
660
661
  warnings.push(`The scheduled run re-enters this CLI at '${cliEntryPath}', which is inside an npx cache ` +
661
662
  "directory. npx caches can be pruned before a future schedule fires, which would make the " +
662
- "run fail with ENOENT. Install the CLI persistently (e.g. `npm i -g @bridge_gpt/mcp-server`) " +
663
+ `run fail with ENOENT. Install the CLI persistently (e.g. \`npm i -g ${MCP_PACKAGE_NAME}\`) ` +
663
664
  "and schedule with the installed binary so the trigger path stays stable.");
664
665
  }
665
666
  const paths = getSchedulePaths(id, deps.homeDir, deps.platform);