@bridge_gpt/mcp-server 0.2.34 → 0.2.37

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 (109) hide show
  1. package/README.md +490 -366
  2. package/build/agent-capabilities/probe-context.js +8 -1
  3. package/build/agent-capabilities/probes.js +7 -1
  4. package/build/agents.generated.js +1 -1
  5. package/build/base-url.js +79 -0
  6. package/build/bridge-api-urls.js +9 -0
  7. package/build/chain-orchestrator.js +93 -15
  8. package/build/claude-review-workflow.js +264 -0
  9. package/build/claude-user-config-doctor.js +317 -0
  10. package/build/cli-release.js +53 -0
  11. package/build/commands.generated.js +6 -5
  12. package/build/conductor/bridge-api-client.js +393 -4
  13. package/build/conductor/deny-enforcement-preflight.js +1 -0
  14. package/build/conductor/done-gate.js +44 -5
  15. package/build/conductor/epic-reconcile.js +6 -0
  16. package/build/conductor/install-doctor.js +462 -0
  17. package/build/conductor-bin.js +3 -3
  18. package/build/conductor-bundle-artifacts.js +37 -15
  19. package/build/credential-store.js +205 -4
  20. package/build/direct-ticket-tools.js +70 -0
  21. package/build/doctor.js +473 -81
  22. package/build/executor/cli.js +83 -6
  23. package/build/executor/credentials.js +39 -11
  24. package/build/executor/deps.js +32 -1
  25. package/build/executor/env.js +71 -28
  26. package/build/executor/heartbeat.js +138 -17
  27. package/build/executor/http-client.js +49 -8
  28. package/build/executor/index.js +4 -0
  29. package/build/executor/job-errors.js +4 -0
  30. package/build/executor/job-runner.js +530 -20
  31. package/build/executor/observation.js +130 -0
  32. package/build/executor/permissions.js +114 -8
  33. package/build/executor/preflight.js +127 -8
  34. package/build/executor/prompt-spec.js +51 -0
  35. package/build/executor/runner.js +23 -2
  36. package/build/executor/service-unit.js +876 -0
  37. package/build/executor/test-clock.js +75 -3
  38. package/build/executor/types.js +4 -18
  39. package/build/executor/worker-command.js +73 -12
  40. package/build/executor/worker-config-isolation.js +287 -0
  41. package/build/executor/worker-finalization.js +68 -14
  42. package/build/executor/worktree.js +46 -4
  43. package/build/index.js +1039 -237
  44. package/build/init.js +503 -111
  45. package/build/install-bridge-conductor.js +491 -0
  46. package/build/install-bridge.js +1188 -247
  47. package/build/install-reexec.js +233 -0
  48. package/build/launcher-config-inspection.js +351 -0
  49. package/build/mcp-host-config.js +11 -1
  50. package/build/mcp-install-state.js +32 -0
  51. package/build/mcp-invoke.js +49 -6
  52. package/build/mcp-provisioning.js +52 -13
  53. package/build/mcp-registration-doctor.js +14 -5
  54. package/build/notifications.js +553 -0
  55. package/build/pipeline-orchestrator.js +146 -4
  56. package/build/pipeline-utils.js +3 -0
  57. package/build/pipelines.generated.js +32 -13
  58. package/build/plan-execution-ledger.js +550 -0
  59. package/build/plan-phase-routing.js +272 -0
  60. package/build/plane/alembic-head.js +110 -0
  61. package/build/plane/build-freshness.js +167 -0
  62. package/build/plane/cli.js +480 -0
  63. package/build/plane/defaults.js +266 -0
  64. package/build/plane/manifest.js +377 -0
  65. package/build/plane/member-logs.js +147 -0
  66. package/build/plane/member-roster.js +147 -0
  67. package/build/plane/preflight.js +289 -0
  68. package/build/plane/shutdown.js +195 -0
  69. package/build/plane/status.js +125 -0
  70. package/build/plane/supervisor.js +569 -0
  71. package/build/plane/test-fakes.js +156 -0
  72. package/build/plane/types.js +75 -0
  73. package/build/readme.generated.js +1 -1
  74. package/build/run-unit-tests-launcher.js +259 -0
  75. package/build/setup-epic.js +772 -28
  76. package/build/sfcc/log-gate.js +38 -11
  77. package/build/sfcc/log-query.js +55 -15
  78. package/build/sfcc/ocapi-shape.js +51 -14
  79. package/build/sfcc/output.js +41 -11
  80. package/build/sfcc/permissions.js +24 -2
  81. package/build/sfcc/read-projection.js +181 -0
  82. package/build/sfcc/read-result.js +158 -0
  83. package/build/sfcc/reads-custom-object-def.js +29 -18
  84. package/build/sfcc/reads-site-preference.js +75 -29
  85. package/build/sfcc/reads-system-object.js +40 -34
  86. package/build/sfcc/sfcc-result.js +106 -0
  87. package/build/sfcc/tool-wrapper.js +56 -13
  88. package/build/sfcc/write-grants.js +45 -22
  89. package/build/sfcc/write-guard.js +21 -13
  90. package/build/sfcc/write-result.js +61 -14
  91. package/build/sfcc/write-tool-common.js +126 -32
  92. package/build/sfcc/writes-system-object.js +11 -50
  93. package/build/start-tickets-prereqs.js +129 -0
  94. package/build/start-tickets.js +17 -13
  95. package/build/ticket-backend-metadata.js +59 -0
  96. package/build/ticket-key-utils.js +92 -0
  97. package/build/tool-error-envelope.js +71 -0
  98. package/build/tool-surface-gating.js +72 -0
  99. package/build/update-status.js +102 -0
  100. package/build/upgrade-advice.js +47 -0
  101. package/build/upgrade-cli.js +412 -110
  102. package/build/version.generated.js +1 -1
  103. package/build/worktree-core.js +73 -0
  104. package/docs/CONDUCTOR.md +132 -6
  105. package/docs/install/mcp-tool-integrations.md +29 -21
  106. package/package.json +9 -6
  107. package/pipelines/implement-ticket.json +19 -4
  108. package/build/conductor/supervisor-judgment-python.js +0 -141
  109. package/build/conductor/supervisor-judgment.js +0 -215
