substrate-ai 0.20.139 → 0.20.141

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.
@@ -0,0 +1,4 @@
1
+ import { AdapterRegistry } from "./dist-DiNK6QOD.js";
2
+ import "./adapter-registry-DIcrxjH8.js";
3
+
4
+ export { AdapterRegistry };
package/dist/cli/index.js CHANGED
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
- import { FileKvStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-BXVyiLiL.js";
2
+ import { FileKvStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-BQRsVP6s.js";
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
5
- import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createPipelineRun, createStderrLogger, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initWorkGraphSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-BWCudDcl.js";
6
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-eaZG_3rN.js";
5
+ import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createPipelineRun, createStderrLogger, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initWorkGraphSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-DiNK6QOD.js";
6
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-CRvusFIv.js";
7
7
  import "../adapter-registry-DIcrxjH8.js";
8
- import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-IvpNQ6Yy.js";
9
- import "../errors-rZ-lz8U0.js";
8
+ import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-Doh2Ion5.js";
9
+ import "../errors-B21JUhcc.js";
10
10
  import "../routing-DFxoKHDt.js";
11
11
  import { WorkGraphRepository } from "../work-graph-repository-DZyJv5pV.js";
12
12
  import "../decisions-CzSIEeGP.js";
13
- import "../decision-router-DblHY8se.js";
14
- import "../interactive-prompt-BypNgFHL.js";
13
+ import "../decision-router-BAPpON_C.js";
14
+ import "../interactive-prompt-CgerI5Y6.js";
15
15
  import "../recovery-engine-BKGBeBnW.js";
16
16
  import "../version-manager-impl-qFBiO4Eh.js";
17
- import { registerUpgradeCommand } from "../upgrade-3NTcs1t7.js";
17
+ import { registerUpgradeCommand } from "../upgrade-DB7KzD9c.js";
18
18
  import { Command } from "commander";
19
19
  import { fileURLToPath } from "url";
20
20
  import { dirname, join, resolve } from "path";
@@ -7036,7 +7036,7 @@ async function runStatusAction(options) {
7036
7036
  logger$15.debug({ err }, "Work graph query failed, continuing without work graph data");
7037
7037
  }
7038
7038
  if (run === void 0) {
7039
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-D27XuFLF.js");
7039
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-Cm-pA1mZ.js");
7040
7040
  const substrateDirPath = join(projectRoot, ".substrate");
7041
7041
  const processInfo = inspectProcessTree$1({
7042
7042
  projectRoot,
@@ -7984,7 +7984,7 @@ function defaultSupervisorDeps() {
7984
7984
  if (cached === null) {
7985
7985
  const { AdapterRegistry: AR } = await import(
7986
7986
  /* @vite-ignore */
7987
- "../adapter-registry-CXIG-OQI.js"
7987
+ "../adapter-registry-qU0IkbbQ.js"
7988
7988
  );
7989
7989
  cached = new AR();
7990
7990
  await cached.discoverAndRegister();
@@ -8551,11 +8551,11 @@ async function runSupervisorAction(options, deps = {}) {
8551
8551
  try {
8552
8552
  const { createExperimenter } = await import(
8553
8553
  /* @vite-ignore */
8554
- "../experimenter-Dn0gGOYl.js"
8554
+ "../experimenter-D55L011w.js"
8555
8555
  );
8556
8556
  const { getLatestRun: getLatest } = await import(
8557
8557
  /* @vite-ignore */
8558
- "../decisions-EQtHqewP.js"
8558
+ "../decisions-Dvw5HhyM.js"
8559
8559
  );
8560
8560
  const expAdapter = createDatabaseAdapter({
8561
8561
  backend: "auto",
@@ -8565,7 +8565,7 @@ async function runSupervisorAction(options, deps = {}) {
8565
8565
  await initSchema(expAdapter);
8566
8566
  const { runRunAction: runPipeline } = await import(
8567
8567
  /* @vite-ignore */
8568
- "../run-Cp19x4Xv.js"
8568
+ "../run-BHRkyn_H.js"
8569
8569
  );
8570
8570
  const runStoryFn = async (opts) => {
8571
8571
  const exitCode = await runPipeline({
@@ -9090,7 +9090,7 @@ async function runMetricsAction(options) {
9090
9090
  const routingConfigPath = join(dbDir, "routing.yml");
9091
9091
  let routingConfig = null;
9092
9092
  if (existsSync$1(routingConfigPath)) try {
9093
- const { loadModelRoutingConfig } = await import("../routing-C0f2cYja.js");
9093
+ const { loadModelRoutingConfig } = await import("../routing-_PGfe_cD.js");
9094
9094
  routingConfig = loadModelRoutingConfig(routingConfigPath);
9095
9095
  } catch {}
9096
9096
  if (routingConfig === null) routingConfig = {
@@ -10505,7 +10505,7 @@ async function listWorktreesAction(options) {
10505
10505
  * @returns - Exit code (0 = success, 1 = error)
10506
10506
  */
10507
10507
  async function cleanupWorktreesAction(options) {
10508
- const { taskId, projectRoot } = options;
10508
+ const { taskId, projectRoot, force } = options;
10509
10509
  try {
10510
10510
  const eventBus = createEventBus();
10511
10511
  const manager = createGitWorktreeManager({
@@ -10513,7 +10513,7 @@ async function cleanupWorktreesAction(options) {
10513
10513
  projectRoot
10514
10514
  });
10515
10515
  if (taskId !== void 0) try {
10516
- await manager.cleanupWorktree(taskId);
10516
+ await manager.cleanupWorktree(taskId, { force: force === true });
10517
10517
  process.stdout.write(`Cleaned up worktree for task "${taskId}"\n`);
10518
10518
  return WORKTREES_EXIT_SUCCESS;
10519
10519
  } catch (err) {
@@ -10526,8 +10526,9 @@ async function cleanupWorktreesAction(options) {
10526
10526
  return WORKTREES_EXIT_ERROR;
10527
10527
  }
10528
10528
  try {
10529
- const cleaned = await manager.cleanupAllWorktrees();
10529
+ const cleaned = await manager.cleanupAllWorktrees({ force: force === true });
10530
10530
  process.stdout.write(`Cleaned up ${cleaned} worktree${cleaned === 1 ? "" : "s"}\n`);
10531
+ if (force !== true) process.stdout.write("Worktrees with uncommitted work or unmerged branch commits were preserved — re-run with --force to discard them.\n");
10531
10532
  return WORKTREES_EXIT_SUCCESS;
10532
10533
  } catch (err) {
10533
10534
  const message = err instanceof Error ? err.message : String(err);
@@ -10550,12 +10551,13 @@ async function cleanupWorktreesAction(options) {
10550
10551
  * @param projectRoot - Project root directory (defaults to process.cwd())
10551
10552
  */
10552
10553
  function registerWorktreesCommand(program, version = "0.0.0", projectRoot = process.cwd()) {
10553
- program.command("worktrees").description("List or clean up substrate git worktrees and their task branches").option("--output-format <format>", "Output format: table (default) or json", "table").option("--json", "Output JSON (shorthand for --output-format json)", false).option("--status <status>", `Filter by task status: ${VALID_STATUSES.join(", ")}`).option("--sort <key>", `Sort by: ${VALID_SORT_KEYS.join(", ")} (default: created)`, "created").option("--cleanup [task-id]", "Remove substrate worktree(s) and branches. Pass a task id to remove just one; omit the arg to remove all.").action(async (opts) => {
10554
+ program.command("worktrees").description("List or clean up substrate git worktrees and their task branches").option("--output-format <format>", "Output format: table (default) or json", "table").option("--json", "Output JSON (shorthand for --output-format json)", false).option("--status <status>", `Filter by task status: ${VALID_STATUSES.join(", ")}`).option("--sort <key>", `Sort by: ${VALID_SORT_KEYS.join(", ")} (default: created)`, "created").option("--cleanup [task-id]", "Remove substrate worktree(s) and branches. Pass a task id to remove just one; omit the arg to remove all.").option("--force", "Discard worktrees even when they hold uncommitted work or unmerged branch commits.", false).action(async (opts) => {
10554
10555
  if (opts.cleanup !== void 0 && opts.cleanup !== false) {
10555
10556
  const taskId = typeof opts.cleanup === "string" && opts.cleanup.trim().length > 0 ? opts.cleanup.trim() : void 0;
10556
10557
  const cleanupExitCode = await cleanupWorktreesAction({
10557
10558
  ...taskId !== void 0 ? { taskId } : {},
10558
- projectRoot
10559
+ projectRoot,
10560
+ force: opts.force
10559
10561
  });
10560
10562
  process.exitCode = cleanupExitCode;
10561
10563
  return;
@@ -13402,8 +13404,8 @@ async function createProgram() {
13402
13404
  /** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
13403
13405
  function checkForUpdatesInBackground(currentVersion) {
13404
13406
  if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
13405
- import("../upgrade-DHHSy4fQ.js").then(async () => {
13406
- const { createVersionManager } = await import("../version-manager-impl-CfzcfFwo.js");
13407
+ import("../upgrade-CTj4hi8J.js").then(async () => {
13408
+ const { createVersionManager } = await import("../version-manager-impl-HJMonRJi.js");
13407
13409
  const vm = createVersionManager();
13408
13410
  const result = await vm.checkForUpdates();
13409
13411
  if (result.updateAvailable) {
@@ -15,6 +15,7 @@ const DECISION_SEVERITY_MAP = {
15
15
  "scope-violation": "fatal",
16
16
  "cross-story-race-recovered": "info",
17
17
  "cross-story-race-still-failed": "critical",
18
+ "auth-failure": "fatal",
18
19
  "pipeline-escalation": "warning"
19
20
  };
20
21
  /**
@@ -29,7 +30,8 @@ const DEFAULT_ACTION_MAP = {
29
30
  "scope-violation": "abort-pipeline",
30
31
  "cross-story-race-recovered": "continue-autonomous",
31
32
  "cross-story-race-still-failed": "escalate-without-halt",
32
- "pipeline-escalation": "escalate-without-halt"
33
+ "pipeline-escalation": "escalate-without-halt",
34
+ "auth-failure": "abort-pipeline"
33
35
  };
34
36
  /** Fallback default action for unknown decision types. */
35
37
  const DEFAULT_DEFAULT_ACTION = "escalate-without-halt";
@@ -94,4 +96,4 @@ function deriveExitCode(outcome) {
94
96
 
95
97
  //#endregion
96
98
  export { DECISION_SEVERITY_MAP, deriveExitCode, routeDecision };
97
- //# sourceMappingURL=decision-router-DblHY8se.js.map
99
+ //# sourceMappingURL=decision-router-BAPpON_C.js.map
@@ -1,4 +1,4 @@
1
- import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunningPipelineRuns, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./dist-BWCudDcl.js";
1
+ import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunningPipelineRuns, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./dist-DiNK6QOD.js";
2
2
  import "./decisions-CzSIEeGP.js";
3
3
 
4
4
  export { getLatestRun };
@@ -9462,6 +9462,39 @@ function checkAdapterVersionCompat(adapterName, actualVersion, tested) {
9462
9462
  const execAsync$2 = promisify(exec);
9463
9463
  /** Default model used when none is specified */
9464
9464
  const DEFAULT_MODEL$1 = "claude-sonnet-4-6";
9465
+ /**
9466
+ * Signatures the Claude Code CLI emits when a dispatch dies on authentication
9467
+ * rather than doing any work (H0.4, field finding #10). Matched
9468
+ * case-insensitively against the dispatch's combined output.
9469
+ *
9470
+ * Field-verified: a stale `ANTHROPIC_API_KEY` in the operator's shell made
9471
+ * spawned CLIs reject with "auth source takes precedence over claude.ai
9472
+ * login · Invalid API key" — surfaced as `create-story-no-file`
9473
+ * (qualityScore 40) or a full 600s timeout, never as an auth error, burning
9474
+ * ~25 minutes and two runs before diagnosis.
9475
+ */
9476
+ const CLAUDE_AUTH_FAILURE_SIGNATURES = [
9477
+ "invalid api key",
9478
+ "auth source takes precedence",
9479
+ "please run /login",
9480
+ "oauth token has expired",
9481
+ "oauth token is invalid",
9482
+ "oauth token revoked",
9483
+ "authentication_error",
9484
+ "credit balance is too low"
9485
+ ];
9486
+ /** Operator-facing remediation appended to auth-failure escalations. */
9487
+ const CLAUDE_AUTH_FAILURE_HINT = "The Claude CLI rejected authentication before doing any work. Every subsequent dispatch in this run would fail identically, so the run was halted. Likely causes, in order: (1) a stale ANTHROPIC_API_KEY exported in the environment that spawned substrate — the CLI prefers it over claude.ai subscription login and rejects it if invalid (substrate scrubs the var on coding dispatches, but keys configured inside Claude Code settings/apiKeyHelper are outside substrate's control; verify with `env -u ANTHROPIC_API_KEY claude -p \"ok\"`); (2) an expired claude.ai session — run `claude login`; (3) an exhausted API credit balance when api_billing is enabled. Fix the credential, then re-run — completed stories are preserved.";
9488
+ /**
9489
+ * Returns the matched auth-failure signature if `output` shows the Claude CLI
9490
+ * dying on authentication, else null. Pure + exported for diagnostics and
9491
+ * testing (mirrors detectCodexSandboxBlock).
9492
+ */
9493
+ function detectClaudeAuthFailure(output) {
9494
+ if (output === void 0 || output === null || output === "") return null;
9495
+ const lower = output.toLowerCase();
9496
+ return CLAUDE_AUTH_FAILURE_SIGNATURES.find((sig) => lower.includes(sig)) ?? null;
9497
+ }
9465
9498
  /** Approximate characters per token for estimation */
9466
9499
  const CHARS_PER_TOKEN$2 = 3;
9467
9500
  /** Estimated output token multiplier relative to input */
@@ -9655,10 +9688,13 @@ var ClaudeCodeAdapter = class ClaudeCodeAdapter {
9655
9688
  if (options.additionalFlags && options.additionalFlags.length > 0) args.push(...options.additionalFlags);
9656
9689
  const envEntries = {};
9657
9690
  if (options.billingMode === "api" && options.apiKey) envEntries.ANTHROPIC_API_KEY = options.apiKey;
9691
+ const unsetEnvKeys = ["CLAUDECODE"];
9692
+ if (options.billingMode !== "api") unsetEnvKeys.push("ANTHROPIC_API_KEY");
9658
9693
  return {
9659
9694
  binary: "claude",
9660
9695
  args,
9661
9696
  env: envEntries,
9697
+ unsetEnvKeys,
9662
9698
  cwd: options.worktreePath,
9663
9699
  stdin: planningPrompt
9664
9700
  };
@@ -11483,5 +11519,5 @@ async function callLLM(params) {
11483
11519
  }
11484
11520
 
11485
11521
  //#endregion
11486
- export { ADVISORY_NOTES, AdapterRegistry, AdtError, BudgetConfigSchema, CODEX_SANDBOX_BLOCK_HINT, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, Categorizer, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, ConsumerAnalyzer, CostTrackerConfigSchema, DEFAULT_CONFIG, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, DoltNotInstalled, DoltQueryError, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, GeminiCLIAdapter, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, LEARNING_FINDING, LogTurnAnalyzer, ModelRoutingConfigSchema, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProviderPolicySchema, ProvidersSchema, Recommender, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TASK_TYPE_PHASE_MAP, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryConfigSchema, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, VersionManagerImpl, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, callLLM, checkDoltInstalled, classifyVersionGap, compareRunMetrics, createAmendmentRun, createConfigSystem, createDatabaseAdapter as createDatabaseAdapter$1, createDecision, createExperimenter, createPipelineRun, createRequirement, createStderrLogger, createVersionManager, detectCodexSandboxBlock, detectInterfaceChanges, determineVerdict, getActiveDecisions, getAllCostEntriesFiltered, getArtifactByTypeForRun, getArtifactsByRun, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getModelTier, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initWorkGraphSchema, initializeDolt, listRequirements, listRunMetrics, loadModelRoutingConfig, loadParentRunDecisions, registerArtifact, resolvePromptFile, supersedeDecision, swallowDebug, tagRunAsBaseline, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics };
11487
- //# sourceMappingURL=dist-BWCudDcl.js.map
11522
+ export { ADVISORY_NOTES, AdapterRegistry, AdtError, BudgetConfigSchema, CLAUDE_AUTH_FAILURE_HINT, CODEX_SANDBOX_BLOCK_HINT, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, Categorizer, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, ConsumerAnalyzer, CostTrackerConfigSchema, DEFAULT_CONFIG, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, DoltNotInstalled, DoltQueryError, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, GeminiCLIAdapter, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, LEARNING_FINDING, LogTurnAnalyzer, ModelRoutingConfigSchema, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProviderPolicySchema, ProvidersSchema, Recommender, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TASK_TYPE_PHASE_MAP, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryConfigSchema, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, VersionManagerImpl, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, callLLM, checkDoltInstalled, classifyVersionGap, compareRunMetrics, createAmendmentRun, createConfigSystem, createDatabaseAdapter as createDatabaseAdapter$1, createDecision, createExperimenter, createPipelineRun, createRequirement, createStderrLogger, createVersionManager, detectClaudeAuthFailure, detectCodexSandboxBlock, detectInterfaceChanges, determineVerdict, getActiveDecisions, getAllCostEntriesFiltered, getArtifactByTypeForRun, getArtifactsByRun, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getModelTier, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initWorkGraphSchema, initializeDolt, listRequirements, listRunMetrics, loadModelRoutingConfig, loadParentRunDecisions, registerArtifact, resolvePromptFile, supersedeDecision, swallowDebug, tagRunAsBaseline, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics };
11523
+ //# sourceMappingURL=dist-DiNK6QOD.js.map
@@ -1,4 +1,4 @@
1
- import { AdtError } from "./dist-BWCudDcl.js";
1
+ import { AdtError } from "./dist-DiNK6QOD.js";
2
2
 
3
3
  //#region src/core/errors.ts
4
4
  /** Error thrown when task configuration is invalid */
@@ -71,4 +71,4 @@ var TaskGraphIncompatibleFormatError = class extends AdtError {
71
71
 
72
72
  //#endregion
73
73
  export { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError };
74
- //# sourceMappingURL=errors-rZ-lz8U0.js.map
74
+ //# sourceMappingURL=errors-B21JUhcc.js.map
@@ -1,3 +1,3 @@
1
- import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-BWCudDcl.js";
1
+ import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-DiNK6QOD.js";
2
2
 
3
3
  export { createExperimenter };
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { DoltClient, DoltQueryError, createDatabaseAdapter$1 as createDatabaseAdapter, getLatestRun, getPipelineRunById, initSchema } from "./dist-BWCudDcl.js";
3
- import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-IvpNQ6Yy.js";
2
+ import { DoltClient, DoltQueryError, createDatabaseAdapter$1 as createDatabaseAdapter, getLatestRun, getPipelineRunById, initSchema } from "./dist-DiNK6QOD.js";
3
+ import { resolveMainRepoRoot, resolveRunManifest } from "./manifest-read-Doh2Ion5.js";
4
4
  import { createRequire } from "module";
5
5
  import { dirname, join } from "path";
6
6
  import { existsSync, readFileSync } from "node:fs";
@@ -1000,4 +1000,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
1000
1000
 
1001
1001
  //#endregion
1002
1002
  export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDoltOperatorReader, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, runHealthAction, validateStoryKey };
1003
- //# sourceMappingURL=health-BXVyiLiL.js.map
1003
+ //# sourceMappingURL=health-BQRsVP6s.js.map
@@ -1,7 +1,7 @@
1
- import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-BXVyiLiL.js";
1
+ import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-BQRsVP6s.js";
2
2
  import "./logger-KeHncl-f.js";
3
- import "./dist-BWCudDcl.js";
4
- import "./manifest-read-IvpNQ6Yy.js";
3
+ import "./dist-DiNK6QOD.js";
4
+ import "./manifest-read-Doh2Ion5.js";
5
5
  import "./work-graph-repository-DZyJv5pV.js";
6
6
  import "./decisions-CzSIEeGP.js";
7
7
 
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { childLogger, createLogger, logger } from "./logger-KeHncl-f.js";
2
2
  import { assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry } from "./helpers-CElYrONe.js";
3
- import { AdapterRegistry, AdtError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter } from "./dist-BWCudDcl.js";
3
+ import { AdapterRegistry, AdtError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter } from "./dist-DiNK6QOD.js";
4
4
  import "./adapter-registry-DIcrxjH8.js";
5
- import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-rZ-lz8U0.js";
5
+ import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-B21JUhcc.js";
6
6
 
7
7
  //#region src/core/di.ts
8
8
  /**
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-IvpNQ6Yy.js";
2
+ import { readCurrentRunId, resolveMainRepoRoot } from "./manifest-read-Doh2Ion5.js";
3
3
  import { join } from "node:path";
4
4
  import { mkdir, readFile, writeFile } from "node:fs/promises";
5
5
  import * as readline from "node:readline";
@@ -180,4 +180,4 @@ async function runInteractivePrompt(decisionContext) {
180
180
 
181
181
  //#endregion
182
182
  export { runInteractivePrompt };
183
- //# sourceMappingURL=interactive-prompt-BypNgFHL.js.map
183
+ //# sourceMappingURL=interactive-prompt-CgerI5Y6.js.map
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from "./logger-KeHncl-f.js";
2
- import { LEARNING_FINDING, createDecision, getDecisionsByCategory } from "./dist-BWCudDcl.js";
2
+ import { LEARNING_FINDING, createDecision, getDecisionsByCategory } from "./dist-DiNK6QOD.js";
3
3
  import * as path$1 from "path";
4
4
  import { join } from "path";
5
5
  import { readFile } from "fs/promises";
@@ -5865,4 +5865,4 @@ async function resolveRunManifest(dbRoot, runId) {
5865
5865
 
5866
5866
  //#endregion
5867
5867
  export { FindingsInjector, RunManifest, RuntimeProbeListSchema, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, readCurrentRunId, renderFindings, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck, runStaleVerificationRecovery };
5868
- //# sourceMappingURL=manifest-read-IvpNQ6Yy.js.map
5868
+ //# sourceMappingURL=manifest-read-Doh2Ion5.js.map
@@ -1,6 +1,6 @@
1
1
  import "../../logger-KeHncl-f.js";
2
- import "../../dist-BWCudDcl.js";
3
- import "../../manifest-read-IvpNQ6Yy.js";
4
- import { runInteractivePrompt } from "../../interactive-prompt-BypNgFHL.js";
2
+ import "../../dist-DiNK6QOD.js";
3
+ import "../../manifest-read-Doh2Ion5.js";
4
+ import { runInteractivePrompt } from "../../interactive-prompt-CgerI5Y6.js";
5
5
 
6
6
  export { runInteractivePrompt };
@@ -1,4 +1,4 @@
1
- import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-BWCudDcl.js";
1
+ import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-DiNK6QOD.js";
2
2
  import "./routing-DFxoKHDt.js";
3
3
 
4
4
  export { loadModelRoutingConfig };
@@ -1,14 +1,14 @@
1
- import "./health-BXVyiLiL.js";
1
+ import "./health-BQRsVP6s.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
- import "./dist-BWCudDcl.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-eaZG_3rN.js";
6
- import "./manifest-read-IvpNQ6Yy.js";
4
+ import "./dist-DiNK6QOD.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-CRvusFIv.js";
6
+ import "./manifest-read-Doh2Ion5.js";
7
7
  import "./routing-DFxoKHDt.js";
8
8
  import "./work-graph-repository-DZyJv5pV.js";
9
9
  import "./decisions-CzSIEeGP.js";
10
- import "./decision-router-DblHY8se.js";
11
- import "./interactive-prompt-BypNgFHL.js";
10
+ import "./decision-router-BAPpON_C.js";
11
+ import "./interactive-prompt-CgerI5Y6.js";
12
12
  import "./recovery-engine-BKGBeBnW.js";
13
13
 
14
14
  export { runRunAction };
@@ -1,11 +1,11 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-BXVyiLiL.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-BQRsVP6s.js";
2
2
  import { createLogger } from "./logger-KeHncl-f.js";
3
3
  import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
4
- import { ADVISORY_NOTES, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, createStderrLogger, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-BWCudDcl.js";
5
- import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-IvpNQ6Yy.js";
4
+ import { ADVISORY_NOTES, CLAUDE_AUTH_FAILURE_HINT, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, createStderrLogger, detectClaudeAuthFailure, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-DiNK6QOD.js";
5
+ import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-Doh2Ion5.js";
6
6
  import { WorkGraphRepository, detectCycles } from "./work-graph-repository-DZyJv5pV.js";
7
- import { deriveExitCode, routeDecision } from "./decision-router-DblHY8se.js";
8
- import { runInteractivePrompt } from "./interactive-prompt-BypNgFHL.js";
7
+ import { deriveExitCode, routeDecision } from "./decision-router-BAPpON_C.js";
8
+ import { runInteractivePrompt } from "./interactive-prompt-CgerI5Y6.js";
9
9
  import { runRecoveryEngine } from "./recovery-engine-BKGBeBnW.js";
10
10
  import { basename, dirname, extname, join } from "path";
11
11
  import { access, readFile, readdir, stat } from "fs/promises";
@@ -159,6 +159,66 @@ function decideWorktreeReclaim(hasUncommittedChanges, commitsAhead, baseBranch)
159
159
  };
160
160
  return { safe: true };
161
161
  }
162
+ /**
163
+ * Decide whether removing a story worktree AND deleting its branch is safe
164
+ * (H0.3, field findings #17/#19). Unsafe when:
165
+ * - the worktree has uncommitted changes (removal destroys the only copy), or
166
+ * - the branch carries commits not reachable from the project's current HEAD
167
+ * (branch -D destroys them — this is where H0.1's wip checkpoints live), or
168
+ * - either state could not be determined (negative unmergedCommits).
169
+ *
170
+ * Pure + exported for testing (mirrors decideWorktreeReclaim; the git I/O that
171
+ * produces the inputs lives in inspectWorktreeRemovalSafety).
172
+ */
173
+ function decideWorktreeRemoval(hasUncommittedChanges, uncommittedFiles, unmergedCommits, branchName) {
174
+ const reasons = [];
175
+ if (hasUncommittedChanges) {
176
+ const preview = uncommittedFiles.slice(0, 10).join(", ");
177
+ const more = uncommittedFiles.length > 10 ? ` (+${String(uncommittedFiles.length - 10)} more)` : "";
178
+ reasons.push(`the worktree has ${String(uncommittedFiles.length)} uncommitted change(s) that removal would destroy` + (preview.length > 0 ? `: ${preview}${more}` : ""));
179
+ }
180
+ if (unmergedCommits > 0) reasons.push(`branch ${branchName} carries ${String(unmergedCommits)} commit(s) not reachable from the current HEAD — deleting the branch would destroy them`);
181
+ if (unmergedCommits < 0) reasons.push("the branch state could not be verified as safe to discard");
182
+ return {
183
+ safe: reasons.length === 0,
184
+ reasons
185
+ };
186
+ }
187
+ /**
188
+ * Gather the inputs for `decideWorktreeRemoval` from git. Thin I/O wrapper:
189
+ * - `git status --porcelain` inside the worktree (skipped when the directory
190
+ * is missing — nothing on disk to lose)
191
+ * - `git rev-list --count HEAD..<branch>` in the project root (commits the
192
+ * branch has that the current checkout does not; 0 when the branch is
193
+ * merged or absent, -1 when the count could not be determined)
194
+ */
195
+ async function inspectWorktreeRemovalSafety(worktreePath, projectRoot, branchName) {
196
+ let hasUncommittedChanges = false;
197
+ let uncommittedFiles = [];
198
+ const worktreeOnDisk = await access$1(worktreePath).then(() => true).catch(() => false);
199
+ if (worktreeOnDisk) {
200
+ const statusResult = await spawnGit(["status", "--porcelain"], { cwd: worktreePath });
201
+ if (statusResult.code === 0) {
202
+ uncommittedFiles = statusResult.stdout.split("\n").filter((line) => line.trim().length > 0).map((line) => line.slice(3).trim());
203
+ hasUncommittedChanges = uncommittedFiles.length > 0;
204
+ } else return decideWorktreeRemoval(false, [], -1, branchName);
205
+ }
206
+ const branchExists = (await spawnGit([
207
+ "rev-parse",
208
+ "--verify",
209
+ branchName
210
+ ], { cwd: projectRoot })).code === 0;
211
+ let unmergedCommits = 0;
212
+ if (branchExists) {
213
+ const aheadResult = await spawnGit([
214
+ "rev-list",
215
+ "--count",
216
+ `HEAD..${branchName}`
217
+ ], { cwd: projectRoot });
218
+ unmergedCommits = aheadResult.code === 0 ? Number.parseInt(aheadResult.stdout.trim(), 10) || 0 : -1;
219
+ }
220
+ return decideWorktreeRemoval(hasUncommittedChanges, uncommittedFiles, unmergedCommits, branchName);
221
+ }
162
222
  async function createWorktree(projectRoot, taskId, branchName, baseBranch, copyFiles = []) {
163
223
  const worktreePath = path$5.join(projectRoot, ".substrate-worktrees", taskId);
164
224
  const worktreeExists = await access$1(worktreePath).then(() => true).catch((err) => {
@@ -518,14 +578,19 @@ var GitWorktreeManagerImpl = class {
518
578
  }, "Worktree created");
519
579
  return info;
520
580
  }
521
- async cleanupWorktree(taskId) {
581
+ async cleanupWorktree(taskId, opts) {
522
582
  const branchName = BRANCH_PREFIX + taskId;
523
583
  const worktreePath = this.getWorktreePath(taskId);
524
584
  this._logger.debug({
525
585
  taskId,
526
586
  branchName,
527
- worktreePath
587
+ worktreePath,
588
+ force: opts?.force === true
528
589
  }, "cleanupWorktree");
590
+ if (opts?.force !== true) {
591
+ const decision = await inspectWorktreeRemovalSafety(worktreePath, this._projectRoot, branchName);
592
+ if (!decision.safe) throw new Error(`refusing to clean up worktree for "${taskId}": ${decision.reasons.join("; ")}.\nInspect first (git -C ${worktreePath} status; git log ${branchName} --oneline) or re-run with --force to discard.`);
593
+ }
529
594
  let worktreeExists = false;
530
595
  try {
531
596
  await access$1(worktreePath);
@@ -563,12 +628,28 @@ var GitWorktreeManagerImpl = class {
563
628
  branchName
564
629
  }, "Worktree cleaned up");
565
630
  }
566
- async cleanupAllWorktrees() {
567
- this._logger.debug({ projectRoot: this._projectRoot }, "cleanupAllWorktrees");
631
+ async cleanupAllWorktrees(opts) {
632
+ this._logger.debug({
633
+ projectRoot: this._projectRoot,
634
+ force: opts?.force === true
635
+ }, "cleanupAllWorktrees");
568
636
  const orphanedPaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
569
637
  let cleaned = 0;
570
638
  for (const worktreePath of orphanedPaths) {
571
639
  const taskId = path$4.basename(worktreePath);
640
+ const branchGuardName = BRANCH_PREFIX + taskId;
641
+ const decision = opts?.force === true ? {
642
+ safe: true,
643
+ reasons: []
644
+ } : await inspectWorktreeRemovalSafety(worktreePath, this._projectRoot, branchGuardName);
645
+ if (!decision.safe) {
646
+ this._logger.warn({
647
+ taskId,
648
+ worktreePath,
649
+ reasons: decision.reasons
650
+ }, "cleanupAllWorktrees: preserving worktree — removal would destroy work (use `substrate worktrees cleanup --force` to discard)");
651
+ continue;
652
+ }
572
653
  let worktreeRemoved = false;
573
654
  try {
574
655
  await removeWorktree(worktreePath, this._projectRoot);
@@ -6813,6 +6894,21 @@ async function runCreateStory(deps, params) {
6813
6894
  if (dispatchResult.parsed === null) {
6814
6895
  const details = dispatchResult.parseError ?? "No YAML block found in output";
6815
6896
  const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
6897
+ const authSignature = detectClaudeAuthFailure(dispatchResult.output);
6898
+ if (authSignature !== null) {
6899
+ logger$21.error({
6900
+ epicId,
6901
+ storyKey,
6902
+ authSignature,
6903
+ rawOutputSnippet: rawSnippet
6904
+ }, "Create-story dispatch died on authentication");
6905
+ return {
6906
+ result: "failed",
6907
+ error: "auth-failure",
6908
+ details: `Claude CLI authentication failure (matched: "${authSignature}"). Agent output: ${rawSnippet}`,
6909
+ tokenUsage
6910
+ };
6911
+ }
6816
6912
  logger$21.warn({
6817
6913
  epicId,
6818
6914
  storyKey,
@@ -13695,6 +13791,7 @@ function createImplementationOrchestrator(deps) {
13695
13791
  const _costChecker = new CostGovernanceChecker();
13696
13792
  let _costWarningEmitted = false;
13697
13793
  let _budgetExhausted = false;
13794
+ let _authFailureHalted = false;
13698
13795
  let _shutdownRequested = false;
13699
13796
  let _inFlightCount = 0;
13700
13797
  let _drainResolve = null;
@@ -14018,6 +14115,21 @@ function createImplementationOrchestrator(deps) {
14018
14115
  stderr: cp.stderr.slice(0, 500)
14019
14116
  }, "escalation checkpoint failed — worktree state remains uncommitted (inspect before any cleanup)");
14020
14117
  }
14118
+ if (escalationWorktree !== void 0 && projectRoot !== void 0) {
14119
+ const leakedFiles = detectWorkOutsideWorktree(escalationWorktree, projectRoot, checkGitDiffFiles);
14120
+ if (leakedFiles.length > 0) {
14121
+ const leakMsg = `PARENT-TREE LEAK: the MAIN checkout at ${projectRoot} carries ${String(leakedFiles.length)} uncommitted change(s) during this story's escalation (e.g. ${leakedFiles.slice(0, 10).join(", ")}). Story output may have landed OUTSIDE the worktree — inspect \`git -C ${projectRoot} status\` BEFORE any cleanup; reconcile-from-disk inspects the branch, not main, and will not see these files.`;
14122
+ payload.issues = [...payload.issues, leakMsg];
14123
+ eventBus.emit("orchestrator:story-warn", {
14124
+ storyKey: payload.storyKey,
14125
+ msg: leakMsg
14126
+ });
14127
+ logger$27.warn({
14128
+ storyKey: payload.storyKey,
14129
+ leakedFileCount: leakedFiles.length
14130
+ }, "escalation parent-tree leak detected");
14131
+ }
14132
+ }
14021
14133
  const diagnosis = generateEscalationDiagnosis(payload.issues, payload.reviewCycles, payload.lastVerdict);
14022
14134
  eventBus.emit("orchestrator:story-escalated", {
14023
14135
  ...payload,
@@ -14494,6 +14606,20 @@ function createImplementationOrchestrator(deps) {
14494
14606
  completedAt: new Date().toISOString()
14495
14607
  });
14496
14608
  await writeStoryMetricsBestEffort(storyKey, "failed", 0);
14609
+ const authSignature = createResult.error === "auth-failure" ? createResult.details ?? "auth-failure" : detectClaudeAuthFailure(errMsg);
14610
+ if (authSignature !== null) {
14611
+ const authDetail = createResult.details ?? errMsg;
14612
+ await emitEscalation({
14613
+ storyKey,
14614
+ lastVerdict: "auth-failure",
14615
+ reviewCycles: 0,
14616
+ issues: [authDetail, CLAUDE_AUTH_FAILURE_HINT],
14617
+ escalationReason: "auth-failure"
14618
+ });
14619
+ await triggerAuthFailureHalt(storyKey, authSignature.slice(0, 200));
14620
+ await persistState();
14621
+ return;
14622
+ }
14497
14623
  const codexHint = detectCodexSandboxBlock(errMsg);
14498
14624
  await emitEscalation({
14499
14625
  storyKey,
@@ -15445,6 +15571,19 @@ function createImplementationOrchestrator(deps) {
15445
15571
  completedAt: new Date().toISOString()
15446
15572
  });
15447
15573
  await writeStoryMetricsBestEffort(storyKey, "failed", 0);
15574
+ const devAuthSignature = detectClaudeAuthFailure(errMsg);
15575
+ if (devAuthSignature !== null) {
15576
+ await emitEscalation({
15577
+ storyKey,
15578
+ lastVerdict: "auth-failure",
15579
+ reviewCycles: 0,
15580
+ issues: [errMsg, CLAUDE_AUTH_FAILURE_HINT],
15581
+ escalationReason: "auth-failure"
15582
+ });
15583
+ await triggerAuthFailureHalt(storyKey, devAuthSignature);
15584
+ await persistState();
15585
+ return;
15586
+ }
15448
15587
  await emitEscalation({
15449
15588
  storyKey,
15450
15589
  lastVerdict: "dev-story-exception",
@@ -17193,6 +17332,64 @@ function createImplementationOrchestrator(deps) {
17193
17332
  * @param result - The ceiling check result
17194
17333
  * @param manifest - The current run manifest data
17195
17334
  */
17335
+ /**
17336
+ * H0.4 (field finding #10): halt the entire run when a dispatch dies on
17337
+ * authentication. Auth failures are environmental, not story-specific —
17338
+ * every subsequent dispatch fails identically, so continuing burns the
17339
+ * whole batch (the field run lost ~25 minutes and two runs to this).
17340
+ * Mirrors handleCeilingExceeded: routes through the Decision Router
17341
+ * (severity fatal → halts under every --halt-on policy), sweeps PENDING
17342
+ * stories to ESCALATED with a named reason, and reuses _budgetExhausted
17343
+ * to stop the dispatch loop.
17344
+ */
17345
+ async function triggerAuthFailureHalt(triggeredStoryKey, matchedSignature) {
17346
+ if (_authFailureHalted) return;
17347
+ _authFailureHalted = true;
17348
+ _budgetExhausted = true;
17349
+ const runId = config.pipelineRunId ?? "unknown";
17350
+ const reason = `agent authentication failure on story ${triggeredStoryKey} (matched: "${matchedSignature}") — all subsequent dispatches would fail identically`;
17351
+ let haltPolicy = "critical";
17352
+ if (runManifest !== null) try {
17353
+ const manifest = await runManifest.read();
17354
+ haltPolicy = manifest.cli_flags.halt_on ?? "critical";
17355
+ } catch {}
17356
+ const routeResult = routeDecision("auth-failure", haltPolicy);
17357
+ eventBus.emit("decision:halt", {
17358
+ runId,
17359
+ decisionType: "auth-failure",
17360
+ severity: routeResult.severity,
17361
+ reason
17362
+ });
17363
+ await runInteractivePrompt({
17364
+ runId,
17365
+ decisionType: "auth-failure",
17366
+ severity: routeResult.severity,
17367
+ summary: reason,
17368
+ defaultAction: routeResult.defaultAction,
17369
+ choices: ["abort-run"],
17370
+ onHaltSkipped: (payload) => {
17371
+ eventBus.emit("decision:halt-skipped-non-interactive", payload);
17372
+ }
17373
+ }).catch((err) => {
17374
+ logger$27.warn({ err }, "interactive prompt failed during auth-failure halt — halting anyway");
17375
+ });
17376
+ for (const [key, state] of _stories) if (state.phase === "PENDING" && key !== triggeredStoryKey) {
17377
+ updateStory(key, {
17378
+ phase: "ESCALATED",
17379
+ error: "auth-failure-halt",
17380
+ completedAt: new Date().toISOString()
17381
+ });
17382
+ if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(key, {
17383
+ status: "escalated",
17384
+ escalation_reason: "auth-failure-halt"
17385
+ }).catch(() => {});
17386
+ }
17387
+ logger$27.error({
17388
+ runId,
17389
+ triggeredStoryKey,
17390
+ matchedSignature
17391
+ }, "RUN HALTED: agent authentication failure — fix credentials and re-run");
17392
+ }
17196
17393
  async function handleCeilingExceeded(triggeredStoryKey, remainingInGroup, result, manifest) {
17197
17394
  const haltPolicy = manifest.cli_flags.halt_on ?? "critical";
17198
17395
  const routeResult = routeDecision("cost-ceiling-exhausted", haltPolicy);
@@ -47736,7 +47933,7 @@ async function runFullPipeline(options) {
47736
47933
  */
47737
47934
  async function emitPreDispatchVersionAdvisory(currentVersion) {
47738
47935
  if (process.env["SUBSTRATE_NO_UPDATE_CHECK"] === "1") return;
47739
- const { createVersionManager } = await import("./version-manager-impl-CfzcfFwo.js");
47936
+ const { createVersionManager } = await import("./version-manager-impl-HJMonRJi.js");
47740
47937
  const vm = createVersionManager();
47741
47938
  const result = await vm.checkForUpdates(true);
47742
47939
  const gap = classifyVersionGap(currentVersion, result.latestVersion);
@@ -47833,4 +48030,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
47833
48030
 
47834
48031
  //#endregion
47835
48032
  export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
47836
- //# sourceMappingURL=run-eaZG_3rN.js.map
48033
+ //# sourceMappingURL=run-CRvusFIv.js.map
@@ -21,7 +21,7 @@ type Severity = 'info' | 'warning' | 'critical' | 'fatal';
21
21
  * All known halt-able decision types (AC1).
22
22
  * Epic 73 (Recovery Engine) will extend this union with additional types.
23
23
  */
24
- type DecisionType = 'cost-ceiling-exhausted' | 'build-verification-failure' | 'recovery-retry-attempt' | 're-scope-proposal' | 'scope-violation' | 'cross-story-race-recovered' | 'cross-story-race-still-failed' | 'pipeline-escalation';
24
+ type DecisionType = 'cost-ceiling-exhausted' | 'build-verification-failure' | 'recovery-retry-attempt' | 're-scope-proposal' | 'scope-violation' | 'cross-story-race-recovered' | 'cross-story-race-still-failed' | 'pipeline-escalation' | 'auth-failure';
25
25
  /**
26
26
  * Maps each known decision type to its severity level.
27
27
  *
@@ -1,3 +1,3 @@
1
- import { DECISION_SEVERITY_MAP, deriveExitCode, routeDecision } from "../../../decision-router-DblHY8se.js";
1
+ import { DECISION_SEVERITY_MAP, deriveExitCode, routeDecision } from "../../../decision-router-BAPpON_C.js";
2
2
 
3
3
  export { DECISION_SEVERITY_MAP, deriveExitCode, routeDecision };
@@ -1,5 +1,5 @@
1
- import "./dist-BWCudDcl.js";
1
+ import "./dist-DiNK6QOD.js";
2
2
  import "./version-manager-impl-qFBiO4Eh.js";
3
- import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-3NTcs1t7.js";
3
+ import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-DB7KzD9c.js";
4
4
 
5
5
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
@@ -1,4 +1,4 @@
1
- import { createVersionManager } from "./dist-BWCudDcl.js";
1
+ import { createVersionManager } from "./dist-DiNK6QOD.js";
2
2
  import { execSync, spawn } from "child_process";
3
3
  import * as readline from "readline";
4
4
 
@@ -123,4 +123,4 @@ function registerUpgradeCommand(program) {
123
123
 
124
124
  //#endregion
125
125
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
126
- //# sourceMappingURL=upgrade-3NTcs1t7.js.map
126
+ //# sourceMappingURL=upgrade-DB7KzD9c.js.map
@@ -1,4 +1,4 @@
1
- import { VersionManagerImpl, createVersionManager } from "./dist-BWCudDcl.js";
1
+ import { VersionManagerImpl, createVersionManager } from "./dist-DiNK6QOD.js";
2
2
  import "./version-manager-impl-qFBiO4Eh.js";
3
3
 
4
4
  export { createVersionManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.139",
3
+ "version": "0.20.141",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,4 +0,0 @@
1
- import { AdapterRegistry } from "./dist-BWCudDcl.js";
2
- import "./adapter-registry-DIcrxjH8.js";
3
-
4
- export { AdapterRegistry };