@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.
- package/README.md +490 -366
- package/build/agent-capabilities/probe-context.js +8 -1
- package/build/agent-capabilities/probes.js +7 -1
- package/build/agents.generated.js +1 -1
- package/build/base-url.js +79 -0
- package/build/bridge-api-urls.js +9 -0
- package/build/chain-orchestrator.js +93 -15
- package/build/claude-review-workflow.js +264 -0
- package/build/claude-user-config-doctor.js +317 -0
- package/build/cli-release.js +53 -0
- package/build/commands.generated.js +6 -5
- package/build/conductor/bridge-api-client.js +393 -4
- package/build/conductor/deny-enforcement-preflight.js +1 -0
- package/build/conductor/done-gate.js +44 -5
- package/build/conductor/epic-reconcile.js +6 -0
- package/build/conductor/install-doctor.js +462 -0
- package/build/conductor-bin.js +3 -3
- package/build/conductor-bundle-artifacts.js +37 -15
- package/build/credential-store.js +205 -4
- package/build/direct-ticket-tools.js +70 -0
- package/build/doctor.js +473 -81
- package/build/executor/cli.js +83 -6
- package/build/executor/credentials.js +39 -11
- package/build/executor/deps.js +32 -1
- package/build/executor/env.js +71 -28
- package/build/executor/heartbeat.js +138 -17
- package/build/executor/http-client.js +49 -8
- package/build/executor/index.js +4 -0
- package/build/executor/job-errors.js +4 -0
- package/build/executor/job-runner.js +530 -20
- package/build/executor/observation.js +130 -0
- package/build/executor/permissions.js +114 -8
- package/build/executor/preflight.js +127 -8
- package/build/executor/prompt-spec.js +51 -0
- package/build/executor/runner.js +23 -2
- package/build/executor/service-unit.js +876 -0
- package/build/executor/test-clock.js +75 -3
- package/build/executor/types.js +4 -18
- package/build/executor/worker-command.js +73 -12
- package/build/executor/worker-config-isolation.js +287 -0
- package/build/executor/worker-finalization.js +68 -14
- package/build/executor/worktree.js +46 -4
- package/build/index.js +1039 -237
- package/build/init.js +503 -111
- package/build/install-bridge-conductor.js +491 -0
- package/build/install-bridge.js +1188 -247
- package/build/install-reexec.js +233 -0
- package/build/launcher-config-inspection.js +351 -0
- package/build/mcp-host-config.js +11 -1
- package/build/mcp-install-state.js +32 -0
- package/build/mcp-invoke.js +49 -6
- package/build/mcp-provisioning.js +52 -13
- package/build/mcp-registration-doctor.js +14 -5
- package/build/notifications.js +553 -0
- package/build/pipeline-orchestrator.js +146 -4
- package/build/pipeline-utils.js +3 -0
- package/build/pipelines.generated.js +32 -13
- package/build/plan-execution-ledger.js +550 -0
- package/build/plan-phase-routing.js +272 -0
- package/build/plane/alembic-head.js +110 -0
- package/build/plane/build-freshness.js +167 -0
- package/build/plane/cli.js +480 -0
- package/build/plane/defaults.js +266 -0
- package/build/plane/manifest.js +377 -0
- package/build/plane/member-logs.js +147 -0
- package/build/plane/member-roster.js +147 -0
- package/build/plane/preflight.js +289 -0
- package/build/plane/shutdown.js +195 -0
- package/build/plane/status.js +125 -0
- package/build/plane/supervisor.js +569 -0
- package/build/plane/test-fakes.js +156 -0
- package/build/plane/types.js +75 -0
- package/build/readme.generated.js +1 -1
- package/build/run-unit-tests-launcher.js +259 -0
- package/build/setup-epic.js +772 -28
- package/build/sfcc/log-gate.js +38 -11
- package/build/sfcc/log-query.js +55 -15
- package/build/sfcc/ocapi-shape.js +51 -14
- package/build/sfcc/output.js +41 -11
- package/build/sfcc/permissions.js +24 -2
- package/build/sfcc/read-projection.js +181 -0
- package/build/sfcc/read-result.js +158 -0
- package/build/sfcc/reads-custom-object-def.js +29 -18
- package/build/sfcc/reads-site-preference.js +75 -29
- package/build/sfcc/reads-system-object.js +40 -34
- package/build/sfcc/sfcc-result.js +106 -0
- package/build/sfcc/tool-wrapper.js +56 -13
- package/build/sfcc/write-grants.js +45 -22
- package/build/sfcc/write-guard.js +21 -13
- package/build/sfcc/write-result.js +61 -14
- package/build/sfcc/write-tool-common.js +126 -32
- package/build/sfcc/writes-system-object.js +11 -50
- package/build/start-tickets-prereqs.js +129 -0
- package/build/start-tickets.js +17 -13
- package/build/ticket-backend-metadata.js +59 -0
- package/build/ticket-key-utils.js +92 -0
- package/build/tool-error-envelope.js +71 -0
- package/build/tool-surface-gating.js +72 -0
- package/build/update-status.js +102 -0
- package/build/upgrade-advice.js +47 -0
- package/build/upgrade-cli.js +412 -110
- package/build/version.generated.js +1 -1
- package/build/worktree-core.js +73 -0
- package/docs/CONDUCTOR.md +132 -6
- package/docs/install/mcp-tool-integrations.md +29 -21
- package/package.json +9 -6
- package/pipelines/implement-ticket.json +19 -4
- package/build/conductor/supervisor-judgment-python.js +0 -141
- 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
|
-
|
|
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
|
|
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
|
-
|
|
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, {
|
package/build/pipeline-utils.js
CHANGED
|
@@ -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).
|