@bridge_gpt/mcp-server 0.2.65 → 0.2.67

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 (132) hide show
  1. package/README.md +269 -82
  2. package/build/agent-capabilities/probes.js +15 -5
  3. package/build/agent-launchers/claude-executor-adapter.js +55 -34
  4. package/build/agent-launchers/executor-adapter.js +34 -4
  5. package/build/agents.generated.js +1 -1
  6. package/build/bounded-wait.js +67 -10
  7. package/build/bridge-config.js +104 -0
  8. package/build/codex-bridge-profile.js +10 -1
  9. package/build/commands.generated.js +12 -12
  10. package/build/conductor/bridge-api-client.js +372 -10
  11. package/build/conductor/bring-up-facts.js +1 -1
  12. package/build/conductor/doctor.js +3 -3
  13. package/build/conductor/epic-child-continuation.js +61 -34
  14. package/build/conductor/epic-implementer-cli.js +34 -6
  15. package/build/conductor/errors.js +4 -3
  16. package/build/conductor/guided-repair.js +327 -0
  17. package/build/conductor/hook-runtime-qualification.js +1 -1
  18. package/build/conductor/merge-execution-contract.js +27 -8
  19. package/build/conductor/merge-execution-eligibility.js +3 -2
  20. package/build/conductor/pr-ci-producer.js +1 -1
  21. package/build/conductor/readiness-cli.js +46 -9
  22. package/build/conductor/readiness-sections.js +41 -6
  23. package/build/conductor/readiness.js +204 -30
  24. package/build/conductor/recovery-cli.js +703 -20
  25. package/build/conductor/recovery-operations.js +392 -3
  26. package/build/conductor/repair-contract.js +112 -3
  27. package/build/conductor/repository-workflow-remedy.js +125 -0
  28. package/build/conductor/tools.js +2 -2
  29. package/build/conductor-bundle-artifacts.js +8 -0
  30. package/build/credential-store.js +5 -4
  31. package/build/diagnostic-text.js +36 -0
  32. package/build/docs.generated.js +8 -3
  33. package/build/doctor.js +70 -10
  34. package/build/drive-epic-key.js +6 -5
  35. package/build/drive-epic.js +479 -131
  36. package/build/epic-coherence-input.js +2 -1
  37. package/build/epic-implementer-bin.js +30 -26
  38. package/build/epic-implementer-bundle-cli.js +2 -2
  39. package/build/epic-launch-diagnostic.js +31 -0
  40. package/build/epic-launch-profile.js +44 -14
  41. package/build/executor/cli.js +3 -2
  42. package/build/executor/completion-contract.js +48 -5
  43. package/build/executor/completion-supervision.js +9 -0
  44. package/build/executor/correction-dispatch.js +60 -0
  45. package/build/executor/env.js +25 -0
  46. package/build/executor/heartbeat.js +1 -1
  47. package/build/executor/http-client.js +35 -0
  48. package/build/executor/integration-job.js +6 -1
  49. package/build/executor/job-errors.js +38 -4
  50. package/build/executor/job-log-registry.js +340 -73
  51. package/build/executor/job-runner.js +485 -74
  52. package/build/executor/job-types.js +8 -13
  53. package/build/executor/observation.js +6 -1
  54. package/build/executor/preflight.js +136 -10
  55. package/build/executor/prompt-spec.js +113 -9
  56. package/build/executor/required-work-ledger.js +6 -1
  57. package/build/executor/resume-pre-spawn.js +2 -0
  58. package/build/executor/runner.js +31 -2
  59. package/build/executor/service-unit.js +7 -1
  60. package/build/executor/stale-artifacts.js +5 -4
  61. package/build/executor/types.js +1 -0
  62. package/build/executor/watch-cli.js +35 -8
  63. package/build/executor/worker-command.js +43 -43
  64. package/build/executor/worker-finalization.js +161 -43
  65. package/build/executor/worker-guard-hook.js +152 -12
  66. package/build/executor/worker-log.js +137 -70
  67. package/build/executor/worktree-gc.js +30 -6
  68. package/build/executor/worktree.js +82 -1
  69. package/build/index.js +482 -660
  70. package/build/init.js +107 -4
  71. package/build/install-bridge-conductor.js +8 -6
  72. package/build/install-bridge.js +287 -23
  73. package/build/install-doctor.js +172 -30
  74. package/build/install-reexec.js +69 -7
  75. package/build/macos-terminal-permission-guidance.js +16 -0
  76. package/build/model-thresholds-tool.js +185 -0
  77. package/build/phase-context-git-probe.js +68 -0
  78. package/build/phase-result-artifacts.js +173 -5
  79. package/build/pipelines.generated.js +19 -25
  80. package/build/plane/alembic-head.js +12 -3
  81. package/build/plane/base-worktree-guard.js +147 -0
  82. package/build/plane/cli.js +217 -17
  83. package/build/plane/code-snapshot.js +468 -0
  84. package/build/plane/defaults.js +48 -3
  85. package/build/plane/endpoint.js +41 -0
  86. package/build/plane/manifest.js +120 -1
  87. package/build/plane/member-roster.js +94 -19
  88. package/build/plane/preflight.js +30 -2
  89. package/build/plane/process-cwd.js +67 -0
  90. package/build/plane/restart.js +542 -0
  91. package/build/plane/shutdown.js +31 -0
  92. package/build/plane/status.js +145 -6
  93. package/build/plane/supervisor.js +588 -177
  94. package/build/plane/types.js +54 -2
  95. package/build/plane/worker-exit-code.js +2 -0
  96. package/build/printed-remedy-commands.js +37 -0
  97. package/build/project-root.js +99 -0
  98. package/build/readiness-check.js +1 -1
  99. package/build/readme.generated.js +1 -1
  100. package/build/review-generation.js +22 -0
  101. package/build/review-tickets.js +156 -13
  102. package/build/setup-epic.js +224 -127
  103. package/build/sfcc/config.js +9 -0
  104. package/build/sfcc/credentials.js +100 -38
  105. package/build/sfcc/hostname.js +67 -0
  106. package/build/sfcc/permissions.js +17 -13
  107. package/build/sfcc/register.js +1 -1
  108. package/build/sfcc/setup-status.js +2 -0
  109. package/build/sfcc/tool-wrapper.js +41 -43
  110. package/build/sfcc/tools-configured.js +96 -0
  111. package/build/sfcc/write-grants.js +17 -11
  112. package/build/sfcc/write-result.js +4 -3
  113. package/build/sfcc/writes-site-preference.js +20 -8
  114. package/build/start-tickets.js +332 -79
  115. package/build/tool-error-envelope.js +61 -0
  116. package/build/upgrade-cli.js +109 -24
  117. package/build/version.generated.js +3 -3
  118. package/build/visual-diff.js +22 -1
  119. package/build/windows-npm-entry.js +103 -0
  120. package/build/worker-guard-hook-bin.js +3 -5
  121. package/build/worker-guard-hook-main.js +47 -0
  122. package/build/worktree-core.js +136 -9
  123. package/docs/EPIC-IMPLEMENTER-INSTALL.md +849 -0
  124. package/docs/EPIC-IMPLEMENTER.md +662 -0
  125. package/docs/install/mcp-tool-integrations.md +25 -15
  126. package/docs/install/sfcc-integration.md +21 -8
  127. package/package.json +1 -1
  128. package/pipelines/implement-ticket.json +1 -1
  129. package/pipelines/plan-epic.json +0 -5
  130. package/pipelines/review-ticket.json +1 -1
  131. package/docs/CONDUCTOR.md +0 -605
  132. package/pipelines/idea-to-pr.json +0 -49
