substrate-ai 0.20.17 → 0.20.19
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
CHANGED
|
@@ -4,7 +4,7 @@ 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, 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-CqtWS9wF.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-2nI3qh0-.js";
|
|
8
8
|
import "../errors-1uLGqnvr.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
@@ -5198,7 +5198,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
5198
5198
|
await initSchema(expAdapter);
|
|
5199
5199
|
const { runRunAction: runPipeline } = await import(
|
|
5200
5200
|
/* @vite-ignore */
|
|
5201
|
-
"../run-
|
|
5201
|
+
"../run-BNCfGm5V.js"
|
|
5202
5202
|
);
|
|
5203
5203
|
const runStoryFn = async (opts) => {
|
|
5204
5204
|
const exitCode = await runPipeline({
|
|
@@ -5737,6 +5737,19 @@ async function runCreateStory(deps, params) {
|
|
|
5737
5737
|
}
|
|
5738
5738
|
const implementationDecisions = await getImplementationDecisions(deps, pipelineRunId);
|
|
5739
5739
|
const epicShardContent = getEpicShard(implementationDecisions, epicId, deps.projectRoot, storyKey);
|
|
5740
|
+
let effectiveSourceAcHash = source_ac_hash;
|
|
5741
|
+
if (epicShardContent.length > 0) {
|
|
5742
|
+
const storySection = extractStorySection(epicShardContent, storyKey);
|
|
5743
|
+
if (storySection !== null) {
|
|
5744
|
+
const computedHash = hashSourceAcSection(storySection);
|
|
5745
|
+
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$18.debug({
|
|
5746
|
+
storyKey,
|
|
5747
|
+
suppliedHash: source_ac_hash,
|
|
5748
|
+
computedHash
|
|
5749
|
+
}, "Orchestrator-supplied source_ac_hash differs from epic_shard content hash — using computed (Story 58-18)");
|
|
5750
|
+
effectiveSourceAcHash = computedHash;
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5740
5753
|
const prevDevNotesContent = getPrevDevNotes(implementationDecisions, epicId);
|
|
5741
5754
|
let storyDefinitionContent = "";
|
|
5742
5755
|
try {
|
|
@@ -5780,9 +5793,9 @@ async function runCreateStory(deps, params) {
|
|
|
5780
5793
|
content: storyTemplateContent,
|
|
5781
5794
|
priority: "important"
|
|
5782
5795
|
},
|
|
5783
|
-
...
|
|
5796
|
+
...effectiveSourceAcHash !== void 0 ? [{
|
|
5784
5797
|
name: "source_ac_hash",
|
|
5785
|
-
content:
|
|
5798
|
+
content: effectiveSourceAcHash,
|
|
5786
5799
|
priority: "required"
|
|
5787
5800
|
}] : []
|
|
5788
5801
|
], TOKEN_CEILING);
|
|
@@ -5968,27 +5981,24 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
5968
5981
|
}
|
|
5969
5982
|
const epicShard = decisions.find((d) => d.category === "epic-shard" && d.key === epicId);
|
|
5970
5983
|
const shardContent = epicShard?.value;
|
|
5971
|
-
if (shardContent) {
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
if (storySection) {
|
|
5975
|
-
logger$18.debug({
|
|
5976
|
-
epicId,
|
|
5977
|
-
storyKey
|
|
5978
|
-
}, "Extracted per-story section from epic shard (pre-37-0 fallback)");
|
|
5979
|
-
return storySection;
|
|
5980
|
-
}
|
|
5984
|
+
if (shardContent && storyKey) {
|
|
5985
|
+
const storySection = extractStorySection(shardContent, storyKey);
|
|
5986
|
+
if (storySection) {
|
|
5981
5987
|
logger$18.debug({
|
|
5982
5988
|
epicId,
|
|
5983
5989
|
storyKey
|
|
5984
|
-
}, "
|
|
5990
|
+
}, "Extracted per-story section from epic shard (pre-37-0 fallback)");
|
|
5991
|
+
return storySection;
|
|
5985
5992
|
}
|
|
5986
|
-
|
|
5993
|
+
logger$18.info({
|
|
5994
|
+
epicId,
|
|
5995
|
+
storyKey
|
|
5996
|
+
}, "Story section absent in decisions-store shard — attempting file-based fallback before returning stale shard");
|
|
5987
5997
|
}
|
|
5988
5998
|
if (projectRoot) {
|
|
5989
5999
|
const fallback = readEpicShardFromFile(projectRoot, epicId);
|
|
5990
6000
|
if (fallback) {
|
|
5991
|
-
logger$18.info({ epicId }, "Using file-based fallback for epic shard
|
|
6001
|
+
logger$18.info({ epicId }, "Using file-based fallback for epic shard");
|
|
5992
6002
|
if (storyKey) {
|
|
5993
6003
|
const storySection = extractStorySection(fallback, storyKey);
|
|
5994
6004
|
if (storySection) {
|
|
@@ -6002,6 +6012,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6002
6012
|
return fallback;
|
|
6003
6013
|
}
|
|
6004
6014
|
}
|
|
6015
|
+
if (shardContent) return shardContent;
|
|
6005
6016
|
return "";
|
|
6006
6017
|
} catch (err) {
|
|
6007
6018
|
logger$18.warn({
|
|
@@ -8776,6 +8787,13 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
8776
8787
|
for (const shard of shards) {
|
|
8777
8788
|
const subsections = parseStorySubsections(shard.epicId, shard.content);
|
|
8778
8789
|
for (const subsection of subsections) {
|
|
8790
|
+
if (subsection.content.length > MAX_EPIC_SHARD_CHARS) logger$11.warn({
|
|
8791
|
+
epicId: shard.epicId,
|
|
8792
|
+
storyKey: subsection.key,
|
|
8793
|
+
originalLength: subsection.content.length,
|
|
8794
|
+
truncatedLength: MAX_EPIC_SHARD_CHARS,
|
|
8795
|
+
droppedChars: subsection.content.length - MAX_EPIC_SHARD_CHARS
|
|
8796
|
+
}, `Epic shard for ${subsection.key} exceeded ${MAX_EPIC_SHARD_CHARS}-char cap and was truncated; tail content lost from decisions store. Consider splitting the story or raising MAX_EPIC_SHARD_CHARS.`);
|
|
8779
8797
|
await createDecision(db, {
|
|
8780
8798
|
pipeline_run_id: null,
|
|
8781
8799
|
phase: "implementation",
|
|
@@ -8897,25 +8915,46 @@ function parseEpicShards(content) {
|
|
|
8897
8915
|
* Parse an epic section's content into per-story subsections.
|
|
8898
8916
|
*
|
|
8899
8917
|
* Matches story headings using three patterns:
|
|
8900
|
-
* - Markdown headings: #{2,6} Story \d
|
|
8901
|
-
* - Bold: **Story \d
|
|
8902
|
-
* - Bare key: \d
|
|
8918
|
+
* - Markdown headings: #{2,6} Story \d+[-._ ]\d+ (e.g., ### Story 37-1: Title or ### Story 1.1)
|
|
8919
|
+
* - Bold: **Story \d+[-._ ]\d+** (e.g., **Story 37-1**)
|
|
8920
|
+
* - Bare key: \d+[-._ ]\d+:\s (e.g., 37-1: Title — must start at line start)
|
|
8903
8921
|
*
|
|
8904
8922
|
* Each subsection spans from its heading to the next matching heading or EOF.
|
|
8905
8923
|
*
|
|
8924
|
+
* Story 58-17: separator normalization. The original regex required `\d+-\d+`
|
|
8925
|
+
* (dash-only). Strata uses `### Story 1.1` (dot-separated) per its BMAD-template
|
|
8926
|
+
* convention. Without separator-agnostic parsing, every Story 1.X heading was
|
|
8927
|
+
* silently invisible to this parser, the matches.length === 0 fallback path
|
|
8928
|
+
* fired, the entire epic was stored as ONE per-epic decision (key=epicId)
|
|
8929
|
+
* truncated at 12K chars. All stories past the truncation point (1.6, 1.8,
|
|
8930
|
+
* 1.9+ in strata's case) were lost from the decisions store, which is the
|
|
8931
|
+
* actual root cause of strata obs_2026-04-20_001 — create-story received
|
|
8932
|
+
* empty input for those stories and hallucinated specs from domain priors.
|
|
8933
|
+
*
|
|
8934
|
+
* Epic 58-5 already made `extractStorySection` separator-agnostic for the
|
|
8935
|
+
* same reason; this matches that precedent at the seed-time parser.
|
|
8936
|
+
*
|
|
8937
|
+
* Captured storyKey is normalized to canonical dash-form (`1.1` → `1-1`) so
|
|
8938
|
+
* decision keys are consistent regardless of the source heading style — a
|
|
8939
|
+
* `--stories 1-9` CLI invocation finds the shard whether the epic used dot,
|
|
8940
|
+
* dash, underscore, or space separators.
|
|
8941
|
+
*
|
|
8906
8942
|
* AC3: If no story headings are found, returns a single per-epic fallback entry
|
|
8907
8943
|
* keyed by epicId — preserving backward-compatible behaviour for unstructured epics.
|
|
8908
8944
|
*/
|
|
8909
8945
|
function parseStorySubsections(epicId, epicContent) {
|
|
8910
|
-
const storyPattern = /(?:^#{2,6}\s+Story\s+(\d
|
|
8946
|
+
const storyPattern = /(?:^#{2,6}\s+Story\s+(\d+[-._ ]\d+)|^\*\*Story\s+(\d+[-._ ]\d+)\*\*|^(\d+[-._ ]\d+):\s)/gim;
|
|
8911
8947
|
const matches = [];
|
|
8912
8948
|
let match$2;
|
|
8913
8949
|
while ((match$2 = storyPattern.exec(epicContent)) !== null) {
|
|
8914
|
-
const
|
|
8915
|
-
if (
|
|
8916
|
-
storyKey,
|
|
8917
|
-
|
|
8918
|
-
|
|
8950
|
+
const rawKey = match$2[1] ?? match$2[2] ?? match$2[3];
|
|
8951
|
+
if (rawKey !== void 0) {
|
|
8952
|
+
const storyKey = rawKey.replace(/[._ ]/g, "-");
|
|
8953
|
+
matches.push({
|
|
8954
|
+
storyKey,
|
|
8955
|
+
startIdx: match$2.index
|
|
8956
|
+
});
|
|
8957
|
+
}
|
|
8919
8958
|
}
|
|
8920
8959
|
if (matches.length === 0) return [{
|
|
8921
8960
|
key: epicId,
|
|
@@ -43291,11 +43330,11 @@ async function runRunAction(options) {
|
|
|
43291
43330
|
});
|
|
43292
43331
|
process.on("SIGINT", () => {
|
|
43293
43332
|
ingestionServer.stop();
|
|
43294
|
-
process.exit(130);
|
|
43333
|
+
setTimeout(() => process.exit(130), 6e3).unref();
|
|
43295
43334
|
});
|
|
43296
43335
|
process.on("SIGTERM", () => {
|
|
43297
43336
|
ingestionServer.stop();
|
|
43298
|
-
process.exit(143);
|
|
43337
|
+
setTimeout(() => process.exit(143), 6e3).unref();
|
|
43299
43338
|
});
|
|
43300
43339
|
}
|
|
43301
43340
|
if (telemetryPersistence !== void 0) {
|
|
@@ -43825,11 +43864,11 @@ async function runFullPipeline(options) {
|
|
|
43825
43864
|
});
|
|
43826
43865
|
process.on("SIGINT", () => {
|
|
43827
43866
|
fpIngestionServer.stop();
|
|
43828
|
-
process.exit(130);
|
|
43867
|
+
setTimeout(() => process.exit(130), 6e3).unref();
|
|
43829
43868
|
});
|
|
43830
43869
|
process.on("SIGTERM", () => {
|
|
43831
43870
|
fpIngestionServer.stop();
|
|
43832
|
-
process.exit(143);
|
|
43871
|
+
setTimeout(() => process.exit(143), 6e3).unref();
|
|
43833
43872
|
});
|
|
43834
43873
|
}
|
|
43835
43874
|
const fpTelemetryPersistence = fullTelemetryEnabled ? new AdapterTelemetryPersistence(adapter) : void 0;
|
|
@@ -44052,4 +44091,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
44052
44091
|
|
|
44053
44092
|
//#endregion
|
|
44054
44093
|
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
44055
|
-
//# sourceMappingURL=run-
|
|
44094
|
+
//# sourceMappingURL=run-2nI3qh0-.js.map
|
|
@@ -2,7 +2,7 @@ import "./health-ZGa9E0D2.js";
|
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
4
|
import "./dist-CqtWS9wF.js";
|
|
5
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-
|
|
5
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-2nI3qh0-.js";
|
|
6
6
|
import "./routing-CcBOCuC9.js";
|
|
7
7
|
import "./decisions-C0pz9Clx.js";
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -29,6 +29,24 @@ Using the context above, write a complete, implementation-ready story file for s
|
|
|
29
29
|
Use the title, description, and acceptance criteria from the Story Definition — do NOT substitute
|
|
30
30
|
a different story from the epic scope. The story key, title, and core scope are non-negotiable.
|
|
31
31
|
|
|
32
|
+
## Input Validation (fail-loud)
|
|
33
|
+
|
|
34
|
+
Before anything else, verify the input contains the source Acceptance Criteria for story `{{story_key}}`. Scan `Epic Scope` and `Story Definition` for BOTH:
|
|
35
|
+
|
|
36
|
+
- A heading matching `Story {{story_key}}` (separators: `-`, `.`, `_`, space).
|
|
37
|
+
- An AC-bearing block within that section (`## Acceptance Criteria`, `### Acceptance Criteria`, `**Acceptance Criteria:**`, etc.).
|
|
38
|
+
|
|
39
|
+
If either is missing — shard truncated, context about other stories only — **do not infer, guess, or hallucinate an AC from the story key or domain priors**. A prior substrate session recorded a shape-specific drift exactly here: no source AC for a "graph builder" story → the agent invented a LanceDB+class-based spec, contradicting the author's explicit "plain JSON adjacency list" directive, purely from a trained pattern.
|
|
40
|
+
|
|
41
|
+
Instead, emit immediately per the Output Contract below:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
result: failure
|
|
45
|
+
error: source-ac-content-missing
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Do NOT write a partial story file. Do NOT paraphrase surrounding context. Do NOT dispatch Write. The orchestrator treats this as terminal — the correct outcome when the input pipeline has degraded.
|
|
49
|
+
|
|
32
50
|
## Instructions
|
|
33
51
|
|
|
34
52
|
1. **Use the Story Definition as your primary input** — it specifies exactly what this story builds. The epic scope provides surrounding context only.
|