@bridge_gpt/mcp-server 0.2.66 → 0.2.68

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 (171) hide show
  1. package/README.md +421 -83
  2. package/build/agent-capabilities/probes.js +15 -5
  3. package/build/agent-launchers/claude-executor-adapter.js +70 -16
  4. package/build/agent-launchers/executor-adapter.js +7 -4
  5. package/build/agents.generated.js +22 -2
  6. package/build/bitbucket-workspace-remote.js +136 -0
  7. package/build/bootstrap-project-identity.js +24 -0
  8. package/build/bounded-wait.js +67 -10
  9. package/build/bridge-permissions.js +829 -0
  10. package/build/claude-settings.js +18 -0
  11. package/build/cli-help.js +21 -0
  12. package/build/command-assets-doctor.js +24 -70
  13. package/build/command-provisioning.js +29 -5
  14. package/build/commands.generated.js +12 -12
  15. package/build/conductor/bridge-api-client.js +857 -1
  16. package/build/conductor/bring-up-facts.js +1 -1
  17. package/build/conductor/command-drift-production.js +92 -0
  18. package/build/conductor/command-drift.js +89 -0
  19. package/build/conductor/doctor.js +72 -29
  20. package/build/conductor/epic-branch-ci-inspection.js +1375 -0
  21. package/build/conductor/epic-implementer-cli.js +98 -28
  22. package/build/conductor/errors.js +4 -3
  23. package/build/conductor/gate-discovery.js +890 -0
  24. package/build/conductor/guided-repair.js +6 -2
  25. package/build/conductor/hook-runtime-qualification.js +1 -1
  26. package/build/conductor/install-doctor.js +15 -3
  27. package/build/conductor/json-output.js +63 -0
  28. package/build/conductor/merge-execution-contract.js +27 -8
  29. package/build/conductor/merge-execution-eligibility.js +3 -2
  30. package/build/conductor/pr-ci-producer.js +1 -1
  31. package/build/conductor/readiness-cli.js +113 -12
  32. package/build/conductor/readiness-sections.js +410 -9
  33. package/build/conductor/readiness.js +388 -33
  34. package/build/conductor/recovery-cli.js +310 -12
  35. package/build/conductor/recovery-operations.js +167 -3
  36. package/build/conductor/repair-contract.js +54 -3
  37. package/build/conductor/repository-workflow-remedy.js +125 -0
  38. package/build/conductor/tools.js +2 -2
  39. package/build/conductor-bundle-artifacts.js +8 -0
  40. package/build/connect-bitbucket-api.js +41 -6
  41. package/build/connect-bitbucket.js +106 -33
  42. package/build/credential-store.js +207 -47
  43. package/build/docs.generated.js +62 -3
  44. package/build/doctor.js +92 -1
  45. package/build/drive-epic-key.js +6 -5
  46. package/build/drive-epic.js +129 -61
  47. package/build/epic-coherence-input.js +2 -1
  48. package/build/epic-coherence-input.test-fixtures.js +4 -3
  49. package/build/epic-implementer-bin.js +1379 -28
  50. package/build/epic-implementer-bundle-cli.js +2 -2
  51. package/build/epic-workarounds-path.js +39 -0
  52. package/build/executor/cli.js +33 -2
  53. package/build/executor/completion-contract.js +66 -10
  54. package/build/executor/completion-supervision.js +4 -0
  55. package/build/executor/deps.js +4 -1
  56. package/build/executor/env.js +19 -0
  57. package/build/executor/gate-qualification-job.js +499 -0
  58. package/build/executor/guarded-fast-forward-push.js +129 -0
  59. package/build/executor/heartbeat.js +1 -1
  60. package/build/executor/http-client.js +20 -0
  61. package/build/executor/integration-job.js +122 -8
  62. package/build/executor/job-errors.js +33 -1
  63. package/build/executor/job-runner.js +813 -87
  64. package/build/executor/likely-tests.js +290 -0
  65. package/build/executor/live-worker-registry.js +1 -1
  66. package/build/executor/observation.js +37 -3
  67. package/build/executor/packaged-recipe.js +106 -0
  68. package/build/executor/permissions.js +115 -28
  69. package/build/executor/platform.js +1 -1
  70. package/build/executor/preflight.js +112 -26
  71. package/build/executor/process-containment.js +36 -12
  72. package/build/executor/process.js +15 -7
  73. package/build/executor/prompt-spec.js +33 -1
  74. package/build/executor/recently-failed-tests-file.js +71 -0
  75. package/build/executor/reconcile-overlap-job.js +41 -23
  76. package/build/executor/required-verification.js +1 -1
  77. package/build/executor/required-work-ledger.js +111 -18
  78. package/build/executor/resume-pre-spawn.js +2 -0
  79. package/build/executor/retirement.js +69 -0
  80. package/build/executor/runner.js +122 -13
  81. package/build/executor/service-unit.js +7 -1
  82. package/build/executor/test-clock.js +15 -0
  83. package/build/executor/types.js +32 -0
  84. package/build/executor/viewer-tabs.js +58 -8
  85. package/build/executor/worker-command.js +23 -7
  86. package/build/executor/worker-diagnostics.js +37 -0
  87. package/build/executor/worker-finalization.js +113 -34
  88. package/build/executor/worker-guard-hook.js +316 -58
  89. package/build/executor/worker-log.js +4 -3
  90. package/build/executor/worker-verification-guidance.js +37 -0
  91. package/build/executor/worktree.js +166 -8
  92. package/build/first-build-advisory.js +97 -0
  93. package/build/generated-assets-advisory.js +14 -0
  94. package/build/generated-assets-catalog.js +66 -0
  95. package/build/generated-assets-context.js +46 -0
  96. package/build/generated-assets-dependencies.js +26 -0
  97. package/build/generated-assets-doctor.js +50 -0
  98. package/build/generated-assets-health.js +65 -0
  99. package/build/generated-assets-host.js +17 -0
  100. package/build/generated-assets-inventory.js +17 -0
  101. package/build/generated-assets-paths.js +60 -0
  102. package/build/generated-assets-publisher.js +133 -0
  103. package/build/generated-assets-remedy.js +25 -0
  104. package/build/generated-assets-repair.js +72 -0
  105. package/build/generated-assets-session.js +71 -0
  106. package/build/generated-assets-test-support.js +35 -0
  107. package/build/index.js +1224 -1054
  108. package/build/init.js +54 -177
  109. package/build/install-bridge-conductor-gate.js +1372 -0
  110. package/build/install-bridge-conductor.js +296 -41
  111. package/build/install-bridge.js +547 -40
  112. package/build/mcp-install-state.js +50 -4
  113. package/build/merge-workflow-install.js +3 -4
  114. package/build/phase-context-git-probe.js +68 -0
  115. package/build/phase-result-artifacts.js +173 -5
  116. package/build/pipeline-utils.js +6 -2
  117. package/build/pipelines.generated.js +34 -160
  118. package/build/plan-execution-ledger.js +2 -32
  119. package/build/plane/alembic-head.js +12 -3
  120. package/build/plane/base-worktree-guard.js +147 -0
  121. package/build/plane/cli.js +217 -17
  122. package/build/plane/code-snapshot.js +468 -0
  123. package/build/plane/defaults.js +48 -3
  124. package/build/plane/endpoint.js +41 -0
  125. package/build/plane/manifest.js +136 -2
  126. package/build/plane/member-roster.js +94 -19
  127. package/build/plane/preflight.js +83 -2
  128. package/build/plane/process-cwd.js +67 -0
  129. package/build/plane/restart.js +542 -0
  130. package/build/plane/shutdown.js +31 -0
  131. package/build/plane/status.js +143 -8
  132. package/build/plane/supervisor.js +586 -179
  133. package/build/plane/types.js +54 -2
  134. package/build/printed-remedy-commands.js +52 -0
  135. package/build/readiness-check.js +1 -1
  136. package/build/readme.generated.js +1 -1
  137. package/build/repair-assets.js +93 -0
  138. package/build/review-generation.js +22 -0
  139. package/build/run-unit-tests-launcher.js +130 -49
  140. package/build/secret-redaction.js +33 -0
  141. package/build/setup-epic.js +152 -22
  142. package/build/sfcc/config.js +9 -0
  143. package/build/sfcc/credentials.js +100 -38
  144. package/build/sfcc/hostname.js +67 -0
  145. package/build/sfcc/permissions.js +17 -13
  146. package/build/sfcc/register.js +1 -1
  147. package/build/sfcc/tool-wrapper.js +39 -43
  148. package/build/sfcc/write-grants.js +17 -11
  149. package/build/sfcc/write-result.js +4 -3
  150. package/build/sfcc/writes-site-preference.js +20 -8
  151. package/build/start-tickets-prereqs.js +70 -16
  152. package/build/start-tickets.js +208 -36
  153. package/build/tool-error-envelope.js +61 -0
  154. package/build/tool-surface-gating.js +36 -0
  155. package/build/upgrade-cli.js +55 -1
  156. package/build/version.generated.js +3 -3
  157. package/build/visual-diff.js +22 -1
  158. package/build/worker-guard-hook-bin.js +4 -6
  159. package/build/worker-guard-hook-main.js +47 -0
  160. package/build/worktree-core.js +145 -6
  161. package/docs/EPIC-IMPLEMENTER-INSTALL.md +867 -0
  162. package/docs/EPIC-IMPLEMENTER.md +728 -0
  163. package/docs/install/mcp-tool-integrations.md +24 -15
  164. package/docs/install/sfcc-integration.md +12 -4
  165. package/package.json +3 -3
  166. package/pipelines/greenfield-setup.json +4 -128
  167. package/pipelines/implement-ticket.json +3 -2
  168. package/pipelines/plan-epic.json +0 -5
  169. package/pipelines/review-ticket.json +1 -1
  170. package/docs/CONDUCTOR.md +0 -605
  171. package/pipelines/idea-to-pr.json +0 -49
