@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
@@ -13,6 +13,7 @@
13
13
  * the runtime graph stays acyclic — `start-tickets.ts` imports values FROM here,
14
14
  * never the reverse.
15
15
  */
16
+ import path from "path";
16
17
  import { resolveBapiCredentials, getPrimaryCredentialStorePath, } from "./credential-store.js";
17
18
  import { resolveStartTicketsRepoName } from "./start-tickets-repo.js";
18
19
  import { probeWorktreeMcpRegistration } from "./mcp-registration-doctor.js";
@@ -40,6 +41,29 @@ export const TMUX_COMMAND = "tmux";
40
41
  export const GIT_FOR_WINDOWS_BASH_HINT = "Install Git for Windows / Git Bash — Worktrunk runs its pre-start / post-start hooks via Git Bash.";
41
42
  /** The read-only doctor invocation surfaced from preflight failures and elsewhere. */
42
43
  export const START_TICKETS_DOCTOR_COMMAND = "npx -y @bridge_gpt/mcp-server doctor";
44
+ /**
45
+ * BAPI-527 live-source checkout guard (conductor durable execution).
46
+ *
47
+ * `BAPI_CONDUCTOR_LIVE_SOURCE_PATH` — OPTIONAL operator-set path to the checkout
48
+ * an operator's live dev server (e.g. `uvicorn main:app --reload`) is running
49
+ * from. When set, unattended conductor/epic/non-mutating start-tickets dispatch
50
+ * refuses to run if the conductor base repo it would operate on resolves to the
51
+ * SAME checkout, because cutting worktrees / touching branches under a live
52
+ * dev-server checkout risks corrupting the operator's working state. No existing
53
+ * "live dev-server source path" convention was found in the codebase during
54
+ * discovery, so this local env contract is introduced here. Read only from the
55
+ * injected `deps.env` (never global `process.env`) so it stays mockable.
56
+ *
57
+ * `BAPI_CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH` — explicit escape hatch. When set
58
+ * to a truthy value (`1`/`true`/`yes`/`on`, case-insensitive) a detected
59
+ * collision is DOWNGRADED from fatal to a loud warning rather than silently
60
+ * ignored, so an operator who genuinely wants same-checkout dispatch can opt in
61
+ * with eyes open.
62
+ */
63
+ export const CONDUCTOR_LIVE_SOURCE_PATH_ENV = "BAPI_CONDUCTOR_LIVE_SOURCE_PATH";
64
+ export const CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH_ENV = "BAPI_CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH";
65
+ /** Stable descriptor id for the live-source checkout guard (used in messages + doctor). */
66
+ export const LIVE_SOURCE_GUARD_ID = "conductor-live-source";
43
67
  /** True only for the three first-class supported platforms. */
44
68
  export function isSupportedStartTicketsPlatform(platform) {
45
69
  return platform === "darwin" || platform === "win32" || platform === "linux";
@@ -254,6 +278,34 @@ function uvDescriptor() {
254
278
  return commandDescriptor("uv", "uv", UV_INSTALL_HINTS);
255
279
  }
256
280
  // ---------------------------------------------------------------------------
281
+ // review-tickets git prerequisite (BAPI-474). review-tickets has its own
282
+ // terminal-launcher-only live preflight (runReviewTicketsPreflight in
283
+ // review-tickets.ts) — separate from getPreflightPrereqDescriptors above,
284
+ // which is start-tickets-specific. Since the parent-fetch-once base pin now
285
+ // requires git for review-tickets too (unless --no-refresh-base is passed),
286
+ // this doctor-only descriptor gives it its own distinctly-labeled,
287
+ // read-only-diagnosable entry rather than relying on the generic start-tickets
288
+ // "git" descriptor, so a user running review-tickets alone can self-diagnose.
289
+ // ---------------------------------------------------------------------------
290
+ const REVIEW_TICKETS_GIT_INSTALL_HINTS = {
291
+ darwin: `${GIT_INSTALL_HINTS.darwin} (or rerun review-tickets with --no-refresh-base to skip the fetch)`,
292
+ linux: `${GIT_INSTALL_HINTS.linux} (or rerun review-tickets with --no-refresh-base to skip the fetch)`,
293
+ win32: `${GIT_INSTALL_HINTS.win32} (or rerun review-tickets with --no-refresh-base to skip the fetch)`,
294
+ };
295
+ function reviewTicketsGitDescriptor() {
296
+ return {
297
+ id: "review-tickets-git",
298
+ label: "git (required by review-tickets base-branch fetch)",
299
+ installHint: REVIEW_TICKETS_GIT_INSTALL_HINTS,
300
+ probe: async (deps) => {
301
+ const found = await isCommandOnPath(deps, "git");
302
+ return found
303
+ ? { found: true, detail: "found on PATH" }
304
+ : { found: false, detail: "review-tickets' parent-fetch-once base pin needs git unless --no-refresh-base is passed" };
305
+ },
306
+ };
307
+ }
308
+ // ---------------------------------------------------------------------------
257
309
  // regression-check (BAPI-460) doctor-only tool descriptors. These probe the
258
310
  // deterministic tooling regression-check relies on (ast-grep, ripgrep,
259
311
  // lizard). They are doctor-diagnosable but NOT preflight blockers: a missing
@@ -270,10 +322,11 @@ const LIZARD_INSTALL_HINTS = {
270
322
  linux: "uv tool install lizard",
271
323
  win32: "uv tool install lizard",
272
324
  };
325
+ const RIPGREP_SHELL_FUNCTION_CAVEAT = "a shell function/alias will not satisfy this check — ripgrep must be installed as a real PATH binary.";
273
326
  const RIPGREP_INSTALL_HINTS = {
274
- darwin: "brew install ripgrep",
275
- linux: "Install ripgrep with your distro package manager, e.g. apt install ripgrep",
276
- win32: "winget install BurntSushi.ripgrep.MSVC",
327
+ darwin: `brew install ripgrep (${RIPGREP_SHELL_FUNCTION_CAVEAT})`,
328
+ linux: `Install ripgrep with your distro package manager, e.g. apt install ripgrep (${RIPGREP_SHELL_FUNCTION_CAVEAT})`,
329
+ win32: `winget install BurntSushi.ripgrep.MSVC (${RIPGREP_SHELL_FUNCTION_CAVEAT})`,
277
330
  };
278
331
  /** ast-grep ships two equivalent binary names (`ast-grep` and `sg`); either satisfies the probe. */
279
332
  function astGrepDescriptor() {
@@ -383,6 +436,107 @@ export function worktreeMcpReachabilityDescriptor() {
383
436
  },
384
437
  };
385
438
  }
