substrate-ai 0.17.1 → 0.18.0
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/adapter-registry-bsm0SCZW.js +4 -0
- package/dist/cli/index.js +148 -37
- package/dist/{decisions-CGNEausW.js → decisions-DMpHsVUn.js} +1 -1
- package/dist/{dist-CLvAwmT7.js → dist-Bm0qSZer.js} +7 -4
- package/dist/{errors-D1LU8CZ9.js → errors-BSpu7pIv.js} +2 -2
- package/dist/{experimenter-D0k2wT3I.js → experimenter-DV-ZC-uX.js} +1 -1
- package/dist/{health-DswaC1q5.js → health-Cx2ZhRNT.js} +2 -2
- package/dist/{health-GEDGgGan.js → health-DRywcMxP.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/{routing-B1aoIz7L.js → routing-CXLeUI-t.js} +1 -1
- package/dist/{run-Bku8fmY3.js → run-gXtnH8lO.js} +518 -6
- package/dist/{run-N5rHJu-Y.js → run-m7RCkpmx.js} +3 -3
- package/dist/{upgrade-DT0I_-1E.js → upgrade-BcL4ZV3o.js} +2 -2
- package/dist/{upgrade-DPdh5w4p.js → upgrade-CbwnF2hv.js} +2 -2
- package/dist/{version-manager-impl-BHnUB2tl.js → version-manager-impl-DBx3ovp9.js} +1 -1
- package/package.json +3 -3
- package/dist/adapter-registry-DbLuI3IA.js +0 -4
package/dist/cli/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, WorkGraphRepository, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, detectCycles, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot } from "../health-
|
|
2
|
+
import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, WorkGraphRepository, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, detectCycles, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot } from "../health-Cx2ZhRNT.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, EXPERIMENT_RESULT, 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, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRequirements, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-
|
|
5
|
+
import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, EXPERIMENT_RESULT, 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, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRequirements, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-Bm0qSZer.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
8
|
-
import "../errors-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-gXtnH8lO.js";
|
|
8
|
+
import "../errors-BSpu7pIv.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
11
11
|
import "../version-manager-impl-BmOWu8ml.js";
|
|
12
|
-
import { registerUpgradeCommand } from "../upgrade-
|
|
12
|
+
import { registerUpgradeCommand } from "../upgrade-BcL4ZV3o.js";
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
15
15
|
import { dirname, join, resolve } from "path";
|
|
@@ -24,7 +24,7 @@ import { isAbsolute, join as join$1 } from "node:path";
|
|
|
24
24
|
import { z } from "zod";
|
|
25
25
|
import * as fs from "node:fs/promises";
|
|
26
26
|
import { access as access$1, readFile as readFile$1, readdir as readdir$1 } from "node:fs/promises";
|
|
27
|
-
import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync, statSync, unlinkSync, writeFileSync as writeFileSync$1 } from "fs";
|
|
27
|
+
import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync, rmSync as rmSync$1, statSync, unlinkSync, writeFileSync as writeFileSync$1 } from "fs";
|
|
28
28
|
import { homedir } from "os";
|
|
29
29
|
import { createRequire } from "node:module";
|
|
30
30
|
import { fileURLToPath as fileURLToPath$1 } from "node:url";
|
|
@@ -1757,14 +1757,16 @@ function clearBmadCommandFiles(commandsDir) {
|
|
|
1757
1757
|
}
|
|
1758
1758
|
async function compileBmadAgents(bmadDir) {
|
|
1759
1759
|
const _require = createRequire(join(__dirname, "synthetic.js"));
|
|
1760
|
-
let
|
|
1760
|
+
let compileAgent;
|
|
1761
1761
|
try {
|
|
1762
1762
|
const pkgJsonPath = _require.resolve("bmad-method/package.json");
|
|
1763
|
-
compilerPath = join(dirname(pkgJsonPath), "tools", "cli", "lib", "agent", "compiler.js");
|
|
1763
|
+
const compilerPath = join(dirname(pkgJsonPath), "tools", "cli", "lib", "agent", "compiler.js");
|
|
1764
|
+
if (!existsSync$1(compilerPath)) return 0;
|
|
1765
|
+
const mod = _require(compilerPath);
|
|
1766
|
+
compileAgent = mod.compileAgent;
|
|
1764
1767
|
} catch {
|
|
1765
1768
|
return 0;
|
|
1766
1769
|
}
|
|
1767
|
-
const { compileAgent } = _require(compilerPath);
|
|
1768
1770
|
const agentDirs = [];
|
|
1769
1771
|
const coreAgentsDir = join(bmadDir, "core", "agents");
|
|
1770
1772
|
if (existsSync$1(coreAgentsDir)) agentDirs.push(coreAgentsDir);
|
|
@@ -1800,6 +1802,76 @@ async function compileBmadAgents(bmadDir) {
|
|
|
1800
1802
|
} catch {}
|
|
1801
1803
|
return compiled;
|
|
1802
1804
|
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Parse a single CSV line, respecting double-quoted fields that may contain
|
|
1807
|
+
* commas and escaped quotes (RFC 4180). Returns an array of field values.
|
|
1808
|
+
*/
|
|
1809
|
+
function parseCSVLine(line) {
|
|
1810
|
+
const fields = [];
|
|
1811
|
+
let current = "";
|
|
1812
|
+
let inQuotes = false;
|
|
1813
|
+
for (let i = 0; i < line.length; i++) {
|
|
1814
|
+
const ch = line[i];
|
|
1815
|
+
if (inQuotes) if (ch === "\"") if (i + 1 < line.length && line[i + 1] === "\"") {
|
|
1816
|
+
current += "\"";
|
|
1817
|
+
i++;
|
|
1818
|
+
} else inQuotes = false;
|
|
1819
|
+
else current += ch;
|
|
1820
|
+
else if (ch === "\"") inQuotes = true;
|
|
1821
|
+
else if (ch === ",") {
|
|
1822
|
+
fields.push(current);
|
|
1823
|
+
current = "";
|
|
1824
|
+
} else current += ch;
|
|
1825
|
+
}
|
|
1826
|
+
fields.push(current);
|
|
1827
|
+
return fields;
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* Install skills from `_bmad/_config/skill-manifest.csv` into `.claude/skills/`.
|
|
1831
|
+
*
|
|
1832
|
+
* Each row in the CSV specifies a canonicalId and a path to the SKILL.md file.
|
|
1833
|
+
* The entire source directory (dirname of the path) is copied to
|
|
1834
|
+
* `.claude/skills/<canonicalId>/`, matching bmad-method's installVerbatimSkills.
|
|
1835
|
+
*
|
|
1836
|
+
* @returns Number of skills installed.
|
|
1837
|
+
*/
|
|
1838
|
+
function installSkillsFromManifest(projectRoot, bmadDir) {
|
|
1839
|
+
const csvPath = join(bmadDir, "_config", "skill-manifest.csv");
|
|
1840
|
+
if (!existsSync$1(csvPath)) return 0;
|
|
1841
|
+
const csvContent = readFileSync$1(csvPath, "utf-8");
|
|
1842
|
+
const lines = csvContent.split("\n").filter((l) => l.trim() !== "");
|
|
1843
|
+
if (lines.length < 2) return 0;
|
|
1844
|
+
const headers = parseCSVLine(lines[0]);
|
|
1845
|
+
const canonicalIdIdx = headers.indexOf("canonicalId");
|
|
1846
|
+
const pathIdx = headers.indexOf("path");
|
|
1847
|
+
if (canonicalIdIdx < 0 || pathIdx < 0) return 0;
|
|
1848
|
+
const bmadFolderName = "_bmad";
|
|
1849
|
+
const bmadPrefix = bmadFolderName + "/";
|
|
1850
|
+
const skillsDir = join(projectRoot, ".claude", "skills");
|
|
1851
|
+
mkdirSync$1(skillsDir, { recursive: true });
|
|
1852
|
+
if (existsSync$1(skillsDir)) try {
|
|
1853
|
+
for (const entry of readdirSync$1(skillsDir, { withFileTypes: true })) if (entry.isDirectory() && entry.name.startsWith("bmad")) rmSync$1(join(skillsDir, entry.name), {
|
|
1854
|
+
recursive: true,
|
|
1855
|
+
force: true
|
|
1856
|
+
});
|
|
1857
|
+
} catch {}
|
|
1858
|
+
let count = 0;
|
|
1859
|
+
for (let i = 1; i < lines.length; i++) {
|
|
1860
|
+
const fields = parseCSVLine(lines[i]);
|
|
1861
|
+
const canonicalId = fields[canonicalIdIdx]?.trim();
|
|
1862
|
+
const skillPath = fields[pathIdx]?.trim();
|
|
1863
|
+
if (!canonicalId || !skillPath) continue;
|
|
1864
|
+
const relativePath = skillPath.startsWith(bmadPrefix) ? skillPath.slice(bmadPrefix.length) : skillPath;
|
|
1865
|
+
const sourceFile = join(bmadDir, relativePath);
|
|
1866
|
+
const sourceDir = dirname(sourceFile);
|
|
1867
|
+
if (!existsSync$1(sourceDir)) continue;
|
|
1868
|
+
const destDir = join(skillsDir, canonicalId);
|
|
1869
|
+
mkdirSync$1(destDir, { recursive: true });
|
|
1870
|
+
cpSync(sourceDir, destDir, { recursive: true });
|
|
1871
|
+
count++;
|
|
1872
|
+
}
|
|
1873
|
+
return count;
|
|
1874
|
+
}
|
|
1803
1875
|
async function scaffoldClaudeCommands(projectRoot, outputFormat) {
|
|
1804
1876
|
const bmadDir = join(projectRoot, "_bmad");
|
|
1805
1877
|
if (!existsSync$1(bmadDir)) return;
|
|
@@ -1822,17 +1894,39 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
|
|
|
1822
1894
|
if (def && typeof def[name] === "function") return def[name];
|
|
1823
1895
|
throw new Error(`${name} is not a constructor`);
|
|
1824
1896
|
};
|
|
1825
|
-
const
|
|
1897
|
+
const agentGenPath = join(installerLibPath, "ide", "shared", "agent-command-generator.js");
|
|
1898
|
+
const workflowGenPath = join(installerLibPath, "ide", "shared", "workflow-command-generator.js");
|
|
1899
|
+
const taskToolGenPath = join(installerLibPath, "ide", "shared", "task-tool-command-generator.js");
|
|
1900
|
+
const manifestGenPath = join(installerLibPath, "core", "manifest-generator.js");
|
|
1901
|
+
const pathUtilsPath = join(installerLibPath, "ide", "shared", "path-utils.js");
|
|
1902
|
+
if (!existsSync$1(agentGenPath)) {
|
|
1903
|
+
logger$15.info("bmad-method generators not available (requires bmad-method with agent/workflow/task-tool generators)");
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
const agentMod = _require(agentGenPath);
|
|
1826
1907
|
const AgentCommandGenerator = resolveExport(agentMod, "AgentCommandGenerator");
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1908
|
+
let WorkflowCommandGenerator = null;
|
|
1909
|
+
let TaskToolCommandGenerator = null;
|
|
1910
|
+
if (existsSync$1(workflowGenPath)) {
|
|
1911
|
+
const workflowMod = _require(workflowGenPath);
|
|
1912
|
+
WorkflowCommandGenerator = resolveExport(workflowMod, "WorkflowCommandGenerator");
|
|
1913
|
+
} else logger$15.info("bmad-method workflow-command-generator not available; will try skill-based installation");
|
|
1914
|
+
if (existsSync$1(taskToolGenPath)) {
|
|
1915
|
+
const taskToolMod = _require(taskToolGenPath);
|
|
1916
|
+
TaskToolCommandGenerator = resolveExport(taskToolMod, "TaskToolCommandGenerator");
|
|
1917
|
+
} else logger$15.info("bmad-method task-tool-command-generator not available; will try skill-based installation");
|
|
1918
|
+
let ManifestGenerator = null;
|
|
1919
|
+
if (existsSync$1(manifestGenPath)) {
|
|
1920
|
+
const manifestMod = _require(manifestGenPath);
|
|
1921
|
+
ManifestGenerator = resolveExport(manifestMod, "ManifestGenerator");
|
|
1922
|
+
}
|
|
1923
|
+
let pathUtils = null;
|
|
1924
|
+
if (existsSync$1(pathUtilsPath)) {
|
|
1925
|
+
const pathUtilsMod = _require(pathUtilsPath);
|
|
1926
|
+
pathUtils = { toDashPath: pathUtilsMod.toDashPath ?? pathUtilsMod.default?.toDashPath };
|
|
1927
|
+
}
|
|
1835
1928
|
const writeDashFallback = async (baseDir, artifacts, acceptTypes) => {
|
|
1929
|
+
if (!pathUtils) return 0;
|
|
1836
1930
|
let written = 0;
|
|
1837
1931
|
for (const artifact of artifacts) {
|
|
1838
1932
|
if (!acceptTypes.includes(artifact.type)) continue;
|
|
@@ -1848,7 +1942,7 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
|
|
|
1848
1942
|
};
|
|
1849
1943
|
const nonCoreModules = scanBmadModules(bmadDir);
|
|
1850
1944
|
const allModules = ["core", ...nonCoreModules];
|
|
1851
|
-
try {
|
|
1945
|
+
if (ManifestGenerator) try {
|
|
1852
1946
|
const manifestGen = new ManifestGenerator();
|
|
1853
1947
|
await manifestGen.generateManifests(bmadDir, allModules, [], { ides: ["claude-code"] });
|
|
1854
1948
|
} catch (manifestErr) {
|
|
@@ -1860,18 +1954,28 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
|
|
|
1860
1954
|
const agentGen = new AgentCommandGenerator("_bmad");
|
|
1861
1955
|
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, nonCoreModules);
|
|
1862
1956
|
const agentCount = typeof agentGen.writeDashArtifacts === "function" ? await agentGen.writeDashArtifacts(commandsDir, agentArtifacts) : await writeDashFallback(commandsDir, agentArtifacts, ["agent-launcher"]);
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
if (
|
|
1957
|
+
let workflowCount = 0;
|
|
1958
|
+
if (WorkflowCommandGenerator) {
|
|
1959
|
+
const workflowGen = new WorkflowCommandGenerator("_bmad");
|
|
1960
|
+
const { artifacts: workflowArtifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
|
|
1961
|
+
workflowCount = typeof workflowGen.writeDashArtifacts === "function" ? await workflowGen.writeDashArtifacts(commandsDir, workflowArtifacts) : await writeDashFallback(commandsDir, workflowArtifacts, ["workflow-command", "workflow-launcher"]);
|
|
1962
|
+
}
|
|
1963
|
+
let taskToolCount = 0;
|
|
1964
|
+
if (TaskToolCommandGenerator) {
|
|
1965
|
+
const taskToolGen = new TaskToolCommandGenerator("_bmad");
|
|
1966
|
+
const { artifacts: taskToolArtifacts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
|
|
1967
|
+
taskToolCount = typeof taskToolGen.writeDashArtifacts === "function" ? await taskToolGen.writeDashArtifacts(commandsDir, taskToolArtifacts) : await writeDashFallback(commandsDir, taskToolArtifacts, ["task", "tool"]);
|
|
1968
|
+
}
|
|
1969
|
+
let skillCount = 0;
|
|
1970
|
+
if (!WorkflowCommandGenerator && !TaskToolCommandGenerator) skillCount = installSkillsFromManifest(projectRoot, bmadDir);
|
|
1971
|
+
const total = agentCount + workflowCount + taskToolCount + skillCount;
|
|
1972
|
+
if (outputFormat !== "json") if (skillCount > 0) process.stdout.write(`Generated ${String(total)} Claude Code commands (${String(agentCount)} agents, ${String(skillCount)} skills)\n`);
|
|
1973
|
+
else process.stdout.write(`Generated ${String(total)} Claude Code commands (${String(agentCount)} agents, ${String(workflowCount)} workflows, ${String(taskToolCount)} tasks/tools)\n`);
|
|
1871
1974
|
logger$15.info({
|
|
1872
1975
|
agentCount,
|
|
1873
1976
|
workflowCount,
|
|
1874
1977
|
taskToolCount,
|
|
1978
|
+
skillCount,
|
|
1875
1979
|
total,
|
|
1876
1980
|
commandsDir
|
|
1877
1981
|
}, "Generated .claude/commands/");
|
|
@@ -2130,7 +2234,7 @@ async function runInitAction(options) {
|
|
|
2130
2234
|
if (doltMode === "auto") await checkDoltInstalled();
|
|
2131
2235
|
await initializeDolt({
|
|
2132
2236
|
projectRoot,
|
|
2133
|
-
schemaPath: fileURLToPath$1(new URL("
|
|
2237
|
+
schemaPath: fileURLToPath$1(new URL("../schema.sql", import.meta.url))
|
|
2134
2238
|
});
|
|
2135
2239
|
doltInitialized = true;
|
|
2136
2240
|
} catch (err) {
|
|
@@ -3025,7 +3129,7 @@ async function runStatusAction(options) {
|
|
|
3025
3129
|
if (run === void 0) run = await getLatestRun(adapter);
|
|
3026
3130
|
}
|
|
3027
3131
|
if (run === void 0) {
|
|
3028
|
-
const { inspectProcessTree } = await import("../health-
|
|
3132
|
+
const { inspectProcessTree } = await import("../health-DRywcMxP.js");
|
|
3029
3133
|
const substrateDirPath = join(projectRoot, ".substrate");
|
|
3030
3134
|
const processInfo = inspectProcessTree({
|
|
3031
3135
|
projectRoot,
|
|
@@ -3910,7 +4014,7 @@ function defaultSupervisorDeps() {
|
|
|
3910
4014
|
if (cached === null) {
|
|
3911
4015
|
const { AdapterRegistry: AR } = await import(
|
|
3912
4016
|
/* @vite-ignore */
|
|
3913
|
-
"../adapter-registry-
|
|
4017
|
+
"../adapter-registry-bsm0SCZW.js"
|
|
3914
4018
|
);
|
|
3915
4019
|
cached = new AR();
|
|
3916
4020
|
await cached.discoverAndRegister();
|
|
@@ -4264,10 +4368,17 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
4264
4368
|
}
|
|
4265
4369
|
while (true) {
|
|
4266
4370
|
const health = await getHealth({
|
|
4267
|
-
runId,
|
|
4371
|
+
runId: state.runId ?? runId,
|
|
4268
4372
|
projectRoot
|
|
4269
4373
|
});
|
|
4270
4374
|
const ts = new Date().toISOString();
|
|
4375
|
+
if (state.runId === void 0 && health.run_id !== null) {
|
|
4376
|
+
state = {
|
|
4377
|
+
...state,
|
|
4378
|
+
runId: health.run_id
|
|
4379
|
+
};
|
|
4380
|
+
log(`Supervisor: auto-bound to active run ${health.run_id}`);
|
|
4381
|
+
}
|
|
4271
4382
|
if (outputFormat === "json") {
|
|
4272
4383
|
const tokenSnapshot = health.run_id !== null ? await getTokenSnapshot(health.run_id, projectRoot) : {
|
|
4273
4384
|
input: 0,
|
|
@@ -4345,11 +4456,11 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
4345
4456
|
try {
|
|
4346
4457
|
const { createExperimenter } = await import(
|
|
4347
4458
|
/* @vite-ignore */
|
|
4348
|
-
"../experimenter-
|
|
4459
|
+
"../experimenter-DV-ZC-uX.js"
|
|
4349
4460
|
);
|
|
4350
4461
|
const { getLatestRun: getLatest } = await import(
|
|
4351
4462
|
/* @vite-ignore */
|
|
4352
|
-
"../decisions-
|
|
4463
|
+
"../decisions-DMpHsVUn.js"
|
|
4353
4464
|
);
|
|
4354
4465
|
const expAdapter = createDatabaseAdapter({
|
|
4355
4466
|
backend: "auto",
|
|
@@ -4359,7 +4470,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
4359
4470
|
await initSchema(expAdapter);
|
|
4360
4471
|
const { runRunAction: runPipeline } = await import(
|
|
4361
4472
|
/* @vite-ignore */
|
|
4362
|
-
"../run-
|
|
4473
|
+
"../run-m7RCkpmx.js"
|
|
4363
4474
|
);
|
|
4364
4475
|
const runStoryFn = async (opts) => {
|
|
4365
4476
|
const exitCode = await runPipeline({
|
|
@@ -4889,7 +5000,7 @@ async function runMetricsAction(options) {
|
|
|
4889
5000
|
const routingConfigPath = join(dbDir, "routing.yml");
|
|
4890
5001
|
let routingConfig = null;
|
|
4891
5002
|
if (existsSync$1(routingConfigPath)) try {
|
|
4892
|
-
const { loadModelRoutingConfig } = await import("../routing-
|
|
5003
|
+
const { loadModelRoutingConfig } = await import("../routing-CXLeUI-t.js");
|
|
4893
5004
|
routingConfig = loadModelRoutingConfig(routingConfigPath);
|
|
4894
5005
|
} catch {}
|
|
4895
5006
|
if (routingConfig === null) routingConfig = {
|
|
@@ -8726,8 +8837,8 @@ async function createProgram() {
|
|
|
8726
8837
|
/** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
|
|
8727
8838
|
function checkForUpdatesInBackground(currentVersion) {
|
|
8728
8839
|
if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
|
|
8729
|
-
import("../upgrade-
|
|
8730
|
-
const { createVersionManager } = await import("../version-manager-impl-
|
|
8840
|
+
import("../upgrade-CbwnF2hv.js").then(async () => {
|
|
8841
|
+
const { createVersionManager } = await import("../version-manager-impl-DBx3ovp9.js");
|
|
8731
8842
|
const vm = createVersionManager();
|
|
8732
8843
|
const result = await vm.checkForUpdates();
|
|
8733
8844
|
if (result.updateAvailable) {
|
|
@@ -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-
|
|
1
|
+
import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunningPipelineRuns, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./dist-Bm0qSZer.js";
|
|
2
2
|
import "./decisions-C0pz9Clx.js";
|
|
3
3
|
|
|
4
4
|
export { getLatestRun };
|
|
@@ -3004,12 +3004,15 @@ async function updatePipelineRunConfig(adapter, id, configJson) {
|
|
|
3004
3004
|
async function createPipelineRun(adapter, input) {
|
|
3005
3005
|
const validated = CreatePipelineRunInputSchema.parse(input);
|
|
3006
3006
|
const id = crypto.randomUUID();
|
|
3007
|
-
|
|
3008
|
-
|
|
3007
|
+
const nowUtc = new Date().toISOString();
|
|
3008
|
+
await adapter.query(`INSERT INTO pipeline_runs (id, methodology, current_phase, status, config_json, created_at, updated_at)
|
|
3009
|
+
VALUES (?, ?, ?, 'running', ?, ?, ?)`, [
|
|
3009
3010
|
id,
|
|
3010
3011
|
validated.methodology,
|
|
3011
3012
|
validated.start_phase ?? null,
|
|
3012
|
-
validated.config_json ?? null
|
|
3013
|
+
validated.config_json ?? null,
|
|
3014
|
+
nowUtc,
|
|
3015
|
+
nowUtc
|
|
3013
3016
|
]);
|
|
3014
3017
|
const rows = await adapter.query("SELECT * FROM pipeline_runs WHERE id = ?", [id]);
|
|
3015
3018
|
return rows[0];
|
|
@@ -10236,4 +10239,4 @@ async function callLLM(params) {
|
|
|
10236
10239
|
|
|
10237
10240
|
//#endregion
|
|
10238
10241
|
export { ADVISORY_NOTES, AdapterRegistry, AdtError, BudgetConfigSchema, 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, IngestionServer, 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, compareRunMetrics, createAmendmentRun, createConfigSystem, createDatabaseAdapter as createDatabaseAdapter$1, createDecision, createDoltClient, createExperimenter, createPipelineRun, createRequirement, createVersionManager, detectInterfaceChanges, determineVerdict, getActiveDecisions, getAllCostEntriesFiltered, getArtifactByTypeForRun, getArtifactsByRun, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getModelTier, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRequirements, listRunMetrics, loadModelRoutingConfig, loadParentRunDecisions, registerArtifact, resolvePromptFile, supersedeDecision, tagRunAsBaseline, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics };
|
|
10239
|
-
//# sourceMappingURL=dist-
|
|
10242
|
+
//# sourceMappingURL=dist-Bm0qSZer.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdtError } from "./dist-
|
|
1
|
+
import { AdtError } from "./dist-Bm0qSZer.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-
|
|
74
|
+
//# sourceMappingURL=errors-BSpu7pIv.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-
|
|
1
|
+
import { buildAuditLogEntry, buildBranchName, buildModificationDirective, buildPRBody, buildWorktreePath, createExperimenter, determineVerdict, resolvePromptFile } from "./dist-Bm0qSZer.js";
|
|
2
2
|
|
|
3
3
|
export { createExperimenter };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLogger } from "./logger-KeHncl-f.js";
|
|
2
|
-
import { DoltClient, DoltQueryError, createDatabaseAdapter$1 as createDatabaseAdapter, getLatestRun, getPipelineRunById, initSchema } from "./dist-
|
|
2
|
+
import { DoltClient, DoltQueryError, createDatabaseAdapter$1 as createDatabaseAdapter, getLatestRun, getPipelineRunById, initSchema } from "./dist-Bm0qSZer.js";
|
|
3
3
|
import { createRequire } from "module";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -1930,4 +1930,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
1930
1930
|
|
|
1931
1931
|
//#endregion
|
|
1932
1932
|
export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createStateStore, detectCycles, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runHealthAction, validateStoryKey };
|
|
1933
|
-
//# sourceMappingURL=health-
|
|
1933
|
+
//# sourceMappingURL=health-Cx2ZhRNT.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
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-Cx2ZhRNT.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
|
-
import "./dist-
|
|
3
|
+
import "./dist-Bm0qSZer.js";
|
|
4
4
|
import "./decisions-C0pz9Clx.js";
|
|
5
5
|
|
|
6
6
|
export { inspectProcessTree };
|
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-
|
|
3
|
+
import { AdapterRegistry, AdtError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter } from "./dist-Bm0qSZer.js";
|
|
4
4
|
import "./adapter-registry-DXLMTmfD.js";
|
|
5
|
-
import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-
|
|
5
|
+
import { BudgetExceededError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-BSpu7pIv.js";
|
|
6
6
|
|
|
7
7
|
//#region src/core/di.ts
|
|
8
8
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-
|
|
1
|
+
import { ModelRoutingConfigSchema, ProviderPolicySchema, RoutingConfigError, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, TASK_TYPE_PHASE_MAP, getModelTier, loadModelRoutingConfig } from "./dist-Bm0qSZer.js";
|
|
2
2
|
import "./routing-CcBOCuC9.js";
|
|
3
3
|
|
|
4
4
|
export { loadModelRoutingConfig };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, resolveMainRepoRoot, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, resolveMainRepoRoot, validateStoryKey } from "./health-Cx2ZhRNT.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, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, 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, getPipelineRunById, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-
|
|
4
|
+
import { ADVISORY_NOTES, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, 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, getPipelineRunById, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-Bm0qSZer.js";
|
|
5
5
|
import { basename, dirname, extname, join } from "path";
|
|
6
6
|
import { access, readFile, readdir, stat } from "fs/promises";
|
|
7
7
|
import { EventEmitter } from "node:events";
|
|
@@ -10149,6 +10149,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
10149
10149
|
completedDispatches: completed,
|
|
10150
10150
|
queuedDispatches: queued
|
|
10151
10151
|
});
|
|
10152
|
+
if (config.pipelineRunId !== void 0) updatePipelineRun(db, config.pipelineRunId, { current_phase: "implementation" }).catch((err) => {
|
|
10153
|
+
logger$21.debug({ err }, "Heartbeat: failed to touch updated_at (non-fatal)");
|
|
10154
|
+
});
|
|
10152
10155
|
const elapsed = Date.now() - _lastProgressTs;
|
|
10153
10156
|
let childPids = [];
|
|
10154
10157
|
let childActive = false;
|
|
@@ -22250,12 +22253,17 @@ var RunStateManager = class {
|
|
|
22250
22253
|
* or `PARTIAL_SUCCESS` for the pipeline to exit normally.
|
|
22251
22254
|
*
|
|
22252
22255
|
* Story 42-16.
|
|
22256
|
+
* Story 49-3: AutoSummarizer integration for long-running convergence loops.
|
|
22253
22257
|
*/
|
|
22254
22258
|
/**
|
|
22255
22259
|
* Create a new `ConvergenceController` instance backed by an in-memory outcome map.
|
|
22260
|
+
*
|
|
22261
|
+
* @param config - Optional configuration. Pass `{ autoSummarizer }` to enable
|
|
22262
|
+
* automatic context compression in long-running convergence loops.
|
|
22256
22263
|
*/
|
|
22257
|
-
function createConvergenceController() {
|
|
22264
|
+
function createConvergenceController(config) {
|
|
22258
22265
|
const outcomes = new Map();
|
|
22266
|
+
let storedContexts = [];
|
|
22259
22267
|
/** Returns true only when id is non-empty AND exists in graph.nodes. */
|
|
22260
22268
|
function isValidTarget(id, graph) {
|
|
22261
22269
|
return id !== "" && graph.nodes.has(id);
|
|
@@ -22315,6 +22323,23 @@ function createConvergenceController() {
|
|
|
22315
22323
|
];
|
|
22316
22324
|
for (const candidate of candidates) if (isValidTarget(candidate, graph)) return candidate;
|
|
22317
22325
|
return null;
|
|
22326
|
+
},
|
|
22327
|
+
recordIterationContext(ctx) {
|
|
22328
|
+
storedContexts.push(ctx);
|
|
22329
|
+
},
|
|
22330
|
+
async prepareForIteration(currentIndex) {
|
|
22331
|
+
if (!config?.autoSummarizer || storedContexts.length === 0) return storedContexts;
|
|
22332
|
+
const uncompressedContexts = storedContexts.filter((c) => !("compressed" in c));
|
|
22333
|
+
if (config.autoSummarizer.shouldTrigger(uncompressedContexts)) {
|
|
22334
|
+
const compressionResult = await config.autoSummarizer.compress(uncompressedContexts, currentIndex);
|
|
22335
|
+
const alreadyCompressed = storedContexts.filter((c) => "compressed" in c);
|
|
22336
|
+
const merged = [...alreadyCompressed, ...compressionResult.iterations].sort((a, b) => a.index - b.index);
|
|
22337
|
+
storedContexts = merged;
|
|
22338
|
+
}
|
|
22339
|
+
return storedContexts;
|
|
22340
|
+
},
|
|
22341
|
+
getStoredContexts() {
|
|
22342
|
+
return storedContexts;
|
|
22318
22343
|
}
|
|
22319
22344
|
};
|
|
22320
22345
|
}
|
|
@@ -22925,6 +22950,43 @@ async function getFactoryRunSummaries(adapter, limit = 20) {
|
|
|
22925
22950
|
});
|
|
22926
22951
|
}
|
|
22927
22952
|
|
|
22953
|
+
//#endregion
|
|
22954
|
+
//#region packages/factory/dist/graph/fidelity.js
|
|
22955
|
+
/**
|
|
22956
|
+
* Map a raw fidelity string to a SummaryLevel for context compression.
|
|
22957
|
+
*
|
|
22958
|
+
* Returns null when no summarization should be applied (fidelity is 'full',
|
|
22959
|
+
* empty, or an unrecognized value). Used by the executor before every node
|
|
22960
|
+
* dispatch to determine whether to call summaryEngine.summarize().
|
|
22961
|
+
*/
|
|
22962
|
+
function parseFidelityLevel(fidelity) {
|
|
22963
|
+
const FIDELITY_MAP = {
|
|
22964
|
+
high: "high",
|
|
22965
|
+
"summary:high": "high",
|
|
22966
|
+
medium: "medium",
|
|
22967
|
+
"summary:medium": "medium",
|
|
22968
|
+
low: "low",
|
|
22969
|
+
draft: "low",
|
|
22970
|
+
"summary:low": "low"
|
|
22971
|
+
};
|
|
22972
|
+
return FIDELITY_MAP[fidelity] ?? null;
|
|
22973
|
+
}
|
|
22974
|
+
/**
|
|
22975
|
+
* Resolve the effective fidelity string for a node about to be dispatched.
|
|
22976
|
+
*
|
|
22977
|
+
* Precedence (highest to lowest):
|
|
22978
|
+
* 1. incomingEdge.fidelity (non-empty)
|
|
22979
|
+
* 2. node.fidelity (non-empty)
|
|
22980
|
+
* 3. graph.defaultFidelity (non-empty)
|
|
22981
|
+
* 4. '' (no fidelity set — parseFidelityLevel will return null)
|
|
22982
|
+
*/
|
|
22983
|
+
function resolveFidelity(node, incomingEdge, graph) {
|
|
22984
|
+
if (incomingEdge?.fidelity) return incomingEdge.fidelity;
|
|
22985
|
+
if (node.fidelity) return node.fidelity;
|
|
22986
|
+
if (graph.defaultFidelity) return graph.defaultFidelity;
|
|
22987
|
+
return "";
|
|
22988
|
+
}
|
|
22989
|
+
|
|
22928
22990
|
//#endregion
|
|
22929
22991
|
//#region packages/factory/dist/graph/executor.js
|
|
22930
22992
|
/**
|
|
@@ -23060,6 +23122,7 @@ function createGraphExecutor() {
|
|
|
23060
23122
|
let firstResumedFidelity = "";
|
|
23061
23123
|
let skipCycleCheck = false;
|
|
23062
23124
|
let skipCompletedPush = false;
|
|
23125
|
+
let lastIncomingEdge = void 0;
|
|
23063
23126
|
let scenarioManifest = null;
|
|
23064
23127
|
if (config.scenarioStore) scenarioManifest = await config.scenarioStore.discover();
|
|
23065
23128
|
const runStateManager = config.dotSource ? new RunStateManager({ runDir: config.logsRoot }) : null;
|
|
@@ -23207,6 +23270,7 @@ function createGraphExecutor() {
|
|
|
23207
23270
|
satisfactionScoreHistory: plateauResult.scores
|
|
23208
23271
|
});
|
|
23209
23272
|
injectRemediationContext(context, remediation);
|
|
23273
|
+
await controller.prepareForIteration(convergenceIteration);
|
|
23210
23274
|
skipCycleCheck = true;
|
|
23211
23275
|
currentNode = retryNode;
|
|
23212
23276
|
continue;
|
|
@@ -23273,6 +23337,25 @@ function createGraphExecutor() {
|
|
|
23273
23337
|
fidelity: firstResumedFidelity
|
|
23274
23338
|
} : currentNode;
|
|
23275
23339
|
firstResumedFidelity = "";
|
|
23340
|
+
if (config.summaryEngine) {
|
|
23341
|
+
const effectiveFidelity = resolveFidelity(nodeToDispatch, lastIncomingEdge, graph);
|
|
23342
|
+
const summaryLevel = parseFidelityLevel(effectiveFidelity);
|
|
23343
|
+
if (summaryLevel !== null) {
|
|
23344
|
+
const nodeContextContent = context.getString("factory.nodeContext", "");
|
|
23345
|
+
if (nodeContextContent !== "") {
|
|
23346
|
+
const summary = await config.summaryEngine.summarize(nodeContextContent, summaryLevel);
|
|
23347
|
+
context.set("factory.compressedNodeContext", summary.content);
|
|
23348
|
+
context.set("factory.nodeContext", summary.content);
|
|
23349
|
+
config.eventBus?.emit("graph:context-summarized", {
|
|
23350
|
+
runId: config.runId,
|
|
23351
|
+
nodeId: nodeToDispatch.id,
|
|
23352
|
+
level: summaryLevel,
|
|
23353
|
+
originalTokenCount: summary.originalTokenCount ?? 0,
|
|
23354
|
+
summaryTokenCount: summary.summaryTokenCount ?? 0
|
|
23355
|
+
});
|
|
23356
|
+
}
|
|
23357
|
+
}
|
|
23358
|
+
}
|
|
23276
23359
|
const startedAt = Date.now();
|
|
23277
23360
|
let outcome = await dispatchWithRetry(nodeToDispatch, context, graph, config, nodeRetries);
|
|
23278
23361
|
if (Date.now() - startedAt < 50) await new Promise((r) => setTimeout(r, 50));
|
|
@@ -23311,6 +23394,11 @@ function createGraphExecutor() {
|
|
|
23311
23394
|
{
|
|
23312
23395
|
const controllerStatus = outcome.status === "SUCCESS" ? "SUCCESS" : outcome.status === "PARTIAL_SUCCESS" ? "PARTIAL_SUCCESS" : "FAILURE";
|
|
23313
23396
|
controller.recordOutcome(nodeToDispatch.id, controllerStatus);
|
|
23397
|
+
const iterContent = context.getString("factory.nodeContext", "");
|
|
23398
|
+
controller.recordIterationContext({
|
|
23399
|
+
index: convergenceIteration,
|
|
23400
|
+
content: iterContent
|
|
23401
|
+
});
|
|
23314
23402
|
}
|
|
23315
23403
|
if (outcome.contextUpdates) for (const [key, value] of Object.entries(outcome.contextUpdates)) context.set(key, value);
|
|
23316
23404
|
context.set("outcome", outcome.status.toLowerCase());
|
|
@@ -23398,6 +23486,7 @@ function createGraphExecutor() {
|
|
|
23398
23486
|
}
|
|
23399
23487
|
const nextNode = graph.nodes.get(edge.toNode);
|
|
23400
23488
|
if (!nextNode) throw new Error(`Edge target node "${edge.toNode}" not found in graph`);
|
|
23489
|
+
lastIncomingEdge = edge;
|
|
23401
23490
|
currentNode = nextNode;
|
|
23402
23491
|
}
|
|
23403
23492
|
} };
|
|
@@ -36236,6 +36325,419 @@ function registerScenariosCommand(program) {
|
|
|
36236
36325
|
});
|
|
36237
36326
|
}
|
|
36238
36327
|
|
|
36328
|
+
//#endregion
|
|
36329
|
+
//#region packages/factory/dist/context/summary-cache.js
|
|
36330
|
+
var SummaryCache = class {
|
|
36331
|
+
config;
|
|
36332
|
+
constructor(config) {
|
|
36333
|
+
this.config = config;
|
|
36334
|
+
}
|
|
36335
|
+
summaryPath(hash, level) {
|
|
36336
|
+
return join$1(this.config.storageDir, this.config.runId, "summaries", `${hash}-${level}.json`);
|
|
36337
|
+
}
|
|
36338
|
+
originalPath(hash) {
|
|
36339
|
+
return join$1(this.config.storageDir, this.config.runId, "summaries", `${hash}.orig`);
|
|
36340
|
+
}
|
|
36341
|
+
async put(summary, originalContent) {
|
|
36342
|
+
const dir = join$1(this.config.storageDir, this.config.runId, "summaries");
|
|
36343
|
+
await mkdir$1(dir, { recursive: true });
|
|
36344
|
+
const record = {
|
|
36345
|
+
summary,
|
|
36346
|
+
cachedAt: new Date().toISOString()
|
|
36347
|
+
};
|
|
36348
|
+
await writeFile$1(this.summaryPath(summary.originalHash, summary.level), JSON.stringify(record, null, 2));
|
|
36349
|
+
if (originalContent !== void 0 && this.config.storeOriginals !== false) await writeFile$1(this.originalPath(summary.originalHash), originalContent);
|
|
36350
|
+
}
|
|
36351
|
+
async get(originalHash, level) {
|
|
36352
|
+
try {
|
|
36353
|
+
const raw = await readFile$1(this.summaryPath(originalHash, level), "utf-8");
|
|
36354
|
+
const record = JSON.parse(raw);
|
|
36355
|
+
return record.summary;
|
|
36356
|
+
} catch (err) {
|
|
36357
|
+
if (err.code === "ENOENT") return null;
|
|
36358
|
+
throw err;
|
|
36359
|
+
}
|
|
36360
|
+
}
|
|
36361
|
+
async getOriginal(originalHash) {
|
|
36362
|
+
try {
|
|
36363
|
+
return await readFile$1(this.originalPath(originalHash), "utf-8");
|
|
36364
|
+
} catch (err) {
|
|
36365
|
+
if (err.code === "ENOENT") return null;
|
|
36366
|
+
throw err;
|
|
36367
|
+
}
|
|
36368
|
+
}
|
|
36369
|
+
};
|
|
36370
|
+
var CachingSummaryEngine = class {
|
|
36371
|
+
inner;
|
|
36372
|
+
cache;
|
|
36373
|
+
name;
|
|
36374
|
+
constructor(inner, cache) {
|
|
36375
|
+
this.inner = inner;
|
|
36376
|
+
this.cache = cache;
|
|
36377
|
+
this.name = `caching(${inner.name})`;
|
|
36378
|
+
}
|
|
36379
|
+
async summarize(content, targetLevel, opts) {
|
|
36380
|
+
const originalHash = createHash("sha256").update(content).digest("hex");
|
|
36381
|
+
const cached = await this.cache.get(originalHash, targetLevel);
|
|
36382
|
+
if (cached !== null) return cached;
|
|
36383
|
+
const summary = await this.inner.summarize(content, targetLevel, opts);
|
|
36384
|
+
await this.cache.put(summary, content);
|
|
36385
|
+
return summary;
|
|
36386
|
+
}
|
|
36387
|
+
async expand(summary, targetLevel, opts) {
|
|
36388
|
+
const original = await this.cache.getOriginal(summary.originalHash);
|
|
36389
|
+
if (original !== null) return original;
|
|
36390
|
+
return this.inner.expand(summary, targetLevel, opts);
|
|
36391
|
+
}
|
|
36392
|
+
};
|
|
36393
|
+
|
|
36394
|
+
//#endregion
|
|
36395
|
+
//#region packages/factory/dist/context/summary-metrics.js
|
|
36396
|
+
/**
|
|
36397
|
+
* Compute the compression ratio of a summary.
|
|
36398
|
+
* Returns summaryTokenCount / originalTokenCount in [0, 1].
|
|
36399
|
+
* Returns -1 as a sentinel when token counts are absent or originalTokenCount is zero.
|
|
36400
|
+
*/
|
|
36401
|
+
function computeCompressionRatio(summary) {
|
|
36402
|
+
if (summary.originalTokenCount === void 0 || summary.originalTokenCount === 0 || summary.summaryTokenCount === void 0) return -1;
|
|
36403
|
+
return summary.summaryTokenCount / summary.originalTokenCount;
|
|
36404
|
+
}
|
|
36405
|
+
/**
|
|
36406
|
+
* Extract key facts from content:
|
|
36407
|
+
* - Fenced code blocks (triple-backtick)
|
|
36408
|
+
* - File-path tokens matching known extensions
|
|
36409
|
+
* - Error-type names
|
|
36410
|
+
*/
|
|
36411
|
+
function extractKeyFacts(content) {
|
|
36412
|
+
const facts = new Set();
|
|
36413
|
+
const codeBlockRegex = /```[\s\S]*?```/g;
|
|
36414
|
+
let match$1;
|
|
36415
|
+
while ((match$1 = codeBlockRegex.exec(content)) !== null) facts.add(match$1[0].trim());
|
|
36416
|
+
const filePathRegex = /[\w./]+(\.ts|\.js|\.json|\.md|\.go|\.py|\.yaml|\.yml)\b/g;
|
|
36417
|
+
while ((match$1 = filePathRegex.exec(content)) !== null) facts.add(match$1[0]);
|
|
36418
|
+
const errorTypeRegex = /\b(Error|Exception|ENOENT|ETIMEDOUT|TypeError|SyntaxError)\b/g;
|
|
36419
|
+
while ((match$1 = errorTypeRegex.exec(content)) !== null) facts.add(match$1[0]);
|
|
36420
|
+
return facts;
|
|
36421
|
+
}
|
|
36422
|
+
/**
|
|
36423
|
+
* Compute the key-fact retention rate between original and summarized content.
|
|
36424
|
+
* Returns the fraction of original key facts that appear in the summarized content.
|
|
36425
|
+
* Returns 1.0 when the original has no key facts.
|
|
36426
|
+
*/
|
|
36427
|
+
function computeKeyFactRetentionRate(original, summarized) {
|
|
36428
|
+
const originalFacts = extractKeyFacts(original);
|
|
36429
|
+
const summarizedFacts = extractKeyFacts(summarized);
|
|
36430
|
+
if (originalFacts.size === 0) return 1;
|
|
36431
|
+
const preserved = [...originalFacts].filter((f$1) => summarizedFacts.has(f$1)).length;
|
|
36432
|
+
return preserved / originalFacts.size;
|
|
36433
|
+
}
|
|
36434
|
+
|
|
36435
|
+
//#endregion
|
|
36436
|
+
//#region packages/factory/dist/context/cli-command.js
|
|
36437
|
+
/** Build a CLIJsonOutput envelope. */
|
|
36438
|
+
function buildJsonOutput(command, data, version) {
|
|
36439
|
+
return {
|
|
36440
|
+
timestamp: new Date().toISOString(),
|
|
36441
|
+
version,
|
|
36442
|
+
command,
|
|
36443
|
+
data
|
|
36444
|
+
};
|
|
36445
|
+
}
|
|
36446
|
+
/** Minimal stub SummaryEngine used when no engineFactory is provided. */
|
|
36447
|
+
var StubSummaryEngine = class {
|
|
36448
|
+
name = "stub";
|
|
36449
|
+
async summarize(content, targetLevel) {
|
|
36450
|
+
const originalHash = createHash("sha256").update(content).digest("hex");
|
|
36451
|
+
return {
|
|
36452
|
+
level: targetLevel,
|
|
36453
|
+
content,
|
|
36454
|
+
originalHash,
|
|
36455
|
+
createdAt: new Date().toISOString()
|
|
36456
|
+
};
|
|
36457
|
+
}
|
|
36458
|
+
async expand(summary) {
|
|
36459
|
+
return summary.content;
|
|
36460
|
+
}
|
|
36461
|
+
};
|
|
36462
|
+
/**
|
|
36463
|
+
* Scan all `*.json` summary files in summariesDir to find the most recently
|
|
36464
|
+
* stored summary matching the given iteration number.
|
|
36465
|
+
*
|
|
36466
|
+
* Matches on `record.summary.iterationIndex === iteration`.
|
|
36467
|
+
* Returns null if no match is found.
|
|
36468
|
+
*/
|
|
36469
|
+
async function findSummaryForIteration(summariesDir, iteration) {
|
|
36470
|
+
let allFiles;
|
|
36471
|
+
try {
|
|
36472
|
+
allFiles = await readdir$1(summariesDir);
|
|
36473
|
+
} catch {
|
|
36474
|
+
return null;
|
|
36475
|
+
}
|
|
36476
|
+
const jsonFiles = allFiles.filter((f$1) => f$1.endsWith(".json"));
|
|
36477
|
+
const matches = [];
|
|
36478
|
+
for (const file of jsonFiles) try {
|
|
36479
|
+
const raw = await readFile$1(join$1(summariesDir, file), "utf-8");
|
|
36480
|
+
const record = JSON.parse(raw);
|
|
36481
|
+
if (record.summary.iterationIndex === iteration) matches.push({
|
|
36482
|
+
hash: record.summary.originalHash,
|
|
36483
|
+
record,
|
|
36484
|
+
cachedAt: new Date(record.cachedAt).getTime()
|
|
36485
|
+
});
|
|
36486
|
+
} catch {}
|
|
36487
|
+
if (matches.length === 0) return null;
|
|
36488
|
+
matches.sort((a, b) => b.cachedAt - a.cachedAt);
|
|
36489
|
+
const best = matches[0];
|
|
36490
|
+
return {
|
|
36491
|
+
hash: best.hash,
|
|
36492
|
+
record: best.record
|
|
36493
|
+
};
|
|
36494
|
+
}
|
|
36495
|
+
/**
|
|
36496
|
+
* Core logic for `factory context summarize`.
|
|
36497
|
+
*
|
|
36498
|
+
* Loads the original content, runs it through CachingSummaryEngine, stores the
|
|
36499
|
+
* result, and prints compression statistics.
|
|
36500
|
+
*
|
|
36501
|
+
* @returns Exit code: 0 on success, 1 on error.
|
|
36502
|
+
*/
|
|
36503
|
+
async function summarizeAction(opts, deps, output = {
|
|
36504
|
+
stdout: process.stdout,
|
|
36505
|
+
stderr: process.stderr
|
|
36506
|
+
}) {
|
|
36507
|
+
const { stdout, stderr } = output;
|
|
36508
|
+
if (!/^\d+$/.test(opts.iteration)) {
|
|
36509
|
+
stderr.write(`Error: --iteration must be a non-negative integer, got: ${opts.iteration}\n`);
|
|
36510
|
+
return 1;
|
|
36511
|
+
}
|
|
36512
|
+
const iteration = parseInt(opts.iteration, 10);
|
|
36513
|
+
const validLevels = [
|
|
36514
|
+
"full",
|
|
36515
|
+
"high",
|
|
36516
|
+
"medium",
|
|
36517
|
+
"low"
|
|
36518
|
+
];
|
|
36519
|
+
if (!validLevels.includes(opts.level)) {
|
|
36520
|
+
stderr.write(`Error: --level must be one of: full, high, medium, low. Got: ${opts.level}\n`);
|
|
36521
|
+
return 1;
|
|
36522
|
+
}
|
|
36523
|
+
const level = opts.level;
|
|
36524
|
+
const summariesDir = join$1(deps.storageDir, "runs", opts.run, "summaries");
|
|
36525
|
+
try {
|
|
36526
|
+
await stat$1(summariesDir);
|
|
36527
|
+
} catch {
|
|
36528
|
+
stderr.write(`Error: Run directory not found: ${summariesDir}\n`);
|
|
36529
|
+
return 1;
|
|
36530
|
+
}
|
|
36531
|
+
const found = await findSummaryForIteration(summariesDir, iteration);
|
|
36532
|
+
if (!found) {
|
|
36533
|
+
stderr.write(`Error: No summary found for iteration ${iteration} in run ${opts.run}\n`);
|
|
36534
|
+
return 1;
|
|
36535
|
+
}
|
|
36536
|
+
const cache = new SummaryCache({
|
|
36537
|
+
runId: opts.run,
|
|
36538
|
+
storageDir: join$1(deps.storageDir, "runs")
|
|
36539
|
+
});
|
|
36540
|
+
const originalContent = await cache.getOriginal(found.hash);
|
|
36541
|
+
if (originalContent === null) {
|
|
36542
|
+
stderr.write(`Error: Original content (.orig) not found for hash ${found.hash.slice(0, 8)} in run ${opts.run}\n`);
|
|
36543
|
+
return 1;
|
|
36544
|
+
}
|
|
36545
|
+
const innerEngine = deps.engineFactory ? deps.engineFactory() : new StubSummaryEngine();
|
|
36546
|
+
const engine = new CachingSummaryEngine(innerEngine, cache);
|
|
36547
|
+
const summary = await engine.summarize(originalContent, level);
|
|
36548
|
+
await cache.put(summary, originalContent);
|
|
36549
|
+
const compressionRatio = computeCompressionRatio(summary);
|
|
36550
|
+
if (opts.outputFormat === "json") {
|
|
36551
|
+
const data = {
|
|
36552
|
+
hash: summary.originalHash,
|
|
36553
|
+
level: summary.level,
|
|
36554
|
+
compressionRatio,
|
|
36555
|
+
summaryTokenCount: summary.summaryTokenCount,
|
|
36556
|
+
originalTokenCount: summary.originalTokenCount
|
|
36557
|
+
};
|
|
36558
|
+
stdout.write(JSON.stringify(buildJsonOutput("factory context summarize", data, deps.version)) + "\n");
|
|
36559
|
+
} else {
|
|
36560
|
+
const ratioStr = compressionRatio >= 0 ? compressionRatio.toFixed(2) : "n/a";
|
|
36561
|
+
stdout.write(`Summarized iteration ${iteration} → level ${level} | hash: ${summary.originalHash.slice(0, 8)} | compression: ${ratioStr}\n`);
|
|
36562
|
+
}
|
|
36563
|
+
return 0;
|
|
36564
|
+
}
|
|
36565
|
+
/**
|
|
36566
|
+
* Core logic for `factory context expand`.
|
|
36567
|
+
*
|
|
36568
|
+
* Finds the stored summary for the given iteration, then expands it back
|
|
36569
|
+
* toward full content (lossless if .orig exists, LLM fallback otherwise).
|
|
36570
|
+
*
|
|
36571
|
+
* @returns Exit code: 0 on success, 1 on error.
|
|
36572
|
+
*/
|
|
36573
|
+
async function expandAction(opts, deps, output = {
|
|
36574
|
+
stdout: process.stdout,
|
|
36575
|
+
stderr: process.stderr
|
|
36576
|
+
}) {
|
|
36577
|
+
const { stdout, stderr } = output;
|
|
36578
|
+
if (!/^\d+$/.test(opts.iteration)) {
|
|
36579
|
+
stderr.write(`Error: --iteration must be a non-negative integer, got: ${opts.iteration}\n`);
|
|
36580
|
+
return 1;
|
|
36581
|
+
}
|
|
36582
|
+
const iteration = parseInt(opts.iteration, 10);
|
|
36583
|
+
const summariesDir = join$1(deps.storageDir, "runs", opts.run, "summaries");
|
|
36584
|
+
try {
|
|
36585
|
+
await stat$1(summariesDir);
|
|
36586
|
+
} catch {
|
|
36587
|
+
stderr.write(`Error: Run directory not found: ${summariesDir}\n`);
|
|
36588
|
+
return 1;
|
|
36589
|
+
}
|
|
36590
|
+
const found = await findSummaryForIteration(summariesDir, iteration);
|
|
36591
|
+
if (!found) {
|
|
36592
|
+
stderr.write(`Error: No summary found for iteration ${iteration} in run ${opts.run}\n`);
|
|
36593
|
+
return 1;
|
|
36594
|
+
}
|
|
36595
|
+
const cache = new SummaryCache({
|
|
36596
|
+
runId: opts.run,
|
|
36597
|
+
storageDir: join$1(deps.storageDir, "runs")
|
|
36598
|
+
});
|
|
36599
|
+
const innerEngine = deps.engineFactory ? deps.engineFactory() : new StubSummaryEngine();
|
|
36600
|
+
const engine = new CachingSummaryEngine(innerEngine, cache);
|
|
36601
|
+
const expandedContent = await engine.expand(found.record.summary, "full");
|
|
36602
|
+
if (opts.outputFormat === "json") {
|
|
36603
|
+
const data = {
|
|
36604
|
+
hash: found.record.summary.originalHash,
|
|
36605
|
+
level: found.record.summary.level,
|
|
36606
|
+
expandedLength: expandedContent.length,
|
|
36607
|
+
content: expandedContent
|
|
36608
|
+
};
|
|
36609
|
+
stdout.write(JSON.stringify(buildJsonOutput("factory context expand", data, deps.version)) + "\n");
|
|
36610
|
+
} else stdout.write(expandedContent + "\n");
|
|
36611
|
+
return 0;
|
|
36612
|
+
}
|
|
36613
|
+
/**
|
|
36614
|
+
* Core logic for `factory context stats`.
|
|
36615
|
+
*
|
|
36616
|
+
* Reads all stored summary records for a run, computes compression metrics,
|
|
36617
|
+
* and prints a formatted table (or JSON array).
|
|
36618
|
+
*
|
|
36619
|
+
* @returns Exit code: 0 on success, 1 on error.
|
|
36620
|
+
*/
|
|
36621
|
+
async function statsAction(opts, deps, output = {
|
|
36622
|
+
stdout: process.stdout,
|
|
36623
|
+
stderr: process.stderr
|
|
36624
|
+
}) {
|
|
36625
|
+
const { stdout, stderr } = output;
|
|
36626
|
+
const summariesDir = join$1(deps.storageDir, "runs", opts.run, "summaries");
|
|
36627
|
+
try {
|
|
36628
|
+
await stat$1(summariesDir);
|
|
36629
|
+
} catch {
|
|
36630
|
+
stderr.write(`Error: Run directory not found: ${summariesDir}\n`);
|
|
36631
|
+
return 1;
|
|
36632
|
+
}
|
|
36633
|
+
let allFiles;
|
|
36634
|
+
try {
|
|
36635
|
+
allFiles = await readdir$1(summariesDir);
|
|
36636
|
+
} catch {
|
|
36637
|
+
stderr.write(`Error: Could not read summaries directory: ${summariesDir}\n`);
|
|
36638
|
+
return 1;
|
|
36639
|
+
}
|
|
36640
|
+
const jsonFiles = allFiles.filter((f$1) => f$1.endsWith(".json"));
|
|
36641
|
+
const rows = [];
|
|
36642
|
+
for (const file of jsonFiles) try {
|
|
36643
|
+
const raw = await readFile$1(join$1(summariesDir, file), "utf-8");
|
|
36644
|
+
const record = JSON.parse(raw);
|
|
36645
|
+
const compressionRatio = computeCompressionRatio(record.summary);
|
|
36646
|
+
let keyFactRetentionRate = -1;
|
|
36647
|
+
try {
|
|
36648
|
+
const origPath = join$1(summariesDir, `${record.summary.originalHash}.orig`);
|
|
36649
|
+
const originalContent = await readFile$1(origPath, "utf-8");
|
|
36650
|
+
keyFactRetentionRate = computeKeyFactRetentionRate(originalContent, record.summary.content);
|
|
36651
|
+
} catch {}
|
|
36652
|
+
rows.push({
|
|
36653
|
+
hash: record.summary.originalHash,
|
|
36654
|
+
level: record.summary.level,
|
|
36655
|
+
compressionRatio,
|
|
36656
|
+
keyFactRetentionRate,
|
|
36657
|
+
cachedAt: record.cachedAt
|
|
36658
|
+
});
|
|
36659
|
+
} catch {}
|
|
36660
|
+
rows.sort((a, b) => new Date(a.cachedAt).getTime() - new Date(b.cachedAt).getTime());
|
|
36661
|
+
if (opts.outputFormat === "json") {
|
|
36662
|
+
stdout.write(JSON.stringify(buildJsonOutput("factory context stats", rows, deps.version)) + "\n");
|
|
36663
|
+
return 0;
|
|
36664
|
+
}
|
|
36665
|
+
if (rows.length === 0) {
|
|
36666
|
+
stdout.write("No summaries found.\n");
|
|
36667
|
+
return 0;
|
|
36668
|
+
}
|
|
36669
|
+
const headers = [
|
|
36670
|
+
"Hash",
|
|
36671
|
+
"Level",
|
|
36672
|
+
"CompRatio",
|
|
36673
|
+
"KeyRetention",
|
|
36674
|
+
"CachedAt"
|
|
36675
|
+
];
|
|
36676
|
+
const tableRows = rows.map((row) => ({
|
|
36677
|
+
Hash: row.hash.slice(0, 8),
|
|
36678
|
+
Level: row.level,
|
|
36679
|
+
CompRatio: row.compressionRatio >= 0 ? row.compressionRatio.toFixed(4) : "n/a",
|
|
36680
|
+
KeyRetention: row.keyFactRetentionRate >= 0 ? row.keyFactRetentionRate.toFixed(4) : "n/a",
|
|
36681
|
+
CachedAt: row.cachedAt
|
|
36682
|
+
}));
|
|
36683
|
+
const widths = headers.map((h) => {
|
|
36684
|
+
const dataMax = tableRows.reduce((max, row) => {
|
|
36685
|
+
const val = row[h] ?? "";
|
|
36686
|
+
return Math.max(max, val.length);
|
|
36687
|
+
}, 0);
|
|
36688
|
+
return Math.max(h.length, dataMax);
|
|
36689
|
+
});
|
|
36690
|
+
const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(" | ");
|
|
36691
|
+
const separator = widths.map((w) => "-".repeat(w)).join("-+-");
|
|
36692
|
+
stdout.write(headerLine + "\n");
|
|
36693
|
+
stdout.write(separator + "\n");
|
|
36694
|
+
for (const row of tableRows) {
|
|
36695
|
+
const line = headers.map((h, i) => (row[h] ?? "").padEnd(widths[i])).join(" | ");
|
|
36696
|
+
stdout.write(line + "\n");
|
|
36697
|
+
}
|
|
36698
|
+
return 0;
|
|
36699
|
+
}
|
|
36700
|
+
/**
|
|
36701
|
+
* Register the `context` subcommand group on the provided factory command.
|
|
36702
|
+
*
|
|
36703
|
+
* Subcommands registered:
|
|
36704
|
+
* factory context summarize --run <id> --iteration <n> --level <level>
|
|
36705
|
+
* factory context expand --run <id> --iteration <n>
|
|
36706
|
+
* factory context stats --run <id>
|
|
36707
|
+
*
|
|
36708
|
+
* @param factoryCmd - The factory Commander command to attach to
|
|
36709
|
+
* @param version - CLI version string for JSON output (e.g. "1.2.3")
|
|
36710
|
+
* @param storageDir - Base storage directory (defaults to `{cwd}/.substrate`)
|
|
36711
|
+
* @param engineFactory - Optional SummaryEngine factory for testing injection
|
|
36712
|
+
*/
|
|
36713
|
+
function registerContextCommand(factoryCmd, version, storageDir, engineFactory) {
|
|
36714
|
+
const resolvedStorageDir = storageDir ?? join$1(process.cwd(), ".substrate");
|
|
36715
|
+
const contextCmd = factoryCmd.command("context").description("Inspect and manage pyramid summaries for factory runs");
|
|
36716
|
+
contextCmd.command("summarize").description("Compress and store a run iteration to the target summary level").requiredOption("--run <id>", "Run ID").requiredOption("--iteration <n>", "Iteration number").requiredOption("--level <level>", "Summary level: high | medium | low").option("--output-format <format>", "Output format: text | json", "text").action(async (opts) => {
|
|
36717
|
+
const code = await summarizeAction(opts, {
|
|
36718
|
+
storageDir: resolvedStorageDir,
|
|
36719
|
+
version,
|
|
36720
|
+
...engineFactory !== void 0 ? { engineFactory } : {}
|
|
36721
|
+
});
|
|
36722
|
+
if (code !== 0) process.exit(code);
|
|
36723
|
+
});
|
|
36724
|
+
contextCmd.command("expand").description("Expand a stored summary for a run iteration back to full content").requiredOption("--run <id>", "Run ID").requiredOption("--iteration <n>", "Iteration number").option("--output-format <format>", "Output format: text | json", "text").action(async (opts) => {
|
|
36725
|
+
const code = await expandAction(opts, {
|
|
36726
|
+
storageDir: resolvedStorageDir,
|
|
36727
|
+
version,
|
|
36728
|
+
...engineFactory !== void 0 ? { engineFactory } : {}
|
|
36729
|
+
});
|
|
36730
|
+
if (code !== 0) process.exit(code);
|
|
36731
|
+
});
|
|
36732
|
+
contextCmd.command("stats").description("Report per-run compression statistics for all stored summaries").requiredOption("--run <id>", "Run ID").option("--output-format <format>", "Output format: text | json", "text").action(async (opts) => {
|
|
36733
|
+
const code = await statsAction(opts, {
|
|
36734
|
+
storageDir: resolvedStorageDir,
|
|
36735
|
+
version
|
|
36736
|
+
});
|
|
36737
|
+
if (code !== 0) process.exit(code);
|
|
36738
|
+
});
|
|
36739
|
+
}
|
|
36740
|
+
|
|
36239
36741
|
//#endregion
|
|
36240
36742
|
//#region packages/factory/dist/twins/schema.js
|
|
36241
36743
|
/**
|
|
@@ -37119,6 +37621,7 @@ function registerFactoryCommand(program, options) {
|
|
|
37119
37621
|
else process.stdout.write(`✗ ${passedCount}/${TOTAL_RULE_COUNT} rules passed, ${errors.length} ${errLabel}, ${warnings.length} ${warnLabel}\n`);
|
|
37120
37622
|
if (errors.length > 0) process.exit(1);
|
|
37121
37623
|
});
|
|
37624
|
+
registerContextCommand(factoryCmd, "0.0.0");
|
|
37122
37625
|
const twinsCmd = factoryCmd.command("twins").description("Digital twin template management");
|
|
37123
37626
|
twinsCmd.command("templates").description("List available built-in twin templates").action(() => {
|
|
37124
37627
|
const templates = listTwinTemplates();
|
|
@@ -37757,9 +38260,8 @@ async function runRunAction(options) {
|
|
|
37757
38260
|
}
|
|
37758
38261
|
const staleRuns = await getRunningPipelineRuns(adapter) ?? [];
|
|
37759
38262
|
if (staleRuns.length > 0) {
|
|
37760
|
-
const processInfo = inspectProcessTree({ projectRoot });
|
|
37761
38263
|
let swept = 0;
|
|
37762
|
-
for (const stale of staleRuns)
|
|
38264
|
+
for (const stale of staleRuns) {
|
|
37763
38265
|
await updatePipelineRun(adapter, stale.id, { status: "failed" });
|
|
37764
38266
|
swept++;
|
|
37765
38267
|
}
|
|
@@ -38439,6 +38941,8 @@ async function runFullPipeline(options) {
|
|
|
38439
38941
|
input_tokens: result.tokenUsage.input,
|
|
38440
38942
|
output_tokens: result.tokenUsage.output,
|
|
38441
38943
|
cost_usd: costUsd
|
|
38944
|
+
}).catch((err) => {
|
|
38945
|
+
logger.warn({ err }, "Failed to record analysis token usage (non-fatal)");
|
|
38442
38946
|
});
|
|
38443
38947
|
}
|
|
38444
38948
|
if (result.result === "failed") {
|
|
@@ -38462,6 +38966,8 @@ async function runFullPipeline(options) {
|
|
|
38462
38966
|
input_tokens: result.tokenUsage.input,
|
|
38463
38967
|
output_tokens: result.tokenUsage.output,
|
|
38464
38968
|
cost_usd: costUsd
|
|
38969
|
+
}).catch((err) => {
|
|
38970
|
+
logger.warn({ err }, "Failed to record planning token usage (non-fatal)");
|
|
38465
38971
|
});
|
|
38466
38972
|
}
|
|
38467
38973
|
if (result.result === "failed") {
|
|
@@ -38488,6 +38994,8 @@ async function runFullPipeline(options) {
|
|
|
38488
38994
|
input_tokens: result.tokenUsage.input,
|
|
38489
38995
|
output_tokens: result.tokenUsage.output,
|
|
38490
38996
|
cost_usd: costUsd
|
|
38997
|
+
}).catch((err) => {
|
|
38998
|
+
logger.warn({ err }, "Failed to record research token usage (non-fatal)");
|
|
38491
38999
|
});
|
|
38492
39000
|
}
|
|
38493
39001
|
if (result.result === "failed") {
|
|
@@ -38511,6 +39019,8 @@ async function runFullPipeline(options) {
|
|
|
38511
39019
|
input_tokens: result.tokenUsage.input,
|
|
38512
39020
|
output_tokens: result.tokenUsage.output,
|
|
38513
39021
|
cost_usd: costUsd
|
|
39022
|
+
}).catch((err) => {
|
|
39023
|
+
logger.warn({ err }, "Failed to record ux-design token usage (non-fatal)");
|
|
38514
39024
|
});
|
|
38515
39025
|
}
|
|
38516
39026
|
if (result.result === "failed") {
|
|
@@ -38534,6 +39044,8 @@ async function runFullPipeline(options) {
|
|
|
38534
39044
|
input_tokens: result.tokenUsage.input,
|
|
38535
39045
|
output_tokens: result.tokenUsage.output,
|
|
38536
39046
|
cost_usd: costUsd
|
|
39047
|
+
}).catch((err) => {
|
|
39048
|
+
logger.warn({ err }, "Failed to record solutioning token usage (non-fatal)");
|
|
38537
39049
|
});
|
|
38538
39050
|
}
|
|
38539
39051
|
if (result.result === "failed") {
|
|
@@ -38752,4 +39264,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
38752
39264
|
|
|
38753
39265
|
//#endregion
|
|
38754
39266
|
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
|
|
38755
|
-
//# sourceMappingURL=run-
|
|
39267
|
+
//# sourceMappingURL=run-gXtnH8lO.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./health-
|
|
1
|
+
import "./health-Cx2ZhRNT.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
|
-
import "./dist-
|
|
5
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, runRunAction } from "./run-
|
|
4
|
+
import "./dist-Bm0qSZer.js";
|
|
5
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, runRunAction } from "./run-gXtnH8lO.js";
|
|
6
6
|
import "./routing-CcBOCuC9.js";
|
|
7
7
|
import "./decisions-C0pz9Clx.js";
|
|
8
8
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createVersionManager } from "./dist-
|
|
1
|
+
import { createVersionManager } from "./dist-Bm0qSZer.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-
|
|
126
|
+
//# sourceMappingURL=upgrade-BcL4ZV3o.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./dist-
|
|
1
|
+
import "./dist-Bm0qSZer.js";
|
|
2
2
|
import "./version-manager-impl-BmOWu8ml.js";
|
|
3
|
-
import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-
|
|
3
|
+
import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-BcL4ZV3o.js";
|
|
4
4
|
|
|
5
5
|
export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "substrate-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Substrate — multi-agent orchestration daemon for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
"substrate:dev": "node dist/cli/index.js"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"bmad-method": "^6.
|
|
71
|
+
"bmad-method": "^6.2.2",
|
|
72
72
|
"commander": "^12.1.0",
|
|
73
73
|
"js-yaml": "^4.1.1",
|
|
74
|
-
"mysql2": "^3.
|
|
74
|
+
"mysql2": "^3.20.0",
|
|
75
75
|
"pino": "^9.6.0",
|
|
76
76
|
"semver": "^7.6.3",
|
|
77
77
|
"zod": "^4.3.6"
|