@@ -18,6 +18,9 @@
18
18
  */
19
19
  import { createHash } from "node:crypto";
20
20
  import { resolveRecipe } from "./pipeline-utils.js";
21
+ import { parseUnsupportedInLocalModeEnvelope } from "./tool-error-envelope.js";
22
+ import { PlanLedgerError } from "./plan-execution-ledger.js";
23
+ import { assertPlanIsRoutable, buildPhaseRoutingContext, extractPlanMetadata, injectPhaseRoutingContext, parseCheckpointResult, phaseForInstructionFile, settlePhaseResult, } from "./plan-phase-routing.js";
21
24
  /**
22
25
  * Derive a STABLE, content-addressed hash of an idea — the basis for the
23
26
  * cross-run idempotency label ``bapi-idea-hash-{idea_hash}``. Normalizes
@@ -328,13 +331,70 @@ export async function resumePipeline(deps, input) {
328
331
  let nextIndex = stepIndex;
329
332
  let approvalAgentResult;
330
333
  if (step.type === "agent_task") {
331
- accumulatedResults.push({
334
+ const entry = {
332
335
  step: step.step,
333
336
  type: "agent_task",
334
337
  ok: true,
335
338
  description: step.description,
336
339
  result: input.agent_result,
337
- });
340
+ };
341
+ // BAPI-763: record the checkpoint's branch/SHA the moment checkpoint-work
342
+ // reports them, so the pre-PR verification phase that runs next can cross-check
343
+ // its own HEAD against the durable state rather than trusting its own account.
344
+ // Only a checkpoint that proved origin contains HEAD is recorded.
345
+ if (step.instruction_file === "checkpoint-work.md") {
346
+ const checkpoint = parseCheckpointResult(input.agent_result);
347
+ if (checkpoint) {
348
+ entry.checkpoint = { branch: checkpoint.branch, sha: checkpoint.sha };
349
+ }
350
+ else {
351
+ entry.plan_routing_diagnostic =
352
+ "checkpoint-work returned no durable checkpoint block (branch/sha with pushed and remoteMatchesHead true); pre-PR verification will fall back to verifying origin directly";
353
+ console.error(`[pipeline] ${entry.plan_routing_diagnostic}`);
354
+ }
355
+ }
356
+ // Settle a routed phase's owned steps into the durable ledger, and persist it on
357
+ // THIS entry — before the run advances, and before any approval gate. A ledger
358
+ // written after the gate is a ledger that does not survive it.
359
+ const phase = phaseForInstructionFile(step.instruction_file);
360
+ const planMetadata = recordedPlanMetadata(accumulatedResults);
361
+ if (phase && planMetadata) {
362
+ const outcome = settlePhaseResult(input.agent_result, planMetadata, phase, recordedLedger(accumulatedResults));
363
+ entry.plan_step_records = outcome.ledger;
364
+ if (outcome.diagnostic) {
365
+ entry.plan_routing_diagnostic = outcome.diagnostic;
366
+ console.error(`[pipeline] ${outcome.diagnostic}`);
367
+ }
368
+ // A phase that reported an envelope which violates the contract has made a
369
+ // claim that does not hold. Recording it would make that claim the durable
370
+ // truth, so the run stops here instead of advancing.
371
+ if (outcome.contractViolation) {
372
+ accumulatedResults.push({ ...entry, ok: false, error: outcome.diagnostic });
373
+ try {
374
+ await persistence.patchRun(row.pipeline_run_id, {
375
+ current_step_index: stepIndex,
376
+ results: accumulatedResults,
377
+ status: "failed",
378
+ expected_status: "paused",
379
+ expected_current_step_index: stepIndex,
380
+ });
381
+ }
382
+ catch {
383
+ // Persisting the failure is best-effort; the envelope below is what the
384
+ // caller acts on either way.
385
+ }
386
+ return {
387
+ status: "failed",
388
+ pipeline_run_id: row.pipeline_run_id,
389
+ pipeline: recipe.pipeline,
390
+ error_code: "VALIDATION",
391
+ error: outcome.diagnostic ?? "invalid phase result",
392
+ step_index: step.step,
393
+ results: accumulatedResults,
394
+ };
395
+ }
396
+ }
397
+ accumulatedResults.push(entry);
338
398
  nextIndex = stepIndex + 1;
339
399
  }
340
400
  else {
@@ -445,6 +505,67 @@ export async function deletePipelineRun(deps, input) {
445
505
  // ---------------------------------------------------------------------------
446
506
  // continuePipelineExecution — shared by run + resume
447
507
  // ---------------------------------------------------------------------------
508
+ // ---------------------------------------------------------------------------
509
+ // BAPI-763 — plan routing state, read back out of ``results``
510
+ // ---------------------------------------------------------------------------
511
+ /** The plan metadata recorded by the plan-generation step, if it ran. */
512
+ function recordedPlanMetadata(results) {
513
+ for (let i = results.length - 1; i >= 0; i -= 1) {
514
+ const metadata = results[i].plan_metadata;
515
+ if (metadata)
516
+ return metadata;
517
+ }
518
+ return undefined;
519
+ }
520
+ /** The durable ledger as of the most recent routed phase. */
521
+ function recordedLedger(results) {
522
+ for (let i = results.length - 1; i >= 0; i -= 1) {
523
+ const records = results[i].plan_step_records;
524
+ if (records)
525
+ return records;
526
+ }
527
+ return [];
528
+ }
529
+ /** Checkpoint branch/SHA recorded by the checkpoint step, if it ran. */
530
+ function recordedCheckpoint(results) {
531
+ for (let i = results.length - 1; i >= 0; i -= 1) {
532
+ const checkpoint = results[i].checkpoint;
533
+ if (checkpoint)
534
+ return checkpoint;
535
+ }
536
+ return undefined;
537
+ }
538
+ /**
539
+ * Attach plan provenance to a completed ``request_plan_generation`` entry and prove
540
+ * the plan is routable before any phase runs.
541
+ *
542
+ * Coverage is asserted here, at the earliest possible moment, because the whole point
543
+ * is to catch a step class that no phase owns while nothing has been produced yet.
544
+ * Discovering it after a pull request is open is discovering it too late.
545
+ *
546
+ * A plan with no metadata does not stop the run: only the implement-ticket recipe is
547
+ * routed, and every other pipeline calls this same code path. The absence is recorded
548
+ * as a diagnostic and the routed phases downstream escalate rather than guess.
549
+ */
550
+ function attachPlanMetadata(entry) {
551
+ if (entry.tool !== "request_plan_generation" || !entry.ok)
552
+ return;
553
+ try {
554
+ const metadata = extractPlanMetadata(entry.result);
555
+ if (!metadata) {
556
+ entry.plan_routing_diagnostic =
557
+ "plan generation returned no provenance metadata; routed phases will escalate rather than infer step ownership from plan prose";
558
+ return;
559
+ }
560
+ assertPlanIsRoutable(metadata);
561
+ entry.plan_metadata = metadata;
562
+ }
563
+ catch (err) {
564
+ const message = err instanceof PlanLedgerError ? err.message : String(err);
565
+ entry.plan_routing_diagnostic = message;
566
+ console.error(`[pipeline] plan routing unavailable: ${message}`);
567
+ }
568
+ }
448
569
  async function continuePipelineExecution(deps, persistence, row, recipe, autoApprove, forceExecuteAtIndex, approvalAgentResult) {
449
570
  let pipelineRunId = row.pipeline_run_id;
450
571
  let stepIndex = row.current_step_index;
@@ -508,6 +629,17 @@ async function continuePipelineExecution(deps, persistence, row, recipe, autoApp
508
629
  step_index: step.step,
509
630
  });