@@ -6,8 +6,8 @@
6
6
  * inside `build/pipelines.generated.js`. `mcp_server/src/` does not exist there,
7
7
  * so an instruction that told the agent to "call `validateConductorBundleInputs`"
8
8
  * would be referencing a path only this repository has. This subcommand is the
9
- * reachable surface, mirroring how `store-and-approve-epic-plan.md` invokes
10
- * `setup-epic` rather than hand-rolling HTTP calls.
9
+ * reachable surface, the same way `setup-epic` is a command rather than
10
+ * hand-rolled HTTP calls.
11
11
  *
12
12
  * It holds no policy of its own: it parses argv, delegates to
13
13
  * `conductor-bundle-artifacts.ts`, and prints a JSON envelope. All I/O is behind
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The one TypeScript spelling of the Epic Implementer workaround folder (BAPI-1399).
3
+ *
4
+ * A worker that defers a MINOR requirement behind a guarded workaround commits a
5
+ * record at `.bridge/epic-workarounds/<TICKET>.md` on its ticket branch. While
6
+ * that folder exists on the epic head, the integration pull request stays in
7
+ * draft: the reconciler's coordinator withholds `mark_ready`
8
+ * (`api/library/epic_implementer/integration_completion.py`), and the local actor
9
+ * re-checks the folder before it takes a pull request out of draft
10
+ * (`executor/integration-job.ts`). Nothing about a workaround is stored in the
11
+ * database or in run state; the hold is worked out from the folder at the exact
12
+ * epic head every time.
13
+ *
14
+ * Python declares the same value once, beside its directory-listing helper in
15
+ * `api/library/github/github_webhooks_lib.py`. The static test
16
+ * `tests/pytest/static/test_epic_workarounds_path_pin.py` fails if any consumer
17
+ * spells the path differently or drops it.
18
+ */
19
+ import { TICKET_KEY_PATTERN } from "./ticket-key-utils.js";
20
+ /** The workaround folder, repository-relative, with its trailing slash. */
21
+ export const EPIC_WORKAROUNDS_DIR = ".bridge/epic-workarounds/";
22
+ /** The folder without its trailing slash: the form a contents API path takes. */
23
+ export const EPIC_WORKAROUNDS_DIR_PATH = EPIC_WORKAROUNDS_DIR.slice(0, -1);
24
+ /** A ticket key: the canonical grammar the Epic Implementer accepts everywhere else. */
25
+ const TICKET_KEY_RE = TICKET_KEY_PATTERN;
26
+ /** Upper bound on a ticket key, so a pasted blob is never a path segment. */
27
+ const MAX_TICKET_KEY_CHARS = 64;
28
+ /**
29
+ * The record path for one ticket, `.bridge/epic-workarounds/<TICKET>.md`, or
30
+ * `null` when the key is not a valid ticket key. A key is never sanitized into a
31
+ * path: anything that is not exactly a key is refused.
32
+ */
33
+ export function epicWorkaroundRecordPath(ticketKey) {
34
+ if (typeof ticketKey !== "string")
35
+ return null;
36
+ if (ticketKey.length > MAX_TICKET_KEY_CHARS || !TICKET_KEY_RE.test(ticketKey))
37
+ return null;
38
+ return `${EPIC_WORKAROUNDS_DIR}${ticketKey}.md`;
39
+ }
@@ -22,6 +22,35 @@ import { startExecutorSleepAssertion } from "./platform.js";
22
22
  import { runExecutor } from "./runner.js";
