@bridge_gpt/mcp-server 0.2.62 → 0.2.66

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 (113) hide show
  1. package/README.md +66 -15
  2. package/build/agent-launchers/claude-executor-adapter.js +145 -20
  3. package/build/agent-launchers/executor-adapter.js +81 -2
  4. package/build/agents.generated.js +10 -1
  5. package/build/bounded-wait.js +32 -1
  6. package/build/bridge-config.js +104 -0
  7. package/build/codex-bridge-profile.js +10 -1
  8. package/build/commands.generated.js +7 -6
  9. package/build/conductor/bridge-api-client.js +565 -32
  10. package/build/conductor/bring-up-facts.js +3 -1
  11. package/build/conductor/doctor.js +23 -14
  12. package/build/conductor/epic-child-continuation.js +351 -0
  13. package/build/conductor/epic-implementer-cli.js +154 -17
  14. package/build/conductor/git-hooks.js +529 -118
  15. package/build/conductor/guided-repair.js +323 -0
  16. package/build/conductor/hook-runtime-qualification.js +340 -0
  17. package/build/conductor/readiness-cli.js +30 -9
  18. package/build/conductor/readiness-sections.js +5 -4
  19. package/build/conductor/readiness.js +45 -12
  20. package/build/conductor/recovery-cli.js +859 -27
  21. package/build/conductor/recovery-operations.js +574 -5
  22. package/build/conductor/repair-contract.js +69 -3
  23. package/build/conductor-bundle-artifacts.js +1 -0
  24. package/build/credential-store.js +52 -13
  25. package/build/diagnostic-text.js +36 -0
  26. package/build/docs.generated.js +3 -2
  27. package/build/doctor.js +147 -21
  28. package/build/drive-epic-key.js +12 -0
  29. package/build/drive-epic.js +1537 -125
  30. package/build/epic-coherence-input-cli.js +137 -0
  31. package/build/epic-coherence-input.js +920 -0
  32. package/build/epic-coherence-input.test-fixtures.js +175 -0
  33. package/build/epic-implementer-bin.js +41 -33
  34. package/build/epic-implementer-bundle-cli.js +14 -1
  35. package/build/epic-launch-diagnostic.js +31 -0
  36. package/build/epic-launch-profile.js +58 -19
  37. package/build/epic-run-status.js +5 -0
  38. package/build/epic-shared/bridge-client.js +46 -4
  39. package/build/executor/cli.js +39 -0
  40. package/build/executor/completion-contract.js +423 -0
  41. package/build/executor/completion-supervision.js +291 -0
  42. package/build/executor/correction-dispatch.js +60 -0
  43. package/build/executor/credentials.js +3 -1
  44. package/build/executor/deps.js +65 -1
  45. package/build/executor/env.js +12 -0
  46. package/build/executor/heartbeat.js +13 -3
  47. package/build/executor/http-client.js +91 -4
  48. package/build/executor/integration-job.js +6 -1
  49. package/build/executor/job-errors.js +61 -4
  50. package/build/executor/job-log-registry.js +340 -73
  51. package/build/executor/job-runner.js +1550 -55
  52. package/build/executor/job-types.js +9 -6
  53. package/build/executor/preflight.js +189 -1
  54. package/build/executor/process-containment.js +756 -0
  55. package/build/executor/process.js +235 -5
  56. package/build/executor/prompt-spec.js +366 -1
  57. package/build/executor/provider-checks.js +69 -0
  58. package/build/executor/rebase-finalization.js +351 -0
  59. package/build/executor/reconcile-overlap-job.js +77 -84
  60. package/build/executor/required-verification.js +313 -0
  61. package/build/executor/required-work-ledger.js +1121 -0
  62. package/build/executor/results.js +142 -0
  63. package/build/executor/resume-pre-spawn.js +87 -4
  64. package/build/executor/runner.js +168 -0
  65. package/build/executor/stale-artifacts.js +5 -4
  66. package/build/executor/test-declaration.js +20 -0
  67. package/build/executor/types.js +13 -0
  68. package/build/executor/watch-cli.js +35 -8
  69. package/build/executor/worker-command.js +70 -34
  70. package/build/executor/worker-finalization.js +168 -26
  71. package/build/executor/worker-guard-hook.js +75 -14
  72. package/build/executor/worker-log.js +137 -70
  73. package/build/executor/worktree-gc.js +30 -6
  74. package/build/executor/worktree.js +13 -0
  75. package/build/executor-launch.js +658 -0
  76. package/build/index.js +594 -1152
  77. package/build/init.js +107 -4
  78. package/build/install-bridge-conductor.js +231 -41
  79. package/build/install-bridge.js +284 -20
  80. package/build/install-doctor.js +172 -30
  81. package/build/install-reexec.js +69 -7
  82. package/build/macos-terminal-permission-guidance.js +16 -0
  83. package/build/merge-pull-request.js +1 -1
  84. package/build/model-thresholds-tool.js +185 -0
  85. package/build/pipelines.generated.js +9 -8
  86. package/build/plan-discovery.js +137 -0
  87. package/build/plan-epic-implementer-eligibility.js +2 -2
  88. package/build/plane/cli.js +37 -3
  89. package/build/plane/member-logs.js +3 -0
  90. package/build/plane/member-roster.js +7 -1
  91. package/build/plane/shutdown.js +59 -1
  92. package/build/plane/status.js +4 -0
  93. package/build/plane/supervisor.js +146 -0
  94. package/build/plane/worker-exit-code.js +2 -0
  95. package/build/project-root.js +99 -0
  96. package/build/readme.generated.js +1 -1
  97. package/build/review-tickets.js +156 -13
  98. package/build/scripts/executor-protocol-contract-driver.js +13 -3
  99. package/build/setup-epic.js +208 -125
  100. package/build/sfcc/setup-status.js +2 -0
  101. package/build/sfcc/tool-wrapper.js +2 -0
  102. package/build/sfcc/tools-configured.js +96 -0
  103. package/build/start-tickets.js +163 -58
  104. package/build/upgrade-cli.js +109 -24
  105. package/build/version.generated.js +3 -3
  106. package/build/windows-npm-entry.js +103 -0
  107. package/build/worker-guard-hook-bin.js +5 -4
  108. package/build/worktree-core.js +6 -5
  109. package/docs/CONDUCTOR.md +116 -2
  110. package/docs/install/mcp-tool-integrations.md +1 -0
  111. package/docs/install/sfcc-integration.md +12 -7
  112. package/package.json +2 -1
  113. package/pipelines/implement-ticket.json +1 -1