510
631
  }
632
+ // BAPI-763: a routed phase is handed its owned step ranges and the durable
633
+ // ledger through the instruction text. Injected here rather than left to the
634
+ // conversation because this is exactly the boundary the conversational
635
+ // hand-off did not survive — the recipe pauses, and the session that resumes
636
+ // may be a different one.
637
+ let instruction = step.instruction ?? "";
638
+ const phase = phaseForInstructionFile(step.instruction_file);
639
+ const planMetadata = recordedPlanMetadata(results);
640
+ if (phase && planMetadata) {
641
+ instruction = injectPhaseRoutingContext(instruction, buildPhaseRoutingContext(planMetadata, phase, recordedLedger(results), recordedCheckpoint(results)));
642
+ }
511
643
  return {
512
644
  status: "needs_agent_task",
513
645
  pipeline_run_id: pipelineRunId,
@@ -515,7 +647,7 @@ async function continuePipelineExecution(deps, persistence, row, recipe, autoApp
515
647
  step_index: step.step,
516
648
  total_steps: totalSteps,
517
649
  step_description: step.description,
518
- instruction: step.instruction ?? "",
650
+ instruction,
519
651
  results,
520
652
  preamble: recipe.agent_instructions,
521
653
  };
@@ -537,6 +669,9 @@ async function continuePipelineExecution(deps, persistence, row, recipe, autoApp
537
669
  if (capturedApprovalAgentResult !== undefined) {
538
670
  entry.approval_agent_result = capturedApprovalAgentResult;
539
671
  }
672
+ // BAPI-763: capture the plan's provenance and prove every step class has an
673
+ // executing phase, before the first routed phase begins.
674
+ attachPlanMetadata(entry);
540
675
  results.push(entry);
541
676
  stepIndex += 1;
542
677
  try {
@@ -569,7 +704,14 @@ async function continuePipelineExecution(deps, persistence, row, recipe, autoApp
569
704
  failureEntry.approval_agent_result = capturedApprovalAgentResult;
570
705
  }
571
706
  results.push(failureEntry);
572
- if (step.on_error === "warn_and_continue") {
707
+ // BAPI-710: an unsupported-local refusal is TERMINAL and overrides
708
+ // `warn_and_continue`. `warn_and_continue` means "this step is optional" —
709
+ // but a 409 saying the repository's backend cannot perform the operation is
710
+ // a permanent property of the repository, not a transient hiccup. Continuing
711
+ // past it converts a hard refusal into a partial success and lets the
712
+ // remaining steps run against work that was never done.
713
+ const unsupportedLocal = parseUnsupportedInLocalModeEnvelope(callResult.error);
714
+ if (step.on_error === "warn_and_continue" && unsupportedLocal === null) {
573
715
  stepIndex += 1;
574
716
  try {
575
717
  await persistence.patchRun(pipelineRunId, {
@@ -222,6 +222,7 @@ export function resolveRecipe(pipeline, instructions, variables, skipSteps, auto
222
222
  throw new Error(`Instruction file "${step.instruction_file}" not found in bundled instructions.`);
223
223
  }
224
224
  rawInstruction = content;
225
+ base.instruction_file = step.instruction_file;
225
226
  }
226
227
  else {
227
228
  rawInstruction = step.instruction;
@@ -236,6 +237,8 @@ export function resolveRecipe(pipeline, instructions, variables, skipSteps, auto
236
237
  "If requires_approval is true, pause before executing. For agent_task steps, the instruction file's own approval format is authoritative — follow it verbatim and do not substitute your own short confirmation prompt. For mcp_call steps with no instruction file, present the resolved params as bullet points and ask for approval. " +
237
238
  'For on_error "halt", stop the pipeline immediately on failure. ' +
238
239
  'For on_error "warn_and_continue", log a warning and proceed. ' +
240
+ "Recipes are re-entrant: a recovery run may begin again at step 1, and a step whose tool reports a server-side reuse (e.g. reused: true) has completed successfully — treat that as the expected fast path, not a failure, and continue. " +
241
+ 'A step can succeed (no on_error handling applies) while its own returned content is a JSON envelope shaped like error: "GATEWAY_TIMEOUT", status: 504, and a recovery_get field — recognize that shape and read it as "server-side processing may still be running", not as a failure or an invitation to retry. Poll the named retrieval tool (or the recovery_get URL) with the same artifact identifier until a terminal response is reached, and never reissue the original request tool. Only fall back to on_error handling if that retrieval itself terminally fails. ' +
239
242
  "Do not skip steps, reorder them, or substitute your own tool calls.";
240
243
  // Default-on: include the upgrade-advice surfacing convention unless the
241
244
  // caller explicitly opts out (BAPI_MCP_UPGRADE_ADVICE_ENABLED=false).