23
23
  import { runExecutorWatchCli } from "./watch-cli.js";
24
24
  import { removeRunExecutorRecordIfOwned } from "../executor-launch.js";
25
+ /** Register an optional parent watch without making the timer a process owner. */
26
+ export function registerExecutorParentWatch(pid, onGone, seams = {
27
+ setInterval: (callback, ms) => setInterval(callback, ms),
28
+ clearInterval: (handle) => clearInterval(handle),
29
+ signalZero: (parentPid) => process.kill(parentPid, 0),
30
+ }) {
31
+ let disposed = false;
32
+ let notified = false;
33
+ const timer = seams.setInterval(() => {
34
+ if (disposed || notified)
35
+ return;
36
+ try {
37
+ seams.signalZero(pid);
38
+ }
39
+ catch (error) {
40
+ if (error.code === "ESRCH") {
41
+ notified = true;
42
+ onGone();
43
+ }
44
+ }
45
+ }, 5_000);
46
+ timer.unref?.();
47
+ return () => {
48
+ if (disposed)
49
+ return;
50
+ disposed = true;
51
+ seams.clearInterval(timer);
52
+ };
53
+ }
25
54
  /** Fixed executor timing/behavior defaults. */
26
55
  const DEFAULT_POLL_INTERVAL_MS = 15_000;
