@bridge_gpt/mcp-server 0.2.10 → 0.2.12

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 (37) hide show
  1. package/README.md +3 -3
  2. package/build/commands.generated.js +6 -6
  3. package/build/conductor/bridge-api-client.js +2 -1
  4. package/build/conductor/cli.js +16 -16
  5. package/build/conductor/doctor.js +1 -1
  6. package/build/conductor/epic-reconcile.js +213 -16
  7. package/build/conductor/epic-runtime.js +89 -6
  8. package/build/conductor/epic-state.js +85 -11
  9. package/build/conductor/errors.js +12 -0
  10. package/build/conductor/git-ci-types.js +10 -0
  11. package/build/conductor/git-producer.js +4 -4
  12. package/build/conductor/merge-ledger.js +7 -7
  13. package/build/conductor/pr-ci-producer.js +6 -6
  14. package/build/conductor/pr-review-producer.js +2 -2
  15. package/build/conductor/producer-ledger.js +5 -5
  16. package/build/conductor/spec-review-producer.js +88 -0
  17. package/build/conductor/store.js +97 -25
  18. package/build/conductor/supervisor-ledger.js +2 -2
  19. package/build/conductor/supervisor-merge.js +5 -5
  20. package/build/conductor/supervisor-message-relay.js +1 -1
  21. package/build/conductor/supervisor-runtime.js +10 -10
  22. package/build/conductor/taxonomy.js +5 -0
  23. package/build/conductor/tools.js +5 -5
  24. package/build/conductor-bin.js +12350 -19
  25. package/build/conductor-claude-hook-bin.js +167 -17
  26. package/build/decision-page-schema.js +26 -0
  27. package/build/doctor.js +200 -0
  28. package/build/index.js +23705 -3630
  29. package/build/install-bridge.js +80 -0
  30. package/build/pipelines.generated.js +70 -48
  31. package/build/readme.generated.js +1 -1
  32. package/build/version.generated.js +1 -1
  33. package/package.json +7 -4
  34. package/pipelines/check-ci-ticket.json +2 -2
  35. package/pipelines/implement-ticket.json +2 -2
  36. package/pipelines/learn-repository.json +84 -42
  37. package/smoke-test/SMOKE-TEST.md +11 -17
@@ -34,10 +34,12 @@
34
34
  * gitignored) and the user-scoped credential store (Step 4).
35
35
  */
36
36
  import { readFile, writeFile, mkdir, stat, rename, chmod, unlink } from "fs/promises";
37
+ import { spawn } from "child_process";
37
38
  import os from "os";
38
39
  import path from "path";
39
40
  import readline from "readline";
40
41
  import { runInit, buildBridgeApiEntry } from "./init.js";
42
+ import { VERSION } from "./version.generated.js";
41
43
  import { validateRepoName } from "./bridge-config.js";
42
44
  import { resolveStartTicketsRepoName } from "./start-tickets-repo.js";
43
45
  import { upsertBapiCredential, getPrimaryCredentialStorePath, } from "./credential-store.js";
@@ -45,6 +47,23 @@ import { DEFAULT_AGENT_NAME, resolveAgentSpec, isAgentName, formatValidAgentName
45
47
  import { buildGenericAgentShellCommand, getDefaultSpawnTerminalTabForPlatform, detectTerminal, createDefaultStartTicketsDeps, } from "./start-tickets.js";
46
48
  /** Redaction sentinel — the API-key value is NEVER printed; this stands in. */
47
49
  export const REDACTED_API_KEY = "<REDACTED>";
50
+ /**
51
+ * Always-surfaced success-path note (BAPI-451 W3, E-3). The pinned launcher's
52
+ * FIRST cold launch can resolve/download the package inline; if the MCP client's
53
+ * connect deadline is very short it may time out before the handshake. Pre-warming
54
+ * (below) makes this rare, but the note is surfaced unconditionally so the
55
+ * fail-soft backstop is always discoverable.
56
+ */
57
+ export const MCP_TIMEOUT_GUIDANCE = "Note: if your MCP client has a very short connect deadline, raise MCP_TIMEOUT for the first launch " +
58
+ "(the initial npx package resolution/download can exceed a short connect timeout).";
59
+ /** The exact, version-pinned launcher spec the pre-warm spawns (fast-exiting --version). */
60
+ export function buildPrewarmArgs() {
61
+ return ["-y", `@bridge_gpt/mcp-server@${VERSION}`, "--version"];
62
+ }
63
+ /** Secret-free preview of the pre-warm command (no env, no key). */
64
+ export function buildPrewarmCommandPreview() {
65
+ return `npx ${buildPrewarmArgs().join(" ")}`;
66
+ }
48
67
  /** The natural-language sequential prompt handed to the spawned agent session. */
49
68
  export const INSTALL_BRIDGE_AGENT_PROMPT = "Please execute the /install-bridge command. Once it completes successfully, execute the /learn-repository command.";
50
69
  /** Default base URL when `BAPI_BASE_URL` is unset (mirrors index.ts). */
@@ -198,6 +217,44 @@ function promptLineViaReadline(promptText) {
198
217
  });
199
218
  });
200
219
  }
