substrate-ai 0.3.0 → 0.3.2
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-PsWhP_1Q.js → adapter-registry-DHl0W-YB.js} +8 -1
- package/dist/cli/index.js +254 -24
- package/dist/{config-migrator-DSi8KhQC.js → config-migrator-CQmBdKeG.js} +9 -3
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1 -1
- package/dist/{run-DP932Mmn.js → run-BJ5z_b2J.js} +2 -2
- package/dist/{run-DO9n3cwy.js → run-Fzhz3-mv.js} +1535 -277
- package/dist/{upgrade-Cvwtnwl4.js → upgrade-DO307rFf.js} +2 -2
- package/dist/{upgrade-CImByfkk.js → upgrade-Ex1ukwsm.js} +3 -3
- package/dist/{version-manager-impl-CizNmmLT.js → version-manager-impl-33JYXsqa.js} +2 -2
- package/dist/version-manager-impl-Dk3S31y6.js +4 -0
- package/package.json +1 -1
- package/dist/version-manager-impl-aL5IemIm.js +0 -4
|
@@ -76,6 +76,13 @@ var ClaudeCodeAdapter = class {
|
|
|
76
76
|
const unsetKeys = ["CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT"];
|
|
77
77
|
if (options.billingMode === "api" && options.apiKey) envEntries.ANTHROPIC_API_KEY = options.apiKey;
|
|
78
78
|
else unsetKeys.push("ANTHROPIC_API_KEY");
|
|
79
|
+
if (options.otlpEndpoint !== void 0) {
|
|
80
|
+
envEntries.CLAUDE_CODE_ENABLE_TELEMETRY = "1";
|
|
81
|
+
envEntries.OTEL_LOGS_EXPORTER = "otlp";
|
|
82
|
+
envEntries.OTEL_METRICS_EXPORTER = "otlp";
|
|
83
|
+
envEntries.OTEL_EXPORTER_OTLP_PROTOCOL = "http/json";
|
|
84
|
+
envEntries.OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;
|
|
85
|
+
}
|
|
79
86
|
return {
|
|
80
87
|
binary: "claude",
|
|
81
88
|
args,
|
|
@@ -815,4 +822,4 @@ var AdapterRegistry = class {
|
|
|
815
822
|
|
|
816
823
|
//#endregion
|
|
817
824
|
export { AdapterRegistry, ClaudeCodeAdapter, CodexCLIAdapter, GeminiCLIAdapter };
|
|
818
|
-
//# sourceMappingURL=adapter-registry-
|
|
825
|
+
//# sourceMappingURL=adapter-registry-DHl0W-YB.js.map
|
package/dist/cli/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_CONFIG, DEFAULT_ROUTING_POLICY, DatabaseWrapper, DoltNotInstalled, FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, checkDoltInstalled, createConfigSystem, createContextCompiler, createDispatcher, createDoltClient, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStateStore, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initializeDolt, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveStoryKeys, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
2
|
+
import { DEFAULT_CONFIG, DEFAULT_ROUTING_POLICY, DatabaseWrapper, DoltNotInstalled, FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, TelemetryPersistence, VALID_PHASES, buildPipelineStatusOutput, checkDoltInstalled, createConfigSystem, createContextCompiler, createDispatcher, createDoltClient, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStateStore, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initializeDolt, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveStoryKeys, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-Fzhz3-mv.js";
|
|
3
3
|
import { createLogger } from "../logger-D2fS2ccL.js";
|
|
4
|
-
import { AdapterRegistry } from "../adapter-registry-
|
|
5
|
-
import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema } from "../config-migrator-
|
|
4
|
+
import { AdapterRegistry } from "../adapter-registry-DHl0W-YB.js";
|
|
5
|
+
import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema } from "../config-migrator-CQmBdKeG.js";
|
|
6
6
|
import { ConfigError, createEventBus } from "../helpers-RL22dYtn.js";
|
|
7
7
|
import { addTokenUsage, createDecision, createPipelineRun, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestRun, getTokenUsageSummary, listRequirements, updatePipelineRun } from "../decisions-Dq4cAA2L.js";
|
|
8
8
|
import { ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, OPERATIONAL_FINDING, STORY_METRICS, aggregateTokenUsageForRun, compareRunMetrics, getBaselineRunMetrics, getRunMetrics, getStoryMetricsForRun, incrementRunRestarts, listRunMetrics, tagRunAsBaseline } from "../operational-Bovj4fS-.js";
|
|
9
9
|
import { abortMerge, createWorktree, getConflictingFiles, getMergedFiles, getOrphanedWorktrees, performMerge, removeBranch, removeWorktree, simulateMerge, verifyGitVersion } from "../git-utils-CtmrZrHS.js";
|
|
10
|
-
import "../version-manager-impl-
|
|
11
|
-
import { registerUpgradeCommand } from "../upgrade-
|
|
10
|
+
import "../version-manager-impl-33JYXsqa.js";
|
|
11
|
+
import { registerUpgradeCommand } from "../upgrade-DO307rFf.js";
|
|
12
12
|
import { Command } from "commander";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
14
14
|
import { dirname, join, resolve } from "path";
|
|
@@ -681,7 +681,7 @@ async function runInitAction(options) {
|
|
|
681
681
|
process.stderr.write(`✗ Dolt initialization failed: ${msg}\n`);
|
|
682
682
|
return INIT_EXIT_ERROR;
|
|
683
683
|
}
|
|
684
|
-
logger$16.warn("Dolt auto-init failed (non-blocking)"
|
|
684
|
+
logger$16.warn({ error: msg }, "Dolt auto-init failed (non-blocking)");
|
|
685
685
|
}
|
|
686
686
|
}
|
|
687
687
|
else logger$16.debug("Dolt step was skipped (--no-dolt)");
|
|
@@ -1362,7 +1362,7 @@ async function runStatusAction(options) {
|
|
|
1362
1362
|
if (stateStore) try {
|
|
1363
1363
|
storeStories = await stateStore.queryStories({});
|
|
1364
1364
|
} catch (err) {
|
|
1365
|
-
logger$13.debug("StateStore query failed, continuing without store data"
|
|
1365
|
+
logger$13.debug({ err }, "StateStore query failed, continuing without store data");
|
|
1366
1366
|
}
|
|
1367
1367
|
if (outputFormat === "json") {
|
|
1368
1368
|
const statusOutput = buildPipelineStatusOutput(run, tokenSummary, decisionsCount, storiesCount);
|
|
@@ -2664,7 +2664,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
2664
2664
|
const expDb = expDbWrapper.db;
|
|
2665
2665
|
const { runRunAction: runPipeline } = await import(
|
|
2666
2666
|
/* @vite-ignore */
|
|
2667
|
-
"../run-
|
|
2667
|
+
"../run-BJ5z_b2J.js"
|
|
2668
2668
|
);
|
|
2669
2669
|
const runStoryFn = async (opts) => {
|
|
2670
2670
|
const exitCode = await runPipeline({
|
|
@@ -2908,8 +2908,217 @@ function registerSupervisorCommand(program, _version = "0.0.0", projectRoot = pr
|
|
|
2908
2908
|
//#endregion
|
|
2909
2909
|
//#region src/cli/commands/metrics.ts
|
|
2910
2910
|
const logger$11 = createLogger("metrics-cmd");
|
|
2911
|
+
async function openTelemetryDb(dbPath) {
|
|
2912
|
+
if (!existsSync(dbPath)) return null;
|
|
2913
|
+
try {
|
|
2914
|
+
const db = new Database(dbPath, { readonly: true });
|
|
2915
|
+
return db;
|
|
2916
|
+
} catch {
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
function rowsToEfficiencyScore(rows) {
|
|
2921
|
+
return rows;
|
|
2922
|
+
}
|
|
2923
|
+
function printEfficiencyTable(scores) {
|
|
2924
|
+
process.stdout.write(`\nEfficiency Scores (${scores.length} records)\n`);
|
|
2925
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
2926
|
+
process.stdout.write(` ${"Story Key".padEnd(14)} ${"Score".padStart(6)} ${"Cache Hit%".padStart(11)} ${"I/O Ratio".padStart(10)} ${"Ctx Mgmt".padStart(9)} Model\n`);
|
|
2927
|
+
process.stdout.write(" " + "─".repeat(76) + "\n");
|
|
2928
|
+
for (const s of scores) {
|
|
2929
|
+
const cacheHitPct = s.totalTurns > 0 ? `${(s.avgCacheHitRate * 100).toFixed(1)}%` : "0.0%";
|
|
2930
|
+
const ioRatio = s.avgIoRatio.toFixed(2);
|
|
2931
|
+
const ctxMgmt = String(Math.round(s.contextManagementSubScore));
|
|
2932
|
+
const model = s.perModelBreakdown.length > 0 ? s.perModelBreakdown[0]?.model ?? "unknown" : "unknown";
|
|
2933
|
+
process.stdout.write(` ${s.storyKey.padEnd(14)} ${String(s.compositeScore).padStart(6)} ${cacheHitPct.padStart(11)} ${ioRatio.padStart(10)} ${ctxMgmt.padStart(9)} ${model}\n`);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
function printRecommendationTable(recs) {
|
|
2937
|
+
process.stdout.write(`\nRecommendations (${recs.length} records)\n`);
|
|
2938
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
2939
|
+
process.stdout.write(` ${"Story".padEnd(12)} ${"Severity".padEnd(10)} ${"Rule".padEnd(24)} ${"Savings Tokens".padStart(15)}\n`);
|
|
2940
|
+
process.stdout.write(" " + "─".repeat(64) + "\n");
|
|
2941
|
+
for (const r of recs) {
|
|
2942
|
+
const savings = r.potentialSavingsTokens !== void 0 ? String(r.potentialSavingsTokens) : "-";
|
|
2943
|
+
process.stdout.write(` ${r.storyKey.padEnd(12)} ${r.severity.padEnd(10)} ${r.ruleId.padEnd(24)} ${savings.padStart(15)}\n`);
|
|
2944
|
+
process.stdout.write(` ${r.title}\n`);
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
function printTurnTable(turns, storyKey) {
|
|
2948
|
+
process.stdout.write(`\nTurn Analysis: ${storyKey} (${turns.length} turns)\n`);
|
|
2949
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
2950
|
+
process.stdout.write(` ${"#".padStart(4)} ${"Tokens In".padStart(10)} ${"Tok Out".padStart(8)} ${"Cache Hit%".padStart(11)} ${"Ctx Size".padStart(9)} Spike\n`);
|
|
2951
|
+
process.stdout.write(" " + "─".repeat(60) + "\n");
|
|
2952
|
+
for (const t of turns) {
|
|
2953
|
+
const cacheHitPct = t.inputTokens > 0 ? `${(t.cacheHitRate * 100).toFixed(1)}%` : "0.0%";
|
|
2954
|
+
const spike = t.isContextSpike ? " ⚠" : "";
|
|
2955
|
+
process.stdout.write(` ${String(t.turnNumber).padStart(4)} ${t.inputTokens.toLocaleString().padStart(10)} ${t.outputTokens.toLocaleString().padStart(8)} ${cacheHitPct.padStart(11)} ${t.contextSize.toLocaleString().padStart(9)}${spike}\n`);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
function printConsumerTable(consumers, storyKey) {
|
|
2959
|
+
process.stdout.write(`\nConsumer Stats: ${storyKey} (${consumers.length} consumers)\n`);
|
|
2960
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
2961
|
+
process.stdout.write(` ${"Consumer Key".padEnd(36)} ${"Category".padEnd(20)} ${"Tokens".padStart(10)} ${"%".padStart(7)}\n`);
|
|
2962
|
+
process.stdout.write(" " + "─".repeat(76) + "\n");
|
|
2963
|
+
for (const c of consumers) {
|
|
2964
|
+
const key = c.consumerKey.slice(0, 34);
|
|
2965
|
+
const pct = `${c.percentage.toFixed(1)}%`;
|
|
2966
|
+
process.stdout.write(` ${key.padEnd(36)} ${c.category.padEnd(20)} ${c.totalTokens.toLocaleString().padStart(10)} ${pct.padStart(7)}\n`);
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
function printCategoryTable(stats, label) {
|
|
2970
|
+
process.stdout.write(`\nCategory Stats${label} (${stats.length} categories)\n`);
|
|
2971
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
2972
|
+
process.stdout.write(` ${"Category".padEnd(22)} ${"Tokens".padStart(12)} ${"%".padStart(8)} ${"Events".padStart(8)} ${"Avg/Event".padStart(10)} Trend\n`);
|
|
2973
|
+
process.stdout.write(" " + "─".repeat(70) + "\n");
|
|
2974
|
+
const sorted = [...stats].sort((a, b) => b.totalTokens - a.totalTokens);
|
|
2975
|
+
for (const c of sorted) {
|
|
2976
|
+
const pct = `${c.percentage.toFixed(1)}%`;
|
|
2977
|
+
const avg = c.avgTokensPerEvent.toFixed(0);
|
|
2978
|
+
process.stdout.write(` ${c.category.padEnd(22)} ${c.totalTokens.toLocaleString().padStart(12)} ${pct.padStart(8)} ${String(c.eventCount).padStart(8)} ${avg.padStart(10)} ${c.trend}\n`);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2911
2981
|
async function runMetricsAction(options) {
|
|
2912
|
-
const { outputFormat, projectRoot, limit = 10, compare, tagBaseline, analysis, sprint, story, taskType, since, aggregate } = options;
|
|
2982
|
+
const { outputFormat, projectRoot, limit = 10, compare, tagBaseline, analysis, sprint, story, taskType, since, aggregate, efficiency, recommendations, turns, consumers, categories, compareStories } = options;
|
|
2983
|
+
const telemetryModes = [
|
|
2984
|
+
efficiency,
|
|
2985
|
+
recommendations,
|
|
2986
|
+
turns,
|
|
2987
|
+
consumers,
|
|
2988
|
+
categories,
|
|
2989
|
+
compareStories
|
|
2990
|
+
].filter(Boolean);
|
|
2991
|
+
if (telemetryModes.length > 1) {
|
|
2992
|
+
process.stderr.write("Error: --efficiency, --recommendations, --turns, --consumers, --categories, and --compare-stories are mutually exclusive\n");
|
|
2993
|
+
return 1;
|
|
2994
|
+
}
|
|
2995
|
+
const hasTelemetryMode = telemetryModes.length > 0;
|
|
2996
|
+
if (hasTelemetryMode && (compare !== void 0 || tagBaseline !== void 0 || analysis !== void 0)) {
|
|
2997
|
+
process.stderr.write("Error: telemetry modes (--efficiency, --recommendations, --turns, --consumers, --categories, --compare-stories) cannot be combined with --compare, --tag-baseline, or --analysis\n");
|
|
2998
|
+
return 1;
|
|
2999
|
+
}
|
|
3000
|
+
if (hasTelemetryMode) {
|
|
3001
|
+
const dbRoot$1 = await resolveMainRepoRoot(projectRoot);
|
|
3002
|
+
const dbPath$1 = join(dbRoot$1, ".substrate", "substrate.db");
|
|
3003
|
+
const doltStatePath = join(dbRoot$1, ".substrate", "state", ".dolt");
|
|
3004
|
+
const doltExists = existsSync(doltStatePath);
|
|
3005
|
+
if (!doltExists && !existsSync(dbPath$1)) {
|
|
3006
|
+
const msg = "No telemetry data yet — run a pipeline with `telemetry.enabled: true`";
|
|
3007
|
+
if (turns !== void 0 || consumers !== void 0) {
|
|
3008
|
+
process.stderr.write(`Error: ${msg}\n`);
|
|
3009
|
+
return 1;
|
|
3010
|
+
}
|
|
3011
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({ message: msg }, "json", true) + "\n");
|
|
3012
|
+
else process.stdout.write(msg + "\n");
|
|
3013
|
+
return 0;
|
|
3014
|
+
}
|
|
3015
|
+
const sqliteDb = await openTelemetryDb(dbPath$1);
|
|
3016
|
+
if (sqliteDb === null) {
|
|
3017
|
+
const msg = "No telemetry data yet — run a pipeline with `telemetry.enabled: true`";
|
|
3018
|
+
if (turns !== void 0 || consumers !== void 0) {
|
|
3019
|
+
process.stderr.write(`Error: ${msg}\n`);
|
|
3020
|
+
return 1;
|
|
3021
|
+
}
|
|
3022
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({ message: msg }, "json", true) + "\n");
|
|
3023
|
+
else process.stdout.write(msg + "\n");
|
|
3024
|
+
return 0;
|
|
3025
|
+
}
|
|
3026
|
+
try {
|
|
3027
|
+
const telemetryPersistence = new TelemetryPersistence(sqliteDb);
|
|
3028
|
+
telemetryPersistence.initSchema();
|
|
3029
|
+
if (efficiency === true) {
|
|
3030
|
+
const scores = await telemetryPersistence.getEfficiencyScores(20);
|
|
3031
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({ efficiency: rowsToEfficiencyScore(scores) }, "json", true) + "\n");
|
|
3032
|
+
else printEfficiencyTable(scores);
|
|
3033
|
+
return 0;
|
|
3034
|
+
}
|
|
3035
|
+
if (recommendations === true) {
|
|
3036
|
+
const recs = story !== void 0 ? await telemetryPersistence.getRecommendations(story) : await telemetryPersistence.getAllRecommendations(50);
|
|
3037
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({
|
|
3038
|
+
recommendations: recs,
|
|
3039
|
+
...story !== void 0 && { storyKey: story }
|
|
3040
|
+
}, "json", true) + "\n");
|
|
3041
|
+
else if (recs.length === 0) {
|
|
3042
|
+
const msg = story !== void 0 ? `No recommendations found for story '${story}'` : "No recommendations yet — run a pipeline with `telemetry.enabled: true`";
|
|
3043
|
+
process.stdout.write(msg + "\n");
|
|
3044
|
+
} else printRecommendationTable(recs);
|
|
3045
|
+
return 0;
|
|
3046
|
+
}
|
|
3047
|
+
if (turns !== void 0) {
|
|
3048
|
+
const turnData = await telemetryPersistence.getTurnAnalysis(turns);
|
|
3049
|
+
if (turnData.length === 0) {
|
|
3050
|
+
const msg = `No turn analysis data found for story '${turns}'`;
|
|
3051
|
+
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
|
|
3052
|
+
else process.stderr.write(`Error: ${msg}\n`);
|
|
3053
|
+
return 1;
|
|
3054
|
+
}
|
|
3055
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({ turns: turnData }, "json", true) + "\n");
|
|
3056
|
+
else printTurnTable(turnData, turns);
|
|
3057
|
+
return 0;
|
|
3058
|
+
}
|
|
3059
|
+
if (consumers !== void 0) {
|
|
3060
|
+
const consumerData = await telemetryPersistence.getConsumerStats(consumers);
|
|
3061
|
+
if (consumerData.length === 0) {
|
|
3062
|
+
const msg = `No consumer stats found for story '${consumers}'`;
|
|
3063
|
+
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
|
|
3064
|
+
else process.stderr.write(`Error: ${msg}\n`);
|
|
3065
|
+
return 1;
|
|
3066
|
+
}
|
|
3067
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({ consumers: consumerData }, "json", true) + "\n");
|
|
3068
|
+
else printConsumerTable(consumerData, consumers);
|
|
3069
|
+
return 0;
|
|
3070
|
+
}
|
|
3071
|
+
if (categories === true) {
|
|
3072
|
+
const storyKey = story;
|
|
3073
|
+
const categoryData = await telemetryPersistence.getCategoryStats(storyKey ?? "");
|
|
3074
|
+
const label = storyKey !== void 0 ? `: ${storyKey}` : "";
|
|
3075
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({
|
|
3076
|
+
categories: categoryData,
|
|
3077
|
+
storyKey
|
|
3078
|
+
}, "json", true) + "\n");
|
|
3079
|
+
else printCategoryTable(categoryData, label);
|
|
3080
|
+
return 0;
|
|
3081
|
+
}
|
|
3082
|
+
if (compareStories !== void 0) {
|
|
3083
|
+
const [keyA, keyB] = compareStories;
|
|
3084
|
+
const [scoreA, scoreB] = await Promise.all([telemetryPersistence.getEfficiencyScore(keyA), telemetryPersistence.getEfficiencyScore(keyB)]);
|
|
3085
|
+
if (scoreA === null || scoreB === null) {
|
|
3086
|
+
const missing = [scoreA === null ? keyA : null, scoreB === null ? keyB : null].filter(Boolean).join(", ");
|
|
3087
|
+
const msg = `No efficiency score found for story: ${missing}`;
|
|
3088
|
+
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
|
|
3089
|
+
else process.stderr.write(`Error: ${msg}\n`);
|
|
3090
|
+
return 1;
|
|
3091
|
+
}
|
|
3092
|
+
const delta = {
|
|
3093
|
+
compositeScore: scoreB.compositeScore - scoreA.compositeScore,
|
|
3094
|
+
cacheHitSubScore: scoreB.cacheHitSubScore - scoreA.cacheHitSubScore,
|
|
3095
|
+
ioRatioSubScore: scoreB.ioRatioSubScore - scoreA.ioRatioSubScore,
|
|
3096
|
+
contextManagementSubScore: scoreB.contextManagementSubScore - scoreA.contextManagementSubScore
|
|
3097
|
+
};
|
|
3098
|
+
if (outputFormat === "json") process.stdout.write(formatOutput({
|
|
3099
|
+
storyA: scoreA,
|
|
3100
|
+
storyB: scoreB,
|
|
3101
|
+
delta
|
|
3102
|
+
}, "json", true) + "\n");
|
|
3103
|
+
else {
|
|
3104
|
+
const sign = (n) => n > 0 ? "+" : "";
|
|
3105
|
+
process.stdout.write(`\nEfficiency Comparison: ${keyA} vs ${keyB}\n`);
|
|
3106
|
+
process.stdout.write("─".repeat(80) + "\n");
|
|
3107
|
+
process.stdout.write(` ${"Metric".padEnd(30)} ${keyA.padStart(12)} ${keyB.padStart(12)} ${"Delta".padStart(10)}\n`);
|
|
3108
|
+
process.stdout.write(" " + "─".repeat(66) + "\n");
|
|
3109
|
+
process.stdout.write(` ${"Composite Score".padEnd(30)} ${String(scoreA.compositeScore).padStart(12)} ${String(scoreB.compositeScore).padStart(12)} ${`${sign(delta.compositeScore)}${delta.compositeScore}`.padStart(10)}\n`);
|
|
3110
|
+
process.stdout.write(` ${"Cache Hit Sub-Score".padEnd(30)} ${scoreA.cacheHitSubScore.toFixed(1).padStart(12)} ${scoreB.cacheHitSubScore.toFixed(1).padStart(12)} ${`${sign(delta.cacheHitSubScore)}${delta.cacheHitSubScore.toFixed(1)}`.padStart(10)}\n`);
|
|
3111
|
+
process.stdout.write(` ${"I/O Ratio Sub-Score".padEnd(30)} ${scoreA.ioRatioSubScore.toFixed(1).padStart(12)} ${scoreB.ioRatioSubScore.toFixed(1).padStart(12)} ${`${sign(delta.ioRatioSubScore)}${delta.ioRatioSubScore.toFixed(1)}`.padStart(10)}\n`);
|
|
3112
|
+
process.stdout.write(` ${"Context Mgmt Sub-Score".padEnd(30)} ${scoreA.contextManagementSubScore.toFixed(1).padStart(12)} ${scoreB.contextManagementSubScore.toFixed(1).padStart(12)} ${`${sign(delta.contextManagementSubScore)}${delta.contextManagementSubScore.toFixed(1)}`.padStart(10)}\n`);
|
|
3113
|
+
}
|
|
3114
|
+
return 0;
|
|
3115
|
+
}
|
|
3116
|
+
} finally {
|
|
3117
|
+
try {
|
|
3118
|
+
sqliteDb.close();
|
|
3119
|
+
} catch {}
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
2913
3122
|
if (analysis !== void 0) {
|
|
2914
3123
|
const dbRoot$1 = await resolveMainRepoRoot(projectRoot);
|
|
2915
3124
|
const reportBase = join(dbRoot$1, "_bmad-output", "supervisor-reports", `${analysis}-analysis`);
|
|
@@ -3142,26 +3351,43 @@ async function runMetricsAction(options) {
|
|
|
3142
3351
|
}
|
|
3143
3352
|
}
|
|
3144
3353
|
function registerMetricsCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
|
|
3145
|
-
program.command("metrics").description("Show historical pipeline run metrics and cross-run comparison").option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--limit <n>", "Number of runs to show (default: 10)", (v) => parseInt(v, 10), 10).option("--compare <run-id-a,run-id-b>", "Compare two runs side-by-side (comma-separated IDs, e.g. abc123,def456)").option("--tag-baseline <run-id>", "Mark a run as the performance baseline").option("--analysis <run-id>", "Read and output the analysis report for the specified run (AC5 of Story 17-3)").option("--sprint <sprint>", "Filter StateStore metrics by sprint (e.g. sprint-1)").option("--story <story-key>", "Filter StateStore metrics by story key (e.g. 26-1)").option("--task-type <type>", "Filter StateStore metrics by task type (e.g. dev-story)").option("--since <iso-date>", "Filter StateStore metrics at or after this ISO timestamp").option("--aggregate", "Aggregate StateStore metrics grouped by task_type").action(async (opts) => {
|
|
3354
|
+
program.command("metrics").description("Show historical pipeline run metrics and cross-run comparison").option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--limit <n>", "Number of runs to show (default: 10)", (v) => parseInt(v, 10), 10).option("--compare <run-id-a,run-id-b>", "Compare two runs side-by-side (comma-separated IDs, e.g. abc123,def456)").option("--tag-baseline <run-id>", "Mark a run as the performance baseline").option("--analysis <run-id>", "Read and output the analysis report for the specified run (AC5 of Story 17-3)").option("--sprint <sprint>", "Filter StateStore metrics by sprint (e.g. sprint-1)").option("--story <story-key>", "Filter StateStore metrics by story key (e.g. 26-1)").option("--task-type <type>", "Filter StateStore metrics by task type (e.g. dev-story)").option("--since <iso-date>", "Filter StateStore metrics at or after this ISO timestamp").option("--aggregate", "Aggregate StateStore metrics grouped by task_type").option("--efficiency", "Show telemetry efficiency scores for recent stories").option("--recommendations", "Show all telemetry recommendations across stories").option("--turns <storyKey>", "Show per-turn analysis for a specific story").option("--consumers <storyKey>", "Show consumer stats for a specific story").option("--categories", "Show category stats (optionally scoped by --story <storyKey>)").option("--compare-stories <storyA,storyB>", "Compare efficiency scores of two stories side-by-side (comma-separated keys)").action(async (opts) => {
|
|
3146
3355
|
const outputFormat = opts.outputFormat === "json" ? "json" : "human";
|
|
3147
3356
|
let compareIds;
|
|
3148
3357
|
if (opts.compare !== void 0) {
|
|
3149
3358
|
const parts = opts.compare.split(",").map((s) => s.trim());
|
|
3150
3359
|
if (parts.length === 2 && parts[0] && parts[1]) compareIds = [parts[0], parts[1]];
|
|
3151
3360
|
}
|
|
3152
|
-
|
|
3361
|
+
let compareStoriesIds;
|
|
3362
|
+
if (opts.compareStories !== void 0) {
|
|
3363
|
+
const parts = opts.compareStories.split(",").map((s) => s.trim());
|
|
3364
|
+
if (parts.length === 2 && parts[0] && parts[1]) compareStoriesIds = [parts[0], parts[1]];
|
|
3365
|
+
else {
|
|
3366
|
+
process.stderr.write("Error: --compare-stories requires exactly two comma-separated story keys\n");
|
|
3367
|
+
process.exitCode = 1;
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
const metricsOpts = {
|
|
3153
3372
|
outputFormat,
|
|
3154
3373
|
projectRoot: opts.projectRoot,
|
|
3155
3374
|
limit: opts.limit,
|
|
3156
|
-
compare: compareIds,
|
|
3157
|
-
tagBaseline: opts.tagBaseline,
|
|
3158
|
-
analysis: opts.analysis,
|
|
3159
|
-
sprint: opts.sprint,
|
|
3160
|
-
story: opts.story,
|
|
3161
|
-
taskType: opts.taskType,
|
|
3162
|
-
since: opts.since,
|
|
3163
|
-
aggregate: opts.aggregate
|
|
3164
|
-
|
|
3375
|
+
...compareIds !== void 0 && { compare: compareIds },
|
|
3376
|
+
...opts.tagBaseline !== void 0 && { tagBaseline: opts.tagBaseline },
|
|
3377
|
+
...opts.analysis !== void 0 && { analysis: opts.analysis },
|
|
3378
|
+
...opts.sprint !== void 0 && { sprint: opts.sprint },
|
|
3379
|
+
...opts.story !== void 0 && { story: opts.story },
|
|
3380
|
+
...opts.taskType !== void 0 && { taskType: opts.taskType },
|
|
3381
|
+
...opts.since !== void 0 && { since: opts.since },
|
|
3382
|
+
...opts.aggregate !== void 0 && { aggregate: opts.aggregate },
|
|
3383
|
+
...opts.efficiency !== void 0 && { efficiency: opts.efficiency },
|
|
3384
|
+
...opts.recommendations !== void 0 && { recommendations: opts.recommendations },
|
|
3385
|
+
...opts.turns !== void 0 && { turns: opts.turns },
|
|
3386
|
+
...opts.consumers !== void 0 && { consumers: opts.consumers },
|
|
3387
|
+
...opts.categories !== void 0 && { categories: opts.categories },
|
|
3388
|
+
...compareStoriesIds !== void 0 && { compareStories: compareStoriesIds }
|
|
3389
|
+
};
|
|
3390
|
+
const exitCode = await runMetricsAction(metricsOpts);
|
|
3165
3391
|
process.exitCode = exitCode;
|
|
3166
3392
|
});
|
|
3167
3393
|
}
|
|
@@ -3291,8 +3517,12 @@ function registerMigrateCommand(program) {
|
|
|
3291
3517
|
}
|
|
3292
3518
|
const result = await migrateDataToDolt(client, snapshot.storyMetrics, false);
|
|
3293
3519
|
if (result.metricsWritten > 0) try {
|
|
3294
|
-
await client.
|
|
3295
|
-
await client.
|
|
3520
|
+
await client.execArgs(["add", "."]);
|
|
3521
|
+
await client.execArgs([
|
|
3522
|
+
"commit",
|
|
3523
|
+
"-m",
|
|
3524
|
+
"Migrate historical data from SQLite"
|
|
3525
|
+
]);
|
|
3296
3526
|
} catch (execErr) {
|
|
3297
3527
|
const msg = execErr instanceof Error ? execErr.message : String(execErr);
|
|
3298
3528
|
process.stderr.write(`Warning: Dolt commit failed (non-fatal): ${msg}\n`);
|
|
@@ -7222,8 +7452,8 @@ async function createProgram() {
|
|
|
7222
7452
|
/** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
|
|
7223
7453
|
function checkForUpdatesInBackground(currentVersion) {
|
|
7224
7454
|
if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
|
|
7225
|
-
import("../upgrade-
|
|
7226
|
-
const { createVersionManager } = await import("../version-manager-impl-
|
|
7455
|
+
import("../upgrade-Ex1ukwsm.js").then(async () => {
|
|
7456
|
+
const { createVersionManager } = await import("../version-manager-impl-Dk3S31y6.js");
|
|
7227
7457
|
const vm = createVersionManager();
|
|
7228
7458
|
const result = await vm.checkForUpdates();
|
|
7229
7459
|
if (result.updateAvailable) {
|
|
@@ -79,6 +79,10 @@ const TokenCeilingsSchema = z.object({
|
|
|
79
79
|
"test-plan": z.number().int().positive("test-plan token ceiling must be a positive integer").optional(),
|
|
80
80
|
"test-expansion": z.number().int().positive("test-expansion token ceiling must be a positive integer").optional()
|
|
81
81
|
});
|
|
82
|
+
const TelemetryConfigSchema = z.object({
|
|
83
|
+
enabled: z.boolean().default(false),
|
|
84
|
+
port: z.number().int().min(1).max(65535).default(4318)
|
|
85
|
+
}).strict();
|
|
82
86
|
/** Current supported config format version */
|
|
83
87
|
const CURRENT_CONFIG_FORMAT_VERSION = "1";
|
|
84
88
|
/** Current supported task graph version */
|
|
@@ -94,7 +98,8 @@ const SubstrateConfigSchema = z.object({
|
|
|
94
98
|
providers: ProvidersSchema,
|
|
95
99
|
cost_tracker: CostTrackerConfigSchema.optional(),
|
|
96
100
|
budget: BudgetConfigSchema.optional(),
|
|
97
|
-
token_ceilings: TokenCeilingsSchema.optional()
|
|
101
|
+
token_ceilings: TokenCeilingsSchema.optional(),
|
|
102
|
+
telemetry: TelemetryConfigSchema.optional()
|
|
98
103
|
}).strict();
|
|
99
104
|
const PartialProviderConfigSchema = ProviderConfigSchema.partial();
|
|
100
105
|
const PartialGlobalSettingsSchema = GlobalSettingsSchema.partial();
|
|
@@ -109,7 +114,8 @@ const PartialSubstrateConfigSchema = z.object({
|
|
|
109
114
|
}).partial().optional(),
|
|
110
115
|
cost_tracker: CostTrackerConfigSchema.partial().optional(),
|
|
111
116
|
budget: BudgetConfigSchema.partial().optional(),
|
|
112
|
-
token_ceilings: TokenCeilingsSchema.optional()
|
|
117
|
+
token_ceilings: TokenCeilingsSchema.optional(),
|
|
118
|
+
telemetry: TelemetryConfigSchema.partial().optional()
|
|
113
119
|
}).strict();
|
|
114
120
|
|
|
115
121
|
//#endregion
|
|
@@ -241,4 +247,4 @@ const defaultConfigMigrator = new ConfigMigrator();
|
|
|
241
247
|
|
|
242
248
|
//#endregion
|
|
243
249
|
export { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SUPPORTED_TASK_GRAPH_VERSIONS, SubstrateConfigSchema, defaultConfigMigrator };
|
|
244
|
-
//# sourceMappingURL=config-migrator-
|
|
250
|
+
//# sourceMappingURL=config-migrator-CQmBdKeG.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -780,6 +780,10 @@ declare const SubstrateConfigSchema: z.ZodObject<{
|
|
|
780
780
|
'test-plan': z.ZodOptional<z.ZodNumber>;
|
|
781
781
|
'test-expansion': z.ZodOptional<z.ZodNumber>;
|
|
782
782
|
}, z.core.$strip>>;
|
|
783
|
+
telemetry: z.ZodOptional<z.ZodObject<{
|
|
784
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
785
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
786
|
+
}, z.core.$strict>>;
|
|
783
787
|
}, z.core.$strict>;
|
|
784
788
|
type SubstrateConfig = z.infer<typeof SubstrateConfigSchema>;
|
|
785
789
|
|
|
@@ -1227,6 +1231,11 @@ interface OrchestratorEvents {
|
|
|
1227
1231
|
modifiedInterfaces: string[];
|
|
1228
1232
|
potentiallyAffectedTests: string[];
|
|
1229
1233
|
};
|
|
1234
|
+
/** Dolt merge conflict detected when merging a story branch into main */
|
|
1235
|
+
'pipeline:state-conflict': {
|
|
1236
|
+
storyKey: string;
|
|
1237
|
+
conflict: unknown;
|
|
1238
|
+
};
|
|
1230
1239
|
/** Per-story metrics snapshot emitted when a story reaches a terminal state (Story 24-4) */
|
|
1231
1240
|
'story:metrics': {
|
|
1232
1241
|
storyKey: string;
|
|
@@ -1407,6 +1416,13 @@ interface AdapterOptions {
|
|
|
1407
1416
|
apiKey?: string;
|
|
1408
1417
|
/** Optional maximum agentic turns (passed as --max-turns to Claude CLI) */
|
|
1409
1418
|
maxTurns?: number;
|
|
1419
|
+
/**
|
|
1420
|
+
* Optional OTLP endpoint URL for telemetry export (Story 27-9).
|
|
1421
|
+
* When set, injects the 5 OTLP env vars into the spawned process so that
|
|
1422
|
+
* Claude Code exports telemetry to the local IngestionServer.
|
|
1423
|
+
* Example: "http://localhost:4318"
|
|
1424
|
+
*/
|
|
1425
|
+
otlpEndpoint?: string;
|
|
1410
1426
|
}
|
|
1411
1427
|
/**
|
|
1412
1428
|
* Capabilities reported by an adapter for this CLI agent.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { childLogger, createLogger, logger } from "./logger-D2fS2ccL.js";
|
|
2
|
-
import { AdapterRegistry, ClaudeCodeAdapter, CodexCLIAdapter, GeminiCLIAdapter } from "./adapter-registry-
|
|
2
|
+
import { AdapterRegistry, ClaudeCodeAdapter, CodexCLIAdapter, GeminiCLIAdapter } from "./adapter-registry-DHl0W-YB.js";
|
|
3
3
|
import { AdtError, BudgetExceededError, ConfigError, ConfigIncompatibleFormatError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError, assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry } from "./helpers-RL22dYtn.js";
|
|
4
4
|
|
|
5
5
|
//#region src/core/di.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { registerRunCommand, runRunAction } from "./run-
|
|
1
|
+
import { registerRunCommand, runRunAction } from "./run-Fzhz3-mv.js";
|
|
2
2
|
import "./logger-D2fS2ccL.js";
|
|
3
|
-
import "./config-migrator-
|
|
3
|
+
import "./config-migrator-CQmBdKeG.js";
|
|
4
4
|
import "./helpers-RL22dYtn.js";
|
|
5
5
|
import "./decisions-Dq4cAA2L.js";
|
|
6
6
|
import "./operational-Bovj4fS-.js";
|