27
56
  const DEFAULT_HEARTBEAT_INTERVAL_MS = 60_000;
@@ -37,9 +66,10 @@ const DEFAULT_JOB_TIMEOUT_SECONDS = 20 * 60;
37
66
  export const DEFAULT_MAX_CONCURRENT = 1;
38
67
  export function getExecutorUsage() {
39
68
  return [
40
- "Usage: mcp-server executor --repo <name> [--repo <name> ...] [options]",
69
+ "Usage: mcp-server executor --repo <name> [--repo <name> ...]",
70
+ " (--epic-run-id <id> | --repo-wide) [options]",
41
71
  "",
42
- "Runs the Epic Conductor v2 local executor: poll → claim → spawn → heartbeat.",
72
+ "Runs the Epic Implementer local executor: poll → claim → spawn → heartbeat.",
43
73
  "",
44
74
  "Options:",
45
75
  " --repo <name> Repo to serve (repeatable).",
@@ -421,6 +451,7 @@ export async function runExecutorCli(argv, overrides = {}) {
421
451
  const createIntegrationClient = overrides.createIntegrationClient ?? createIntegrationActionHttpClient;
422
452
  const runnerSeams = {
423
453
  onSignal: overrides.onSignal ?? defaultSignalRegistrar,
454
+ watchParent: registerExecutorParentWatch,
424
455
  // BAPI-1279 — on a terminal exit, delete the launcher record drive-epic
425
456
  // wrote for this run, but only if it still names THIS instance (its id, and
426
457
  // this process or the relay that started it). Advisory: a failure here
@@ -53,6 +53,37 @@ export const SUPPORTED_COMPLETION_RUNTIME = {
53
53
  platform: "darwin-arm64",
54
54
  event_schema: "claude-stream-json.lifecycle.v1",
55
55
  };
56
+ /** Oldest Claude CLI version whose lifecycle events were measured. */
57
+ export const MIN_CLI_VERSION = "2.1.282";
58
+ /** The four platform ids `<process.platform>-<process.arch>` the executor can produce. */
59
+ export const SUPPORTED_PLATFORMS = ["darwin-arm64", "darwin-x64", "linux-x64", "linux-arm64"];
60
+ /** Names the lifecycle parser version. A constant, never a probed value. */
61
+ export const EVENT_SCHEMA = "claude-stream-json.lifecycle.v1";
62
+ const CLI_VERSION_RE = /^(0|[1-9][0-9]{0,3})\.(0|[1-9][0-9]{0,3})\.(0|[1-9][0-9]{0,5})(?: \(Claude Code\))?$/;
63
+ /**
64
+ * Parse `major.minor.patch` with an optional exact ` (Claude Code)` suffix into its
65
+ * numeric triple. Prereleases, whitespace, non-numeric segments, leading zeros, and
66
+ * non-strings are `null`. Mirror of `normalize_cli_version` in the Python contract.
67
+ */
68
+ export function parseCliVersion(value) {
69
+ if (typeof value !== "string")
70
+ return null;
71
+ const match = CLI_VERSION_RE.exec(value);
72
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
73
+ }
74
+ /** The normalized `major.minor.patch` text, or `null` when the version is not strict. */
75
+ export function normalizeCliVersion(value) {
76
+ const parsed = parseCliVersion(value);
77
+ return parsed ? parsed.join(".") : null;
78
+ }
79
+ /** Is version triple `a` at or above `b`? */
80
+ export function cliVersionAtLeast(a, b) {
81
+ for (let i = 0; i < 3; i += 1) {
82
+ if (a[i] !== b[i])
83
+ return a[i] > b[i];
84
+ }
85
+ return true;
86
+ }
56
87
  export const EVIDENCE_VALUES = ["sufficient", "insufficient"];
57
88
  export const INSUFFICIENT_REASON_VALUES = [
58
89
  "no_init_event",
@@ -200,6 +231,10 @@ export const COMPLETION_CAUSE_VALUES = [
200
231
  "cleanup_unconfirmed",
201
232
  "verification_runner_unavailable",
202
233
  ];
234
+ export const END_CAUSE_VALUES = [
235
+ "worker_exit", "completion_window", "job_timeout", "executor_abort",
236
+ "executor_shutdown", "server_stop", "lease_lost",
237
+ ];
203
238
  export const MAX_TASKS = 64;
204
239
  export const MAX_DENIALS = 32;
205
240
  export const MAX_IDENTIFIER_CHARS = 128;
@@ -239,13 +274,23 @@ export function isCoveredJobType(jobType) {
239
274
  export function claimRequiresCompletionEvidence(requiredCapabilities) {
240
275
  return Array.isArray(requiredCapabilities) && requiredCapabilities.includes(COMPLETION_EVIDENCE_CAPABILITY);
241
276
  }
277
+ /**
278
+ * True for the measured baseline or a newer supported runtime: adapter `claude`, the
279
+ * lifecycle event schema, a closed platform id, and a strict numeric version at or
280
+ * above {@link MIN_CLI_VERSION}. Mirror of `runtime_matches_supported` in Python.
281
+ */
242
282
  export function runtimeMatchesSupported(runtime) {
243
283
  if (!runtime)
244
284
  return false;
285
+ const version = parseCliVersion(runtime.cli_version);
286
+ const minimum = parseCliVersion(MIN_CLI_VERSION);
245
287
  return (runtime.adapter === SUPPORTED_COMPLETION_RUNTIME.adapter &&
246
- runtime.cli_version === SUPPORTED_COMPLETION_RUNTIME.cli_version &&
247
- runtime.platform === SUPPORTED_COMPLETION_RUNTIME.platform &&
248
- runtime.event_schema === SUPPORTED_COMPLETION_RUNTIME.event_schema);
288
+ runtime.event_schema === EVENT_SCHEMA &&
289
+ typeof runtime.platform === "string" &&
290
+ SUPPORTED_PLATFORMS.includes(runtime.platform) &&
291
+ version !== null &&
292
+ minimum !== null &&
293
+ cliVersionAtLeast(version, minimum));
249
294
  }
250
295
  export function unresolvedRequiredTasks(envelope) {
251
296
  return envelope.tasks.filter((t) => t.required && !TASK_RESOLVING_STATES.has(t.state));
@@ -318,16 +363,25 @@ export function deriveCompletionCause(envelope) {
318
363
  if (blocking.length > 0 && envelope.evidence === "sufficient" && blocking.some((d) => d.result_after_denial)) {
319
364
  return "permission_stop";
320
365
  }
321
- if (envelope.cleanup.verdict !== "confirmed" || envelope.cleanup.survivors !== 0)
322
- return "cleanup_unconfirmed";
323
366
  const unresolved = envelope.tasks.some((t) => t.required && !TASK_RESOLVING_STATES.has(t.state));
324
- if (blocking.length > 0 ||
367
+ const requiredWorkIncomplete = blocking.length > 0 ||
325
368
  envelope.evidence !== "sufficient" ||
326
369
  envelope.execution !== "complete" ||
327
370
  unresolved ||
328
- envelope.verification === "incomplete") {
329
- return "required_work_incomplete";
371
+ envelope.verification === "incomplete";
372
+ // One exception to cleanup precedence: a completed sweep with no survivor and
373
+ // exactly the single reason `ownership_unverifiable` yields to unfinished
374
+ // work. Exact array checks, so a mixed list (e.g. with `not_run`) never does.
375
+ const narrowCleanupUncertainty = envelope.cleanup.verdict === "unconfirmed" &&
376
+ envelope.cleanup.survivors === 0 &&
377
+ envelope.cleanup.reasons.length === 1 &&
378
+ envelope.cleanup.reasons[0] === "ownership_unverifiable";
379
+ if ((envelope.cleanup.verdict !== "confirmed" || envelope.cleanup.survivors !== 0) &&
380
+ !(narrowCleanupUncertainty && requiredWorkIncomplete)) {
381
+ return "cleanup_unconfirmed";
330
382
  }
383
+ if (requiredWorkIncomplete)
384
+ return "required_work_incomplete";
331
385
  if (envelope.verification === "unavailable")
332
386
  return "verification_runner_unavailable";
333
387
  if (envelope.verification === "failed")
@@ -366,7 +420,9 @@ export function buildNotLaunchedEnvelope(input) {
366
420
  binding: { ...input.binding },
367
421
  session_id: null,
368
422
  evidence: "insufficient",
369
- insufficient_reasons: ["worker_not_launched"],
423
+ insufficient_reasons: input.unsupportedRuntime
424
+ ? ["worker_not_launched", "unsupported_runtime"]
425
+ : ["worker_not_launched"],
370
426
  execution: "unknown",
371
427
  verification: input.verification,
372
428
  finalization: "unknown",
@@ -381,7 +437,7 @@ export function buildNotLaunchedEnvelope(input) {
381
437
  denials: [],
382
438
  missing_capabilities: [],
383
439
  results_seen: 0,
384
- cause: null,
440
+ cause: input.unsupportedRuntime ? "unsupported_completion_evidence" : null,
385
441
  ...(input.verificationFacts ? { verification_facts: input.verificationFacts } : {}),
386
442
  };
387
443
  }
@@ -228,6 +228,10 @@ export function finalizationFacts(outcome) {
228
228
  // and neither push nor PR is inferred satisfied.
229
229
  case "WorkerFinalizationPublicationUnverified":
230
230
  return { verdict: "unknown", pushSatisfied: false, prSatisfied: false };
231
+ // BAPI-1357: the origin lookup could not be trusted, so the branch was not
232
+ // observed missing either. Unknown, and neither obligation is inferred met.
233
+ case "WorkerFinalizationOriginUnverifiable":
234
+ return { verdict: "unknown", pushSatisfied: false, prSatisfied: false };
231
235
  default:
232
236
  return { verdict: "unknown", pushSatisfied: false, prSatisfied: false };
233
237
  }
@@ -1,3 +1,4 @@
1
+ import { recordProvisionedAssets } from "../generated-assets-inventory.js";
1
2
  /**
2
3
  * Default (production) executor dependencies (BAPI-534, TDD §7).
3
4
  *
@@ -70,6 +71,7 @@ export function createDefaultExecutorDeps() {
70
71
  cwd: options?.cwd,
71
72
  env: options?.env,
72
73
  timeout: options?.timeoutMs,
74
+ signal: options?.signal,
73
75
  maxBuffer: MAX_COMMAND_BUFFER,
74
76
  encoding: "utf8",
75
77
  shell: false,
@@ -78,7 +80,7 @@ export function createDefaultExecutorDeps() {
78
80
  }
79
81
  catch (err) {
80
82
  const e = err;
81
- const exitCode = typeof e.code === "number" ? e.code : 1;
83
+ const exitCode = e.killed || e.code === "ABORT_ERR" ? 124 : typeof e.code === "number" ? e.code : 1;
82
84
  return { stdout: e.stdout ?? "", stderr: e.stderr ?? "", exitCode };
83
85
  }
84
86
  },
@@ -137,6 +139,7 @@ export function createDefaultExecutorDeps() {
137
139
  },
138
140
  };
139
141
  },
142
+ recordPackagedAssets: recordProvisionedAssets,
140
143
  readFile: (filePath) => readFile(filePath, "utf-8"),
141
144
  writeFile: (filePath, data) => writeFile(filePath, data, "utf-8"),
142
145
  appendFile: (filePath, data) => appendFile(filePath, data, "utf-8"),
@@ -329,3 +329,22 @@ export function buildExecutorBaseWorkerEnv(parentEnv, options = {}) {
329
329
  // per call site.
330
330
  return env;
331
331
  }
332
+ /**
333
+ * The environment for a headless agent run that is not a worker job, such as the
334
+ * executor's deny-enforcement probe (BAPI-1386).
335
+ *
336
+ * The probe must see what a worker sees. Spawned from an executor that is itself
337
+ * running inside a Claude session, it would otherwise inherit that session's
338
+ * nested-session variables, and the CLI can refuse to start a tool call there. So
339
+ * this reuses the worker allowlist and worker-injected defaults behind
340
+ * {@link buildExecutorBaseWorkerEnv} rather than keeping a deny-list of Claude
341
+ * variable names, which would go stale with every CLI release. No job-specific
342
+ * option is set: the result carries no branch, base, scope, or correction marker.
343
+ *
344
+ * Applied only where the executor builds the deny probe's context. The shared
345
+ * `runHeadless()` passes its supplied environment through unchanged, so standalone
346
+ * capability probes are not filtered.
347
+ */
348
+ export function buildHeadlessAgentEnv(parentEnv) {
349
+ return buildExecutorBaseWorkerEnv(parentEnv);
350
+ }