220
+ /**
221
+ * Default pre-warm spawner (BAPI-451 W3). Spawns array-based (`shell: false`) so
222
+ * no argument is ever shell-interpreted, ignores all child stdio (node-gyp /
223
+ * download noise stays out of the CLI UX), bounds the run with a 60s timeout, and
224
+ * passes a SANITIZED env clone with `BAPI_API_KEY` deleted — the `--version`
225
+ * pre-warm never needs the key, and it must never reach an npm lifecycle script.
226
+ * Always resolves (never rejects): a spawn error / non-zero exit / timeout becomes
227
+ * `{ ok: false, warning }` with secret-free warning text.
228
+ */
229
+ function spawnPrewarmDefault(command, args, env) {
230
+ return new Promise((resolve) => {
231
+ const sanitizedEnv = { ...env };
232
+ delete sanitizedEnv.BAPI_API_KEY;
233
+ try {
234
+ const child = spawn(command, args, {
235
+ shell: false,
236
+ stdio: "ignore",
237
+ timeout: 60_000,
238
+ env: sanitizedEnv,
239
+ });
240
+ child.on("error", () => resolve({ ok: false, warning: "the pre-warm process could not be started" }));
241
+ child.on("close", (code, signal) => {
242
+ if (signal) {
243
+ resolve({ ok: false, warning: `the pre-warm process timed out or was terminated (${signal})` });
244
+ }
245
+ else if (code === 0) {
246
+ resolve({ ok: true });
247
+ }
248
+ else {
249
+ resolve({ ok: false, warning: `the pre-warm process exited with code ${code}` });
250
+ }
251
+ });
252
+ }
253
+ catch {
254
+ resolve({ ok: false, warning: "the pre-warm process could not be started" });
255
+ }
256
+ });
257
+ }
201
258
  /** Build default deps from the live process. */
202
259
  export function createDefaultInstallBridgeDeps() {
203
260
  const isTTY = Boolean(process.stdin.isTTY);
@@ -217,6 +274,7 @@ export function createDefaultInstallBridgeDeps() {
217
274
  promptSecret: isTTY ? promptSecretViaReadline : undefined,
218
275
  promptLine: isTTY ? promptLineViaReadline : undefined,
219
276
  fetch: (...args) => fetch(...args),
277
+ spawnPrewarm: spawnPrewarmDefault,
220
278
  runInit,
221
279
  upsertCredential: upsertBapiCredential,
222
280
  buildShellCommand: buildGenericAgentShellCommand,
@@ -472,6 +530,8 @@ export function buildDryRunPreview(plan) {
472
530
  ...(plan.manualEditors.length > 0
473
531
  ? [` ${plan.manualEditors.join(" + ")}: detected (global config) — manual setup instructions would be printed.`]
474
532
  : []),
533
+ `Step 3b — pre-warm the version-pinned launcher bucket (fail-open, env sanitized — BAPI_API_KEY removed): ${plan.prewarmCommand}`,
534
+ MCP_TIMEOUT_GUIDANCE,
475
535
  `Step 4 — persist routing credential: target ${plan.credentialTarget} at ${plan.credentialStorePath}`,
476
536
  `Step 5 — spawn agent session: ${plan.spawnCommand}`,
477
537
  ];
@@ -590,6 +650,7 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
590
650
  credentialTarget: `bapi:${repoName}`,
591
651
  credentialStorePath,
592
652
  pingUrl: buildPingUrl(baseUrl, repoName),
653
+ prewarmCommand: buildPrewarmCommandPreview(),
593
654
  spawnCommand,
594
655
  };
595
656
  // ---- --dry-run: preview every step, strictly no side effects ----
@@ -639,6 +700,25 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
639
700
  const manualInstructions = buildManualHostInstructions(entry, manualEditors);
640
701
  if (manualInstructions)
641
702
  log(manualInstructions);
703
+ // ---- Step 3b — pre-warm the @${VERSION}-pinned _npx bucket (BAPI-451 W3) ----
704
+ // The launcher just written is pinned to @${VERSION}, a DIFFERENT _npx bucket
705
+ // than the @latest bucket this `npx … install-bridge` invocation warmed. Spawn
706
+ // the exact pinned launcher once with the fast-exiting `--version` flag so the
707
+ // first real MCP launch resolves from a warm bucket instead of paying the cold
708
+ // install inline (which can exceed the client's connect deadline). Strictly
709
+ // fail-open: a failure warns (secret-free) but never fails the install.
710
+ log(" pre-warming the version-pinned launcher bucket…");
711
+ const prewarm = await deps.spawnPrewarm("npx", buildPrewarmArgs(), deps.env);
712
+ if (prewarm.ok) {
713
+ log(" launcher bucket warmed (the first MCP launch will not pay a cold install).");
714
+ log(` ${MCP_TIMEOUT_GUIDANCE}`);
715
+ }
716
+ else {
717
+ // Escalate to a stronger, still secret-free warning when pre-warm didn't
718
+ // complete cleanly — but the install itself still succeeds (exit unaffected).
719
+ errorLog(`Warning: could not pre-warm the version-pinned launcher bucket${prewarm.warning ? ` (${prewarm.warning})` : ""}. ` +
720
+ `The first MCP launch may pay a one-time cold install and could be slow. ${MCP_TIMEOUT_GUIDANCE}`);
721
+ }
642
722
  // ---- Step 4 — persist routing credential (non-blocking / fail-open) ----
643
723
  log("Step 4/5 — persisting routing credential…");
644
724
  try {