439
+ /**
440
+ * Conservatively normalize a filesystem path for comparison: trim, drop a
441
+ * trailing separator, and resolve `.`/`..` segments via `path.resolve`. Symlink
442
+ * canonicalization is handled UPSTREAM by `git rev-parse --show-toplevel` (which
443
+ * returns the real, absolute repo root); this in-memory step is the fallback for
444
+ * a path that is not a git work tree. Never touches the filesystem.
445
+ */
446
+ export function normalizeCheckoutPath(rawPath) {
447
+ const trimmed = rawPath.trim();
448
+ const resolved = path.resolve(trimmed);
449
+ // Strip a redundant trailing separator (path.resolve already removes most, but
450
+ // a bare root like "/" must be preserved).
451
+ return resolved.length > 1 ? resolved.replace(/[\\/]+$/, "") : resolved;
452
+ }
453
+ /**
454
+ * Resolve the repository ROOT for a path using the authoritative, read-only
455
+ * `git -C <path> rev-parse --show-toplevel`. Falls back to conservative
456
+ * in-memory normalization when the target is not a git work tree (or git is
457
+ * unavailable) so the guard still produces a comparable path. Never mutates.
458
+ */
459
+ export async function resolveRepoRootPath(deps, targetPath) {
460
+ const result = await deps.runCommand("git", ["-C", targetPath, "rev-parse", "--show-toplevel"], { cwd: deps.cwd });
461
+ if (commandSucceeded(result)) {
462
+ const top = result.stdout.trim();
463
+ if (top.length > 0)
464
+ return normalizeCheckoutPath(top);
465
+ }
466
+ return normalizeCheckoutPath(targetPath);
467
+ }
468
+ /** True when the override env is set to a recognized truthy value (case-insensitive). */
469
+ export function isLiveSourceDispatchOverrideEnabled(env) {
470
+ const raw = env[CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH_ENV];
471
+ if (raw === undefined)
472
+ return false;
473
+ return ["1", "true", "yes", "on"].includes(raw.trim().toLowerCase());
474
+ }
475
+ /**
476
+ * Evaluate the live-source guard read-only. Resolves the conductor base repo root
477
+ * (from `deps.cwd`) and the configured live-source root, then compares them after
478
+ * conservative normalization. Returns one of three states; never throws, never
479
+ * mutates.
480
+ */
481
+ export async function evaluateLiveSourceGuard(deps) {
482
+ const rawLiveSource = deps.env[CONDUCTOR_LIVE_SOURCE_PATH_ENV];
483
+ if (!rawLiveSource || rawLiveSource.trim().length === 0) {
484
+ return {
485
+ state: "not-configured",
486
+ detail: `no live dev-server source configured (${CONDUCTOR_LIVE_SOURCE_PATH_ENV} unset) — guard inactive`,
487
+ };
488
+ }
489
+ const baseRepoPath = await resolveRepoRootPath(deps, deps.cwd);
490
+ const liveSourcePath = await resolveRepoRootPath(deps, rawLiveSource);
491
+ if (baseRepoPath === liveSourcePath) {
492
+ return {
493
+ state: "collision",
494
+ detail: `COLLISION: the conductor base checkout (${baseRepoPath}) is the SAME checkout as the ` +
495
+ `configured live dev-server source (${CONDUCTOR_LIVE_SOURCE_PATH_ENV}). Unattended dispatch ` +
496
+ `would create worktrees / touch branches under a running dev server.`,
497
+ baseRepoPath,
498
+ liveSourcePath,
499
+ };
500
+ }
501
+ return {
502
+ state: "safe",
503
+ detail: `safe: conductor base checkout (${baseRepoPath}) differs from the configured live ` +
504
+ `dev-server source (${liveSourcePath})`,
505
+ baseRepoPath,
506
+ liveSourcePath,
507
+ };
508
+ }
509
+ /** Per-OS remediation hint for the live-source guard (secret-free). */
510
+ const LIVE_SOURCE_GUARD_HINT = `Point ${CONDUCTOR_LIVE_SOURCE_PATH_ENV} at your live dev server's checkout ONLY when it ` +
511
+ `differs from this conductor base checkout, or dispatch the conductor from a separate clone. ` +
512
+ `To override the guard and dispatch anyway (not recommended), set ` +
513
+ `${CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH_ENV}=1.`;
514
+ const LIVE_SOURCE_GUARD_INSTALL_HINTS = {
515
+ darwin: LIVE_SOURCE_GUARD_HINT,
516
+ linux: LIVE_SOURCE_GUARD_HINT,
517
+ win32: LIVE_SOURCE_GUARD_HINT,
518
+ };
519
+ /**
520
+ * Doctor-only, strictly read-only descriptor that surfaces the three live-source
521
+ * guard states through the EXISTING doctor render (found + detail / missing +
522
+ * install hint):
523
+ * - not-configured → `found: true` (guard inactive, neutral)
524
+ * - safe → `found: true` (different checkouts, safe)
525
+ * - collision → `found: false` (renders as a flagged problem + override hint)
526
+ * The runtime path specifics ride in `detail` for programmatic consumers.
527
+ */
528
+ export function liveSourceGuardDescriptor() {
529
+ return {
530
+ id: LIVE_SOURCE_GUARD_ID,
531
+ label: "Conductor live-source checkout guard",
532
+ installHint: LIVE_SOURCE_GUARD_INSTALL_HINTS,
533
+ probe: async (deps) => {
534
+ const outcome = await evaluateLiveSourceGuard(deps);
535
+ // Only a collision reads as a problem; not-configured and safe are neutral.
536
+ return { found: outcome.state !== "collision", detail: outcome.detail };
537
+ },
538
+ };
539
+ }
386
540
  /**
387
541
  * The exact existing live-preflight requirement set per platform, plus the git
388
542
  * work-tree custom check appended after the command checks. This is the ONLY
@@ -427,6 +581,8 @@ export function getDoctorOnlyPrereqDescriptors(_platform, _env, agent) {
427
581
  astGrepDescriptor(),
428
582
  lizardDescriptor(),
429
583
  ripgrepDescriptor(),
584
+ reviewTicketsGitDescriptor(),
585
+ liveSourceGuardDescriptor(),
430
586
  ];
431
587
  }
432
588
  /**
@@ -467,8 +623,14 @@ export async function probePrerequisite(deps, descriptor) {
467
623
  * `runPreflight` behaviour). Iterates the shared preflight descriptors in order
468
624
  * and returns on the first missing one. `uv` and the selected agent are NOT
469
625
  * enforced here — they are doctor-only. Never throws.
626
+ *
627
+ * BAPI-527: when `options.enforceLiveSourceGuard` is set (unattended
628
+ * conductor/epic/non-mutating dispatch), the live-source checkout guard is
629
+ * additionally evaluated after the standard loop — a collision is fatal
630
+ * (`live-source-collision`) unless the override env downgrades it to a returned
631
+ * `warning`.
470
632
  */