@@ -35,7 +35,8 @@
35
35
  import os from "node:os";
36
36
  import { readFile as fsReadFile, stat as fsStat } from "node:fs/promises";
37
37
  import { collectConductorReadinessGate, formatConductorReadinessGateReport, } from "./readiness.js";
38
- import { resolveConductorBridgeApiAccess } from "./bridge-api-client.js";
38
+ import { readinessEndpointEnvironments, resolveConductorBridgeApiAccess, resolveEpicLaunchBridgeApiAccess } from "./bridge-api-client.js";
39
+ import { validateHttpBaseUrl } from "../base-url.js";
39
40
  import { claudeReviewWorkflowPath } from "../claude-review-workflow.js";
40
41
  import { runDefaultPlanePreflight } from "../plane/cli.js";
41
42
  /** Fixed notice emitted to stderr when a source could not be collected. */
@@ -43,7 +44,7 @@ export const READINESS_COLLECTION_NOTICE = "one or more readiness sources could
43
44
  /** Usage text for `epic-implementer readiness`. */
44
45
  export function getReadinessUsage() {
45
46
  return [
46
- "Usage: epic-implementer readiness [--json] [--no-deny-probe]",
47
+ "Usage: epic-implementer readiness [--json] [--no-deny-probe] [--base-url <url>]",
47
48
  "",
48
49
  "Read-only ADVISORY report of every conductor prerequisite, consolidated from the",
49
50
  "Bridge install checklist, the epic-implementer doctor, the plane preflight, and the",
@@ -58,19 +59,31 @@ export function getReadinessUsage() {
58
59
  " --json Print the versioned structured report as JSON",
59
60
  " --no-deny-probe Accepted for parity with `epic-implementer doctor`; inert here, because",
60
61
  " this command never spawns the deny-enforcement probe",
62
+ " --base-url <url> Select a read-only Bridge API endpoint for this report;",
63
+ " this does not authorize or supply a credential",
61
64
  " --help Print this usage message",
62
65
  ].join("\n");
63
66
  }
64
67
  /** Parse `epic-implementer readiness` argv. Unknown flags and positionals are errors. */
65
68
  export function parseReadinessArgs(argv) {
66
69
  const parsed = { json: false, help: false, noDenyProbe: false };
67
- for (const token of argv) {
70
+ for (let index = 0; index < argv.length; index++) {
71
+ const token = argv[index];
68
72
  if (token === "--json")
69
73
  parsed.json = true;
70
74
  else if (token === "--no-deny-probe")
71
75
  parsed.noDenyProbe = true;
72
76
  else if (token === "--help" || token === "-h")
73
77
  parsed.help = true;
78
+ else if (token === "--base-url") {
79
+ const raw = argv[++index];
80
+ if (!raw || raw.startsWith("--"))
81
+ return { error: "--base-url requires an HTTP(S) URL." };
82
+ const valid = validateHttpBaseUrl(raw);
83
+ if (!valid.ok)
84
+ return { error: "--base-url requires a valid HTTP(S) URL." };
85
+ parsed.baseUrl = valid.baseUrl;
86
+ }
74
87
  else
75
88
  return { error: `Unknown argument "${token}". Run "epic-implementer readiness --help" for usage.` };
76
89
  }
@@ -83,8 +96,16 @@ export function parseReadinessArgs(argv) {
83
96
  * epic-implementer doctor's local inspections, and the same plane preflight
84
97
  * `plane up` and `drive-epic` run. Nothing is re-implemented here.
85
98
  */
86
- async function collectProductionReport(repoRoot, env) {
87
- const accessResult = await resolveConductorBridgeApiAccess({ env, cwd: repoRoot });
99
+ async function collectProductionReport(repoRoot, env, baseUrl) {
100
+ const { reportEnv, resolverEnv } = readinessEndpointEnvironments(env, baseUrl);
101
+ const accessResult = baseUrl === undefined
102
+ ? await resolveConductorBridgeApiAccess({ env: reportEnv, cwd: repoRoot })
103
+ : await resolveEpicLaunchBridgeApiAccess({ baseUrl }, { env: resolverEnv, cwd: repoRoot });
104
+ if (baseUrl !== undefined && !accessResult.ok) {
105
+ // A refused override is never permission for a downstream doctor collector
106
+ // to resolve credentials afresh from the general CLI environment.
107
+ return collectConductorReadinessGate({ repoName: null });
108
+ }
88
109
  const access = accessResult.ok ? accessResult.access : null;
89
110
  return collectConductorReadinessGate({
90
111
  // Never guessed: an unresolved identity is reported as such rather than
@@ -101,7 +122,7 @@ async function collectProductionReport(repoRoot, env) {
101
122
  readWorkflowFile: () => fsReadFile(claudeReviewWorkflowPath(repoRoot), "utf-8"),
102
123
  projectRoot: repoRoot,
103
124
  installDoctorDeps: {
104
- env,
125
+ env: reportEnv,
105
126
  cwd: repoRoot,
106
127
  platform: process.platform,
107
128
  homedir: os.homedir,
@@ -112,8 +133,8 @@ async function collectProductionReport(repoRoot, env) {
112
133
  },
113
134
  // The deny-enforcement probe is never spawned from this command; the check
114
135
  // is reported as an explicit skip naming `epic-implementer doctor` instead.
115
- conductorDoctorDeps: { env, skipDenyProbe: true },
116
- runPlanePreflight: () => runDefaultPlanePreflight(repoRoot, env),
136
+ conductorDoctorDeps: { env: reportEnv, skipDenyProbe: true },
137
+ runPlanePreflight: () => runDefaultPlanePreflight(repoRoot, reportEnv),
117
138
  });
118
139
  }
119
140
  /**
@@ -138,7 +159,7 @@ export async function runConductorReadinessCommand(argv, deps = {}) {
138
159
  }
139
160
  const cwd = deps.cwd ?? process.cwd();
140
161
  const env = deps.env ?? process.env;
141
- const collect = deps.collect ?? ((repoRoot) => collectProductionReport(repoRoot, env));
162
+ const collect = deps.collect ?? ((repoRoot) => collectProductionReport(repoRoot, env, parsed.baseUrl));
142
163
  const report = await collect(cwd);
143
164
  // Fixed, sanitized, and stderr-only: never a credential, exception, header,
144
165
  // body, subprocess output, or absolute path. It fires on a COLLECTION gap,
@@ -771,12 +771,13 @@ export function conductorHookTargetsSection(legacyConductor, conductorContext) {
771
771
  detail: "advisory — not a git worktree, so no managed conductor hooks apply",
772
772
  };
773
773
  }
774
+ // BAPI-1290: the shared per-hook `usable` verdict — a recognized command, an
775
+ // executable hook, and a qualified persistent runtime whose Node and native
776
+ // binding load. A file that merely exists is not delivery, and a hook without
777
+ // that verdict (an older or partial report) is unknown, never usable.
774
778
  const usable = (name) => {
775
779
  const hook = (hooks.hooks ?? []).find((h) => h.name === name);
776
- return (hook !== undefined &&
777
- hook.exists &&
778
- hook.managed_block_present &&
779
- hook.embedded_bin_is_file);
780
+ return hook !== undefined && hook.usable === true;
780
781
  };
781
782
  const rendered = MANAGED_HOOK_NAMES.map((name) => `${name}=${usable(name)}`).join(", ");
782
783
  const allUsable = MANAGED_HOOK_NAMES.every((name) => usable(name));
@@ -141,7 +141,7 @@ export const SERVER_READINESS_DESCRIPTORS = [
141
141
  { id: "executor-readiness", label: "Executor server observation" },
142
142
  { id: "review-workflow", label: "Review workflow protocol" },
143
143
  { id: "conductor-ci-workflow", label: "Conductor CI migration guard" },
144
- // BAPI-1102 — the two ONE-TIME unattended prerequisites plus the aggregate the
144
+ // BAPI-1102 — the two unattended repository prerequisites plus the aggregate the
145
145
  // third unattended refusal reads. Noun phrases, like every row above: these
146
146
  // render as list items under a source heading, not as sentences.
147
147
  { id: "unattended-consent", label: "Repository unattended consent" },
@@ -189,8 +189,10 @@ const SERVER_REMEDIATIONS = {
189
189
  olderServer: "upgrade the Bridge API deploy so it reports this fact; its state is unknown here, not healthy.",
190
190
  // BAPI-1102. Each names the ONE action that clears it, and none of them
191
191
  // mentions a webhook URL, a destination, or any configuration value.
192
- unattendedConsent: "set `unattended_epic_implementer_allowed` for this repository (docs/claude/account-settings-operator-runbook.md), or run setup with --attended.",
193
- unattendedNotifyDefault: "supply a --policy-file declaring notify.webhook_url, or run setup with --attended; an unattended run must have a working escalation channel, and notify.local_sink is not one.",
192
+ // BAPI-1273: consent defaults ON; the repository owner switches it on the
193
+ // admin panel's Setup page. No MCP or CLI surface ever writes it.
194
+ unattendedConsent: "turn on 'Allow unattended Epic Implementer runs' on the repository's Setup page in the Bridge admin panel, or run setup with --attended. If it is already on, contact Bridge support.",
195
+ unattendedNotifyDefault: "supply a --policy-file declaring notify.webhook_url, or add an email address to the account so escalation alerts can be emailed, or run setup with --attended; an unattended run must have a working escalation channel, and notify.local_sink is not one.",
194
196
  repositoryWorkflowReadiness: "run `install-bridge conductor` so the review and conductor-CI workflows are confirmed on the default branch, or run setup with --attended.",
195
197
  // BAPI-1135. Both are IMPORTED from the shared classifier rather than written
196
198
  // out here, so the remedy command has exactly one spelling across the refusal,
@@ -336,7 +338,28 @@ export function mapServerReadinessToChecks(readiness, failure = "unreachable") {
336
338
  });
337
339
  // BAPI-1260 — appended ONLY when the server reported the block, so every
338
340
  // pre-BAPI-1260 report keeps exactly the descriptor set above.
339
- return [...described, ...admissionEvidenceChecks(readiness)];
341
+ return [...described, ...admissionEvidenceChecks(readiness), ...genericDiagnosticChecks(readiness)];
342
+ }
343
+ function genericDiagnosticChecks(readiness) {
344
+ return (readiness.diagnostics ?? []).map((diagnostic, index) => {
345
+ const inapplicable = diagnostic.applicability === "inapplicable";
346
+ const declared = diagnostic.severity !== null && diagnostic.applicability !== null;
347
+ const satisfied = declared && diagnostic.verdict === "passed" && diagnostic.applicability === "applicable";
348
+ const advisory = diagnostic.severity === "advisory";
349
+ const status = !declared ? "fail" : inapplicable ? "skip" : satisfied ? "pass" : advisory ? "warn" : "fail";
350
+ return createReadinessCheckSafely({
351
+ id: `server.diagnostic-${index + 1}-${diagnostic.id.replace(/[_.]/g, "-")}`,
352
+ source: "server",
353
+ label: `Server diagnostic ${diagnostic.id}`,
354
+ status,
355
+ detail: `severity ${diagnostic.severity ?? "unknown"}; applicability ${diagnostic.applicability ?? "unknown"}; verdict ${diagnostic.verdict}`,
356
+ ...(status === "pass" ? {} : {
357
+ remediation: status === "skip"
358
+ ? "This diagnostic does not apply to the selected topology."
359
+ : "Restore the diagnostic producer or resolve the reported condition before launch.",
360
+ }),
361
+ });
362
+ });
340
363
  }
341
364
  /** Human labels for the known BAPI-1260 evidence predicates. */
342
365
  const ADMISSION_EVIDENCE_LABELS = {
@@ -351,7 +374,7 @@ const ADMISSION_EVIDENCE_LABELS = {
351
374
  /** Who acts, in fixed prose. Never a value from the payload. */
352
375
  const ADMISSION_OWNER_REMEDIATION = {
353
376
  operator: "the operator re-runs guided setup (`install conductor --launch-profile <name>`) and re-observes.",
354
- repository_admin: "a repository administrator resolves it through the account-settings runbook; setup never grants it.",
377
+ repository_admin: "a repository administrator resolves it (unattended consent is the 'Allow unattended Epic Implementer runs' toggle on the repository's Setup page in the Bridge admin panel); setup never grants it.",
355
378
  bridge_operations: "escalate to Bridge operations; this is not something an operator command can change.",
356
379
  };
357
380
  /**
@@ -485,7 +508,7 @@ function unattendedOutcomes(readiness) {
485
508
  : {
486
509
  id: "unattended-consent",
487
510
  status: "warn",
488
- detail: "unattended_epic_implementer_allowed is NOT set — an unattended run will be refused before it is created",
511
+ detail: "unattended runs are off for this repository — an unattended run will be refused before it is created",
489
512
  remediation: SERVER_REMEDIATIONS.unattendedConsent,
490
513
  },
491
514
  u.notify_webhook_default_declared
@@ -498,12 +521,21 @@ function unattendedOutcomes(readiness) {
498
521
  ? "a notify webhook default is declared and verified"
499
522
  : "a notify webhook default is declared (verified at approval, not here)",
500
523
  }
501
- : {
502
- id: "unattended-notify-default",
503
- status: "warn",
504
- detail: "no repository notify webhook default is declared — an unattended run needs an escalation channel, and no column supplies a repository default today, so the run must declare notify.webhook_url itself",
505
- remediation: SERVER_REMEDIATIONS.unattendedNotifyDefault,
506
- },
524
+ : u.escalation_email_available === true
525
+ ? {
526
+ // BAPI-1274 — with no webhook declared, escalation alerts go to the
527
+ // account's email address. Presence only: the address is never
528
+ // reported by the server and is never rendered here.
529
+ id: "unattended-notify-default",
530
+ status: "pass",
531
+ detail: "No webhook declared; escalation alerts will be emailed to the account's email address",
532
+ }
533
+ : {
534
+ id: "unattended-notify-default",
535
+ status: "warn",
536
+ detail: "no repository notify webhook default is declared — an unattended run needs an escalation channel, and no column supplies a repository default today, so the run must declare notify.webhook_url itself or the account needs an email address for escalation alerts",
537
+ remediation: SERVER_REMEDIATIONS.unattendedNotifyDefault,
538
+ },
507
539
  u.repository_readiness_confirmed
508
540
  ? {
509
541
  id: "repository-workflow-readiness",
@@ -891,6 +923,7 @@ export async function collectConductorReadinessGate(deps) {
891
923
  repoName: deps.repoName ?? null,
892
924
  unavailableSources,
893
925
  checks: validated,
926
+ ...(installReport?.readiness?.diagnostics ? { diagnostics: installReport.readiness.diagnostics } : {}),
894
927
  summary: summarizeReadinessChecks(validated),
895
928
  };
896
929
  }