@@ -59,7 +59,7 @@ export const PHASE_RESULT_ARTIFACT_VERSION = 1;
59
59
  * it reaches the filesystem, rather than being sanitized into something that
60
60
  * silently addresses a different ticket's artifact.
61
61
  */
62
- const TICKET_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9]*-\d+$/;
62
+ const TICKET_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\d+$/;
63
63
  /** Terminal dispositions that mean "this step is done; do not redo it". */
64
64
  const REENTRY_TERMINAL_DISPOSITIONS = new Set([
65
65
  "executed",
@@ -74,6 +74,24 @@ const REENTRY_TERMINAL_DISPOSITIONS = new Set([
74
74
  */
75
75
  export const INLINE_ROUTING_SOURCE = "inline:get_plan_metadata+phase_result_artifacts";
76
76
  // ---------------------------------------------------------------------------
77
+ // Shapes
78
+ // ---------------------------------------------------------------------------
79
+ /**
80
+ * Why a checkpoint is not trusted as commit evidence. Closed vocabulary: these
81
+ * tokens are the only diagnostics a response may carry about a failed probe, so
82
+ * no raw git output, path, or credential can ride along.
83
+ */
84
+ export const CHECKPOINT_STALE_REASONS = [
85
+ "not_ancestor",
86
+ "git_unavailable",
87
+ "invalid_sha",
88
+ "probe_failed",
89
+ "head_unavailable",
90
+ "checkpoint_changed",
91
+ "coverage_mismatch",
92
+ "not_evaluated",
93
+ ];
94
+ // ---------------------------------------------------------------------------
77
95
  // Path safety
78
96
  // ---------------------------------------------------------------------------
79
97
  function assertValidTicketKey(ticketKey) {
@@ -265,6 +283,9 @@ export async function loadInlinePhaseContext(options) {
265
283
  const fingerprint = planFingerprint(metadata);
266
284
  let ledger = [];
267
285
  const artifactPaths = [];
286
+ // Latest record index per produce step, within the produce artifact's own list.
287
+ const produceLatestIndex = new Map();
288
+ let produceRecordCount = 0;
268
289
  // Canonical phase order, not directory order: the ledger is chronological and
269
290
  // production always precedes the phases that verify it.
270
291
  for (const priorPhase of PLAN_PHASES) {
@@ -277,21 +298,72 @@ export async function loadInlinePhaseContext(options) {
277
298
  // Re-check against the CURRENT metadata: an artifact that was valid when
278
299
  // written must still describe steps this phase owns under the plan in play now.
279
300
  const routable = assertStoredRecordsRoutable(artifact.records, metadata, priorPhase, relativePath);
301
+ if (priorPhase === "produce") {
302
+ produceRecordCount = routable.length;
303
+ routable.forEach((record, index) => produceLatestIndex.set(record.stepId, index));
304
+ }
280
305
  ledger = [...ledger, ...sanitizePlanStepRecords(routable)];
281
306
  artifactPaths.push(relativePath);
282
307
  }
283
308
  const checkpoint = await readInlineCheckpoint(docsDir, ticketKey);
284
309
  if (checkpoint)
285
310
  artifactPaths.push(checkpointRelativePath(ticketKey));
311
+ // Reachability is decided by the caller's git probe. Anything other than a
312
+ // confirmed `true` fails toward redo, and a checkpoint that changed between the
313
+ // probe and this load is not the one that was probed.
314
+ let reachable = options.checkpointReachable ?? "unknown";
315
+ let staleReason;
316
+ if (reachable === "unknown") {
317
+ staleReason = options.checkpointUnknownReason ?? "not_evaluated";
318
+ }
319
+ else if (reachable === false) {
320
+ staleReason = "not_ancestor";
321
+ }
322
+ if (checkpoint &&
323
+ reachable !== "unknown" &&
324
+ options.probedCheckpoint !== undefined &&
325
+ !sameCheckpoint(options.probedCheckpoint, checkpoint)) {
326
+ reachable = "unknown";
327
+ staleReason = "checkpoint_changed";
328
+ }
329
+ // A checkpoint covers the produce prefix only when its binding is intact.
330
+ const coverageIntact = checkpoint !== undefined &&
331
+ checkpoint.producedRecordCount > 0 &&
332
+ checkpoint.producedRecordCount <= produceRecordCount &&
333
+ checkpoint.producePlanFingerprint === fingerprint;
334
+ const coveredCount = checkpoint && reachable === true && coverageIntact
335
+ ? checkpoint.producedRecordCount
336
+ : 0;
337
+ if (checkpoint &&
338
+ reachable === true &&
339
+ checkpoint.producedRecordCount > 0 &&
340
+ !coverageIntact) {
341
+ staleReason = "coverage_mismatch";
342
+ }
286
343
  const current = currentLedgerState(ledger);
287
344
  const currentRecordsByStep = {};
288
345
  const terminalStepIds = [];
346
+ const uncommittedStepIds = [];
289
347
  for (const [stepId, record] of current) {
290
348
  currentRecordsByStep[stepId] = record;
291
- if (REENTRY_TERMINAL_DISPOSITIONS.has(record.disposition))
349
+ if (!REENTRY_TERMINAL_DISPOSITIONS.has(record.disposition))
350
+ continue;
351
+ const producedAt = produceLatestIndex.get(stepId);
352
+ if (producedAt !== undefined && producedAt >= coveredCount) {
353
+ // Latest produce record is not inside the committed prefix: the work it
354
+ // describes is not evidenced at the evaluated HEAD.
355
+ uncommittedStepIds.push(stepId);
356
+ }
357
+ else {
292
358
  terminalStepIds.push(stepId);
359
+ }
293
360
  }
294
361
  terminalStepIds.sort((a, b) => a - b);
362
+ uncommittedStepIds.sort((a, b) => a - b);
363
+ const checkpointIsEvidence = checkpoint !== undefined && reachable === true && staleReason === undefined;
364
+ const ledgerNote = uncommittedStepIds.length > 0
365
+ ? "Produce steps listed in uncommittedStepIds are recorded as done but no reachable checkpoint covers them, so redo them (checking for equivalent existing work first) and do not report them as already done."
366
+ : "";
295
367
  return {
296
368
  phase,
297
369
  routingSource: INLINE_ROUTING_SOURCE,
@@ -306,12 +378,40 @@ export async function loadInlinePhaseContext(options) {
306
378
  ledger,
307
379
  currentRecordsByStep,
308
380
  terminalStepIds,
381
+ uncommittedStepIds,
382
+ ledgerNote,
309
383
  unresolved: unresolvedLedgerRecords(ledger),
310
- ...(checkpoint ? { checkpoint } : {}),
384
+ ...(options.evaluatedHead ? { evaluatedHead: options.evaluatedHead } : {}),
385
+ ...(checkpoint && checkpointIsEvidence
386
+ ? { checkpoint: { branch: checkpoint.branch, sha: checkpoint.sha } }
387
+ : {}),
388
+ ...(checkpoint && !checkpointIsEvidence
389
+ ? {
390
+ staleCheckpoint: {
391
+ branch: checkpoint.branch,
392
+ sha: checkpoint.sha,
393
+ reason: staleReason ?? "not_evaluated",
394
+ },
395
+ }
396
+ : {}),
311
397
  artifactPaths,
312
398
  };
313
399
  }
314
- async function readInlineCheckpoint(docsDir, ticketKey) {
400
+ function sameCheckpoint(a, b) {
401
+ return (a.branch === b.branch &&
402
+ a.sha === b.sha &&
403
+ a.producedRecordCount === b.producedRecordCount &&
404
+ a.producePlanFingerprint === b.producePlanFingerprint);
405
+ }
406
+ /**
407
+ * Read and structurally validate the checkpoint artifact.
408
+ *
409
+ * Filesystem only. A legacy checkpoint with no coverage fields reads as covering
410
+ * zero produce records; it is never upgraded by inferring coverage from the
411
+ * current ledger. Malformed coverage, or a mis-versioned artifact, fails closed.
412
+ */
413
+ export async function readInlineCheckpoint(docsDir, ticketKey) {
414
+ ticketKey = assertValidTicketKey(ticketKey);
315
415
  const relativePath = checkpointRelativePath(ticketKey);
316
416
  const absolutePath = resolveWithinRoot(docsDir, relativePath);
317
417
  const parsed = await readJsonArtifact(absolutePath, relativePath);
@@ -333,7 +433,69 @@ async function readInlineCheckpoint(docsDir, ticketKey) {
333
433
  artifact.sha.trim() === "") {
334
434
  throw new PlanLedgerError(`${relativePath} is missing its branch or sha`);
335
435
  }
336
- return { branch: artifact.branch, sha: artifact.sha };
436
+ const hasCount = artifact.produce_record_count !== undefined;
437
+ const fingerprintValue = artifact.produce_plan_fingerprint;
438
+ if (!hasCount) {
439
+ if (fingerprintValue !== undefined && fingerprintValue !== null) {
440
+ throw new PlanLedgerError(`${relativePath} has a produce fingerprint but no record count`);
441
+ }
442
+ return {
443
+ branch: artifact.branch,
444
+ sha: artifact.sha,
445
+ producedRecordCount: 0,
446
+ producePlanFingerprint: null,
447
+ };
448
+ }
449
+ const count = artifact.produce_record_count;
450
+ if (typeof count !== "number" || !Number.isInteger(count) || count < 0) {
451
+ throw new PlanLedgerError(`${relativePath} has an invalid produce_record_count`);
452
+ }
453
+ if (count > 0 && (typeof fingerprintValue !== "string" || fingerprintValue === "")) {
454
+ throw new PlanLedgerError(`${relativePath} covers produce records but has no valid produce_plan_fingerprint`);
455
+ }
456
+ if (count === 0 &&
457
+ fingerprintValue !== undefined &&
458
+ fingerprintValue !== null &&
459
+ typeof fingerprintValue !== "string") {
460
+ throw new PlanLedgerError(`${relativePath} has an invalid produce_plan_fingerprint`);
461
+ }
462
+ return {
463
+ branch: artifact.branch,
464
+ sha: artifact.sha,
465
+ producedRecordCount: count,
466
+ producePlanFingerprint: typeof fingerprintValue === "string" && fingerprintValue !== "" ? fingerprintValue : null,
467
+ };
468
+ }
469
+ /**
470
+ * How much of the produce artifact a checkpoint written now would cover.
471
+ *
472
+ * Structural validation only, with no plan metadata fetch: the count and the
473
+ * artifact's stored fingerprint are read as written. An absent artifact covers
474
+ * zero records, and nothing is created to calculate that.
475
+ */
476
+ async function readProduceCoverage(docsDir, ticketKey) {
477
+ const relativePath = phaseResultRelativePath(ticketKey, "produce");
478
+ const absolutePath = resolveWithinRoot(docsDir, relativePath);
479
+ const parsed = await readJsonArtifact(absolutePath, relativePath);
480
+ if (parsed === undefined)
481
+ return { count: 0, fingerprint: null };
482
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
483
+ throw new PlanLedgerError(`${relativePath} is not a phase-result artifact object`);
484
+ }
485
+ const artifact = parsed;
486
+ if (artifact.artifact_version !== PHASE_RESULT_ARTIFACT_VERSION) {
487
+ throw new PlanLedgerError(`${relativePath} has unsupported artifact_version ${String(artifact.artifact_version)}; expected ${PHASE_RESULT_ARTIFACT_VERSION}`);
488
+ }
489
+ if (artifact.ticket_key !== ticketKey || artifact.phase !== "produce") {
490
+ throw new PlanLedgerError(`${relativePath} does not describe the produce phase of '${ticketKey}'`);
491
+ }
492
+ if (typeof artifact.plan_fingerprint !== "string" || artifact.plan_fingerprint === "") {
493
+ throw new PlanLedgerError(`${relativePath} has no plan_fingerprint`);
494
+ }
495
+ if (!Array.isArray(artifact.records)) {
496
+ throw new PlanLedgerError(`${relativePath} has no records array`);
497
+ }
498
+ return { count: artifact.records.length, fingerprint: artifact.plan_fingerprint };
337
499
  }
338
500
  // ---------------------------------------------------------------------------
339
501
  // Writing
@@ -435,6 +597,10 @@ export async function writeInlineCheckpoint(options) {
435
597
  if (checkpoint.pushed !== true || checkpoint.remoteMatchesHead !== true) {
436
598
  throw new PlanLedgerError("checkpoint must report pushed and remoteMatchesHead true; a checkpoint that is not on origin is not a checkpoint");
437
599
  }
600
+ // Coverage is derived here from the produce artifact as it stands, never taken
601
+ // from the caller: the push facts above are the caller's claim, but what the
602
+ // push covers is a fact about the ledger this module owns.
603
+ const coverage = await readProduceCoverage(docsDir, ticketKey);
438
604
  const relativePath = checkpointRelativePath(ticketKey);
439
605
  const absolutePath = resolveWithinRoot(docsDir, relativePath);
440
606
  const artifact = {
@@ -444,6 +610,8 @@ export async function writeInlineCheckpoint(options) {
444
610
  sha,
445
611
  pushed: true,
446
612
  remote_matches_head: true,
613
+ produce_record_count: coverage.count,
614
+ produce_plan_fingerprint: coverage.fingerprint,
447
615
  };
448
616
  await writeAtomically(absolutePath, relativePath, artifact);
449
617
  return { branch, sha, artifactPath: relativePath };