471
- export async function enforcePreflightPrerequisites(deps) {
633
+ export async function enforcePreflightPrerequisites(deps, options = {}) {
472
634
  const descriptorsResult = getPreflightPrereqDescriptors(deps.platform, deps.env);
473
635
  if (!descriptorsResult.ok) {
474
636
  return { ok: false, reason: "unsupported-platform", error: descriptorsResult.error };
@@ -483,5 +645,24 @@ export async function enforcePreflightPrerequisites(deps) {
483
645
  return { ok: false, reason: "missing-prerequisite", error };
484
646
  }
485
647
  }
648
+ // BAPI-527 live-source checkout guard (unattended dispatch only). Read-only.
649
+ if (options.enforceLiveSourceGuard) {
650
+ const guard = await evaluateLiveSourceGuard(deps);
651
+ if (guard.state === "collision") {
652
+ const base = `Live-source checkout guard (${LIVE_SOURCE_GUARD_ID}): ${guard.detail}`;
653
+ if (isLiveSourceDispatchOverrideEnabled(deps.env)) {
654
+ return {
655
+ ok: true,
656
+ warning: `${base} Proceeding anyway because ${CONDUCTOR_ALLOW_LIVE_SOURCE_DISPATCH_ENV} is set — ` +
657
+ `dispatching under a live dev-server checkout can corrupt the operator's working state.`,
658
+ };
659
+ }
660
+ return {
661
+ ok: false,
662
+ reason: "live-source-collision",
663
+ error: `${base} Refusing unattended dispatch. ${LIVE_SOURCE_GUARD_HINT}`,
664
+ };
665
+ }
666
+ }
486
667
  return { ok: true };
487
668
  }