substrate-ai 0.20.63 → 0.20.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +10 -9
- package/dist/decision-router-BA__VYIp.js +97 -0
- package/dist/{health-CJqd1FzY.js → health-CLNmnZiw.js} +1 -1
- package/dist/{health-C-KOZrFJ.js → health-DudlnqXd.js} +11 -2
- package/dist/index.d.ts +76 -1
- package/dist/{run-CHUFlRbH.js → run-CCxsv-9M.js} +184 -17
- package/dist/{run-Z_-caE_i.js → run-ChxsPICN.js} +3 -2
- package/dist/src/modules/decision-router/index.d.ts +88 -0
- package/dist/src/modules/decision-router/index.js +3 -0
- package/dist/{upgrade-C8LAnB6W.js → upgrade-OFeC_NIx.js} +2 -2
- package/dist/{upgrade-CAqLkNUP.js → upgrade-aW7GYL2F.js} +1 -1
- package/dist/{version-manager-impl-DaA_ALYK.js → version-manager-impl-BCSf5E3j.js} +1 -1
- package/package.json +1 -1
- /package/dist/{experimenter-DxxwicpK.js → experimenter-BgpUcUaW.js} +0 -0
- /package/dist/{version-manager-impl-BmOWu8ml.js → version-manager-impl-FH4TTnXm.js} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, readCurrentRunId, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-
|
|
2
|
+
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, readCurrentRunId, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-DudlnqXd.js";
|
|
3
3
|
import { createLogger } from "../logger-KeHncl-f.js";
|
|
4
4
|
import { createEventBus } from "../helpers-CElYrONe.js";
|
|
5
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, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-W2emvN3F.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-CCxsv-9M.js";
|
|
8
8
|
import "../errors-CKFu8YI9.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
11
|
-
import "../
|
|
12
|
-
import
|
|
11
|
+
import "../decision-router-BA__VYIp.js";
|
|
12
|
+
import "../version-manager-impl-FH4TTnXm.js";
|
|
13
|
+
import { registerUpgradeCommand } from "../upgrade-aW7GYL2F.js";
|
|
13
14
|
import { Command } from "commander";
|
|
14
15
|
import { fileURLToPath } from "url";
|
|
15
16
|
import { dirname, join, resolve } from "path";
|
|
@@ -7486,7 +7487,7 @@ async function runStatusAction(options) {
|
|
|
7486
7487
|
logger$15.debug({ err }, "Work graph query failed, continuing without work graph data");
|
|
7487
7488
|
}
|
|
7488
7489
|
if (run === void 0) {
|
|
7489
|
-
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-
|
|
7490
|
+
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-CLNmnZiw.js");
|
|
7490
7491
|
const substrateDirPath = join(projectRoot, ".substrate");
|
|
7491
7492
|
const processInfo = inspectProcessTree$1({
|
|
7492
7493
|
projectRoot,
|
|
@@ -9018,7 +9019,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
9018
9019
|
try {
|
|
9019
9020
|
const { createExperimenter } = await import(
|
|
9020
9021
|
/* @vite-ignore */
|
|
9021
|
-
"../experimenter-
|
|
9022
|
+
"../experimenter-BgpUcUaW.js"
|
|
9022
9023
|
);
|
|
9023
9024
|
const { getLatestRun: getLatest } = await import(
|
|
9024
9025
|
/* @vite-ignore */
|
|
@@ -9032,7 +9033,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
9032
9033
|
await initSchema(expAdapter);
|
|
9033
9034
|
const { runRunAction: runPipeline } = await import(
|
|
9034
9035
|
/* @vite-ignore */
|
|
9035
|
-
"../run-
|
|
9036
|
+
"../run-ChxsPICN.js"
|
|
9036
9037
|
);
|
|
9037
9038
|
const runStoryFn = async (opts) => {
|
|
9038
9039
|
const exitCode = await runPipeline({
|
|
@@ -14035,8 +14036,8 @@ async function createProgram() {
|
|
|
14035
14036
|
/** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
|
|
14036
14037
|
function checkForUpdatesInBackground(currentVersion) {
|
|
14037
14038
|
if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
|
|
14038
|
-
import("../upgrade-
|
|
14039
|
-
const { createVersionManager } = await import("../version-manager-impl-
|
|
14039
|
+
import("../upgrade-OFeC_NIx.js").then(async () => {
|
|
14040
|
+
const { createVersionManager } = await import("../version-manager-impl-BCSf5E3j.js");
|
|
14040
14041
|
const vm = createVersionManager();
|
|
14041
14042
|
const result = await vm.checkForUpdates();
|
|
14042
14043
|
if (result.updateAvailable) {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//#region src/modules/decision-router/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Maps each known decision type to its severity level.
|
|
4
|
+
*
|
|
5
|
+
* Epic 70: cross-story-race-recovered (info — log only, no halt) and
|
|
6
|
+
* cross-story-race-still-failed (critical — recovery exhausted, halt for operator)
|
|
7
|
+
* motivate the registry pattern. Epic 73 (Recovery Engine) will register
|
|
8
|
+
* additional decision types here.
|
|
9
|
+
*/
|
|
10
|
+
const DECISION_SEVERITY_MAP = {
|
|
11
|
+
"cost-ceiling-exhausted": "critical",
|
|
12
|
+
"build-verification-failure": "critical",
|
|
13
|
+
"recovery-retry-attempt": "info",
|
|
14
|
+
"re-scope-proposal": "warning",
|
|
15
|
+
"scope-violation": "fatal",
|
|
16
|
+
"cross-story-race-recovered": "info",
|
|
17
|
+
"cross-story-race-still-failed": "critical",
|
|
18
|
+
"pipeline-escalation": "warning"
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Default action to apply when a decision does NOT trigger a halt.
|
|
22
|
+
* Caller invokes the returned defaultAction string autonomously.
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_ACTION_MAP = {
|
|
25
|
+
"cost-ceiling-exhausted": "skip-remaining",
|
|
26
|
+
"build-verification-failure": "escalate-without-halt",
|
|
27
|
+
"recovery-retry-attempt": "continue-autonomous",
|
|
28
|
+
"re-scope-proposal": "escalate-without-halt",
|
|
29
|
+
"scope-violation": "abort-pipeline",
|
|
30
|
+
"cross-story-race-recovered": "continue-autonomous",
|
|
31
|
+
"cross-story-race-still-failed": "escalate-without-halt",
|
|
32
|
+
"pipeline-escalation": "escalate-without-halt"
|
|
33
|
+
};
|
|
34
|
+
/** Fallback default action for unknown decision types. */
|
|
35
|
+
const DEFAULT_DEFAULT_ACTION = "escalate-without-halt";
|
|
36
|
+
/**
|
|
37
|
+
* Route a halt-able decision through the autonomy policy.
|
|
38
|
+
*
|
|
39
|
+
* Pure function — no I/O, no side effects. All orchestrator state interactions
|
|
40
|
+
* remain in orchestrator-impl.ts.
|
|
41
|
+
*
|
|
42
|
+
* Halt policy logic (AC4):
|
|
43
|
+
* - 'all': halts on info | warning | critical | fatal
|
|
44
|
+
* - 'critical': halts on critical | fatal (default)
|
|
45
|
+
* - 'none': halts ONLY on fatal (scope violations bypass the autonomy-gradient
|
|
46
|
+
* policy — they are always halts regardless of the chosen policy)
|
|
47
|
+
*
|
|
48
|
+
* Fatal always halts regardless of policy — hard safety invariant, not configurable.
|
|
49
|
+
*
|
|
50
|
+
* Unknown decision types default to severity 'critical' (safe default, AC9e).
|
|
51
|
+
*
|
|
52
|
+
* @param decision - The decision type string to route
|
|
53
|
+
* @param policy - The autonomy policy from the --halt-on CLI flag
|
|
54
|
+
* @returns { halt: boolean, defaultAction: string, severity: Severity }
|
|
55
|
+
*/
|
|
56
|
+
function routeDecision(decision, policy) {
|
|
57
|
+
const severity = DECISION_SEVERITY_MAP[decision] ?? "critical";
|
|
58
|
+
let halt;
|
|
59
|
+
switch (policy) {
|
|
60
|
+
case "all":
|
|
61
|
+
halt = true;
|
|
62
|
+
break;
|
|
63
|
+
case "critical":
|
|
64
|
+
halt = severity === "critical" || severity === "fatal";
|
|
65
|
+
break;
|
|
66
|
+
case "none":
|
|
67
|
+
halt = severity === "fatal";
|
|
68
|
+
break;
|
|
69
|
+
default: halt = severity === "critical" || severity === "fatal";
|
|
70
|
+
}
|
|
71
|
+
if (severity === "fatal") halt = true;
|
|
72
|
+
const defaultAction = DEFAULT_ACTION_MAP[decision] ?? DEFAULT_DEFAULT_ACTION;
|
|
73
|
+
return {
|
|
74
|
+
halt,
|
|
75
|
+
defaultAction,
|
|
76
|
+
severity
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Derive the machine-readable exit code from pipeline completion results.
|
|
81
|
+
*
|
|
82
|
+
* - Exit `0` when all stories succeeded (or recovered cleanly)
|
|
83
|
+
* - Exit `1` when some stories escalated; run completed
|
|
84
|
+
* - Exit `2` when run-level failure (cost ceiling, fatal halt, orchestrator died, stories failed)
|
|
85
|
+
*
|
|
86
|
+
* @param outcome - Pipeline completion outcome data
|
|
87
|
+
* @returns 0 (success), 1 (escalated), or 2 (failure)
|
|
88
|
+
*/
|
|
89
|
+
function deriveExitCode(outcome) {
|
|
90
|
+
if (outcome.failed.length > 0 || outcome.costCeilingExhausted === true || outcome.fatalHaltReached === true || outcome.orchestratorDied === true) return 2;
|
|
91
|
+
if (outcome.escalated.length > 0 && outcome.failed.length === 0) return 1;
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { DECISION_SEVERITY_MAP, deriveExitCode, routeDecision };
|
|
97
|
+
//# sourceMappingURL=decision-router-BA__VYIp.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-
|
|
1
|
+
import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-DudlnqXd.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./dist-W2emvN3F.js";
|
|
4
4
|
import "./decisions-C0pz9Clx.js";
|
|
@@ -5787,7 +5787,16 @@ const CliFlagsSchema = z.object({
|
|
|
5787
5787
|
cost_ceiling: z.number().positive().optional(),
|
|
5788
5788
|
agent: z.string().optional(),
|
|
5789
5789
|
skip_verification: z.boolean().optional(),
|
|
5790
|
-
events: z.boolean().optional()
|
|
5790
|
+
events: z.boolean().optional(),
|
|
5791
|
+
non_interactive: z.boolean().optional(),
|
|
5792
|
+
halt_skipped: z.boolean().optional(),
|
|
5793
|
+
halt_skipped_decisions: z.array(z.object({
|
|
5794
|
+
decisionType: z.string(),
|
|
5795
|
+
severity: z.string(),
|
|
5796
|
+
defaultAction: z.string(),
|
|
5797
|
+
reason: z.string(),
|
|
5798
|
+
skippedAt: z.string()
|
|
5799
|
+
})).optional()
|
|
5791
5800
|
});
|
|
5792
5801
|
|
|
5793
5802
|
//#endregion
|
|
@@ -7564,4 +7573,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
7564
7573
|
|
|
7565
7574
|
//#endregion
|
|
7566
7575
|
export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, __commonJS, __require, __toESM, aggregateProbeAuthorMetrics, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, createStateStore, detectCycles, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, parseRuntimeProbes, readCurrentRunId, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runHealthAction, runStaleVerificationRecovery, validateStoryKey };
|
|
7567
|
-
//# sourceMappingURL=health-
|
|
7576
|
+
//# sourceMappingURL=health-DudlnqXd.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -732,6 +732,28 @@ interface CostCeilingReachedEvent {
|
|
|
732
732
|
/** 'critical' when halt_on is 'all' or 'critical'; absent when 'none' */
|
|
733
733
|
severity?: string;
|
|
734
734
|
}
|
|
735
|
+
/**
|
|
736
|
+
* Emitted when --non-interactive mode suppresses a halt decision and applies
|
|
737
|
+
* the default action autonomously instead of prompting the operator.
|
|
738
|
+
*
|
|
739
|
+
* Story 72-2: closes the NDJSON protocol gap — operators can see which halts
|
|
740
|
+
* were auto-skipped and what actions were applied via `substrate report`.
|
|
741
|
+
*/
|
|
742
|
+
interface DecisionHaltSkippedNonInteractiveEvent {
|
|
743
|
+
type: 'decision:halt-skipped-non-interactive';
|
|
744
|
+
/** ISO-8601 timestamp generated at emit time */
|
|
745
|
+
ts: string;
|
|
746
|
+
/** Pipeline run ID */
|
|
747
|
+
run_id: string;
|
|
748
|
+
/** Halt decision type that was skipped (e.g., 'halt:escalation', 'cost-ceiling-exhausted') */
|
|
749
|
+
decision_type: string;
|
|
750
|
+
/** Severity of the skipped halt (e.g., 'critical') */
|
|
751
|
+
severity: string;
|
|
752
|
+
/** Action that was applied in place of the operator prompt (e.g., 'continue-autonomous') */
|
|
753
|
+
default_action: string;
|
|
754
|
+
/** Human-readable reason for skipping */
|
|
755
|
+
reason: string;
|
|
756
|
+
}
|
|
735
757
|
/**
|
|
736
758
|
* Discriminated union of all pipeline event types.
|
|
737
759
|
*
|
|
@@ -744,7 +766,7 @@ interface CostCeilingReachedEvent {
|
|
|
744
766
|
* }
|
|
745
767
|
* ```
|
|
746
768
|
*/
|
|
747
|
-
type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | PipelinePreFlightFailureEvent | PipelineProfileStaleEvent | PipelineContractMismatchEvent | PipelineContractVerificationSummaryEvent | StoryPhaseEvent | StoryDoneEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | StoryZeroDiffEscalationEvent | StoryBuildVerificationFailedEvent | StoryBuildVerificationPassedEvent | StoryInterfaceChangeWarningEvent | StoryMetricsEvent | SupervisorPollEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent | RoutingModelSelectedEvent | PipelinePhaseStartEvent | PipelinePhaseCompleteEvent | StoryAutoApprovedEvent | VerificationCheckCompleteEvent | VerificationStoryCompleteEvent | CostWarningEvent | CostCeilingReachedEvent; //#endregion
|
|
769
|
+
type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | PipelinePreFlightFailureEvent | PipelineProfileStaleEvent | PipelineContractMismatchEvent | PipelineContractVerificationSummaryEvent | StoryPhaseEvent | StoryDoneEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | StoryZeroDiffEscalationEvent | StoryBuildVerificationFailedEvent | StoryBuildVerificationPassedEvent | StoryInterfaceChangeWarningEvent | StoryMetricsEvent | SupervisorPollEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent | RoutingModelSelectedEvent | PipelinePhaseStartEvent | PipelinePhaseCompleteEvent | StoryAutoApprovedEvent | VerificationCheckCompleteEvent | VerificationStoryCompleteEvent | CostWarningEvent | CostCeilingReachedEvent | DecisionHaltSkippedNonInteractiveEvent; //#endregion
|
|
748
770
|
//#region packages/core/dist/types.d.ts
|
|
749
771
|
|
|
750
772
|
/**
|
|
@@ -2507,6 +2529,59 @@ interface OrchestratorEvents {
|
|
|
2507
2529
|
freshFindings: unknown[];
|
|
2508
2530
|
recoveryDurationMs: number;
|
|
2509
2531
|
};
|
|
2532
|
+
/**
|
|
2533
|
+
* Story 72-2: A critical halt decision was skipped under --non-interactive mode.
|
|
2534
|
+
*
|
|
2535
|
+
* Emitted when the pipeline would have prompted the operator (interactive stdin
|
|
2536
|
+
* read) but --non-interactive suppressed stdin and auto-applied the default
|
|
2537
|
+
* action instead. Operators reviewing the run via `substrate report` can see
|
|
2538
|
+
* which halts were auto-skipped and what actions were applied.
|
|
2539
|
+
*
|
|
2540
|
+
* Mirror of CoreEvents['decision:halt-skipped-non-interactive']; both must stay
|
|
2541
|
+
* in sync.
|
|
2542
|
+
*/
|
|
2543
|
+
'decision:halt-skipped-non-interactive': {
|
|
2544
|
+
runId: string;
|
|
2545
|
+
/** Halt decision type that was skipped (e.g., 'halt:escalation', 'halt:critical'). */
|
|
2546
|
+
decisionType: string;
|
|
2547
|
+
/** Severity of the skipped halt (e.g., 'critical'). */
|
|
2548
|
+
severity: string;
|
|
2549
|
+
/** Action that was applied in place of the operator prompt (e.g., 'continue'). */
|
|
2550
|
+
defaultAction: string;
|
|
2551
|
+
/** Human-readable reason for skipping (e.g., 'non-interactive: stdin prompt suppressed'). */
|
|
2552
|
+
reason: string;
|
|
2553
|
+
};
|
|
2554
|
+
/**
|
|
2555
|
+
* Story 72-1: A halt-able decision was routed and the policy requires halting.
|
|
2556
|
+
* Emitted when routeDecision() returns halt=true for a given policy.
|
|
2557
|
+
* Mirror of CoreEvents['decision:halt']; both must stay in sync.
|
|
2558
|
+
*/
|
|
2559
|
+
'decision:halt': {
|
|
2560
|
+
runId: string;
|
|
2561
|
+
/** The decision type that triggered the halt (e.g., 'cost-ceiling-exhausted'). */
|
|
2562
|
+
decisionType: string;
|
|
2563
|
+
/** Severity of the decision (e.g., 'critical', 'fatal'). */
|
|
2564
|
+
severity: string;
|
|
2565
|
+
/** Human-readable reason for the halt. */
|
|
2566
|
+
reason: string;
|
|
2567
|
+
};
|
|
2568
|
+
/**
|
|
2569
|
+
* Story 72-1: A halt-able decision was routed and the policy allows autonomous action.
|
|
2570
|
+
* Emitted when routeDecision() returns halt=false for a given policy.
|
|
2571
|
+
* Caller applies defaultAction without operator intervention.
|
|
2572
|
+
* Mirror of CoreEvents['decision:autonomous']; both must stay in sync.
|
|
2573
|
+
*/
|
|
2574
|
+
'decision:autonomous': {
|
|
2575
|
+
runId: string;
|
|
2576
|
+
/** The decision type that was routed autonomously (e.g., 'build-verification-failure'). */
|
|
2577
|
+
decisionType: string;
|
|
2578
|
+
/** Severity of the decision (e.g., 'info', 'warning', 'critical'). */
|
|
2579
|
+
severity: string;
|
|
2580
|
+
/** The action applied autonomously (e.g., 'escalate-without-halt', 'continue-autonomous'). */
|
|
2581
|
+
defaultAction: string;
|
|
2582
|
+
/** Human-readable reason for autonomous action. */
|
|
2583
|
+
reason: string;
|
|
2584
|
+
};
|
|
2510
2585
|
}
|
|
2511
2586
|
|
|
2512
2587
|
//#endregion
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, runStaleVerificationRecovery, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, runStaleVerificationRecovery, validateStoryKey } from "./health-DudlnqXd.js";
|
|
2
2
|
import { createLogger } from "./logger-KeHncl-f.js";
|
|
3
3
|
import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
|
|
4
4
|
import { ADVISORY_NOTES, 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, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-W2emvN3F.js";
|
|
5
|
+
import { deriveExitCode, routeDecision } from "./decision-router-BA__VYIp.js";
|
|
5
6
|
import { basename, dirname, extname, join } from "path";
|
|
6
7
|
import { access, readFile, readdir, stat } from "fs/promises";
|
|
7
8
|
import { EventEmitter } from "node:events";
|
|
@@ -1764,7 +1765,7 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
1764
1765
|
{
|
|
1765
1766
|
name: "action",
|
|
1766
1767
|
type: "string",
|
|
1767
|
-
description: "Action taken
|
|
1768
|
+
description: "Action taken — stopped when policy requires halt, or the defaultAction when proceeding autonomously."
|
|
1768
1769
|
},
|
|
1769
1770
|
{
|
|
1770
1771
|
name: "skipped_stories",
|
|
@@ -1774,10 +1775,47 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
1774
1775
|
{
|
|
1775
1776
|
name: "severity",
|
|
1776
1777
|
type: "string",
|
|
1777
|
-
description: "
|
|
1778
|
+
description: "Severity from routeDecision (critical for cost-ceiling-exhausted).",
|
|
1778
1779
|
optional: true
|
|
1779
1780
|
}
|
|
1780
1781
|
]
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
type: "decision:halt-skipped-non-interactive",
|
|
1785
|
+
description: "A critical halt decision was skipped under --non-interactive mode; default action was applied autonomously.",
|
|
1786
|
+
when: "Emitted when --non-interactive suppresses an operator prompt and applies the default action. Story 72-2.",
|
|
1787
|
+
fields: [
|
|
1788
|
+
{
|
|
1789
|
+
name: "ts",
|
|
1790
|
+
type: "string",
|
|
1791
|
+
description: "Timestamp."
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
name: "run_id",
|
|
1795
|
+
type: "string",
|
|
1796
|
+
description: "Pipeline run ID."
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
name: "decision_type",
|
|
1800
|
+
type: "string",
|
|
1801
|
+
description: "Halt decision type that was skipped (e.g., halt:escalation)."
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
name: "severity",
|
|
1805
|
+
type: "string",
|
|
1806
|
+
description: "Severity of the skipped halt (e.g., critical)."
|
|
1807
|
+
},
|
|
1808
|
+
{
|
|
1809
|
+
name: "default_action",
|
|
1810
|
+
type: "string",
|
|
1811
|
+
description: "Action applied in place of the operator prompt."
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
name: "reason",
|
|
1815
|
+
type: "string",
|
|
1816
|
+
description: "Human-readable reason for skipping."
|
|
1817
|
+
}
|
|
1818
|
+
]
|
|
1781
1819
|
}
|
|
1782
1820
|
];
|
|
1783
1821
|
/**
|
|
@@ -14284,6 +14322,27 @@ function createImplementationOrchestrator(deps) {
|
|
|
14284
14322
|
}, "Build-fix dispatch failed — escalating");
|
|
14285
14323
|
}
|
|
14286
14324
|
if (!buildFixPassed) {
|
|
14325
|
+
let buildHaltPolicy = "critical";
|
|
14326
|
+
if (runManifest !== null && runManifest !== void 0) try {
|
|
14327
|
+
const manifestData = await runManifest.read();
|
|
14328
|
+
buildHaltPolicy = manifestData.cli_flags.halt_on ?? "critical";
|
|
14329
|
+
} catch {}
|
|
14330
|
+
const buildRouteResult = routeDecision("build-verification-failure", buildHaltPolicy);
|
|
14331
|
+
const buildRunId = config.pipelineRunId ?? "unknown";
|
|
14332
|
+
const buildReason = `build verification failed for story ${storyKey}`;
|
|
14333
|
+
if (buildRouteResult.halt) eventBus.emit("decision:halt", {
|
|
14334
|
+
runId: buildRunId,
|
|
14335
|
+
decisionType: "build-verification-failure",
|
|
14336
|
+
severity: buildRouteResult.severity,
|
|
14337
|
+
reason: buildReason
|
|
14338
|
+
});
|
|
14339
|
+
else eventBus.emit("decision:autonomous", {
|
|
14340
|
+
runId: buildRunId,
|
|
14341
|
+
decisionType: "build-verification-failure",
|
|
14342
|
+
severity: buildRouteResult.severity,
|
|
14343
|
+
defaultAction: buildRouteResult.defaultAction,
|
|
14344
|
+
reason: buildReason
|
|
14345
|
+
});
|
|
14287
14346
|
eventBus.emit("story:build-verification-failed", {
|
|
14288
14347
|
storyKey,
|
|
14289
14348
|
exitCode: buildVerifyResult.exitCode ?? 1,
|
|
@@ -14292,7 +14351,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
14292
14351
|
logger$26.warn({
|
|
14293
14352
|
storyKey,
|
|
14294
14353
|
reason,
|
|
14295
|
-
exitCode: buildVerifyResult.exitCode
|
|
14354
|
+
exitCode: buildVerifyResult.exitCode,
|
|
14355
|
+
routedHalt: buildRouteResult.halt,
|
|
14356
|
+
defaultAction: buildRouteResult.defaultAction
|
|
14296
14357
|
}, "Build verification failed — escalating story");
|
|
14297
14358
|
updateStory(storyKey, {
|
|
14298
14359
|
phase: "ESCALATED",
|
|
@@ -15234,7 +15295,23 @@ function createImplementationOrchestrator(deps) {
|
|
|
15234
15295
|
* @param manifest - The current run manifest data
|
|
15235
15296
|
*/
|
|
15236
15297
|
async function handleCeilingExceeded(triggeredStoryKey, remainingInGroup, result, manifest) {
|
|
15237
|
-
const
|
|
15298
|
+
const haltPolicy = manifest.cli_flags.halt_on ?? "critical";
|
|
15299
|
+
const routeResult = routeDecision("cost-ceiling-exhausted", haltPolicy);
|
|
15300
|
+
const runId = config.pipelineRunId ?? "unknown";
|
|
15301
|
+
const reason = `cost ceiling exceeded: ${result.cumulative.toFixed(4)} USD >= ${result.ceiling} USD`;
|
|
15302
|
+
if (routeResult.halt) eventBus.emit("decision:halt", {
|
|
15303
|
+
runId,
|
|
15304
|
+
decisionType: "cost-ceiling-exhausted",
|
|
15305
|
+
severity: routeResult.severity,
|
|
15306
|
+
reason
|
|
15307
|
+
});
|
|
15308
|
+
else eventBus.emit("decision:autonomous", {
|
|
15309
|
+
runId,
|
|
15310
|
+
decisionType: "cost-ceiling-exhausted",
|
|
15311
|
+
severity: routeResult.severity,
|
|
15312
|
+
defaultAction: routeResult.defaultAction,
|
|
15313
|
+
reason
|
|
15314
|
+
});
|
|
15238
15315
|
const allSkipped = [triggeredStoryKey, ...remainingInGroup];
|
|
15239
15316
|
for (const [key, state] of _stories) if (state.phase === "PENDING" && !allSkipped.includes(key)) allSkipped.push(key);
|
|
15240
15317
|
for (const key of allSkipped) {
|
|
@@ -15248,16 +15325,18 @@ function createImplementationOrchestrator(deps) {
|
|
|
15248
15325
|
eventBus.emit("cost:ceiling-reached", {
|
|
15249
15326
|
cumulative_cost: result.cumulative,
|
|
15250
15327
|
ceiling: result.ceiling,
|
|
15251
|
-
halt_on:
|
|
15252
|
-
action: "stopped",
|
|
15328
|
+
halt_on: haltPolicy,
|
|
15329
|
+
action: routeResult.halt ? "stopped" : routeResult.defaultAction,
|
|
15253
15330
|
skipped_stories: allSkipped,
|
|
15254
|
-
|
|
15331
|
+
severity: routeResult.severity
|
|
15255
15332
|
});
|
|
15256
15333
|
_budgetExhausted = true;
|
|
15257
15334
|
logger$26.warn({
|
|
15258
15335
|
skipped: allSkipped.length,
|
|
15259
15336
|
cumulative: result.cumulative,
|
|
15260
|
-
ceiling: result.ceiling
|
|
15337
|
+
ceiling: result.ceiling,
|
|
15338
|
+
routedHalt: routeResult.halt,
|
|
15339
|
+
defaultAction: routeResult.defaultAction
|
|
15261
15340
|
}, "Cost ceiling reached — stopping dispatch");
|
|
15262
15341
|
}
|
|
15263
15342
|
/**
|
|
@@ -44204,6 +44283,17 @@ function wireNdjsonEmitter(eventBus, ndjsonEmitter) {
|
|
|
44204
44283
|
...payload.severity !== void 0 ? { severity: payload.severity } : {}
|
|
44205
44284
|
});
|
|
44206
44285
|
});
|
|
44286
|
+
eventBus.on("decision:halt-skipped-non-interactive", (payload) => {
|
|
44287
|
+
ndjsonEmitter.emit({
|
|
44288
|
+
type: "decision:halt-skipped-non-interactive",
|
|
44289
|
+
ts: new Date().toISOString(),
|
|
44290
|
+
run_id: payload.runId,
|
|
44291
|
+
decision_type: payload.decisionType,
|
|
44292
|
+
severity: payload.severity,
|
|
44293
|
+
default_action: payload.defaultAction,
|
|
44294
|
+
reason: payload.reason
|
|
44295
|
+
});
|
|
44296
|
+
});
|
|
44207
44297
|
}
|
|
44208
44298
|
/**
|
|
44209
44299
|
* Resolve the `probeAuthorStateIntegrating` boolean from CLI flag and env var.
|
|
@@ -44220,8 +44310,20 @@ function resolveProbeAuthorStateIntegrating(cliFlag) {
|
|
|
44220
44310
|
if (envVal !== void 0) return envVal === "on";
|
|
44221
44311
|
return true;
|
|
44222
44312
|
}
|
|
44313
|
+
/**
|
|
44314
|
+
* Story 72-2: --non-interactive + Machine-Readable Exit Codes.
|
|
44315
|
+
*
|
|
44316
|
+
* Phase D Story 54-6 (2026-04-05): original headless CI/CD spec.
|
|
44317
|
+
* Story 72-1: Decision Router providing routeDecision defaultAction authority.
|
|
44318
|
+
* Story 72-2 (this code): --non-interactive flag that suppresses stdin reads,
|
|
44319
|
+
* auto-applies default actions via routeDecision, and returns exit codes 0/1/2.
|
|
44320
|
+
*
|
|
44321
|
+
* Enables strata + agent-mesh cross-project CI/CD invocation:
|
|
44322
|
+
* substrate run --non-interactive --halt-on none --events --output-format json
|
|
44323
|
+
*/
|
|
44223
44324
|
async function runRunAction(options) {
|
|
44224
|
-
const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, epic: epicNumber, dryRun, maxReviewCycles = 2, engine, agent: agentId, registry: injectedRegistry, haltOn, costCeiling, probeAuthor, probeAuthorStateIntegrating: probeAuthorStateIntegratingFlag } = options;
|
|
44325
|
+
const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, epic: epicNumber, dryRun, maxReviewCycles = 2, engine, agent: agentId, registry: injectedRegistry, haltOn: haltOnOpt, costCeiling, probeAuthor, probeAuthorStateIntegrating: probeAuthorStateIntegratingFlag, nonInteractive } = options;
|
|
44326
|
+
const haltOn = haltOnOpt;
|
|
44225
44327
|
const VALID_PROBE_AUTHOR_MODES = [
|
|
44226
44328
|
"enabled",
|
|
44227
44329
|
"disabled",
|
|
@@ -44534,11 +44636,12 @@ async function runRunAction(options) {
|
|
|
44534
44636
|
const runsDir = join(dbDir, "runs");
|
|
44535
44637
|
const cliFlags = {
|
|
44536
44638
|
...parsedStoryKeys.length > 0 ? { stories: parsedStoryKeys } : {},
|
|
44537
|
-
halt_on: haltOn ?? "
|
|
44639
|
+
halt_on: haltOn ?? "critical",
|
|
44538
44640
|
...costCeiling !== void 0 ? { cost_ceiling: costCeiling } : {},
|
|
44539
44641
|
...agentId !== void 0 ? { agent: agentId } : {},
|
|
44540
44642
|
...skipVerification === true ? { skip_verification: true } : {},
|
|
44541
|
-
...eventsFlag === true ? { events: true } : {}
|
|
44643
|
+
...eventsFlag === true ? { events: true } : {},
|
|
44644
|
+
...nonInteractive === true ? { non_interactive: true } : {}
|
|
44542
44645
|
};
|
|
44543
44646
|
const manifest = RunManifest.open(pipelineRun.id, runsDir);
|
|
44544
44647
|
await manifest.patchCLIFlags(cliFlags);
|
|
@@ -44565,6 +44668,14 @@ async function runRunAction(options) {
|
|
|
44565
44668
|
});
|
|
44566
44669
|
} catch {}
|
|
44567
44670
|
const eventBus = createEventBus();
|
|
44671
|
+
let _costCeilingExhausted = false;
|
|
44672
|
+
let _fatalHaltReached = false;
|
|
44673
|
+
eventBus.on("cost:ceiling-reached", () => {
|
|
44674
|
+
_costCeilingExhausted = true;
|
|
44675
|
+
});
|
|
44676
|
+
eventBus.on("decision:halt", (payload) => {
|
|
44677
|
+
if (payload.severity === "fatal") _fatalHaltReached = true;
|
|
44678
|
+
});
|
|
44568
44679
|
const contextCompiler = createContextCompiler({ db: adapter });
|
|
44569
44680
|
if (!injectedRegistry) throw new Error("AdapterRegistry is required — must be initialized at CLI startup");
|
|
44570
44681
|
const routingConfigPath = join(projectRoot, "substrate.routing.yml");
|
|
@@ -44705,7 +44816,7 @@ async function runRunAction(options) {
|
|
|
44705
44816
|
if (tuiFlag === true && !isTuiCapable()) printNonTtyWarning();
|
|
44706
44817
|
if (verboseFlag !== true && eventsFlag !== true) process.env.LOG_LEVEL = "silent";
|
|
44707
44818
|
let tuiApp;
|
|
44708
|
-
if (tuiFlag === true && isTuiCapable() && eventsFlag !== true && outputFormat === "human") {
|
|
44819
|
+
if (tuiFlag === true && nonInteractive !== true && isTuiCapable() && eventsFlag !== true && outputFormat === "human") {
|
|
44709
44820
|
tuiApp = createTuiApp(process.stdout, process.stdin);
|
|
44710
44821
|
tuiApp.handleEvent({
|
|
44711
44822
|
type: "pipeline:start",
|
|
@@ -45098,13 +45209,52 @@ async function runRunAction(options) {
|
|
|
45098
45209
|
engineType: resolvedEngine,
|
|
45099
45210
|
concurrency
|
|
45100
45211
|
});
|
|
45212
|
+
if (nonInteractive === true) {
|
|
45213
|
+
if (escalatedKeys.length > 0 || _costCeilingExhausted || _fatalHaltReached) {
|
|
45214
|
+
const haltPolicy = haltOn ?? "critical";
|
|
45215
|
+
const routeResult = routeDecision("pipeline-escalation", haltPolicy);
|
|
45216
|
+
eventBus.emit("decision:halt-skipped-non-interactive", {
|
|
45217
|
+
runId: pipelineRun.id,
|
|
45218
|
+
decisionType: "pipeline-escalation",
|
|
45219
|
+
severity: routeResult.severity,
|
|
45220
|
+
defaultAction: routeResult.defaultAction,
|
|
45221
|
+
reason: "non-interactive: stdin prompt suppressed"
|
|
45222
|
+
});
|
|
45223
|
+
try {
|
|
45224
|
+
const runsDir = join(dbDir, "runs");
|
|
45225
|
+
const runManifestForHalt = RunManifest.open(pipelineRun.id, runsDir);
|
|
45226
|
+
await runManifestForHalt.update({ cli_flags: {
|
|
45227
|
+
halt_on: haltPolicy,
|
|
45228
|
+
halt_skipped: true,
|
|
45229
|
+
halt_skipped_decisions: [{
|
|
45230
|
+
decisionType: "pipeline-escalation",
|
|
45231
|
+
severity: routeResult.severity,
|
|
45232
|
+
defaultAction: routeResult.defaultAction,
|
|
45233
|
+
reason: "non-interactive: stdin prompt suppressed",
|
|
45234
|
+
skippedAt: new Date().toISOString()
|
|
45235
|
+
}]
|
|
45236
|
+
} });
|
|
45237
|
+
} catch (haltManifestErr) {
|
|
45238
|
+
logger.warn({ err: haltManifestErr }, "Failed to write halt-skipped to manifest (best-effort)");
|
|
45239
|
+
}
|
|
45240
|
+
}
|
|
45241
|
+
const derivedCode = deriveExitCode({
|
|
45242
|
+
succeeded: succeededKeys,
|
|
45243
|
+
escalated: escalatedKeys,
|
|
45244
|
+
failed: failedKeys,
|
|
45245
|
+
total: storyKeys.length,
|
|
45246
|
+
costCeilingExhausted: _costCeilingExhausted,
|
|
45247
|
+
fatalHaltReached: _fatalHaltReached
|
|
45248
|
+
});
|
|
45249
|
+
return derivedCode;
|
|
45250
|
+
}
|
|
45101
45251
|
return 0;
|
|
45102
45252
|
} catch (err) {
|
|
45103
45253
|
const msg = err instanceof Error ? err.message : String(err);
|
|
45104
45254
|
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
|
|
45105
45255
|
else process.stderr.write(`Error: ${msg}\n`);
|
|
45106
45256
|
logger.error({ err }, "run failed");
|
|
45107
|
-
return 1;
|
|
45257
|
+
return nonInteractive === true ? 2 : 1;
|
|
45108
45258
|
} finally {
|
|
45109
45259
|
try {
|
|
45110
45260
|
await adapter.close();
|
|
@@ -45578,7 +45728,22 @@ async function runFullPipeline(options) {
|
|
|
45578
45728
|
}
|
|
45579
45729
|
}
|
|
45580
45730
|
function registerRunCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
|
|
45581
|
-
program.command("run").description("Run the autonomous pipeline (use --from to start from a specific phase)").option("--pack <name>", "Methodology pack name", "bmad").option("--from <phase>", "Start from this phase: analysis, planning, solutioning, implementation").option("--stop-after <phase>", "Stop pipeline after this phase completes").option("--concept <text>", "Inline concept text (required when --from analysis)").option("--concept-file <path>", "Path to a file containing the concept text").option("--stories <keys>", "Comma-separated story keys (e.g., 10-1,10-2)").option("--epic <n>", "Scope story discovery to a single epic number (e.g., 27)", (v) => parseInt(v, 10)).option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--verbose", "Show detailed pino log output").option("--help-agent", "Print a machine-optimized prompt fragment for AI agents and exit").option("--tui", "Show TUI dashboard").option("--skip-ux", "Skip the UX design phase even if enabled in the pack manifest").option("--research", "Enable the research phase even if not set in the pack manifest").option("--skip-research", "Skip the research phase even if enabled in the pack manifest").option("--skip-preflight", "Skip the pre-flight build check (escape hatch for known-broken projects)").option("--skip-verification", "Skip the post-dispatch verification pipeline (Story 51-5)").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--dry-run", "Preview routing and repo-map injection without dispatching (Story 28-9)").option("--engine <type>", "Execution engine: linear (default) or graph").option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").option("--halt-on <severity>", "Halt pipeline on escalation severity: all | critical | none (default:
|
|
45731
|
+
program.command("run").description("Run the autonomous pipeline (use --from to start from a specific phase)").option("--pack <name>", "Methodology pack name", "bmad").option("--from <phase>", "Start from this phase: analysis, planning, solutioning, implementation").option("--stop-after <phase>", "Stop pipeline after this phase completes").option("--concept <text>", "Inline concept text (required when --from analysis)").option("--concept-file <path>", "Path to a file containing the concept text").option("--stories <keys>", "Comma-separated story keys (e.g., 10-1,10-2)").option("--epic <n>", "Scope story discovery to a single epic number (e.g., 27)", (v) => parseInt(v, 10)).option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--verbose", "Show detailed pino log output").option("--help-agent", "Print a machine-optimized prompt fragment for AI agents and exit").option("--tui", "Show TUI dashboard").option("--skip-ux", "Skip the UX design phase even if enabled in the pack manifest").option("--research", "Enable the research phase even if not set in the pack manifest").option("--skip-research", "Skip the research phase even if enabled in the pack manifest").option("--skip-preflight", "Skip the pre-flight build check (escape hatch for known-broken projects)").option("--skip-verification", "Skip the post-dispatch verification pipeline (Story 51-5)").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--dry-run", "Preview routing and repo-map injection without dispatching (Story 28-9)").option("--engine <type>", "Execution engine: linear (default) or graph").option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").option("--halt-on <severity>", "Halt pipeline on escalation severity: all | critical | none (default: critical)", "critical").option("--cost-ceiling <amount>", "Maximum cost ceiling in USD (positive number); halts pipeline when exceeded", parseFloat).option("--probe-author <mode>", "probe-author phase mode: enabled | disabled | auto (default: auto = SUBSTRATE_PROBE_AUTHOR_ENABLED env, default true) (Story 60-14)", "auto").option("--probe-author-state-integrating <value>", "Disable probe-author dispatch for state-integrating ACs (Phase 3). Use to ramp DOWN if catch rate drops below the GREEN threshold. Values: on | off (default: on)").option("--non-interactive", [
|
|
45732
|
+
"Run without operator prompts (CI/CD mode). Suppresses all stdin reads,",
|
|
45733
|
+
"auto-applies default actions for halt decisions, and returns machine-readable",
|
|
45734
|
+
"exit codes: 0=all stories succeeded, 1=some escalated, 2=run-level failure.",
|
|
45735
|
+
"",
|
|
45736
|
+
"Canonical CI/CD invocation:",
|
|
45737
|
+
" substrate run --non-interactive --halt-on none --events --output-format json",
|
|
45738
|
+
"",
|
|
45739
|
+
"Exit code semantics:",
|
|
45740
|
+
" 0 All stories succeeded (or recovered cleanly)",
|
|
45741
|
+
" 1 Some stories escalated; run completed",
|
|
45742
|
+
" 2 Run-level failure (cost ceiling exhausted, fatal halt, orchestrator died)",
|
|
45743
|
+
"",
|
|
45744
|
+
"--halt-on defaults to critical. Skipped halt decisions are recorded as",
|
|
45745
|
+
"decision:halt-skipped-non-interactive events in --non-interactive mode."
|
|
45746
|
+
].join("\n ")).action(async (opts) => {
|
|
45582
45747
|
if (opts.helpAgent) {
|
|
45583
45748
|
process.exitCode = await runHelpAgent();
|
|
45584
45749
|
return;
|
|
@@ -45622,12 +45787,14 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
45622
45787
|
haltOn: opts.haltOn,
|
|
45623
45788
|
costCeiling: opts.costCeiling,
|
|
45624
45789
|
probeAuthor: opts.probeAuthor,
|
|
45625
|
-
probeAuthorStateIntegrating: opts.probeAuthorStateIntegrating
|
|
45790
|
+
probeAuthorStateIntegrating: opts.probeAuthorStateIntegrating,
|
|
45791
|
+
nonInteractive: opts.nonInteractive
|
|
45626
45792
|
});
|
|
45793
|
+
if (opts.nonInteractive === true) process.exit(exitCode);
|
|
45627
45794
|
process.exitCode = exitCode;
|
|
45628
45795
|
});
|
|
45629
45796
|
}
|
|
45630
45797
|
|
|
45631
45798
|
//#endregion
|
|
45632
45799
|
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, 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 };
|
|
45633
|
-
//# sourceMappingURL=run-
|
|
45800
|
+
//# sourceMappingURL=run-CCxsv-9M.js.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import "./health-
|
|
1
|
+
import "./health-DudlnqXd.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
4
|
import "./dist-W2emvN3F.js";
|
|
5
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-
|
|
5
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-CCxsv-9M.js";
|
|
6
6
|
import "./routing-CcBOCuC9.js";
|
|
7
7
|
import "./decisions-C0pz9Clx.js";
|
|
8
|
+
import "./decision-router-BA__VYIp.js";
|
|
8
9
|
|
|
9
10
|
export { runRunAction };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//#region src/modules/decision-router/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Decision Router — Phase D Story 54-2 (2026-04-05): original autonomy-gradient spec.
|
|
4
|
+
* Story 72-1: --halt-on flag + Decision Router (this file).
|
|
5
|
+
* Classifies every halt-able decision by severity and enforces the chosen autonomy policy.
|
|
6
|
+
* Exports routeDecision(decision, policy) pure function for orchestrator consumption.
|
|
7
|
+
* Epic 70: cross-story-race decision types (cross-story-race-recovered,
|
|
8
|
+
* cross-story-race-still-failed) motivate the registry pattern — different halt semantics
|
|
9
|
+
* based on severity (info vs critical).
|
|
10
|
+
* Epic 73 (Recovery Engine) will register additional decision types via DECISION_SEVERITY_MAP.
|
|
11
|
+
*
|
|
12
|
+
* Story 72-2: --non-interactive flag consuming routeDecision for stdin suppression.
|
|
13
|
+
* Enables strata + agent-mesh cross-project CI/CD invocation.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Severity of a halt-able decision.
|
|
17
|
+
* Controls which autonomy policies trigger a halt.
|
|
18
|
+
*/
|
|
19
|
+
type Severity = 'info' | 'warning' | 'critical' | 'fatal';
|
|
20
|
+
/**
|
|
21
|
+
* All known halt-able decision types (AC1).
|
|
22
|
+
* Epic 73 (Recovery Engine) will extend this union with additional types.
|
|
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';
|
|
25
|
+
/**
|
|
26
|
+
* Maps each known decision type to its severity level.
|
|
27
|
+
*
|
|
28
|
+
* Epic 70: cross-story-race-recovered (info — log only, no halt) and
|
|
29
|
+
* cross-story-race-still-failed (critical — recovery exhausted, halt for operator)
|
|
30
|
+
* motivate the registry pattern. Epic 73 (Recovery Engine) will register
|
|
31
|
+
* additional decision types here.
|
|
32
|
+
*/
|
|
33
|
+
declare const DECISION_SEVERITY_MAP: Record<DecisionType, Severity>;
|
|
34
|
+
/**
|
|
35
|
+
* Route a halt-able decision through the autonomy policy.
|
|
36
|
+
*
|
|
37
|
+
* Pure function — no I/O, no side effects. All orchestrator state interactions
|
|
38
|
+
* remain in orchestrator-impl.ts.
|
|
39
|
+
*
|
|
40
|
+
* Halt policy logic (AC4):
|
|
41
|
+
* - 'all': halts on info | warning | critical | fatal
|
|
42
|
+
* - 'critical': halts on critical | fatal (default)
|
|
43
|
+
* - 'none': halts ONLY on fatal (scope violations bypass the autonomy-gradient
|
|
44
|
+
* policy — they are always halts regardless of the chosen policy)
|
|
45
|
+
*
|
|
46
|
+
* Fatal always halts regardless of policy — hard safety invariant, not configurable.
|
|
47
|
+
*
|
|
48
|
+
* Unknown decision types default to severity 'critical' (safe default, AC9e).
|
|
49
|
+
*
|
|
50
|
+
* @param decision - The decision type string to route
|
|
51
|
+
* @param policy - The autonomy policy from the --halt-on CLI flag
|
|
52
|
+
* @returns { halt: boolean, defaultAction: string, severity: Severity }
|
|
53
|
+
*/
|
|
54
|
+
declare function routeDecision(decision: string, policy: 'all' | 'critical' | 'none'): {
|
|
55
|
+
halt: boolean;
|
|
56
|
+
defaultAction: string;
|
|
57
|
+
severity: Severity;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Inputs for exit code derivation from pipeline completion results.
|
|
61
|
+
* Used by the CLI layer to derive the machine-readable exit code (0/1/2)
|
|
62
|
+
* for non-interactive CI/CD invocations.
|
|
63
|
+
*/
|
|
64
|
+
interface PipelineOutcome {
|
|
65
|
+
succeeded: string[];
|
|
66
|
+
recovered?: string[];
|
|
67
|
+
escalated: string[];
|
|
68
|
+
failed: string[];
|
|
69
|
+
total: number;
|
|
70
|
+
costCeilingExhausted?: boolean;
|
|
71
|
+
fatalHaltReached?: boolean;
|
|
72
|
+
orchestratorDied?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Derive the machine-readable exit code from pipeline completion results.
|
|
76
|
+
*
|
|
77
|
+
* - Exit `0` when all stories succeeded (or recovered cleanly)
|
|
78
|
+
* - Exit `1` when some stories escalated; run completed
|
|
79
|
+
* - Exit `2` when run-level failure (cost ceiling, fatal halt, orchestrator died, stories failed)
|
|
80
|
+
*
|
|
81
|
+
* @param outcome - Pipeline completion outcome data
|
|
82
|
+
* @returns 0 (success), 1 (escalated), or 2 (failure)
|
|
83
|
+
*/
|
|
84
|
+
declare function deriveExitCode(outcome: PipelineOutcome): 0 | 1 | 2; //#endregion
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=index.d.ts.map
|
|
87
|
+
export { DECISION_SEVERITY_MAP, DecisionType, PipelineOutcome, Severity, deriveExitCode, routeDecision };
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./dist-W2emvN3F.js";
|
|
2
|
-
import "./version-manager-impl-
|
|
3
|
-
import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-
|
|
2
|
+
import "./version-manager-impl-FH4TTnXm.js";
|
|
3
|
+
import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-aW7GYL2F.js";
|
|
4
4
|
|
|
5
5
|
export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|