@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
package/build/init.js CHANGED
@@ -20,7 +20,8 @@ import { reconstructAgentMarkdown, translateAgentToCopilot } from "./agent-utils
20
20
  import { validateRepoName, resolveRepoNameForProjectRoot } from "./bridge-config.js";
21
21
  import { ensureGitignored as ensureGitignoredShared } from "./git-ignore-utils.js";
22
22
  import { resolveBapiCredentials } from "./credential-store.js";
23
- import { BRIDGE_ENTRY_KEY, describeLauncherReason, inspectLauncherConfigs, isPrerequisiteFailure, launcherTargetFor, } from "./launcher-config-inspection.js";
23
+ import { describeLauncherReason, DUPLICATE_REGISTRATION_GUIDANCE, inspectLauncherConfigs, isPrerequisiteFailure, launcherTargetFor, } from "./launcher-config-inspection.js";
24
+ import { MCP_SERVER_NAME, MCP_PACKAGE_NAME, resolveRegistrationKey, } from "./mcp-identity.js";
24
25
  // ---------------------------------------------------------------------------
25
26
  // CLI: --init scaffolds slash commands and MCP configs into the current project
26
27
  // ---------------------------------------------------------------------------
@@ -59,7 +60,7 @@ export function buildBridgeApiEntry(cwd, metadata) {
59
60
  // EVERY branch — the server self-resolves it at runtime.
60
61
  return {
61
62
  command: "npx",
62
- args: ["-y", "--prefer-offline", `@bridge_gpt/mcp-server@${VERSION}`, "serve"],
63
+ args: ["-y", "--prefer-offline", `${MCP_PACKAGE_NAME}@${VERSION}`, "serve"],
63
64
  env: {
64
65
  BAPI_BASE_URL: metadata?.baseUrl ?? DEFAULT_BRIDGE_BASE_URL,
65
66
  BAPI_REPO_NAME: metadata?.repoName ?? PLACEHOLDER_REPO_NAME,
@@ -68,8 +69,6 @@ export function buildBridgeApiEntry(cwd, metadata) {
68
69
  },
69
70
  };
70
71
  }
71
- /** The package-name prefix every Bridge launcher spec starts with. */
72
- const BRIDGE_PACKAGE_PREFIX = "@bridge_gpt/mcp-server";
73
72
  /**
74
73
  * Refresh ONLY the package-spec token of an existing launcher args array
75
74
  * (BAPI-714, Group C).
@@ -95,7 +94,7 @@ export function refreshBridgeApiPackageSpec(args, spec) {
95
94
  const tokens = args.filter((a) => typeof a === "string");
96
95
  if (tokens.length !== args.length)
97
96
  return null;
98
- const index = tokens.findIndex((token) => token.startsWith(BRIDGE_PACKAGE_PREFIX));
97
+ const index = tokens.findIndex((token) => token.startsWith(MCP_PACKAGE_NAME));
99
98
  if (index === -1)
100
99
  return null;
101
100
  const next = [...tokens];
@@ -104,7 +103,7 @@ export function refreshBridgeApiPackageSpec(args, spec) {
104
103
  }
105
104
  /** The exact package spec a launcher generated by THIS build should carry. */
106
105
  export function currentBridgePackageSpec() {
107
- return `${BRIDGE_PACKAGE_PREFIX}@${VERSION}`;
106
+ return `${MCP_PACKAGE_NAME}@${VERSION}`;
108
107
  }
109
108
  /**
110
109
  * Choose the `repo_name` written into a scaffolded `.bridge/config`. Uses the
@@ -224,16 +223,47 @@ export async function resolveInitScaffoldAssets(options) {
224
223
  ];
225
224
  return { ide, pipelinesDir, instructionsDir, commitSafePaths };
226
225
  }
226
+ /**
227
+ * Thrown when a profile merge finds a config carrying BOTH recognized
228
+ * registration keys (BAPI-807). Raised before ANY file is written, so the
229
+ * operation is all-or-nothing.
230
+ */
231
+ export class DuplicateRegistrationError extends Error {
232
+ relPaths;
233
+ constructor(relPaths) {
234
+ super(`Cannot update the Bridge MCP profile:\n${relPaths
235
+ .map((p) => ` ${p}: ${DUPLICATE_REGISTRATION_GUIDANCE}`)
236
+ .join("\n")}`);
237
+ this.name = "DuplicateRegistrationError";
238
+ this.relPaths = relPaths;
239
+ }
240
+ }
227
241
  /**
228
242
  * Merge a group token (e.g. "sfcc") into the BRIDGE_MCP_PROFILE env value of the
229
- * `bridge-api` entry in each present MCP config file (.mcp.json, .vscode/mcp.json,
243
+ * Bridge entry in each present MCP config file (.mcp.json, .vscode/mcp.json,
230
244
  * .cursor/mcp.json). Existing tokens are preserved; the merge is idempotent.
231
245
  *
232
- * Only files where a `bridge-api` entry already exists are modified — new files
233
- * are never created by this helper.
246
+ * Only files where a recognized Bridge entry already exists are modified — new
247
+ * files are never created by this helper, and the entry is updated under the key
248
+ * it actually lives under (`bridge` or the permanently supported `bridge-api`),
249
+ * never renamed.
250
+ *
251
+ * BAPI-807: every present target is READ AND RESOLVED first, and only then is
252
+ * anything written. A both-key config in the third file must not be discovered
253
+ * after the first two were already modified — that would leave the project
254
+ * half-updated with no record of what moved, which is the same all-or-nothing
255
+ * guarantee `runInit`'s preflight provides.
234
256
  *
235
257
  * Returns the final resolved profile string (comma-joined) after merging, or an
236
258
  * empty string if no config file was found or updated.
259
+ *
260
+ * Its READ-ONLY counterpart is `inspectBridgeApiProfileToken`
261
+ * ({@link file:./mcp-host-config.ts}), which reports token presence across the
262
+ * same three configs without writing. Callers that need to say WHICH config
263
+ * carries the token must use it: this function returns a merged profile string,
264
+ * not a per-config roster (BAPI-775).
265
+ *
266
+ * @throws {DuplicateRegistrationError} when any target carries both keys.
237
267
  */
238
268
  export async function mergeBridgeApiProfileToken(cwd, token) {
239
269
  const targets = [
@@ -241,7 +271,9 @@ export async function mergeBridgeApiProfileToken(cwd, token) {
241
271
  { path: ".vscode/mcp.json", topLevelKey: "servers" },
242
272
  { path: ".cursor/mcp.json", topLevelKey: "mcpServers" },
243
273
  ];
244
- let lastProfile = "";
274
+ // ---- Pass 1: read + resolve every target. No writes. ----
275
+ const pending = [];
276
+ const conflicts = [];
245
277
  for (const target of targets) {
246
278
  const fullPath = path.join(cwd, target.path);
247
279
  let raw;
@@ -259,10 +291,25 @@ export async function mergeBridgeApiProfileToken(cwd, token) {
259
291
  continue; // invalid JSON — skip
260
292
  }
261
293
  const topLevel = parsed[target.topLevelKey];
262
- if (!topLevel || !topLevel["bridge-api"]) {
263
- continue; // no bridge-api entry — skip
294
+ const resolution = resolveRegistrationKey(topLevel);
295
+ if (resolution.state === "conflict") {
296
+ conflicts.push(target.path);
297
+ continue;
298
+ }
299
+ if (resolution.state === "absent") {
300
+ continue; // no recognized Bridge entry — skip
264
301
  }
265
- const entry = topLevel["bridge-api"];
302
+ const entry = topLevel[resolution.key];
303
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
304
+ continue; // present key but not an updatable entry — skip
305
+ }
306
+ pending.push({ fullPath, parsed, entry });
307
+ }
308
+ if (conflicts.length > 0)
309
+ throw new DuplicateRegistrationError(conflicts);
310
+ // ---- Pass 2: apply. Every target here was proven unambiguous above. ----
311
+ let lastProfile = "";
312
+ for (const { fullPath, parsed, entry } of pending) {
266
313
  if (!entry.env)
267
314
  entry.env = {};
268
315
  const existing = entry.env.BRIDGE_MCP_PROFILE;
@@ -329,7 +376,7 @@ export class InitPreflightError extends Error {
329
376
  }
330
377
  }
331
378
  /**
332
- * Resolve the non-secret identity a NEW `bridge-api` entry should carry.
379
+ * Resolve the non-secret identity a NEW Bridge entry should carry.
333
380
  *
334
381
  * Precedence (plan Step 3.9): an explicit caller context wins; then an explicit
335
382
  * `BAPI_REPO_NAME`; then the committed `.bridge/config` / git-derived identity.
@@ -454,7 +501,7 @@ export async function runInit(cwd, options = {}) {
454
501
  stat: options.io?.stat ?? stat,
455
502
  };
456
503
  const targetVersion = options.targetVersion ?? VERSION;
457
- const targetSpec = `@bridge_gpt/mcp-server@${targetVersion}`;
504
+ const targetSpec = `${MCP_PACKAGE_NAME}@${targetVersion}`;
458
505
  const say = options.stdout ?? ((m) => console.log(m));
459
506
  const warn = options.stderr ?? ((m) => console.error(m));
460
507
  // ---- Phase 1: IDE Detection ----
@@ -467,7 +514,7 @@ export async function runInit(cwd, options = {}) {
467
514
  console.log(`Bridge API --init: detected IDEs: ${detectedIDEs.join(", ")}`);
468
515
  // ---- Phase 2: Windsurf manual instructions ----
469
516
  if (ideDetection.windsurf) {
470
- const windsurfSnippet = JSON.stringify({ mcpServers: { "bridge-api": buildBridgeApiEntry(cwd) } }, null, 2);
517
+ const windsurfSnippet = JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: buildBridgeApiEntry(cwd) } }, null, 2);
471
518
  console.log("\n⚠ Windsurf does not support project-local MCP configuration.\n" +
472
519
  "Add the following to ~/.codeium/windsurf/mcp_config.json:\n\n" +
473
520
  windsurfSnippet + "\n");
@@ -539,6 +586,7 @@ export async function runInit(cwd, options = {}) {
539
586
  structuredActions.push({
540
587
  relPath: target.path,
541
588
  kind: "skipped-worktree-shim",
589
+ registrationKey: found.registrationKey ?? undefined,
542
590
  });
543
591
  continue;
544
592
  }
@@ -555,14 +603,17 @@ export async function runInit(cwd, options = {}) {
555
603
  kind: "skipped-ahead",
556
604
  fromVersion: found.currentVersion ?? undefined,
557
605
  fromSpec: found.spec ?? undefined,
606
+ registrationKey: found.registrationKey ?? undefined,
558
607
  });
559
608
  continue;
560
609
  }
561
610
  if (found.action === "create") {
611
+ // A CREATE is by definition an absent registration, so the key is the
612
+ // canonical one. `add` below is the same case in an existing file.
562
613
  await io.mkdir(path.dirname(fullPath), { recursive: true });
563
614
  const content = {
564
615
  [target.topLevelKey]: {
565
- [BRIDGE_ENTRY_KEY]: buildBridgeApiEntry(cwd, newEntryMetadata),
616
+ [MCP_SERVER_NAME]: buildBridgeApiEntry(cwd, newEntryMetadata),
566
617
  },
567
618
  };
568
619
  await io.writeFile(fullPath, JSON.stringify(content, null, 2) + "\n", "utf-8");
@@ -573,6 +624,7 @@ export async function runInit(cwd, options = {}) {
573
624
  kind: "created",
574
625
  toVersion: targetVersion,
575
626
  unconfigured: !entryReady,
627
+ registrationKey: MCP_SERVER_NAME,
576
628
  });
577
629
  if (!entryReady) {
578
630
  readinessWarnings.push({
@@ -589,9 +641,11 @@ export async function runInit(cwd, options = {}) {
589
641
  const raw = await io.readFile(fullPath, "utf-8");
590
642
  const parsed = JSON.parse(raw);
591
643
  if (found.action === "add") {
644
+ // No recognized key was present (the preflight proved it), so this is a
645
+ // fresh registration and uses MCP_SERVER_NAME.
592
646
  if (!parsed[target.topLevelKey])
593
647
  parsed[target.topLevelKey] = {};
594
- parsed[target.topLevelKey][BRIDGE_ENTRY_KEY] = buildBridgeApiEntry(cwd, newEntryMetadata);
648
+ parsed[target.topLevelKey][MCP_SERVER_NAME] = buildBridgeApiEntry(cwd, newEntryMetadata);
595
649
  await io.writeFile(fullPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
596
650
  configActions.push({ path: target.path, action: "added entry" });
597
651
  structuredActions.push({
@@ -599,6 +653,7 @@ export async function runInit(cwd, options = {}) {
599
653
  kind: "added",
600
654
  toVersion: targetVersion,
601
655
  unconfigured: !entryReady,
656
+ registrationKey: MCP_SERVER_NAME,
602
657
  });
603
658
  if (!entryReady) {
604
659
  readinessWarnings.push({
@@ -614,7 +669,12 @@ export async function runInit(cwd, options = {}) {
614
669
  // rewrote it to "npx" unconditionally, silently replacing a custom
615
670
  // launcher), and `refreshBridgeApiPackageSpec` preserves the bare-versus-
616
671
  // `serve` composition plus every surrounding argument (BAPI-714 C-3).
617
- const entry = parsed[target.topLevelKey][BRIDGE_ENTRY_KEY];
672
+ //
673
+ // BAPI-807: the entry is reached through the key the PREFLIGHT resolved,
674
+ // not through MCP_SERVER_NAME. Indexing by the canonical name here is what
675
+ // would turn a `bridge-api` project's repin into a second `bridge` entry.
676
+ const registrationKey = found.registrationKey ?? MCP_SERVER_NAME;
677
+ const entry = parsed[target.topLevelKey][registrationKey];
618
678
  const refreshed = refreshBridgeApiPackageSpec(entry.args, targetSpec);
619
679
  if (refreshed === null) {
620
680
  // Unreachable: preflight classifies an unrecognizable args array as
@@ -641,6 +701,7 @@ export async function runInit(cwd, options = {}) {
641
701
  fromVersion: found.currentVersion ?? undefined,
642
702
  fromSpec: found.spec ?? undefined,
643
703
  toVersion: targetVersion,
704
+ registrationKey,
644
705
  });
645
706
  // An existing entry that still says YOUR_REPO_NAME loads without error and
646
707
  // authenticates as nobody. Its env is left exactly as-is — but the run is
@@ -666,7 +727,7 @@ export async function runInit(cwd, options = {}) {
666
727
  const existing = readinessWarnings.filter((w) => w.kind === "unconfigured-entry-existing");
667
728
  warn("\n⚠ Bridge API MCP configuration is NOT ready to authenticate.");
668
729
  if (created.length > 0) {
669
- warn(` Wrote an UNCONFIGURED bridge-api entry (BAPI_REPO_NAME=${PLACEHOLDER_REPO_NAME}) to: ${created
730
+ warn(` Wrote an UNCONFIGURED ${MCP_SERVER_NAME} entry (BAPI_REPO_NAME=${PLACEHOLDER_REPO_NAME}) to: ${created
670
731
  .map((w) => w.relPath)
671
732
  .join(", ")}`);
672
733
  warn(identity.repoName
@@ -677,11 +738,11 @@ export async function runInit(cwd, options = {}) {
677
738
  }
678
739
  }
679
740
  if (existing.length > 0) {
680
- warn(` Existing bridge-api entry still uses the ${PLACEHOLDER_REPO_NAME} placeholder in: ${existing
741
+ warn(` Existing Bridge entry still uses the ${PLACEHOLDER_REPO_NAME} placeholder in: ${existing
681
742
  .map((w) => w.relPath)
682
743
  .join(", ")}`);
683
744
  }
684
- warn(" Fix with: npx -y @bridge_gpt/mcp-server install (or set BAPI_REPO_NAME and store a key with the install flow)");
745
+ warn(` Fix with: npx -y ${MCP_PACKAGE_NAME} install (or set BAPI_REPO_NAME and store a key with the install flow)`);
685
746
  }
686
747
  // ---- Phase 4: Scaffold slash command directories ----
687
748
  const commandDirs = [path.join(cwd, ".claude", "commands")];