substrate-ai 0.20.31 → 0.20.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +4 -4
- package/dist/{health-B0cPyaYJ.js → health-DJ4z2uWN.js} +189 -19
- package/dist/{health-C6pR6QvM.js → health-DLqMd9uN.js} +1 -1
- package/dist/{run-Dt5fuOCt.js → run-D-OcJNtZ.js} +2 -2
- package/dist/{run-C8IJQ5i5.js → run-DGyWCmcu.js} +989 -417
- package/package.json +1 -1
- package/packs/bmad/prompts/dev-story.md +2 -0
- package/packs/bmad/prompts/probe-author.md +154 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, RuntimeProbeListSchema, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, detectsEventDrivenAC, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-DJ4z2uWN.js";
|
|
2
2
|
import { createLogger } from "./logger-KeHncl-f.js";
|
|
3
3
|
import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
|
|
4
4
|
import { ADVISORY_NOTES, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-CqtWS9wF.js";
|
|
@@ -9,11 +9,12 @@ import yaml from "js-yaml";
|
|
|
9
9
|
import * as actualFS from "node:fs";
|
|
10
10
|
import { accessSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
|
|
11
11
|
import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
|
|
12
|
+
import * as path$2 from "node:path";
|
|
12
13
|
import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, resolve as resolve$1, win32 } from "node:path";
|
|
13
14
|
import { tmpdir } from "node:os";
|
|
14
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
15
16
|
import { z } from "zod";
|
|
16
|
-
import { access as access$1, lstat, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, readlink, realpath, stat as stat$1, unlink, writeFile as writeFile$1 } from "node:fs/promises";
|
|
17
|
+
import { access as access$1, lstat, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, readlink, realpath, rename, stat as stat$1, unlink, writeFile as writeFile$1 } from "node:fs/promises";
|
|
17
18
|
import { existsSync as existsSync$1, lstatSync, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdir as readdir$2, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
18
19
|
import { promisify } from "node:util";
|
|
19
20
|
import { fileURLToPath } from "node:url";
|
|
@@ -2122,7 +2123,7 @@ async function runHelpAgent() {
|
|
|
2122
2123
|
|
|
2123
2124
|
//#endregion
|
|
2124
2125
|
//#region src/persistence/dolt-server.ts
|
|
2125
|
-
const logger$
|
|
2126
|
+
const logger$25 = createLogger("dolt-server");
|
|
2126
2127
|
/**
|
|
2127
2128
|
* Start a dolt sql-server for the given project, if Dolt is available and no
|
|
2128
2129
|
* server is already running (socket already exists).
|
|
@@ -2139,7 +2140,7 @@ async function startDoltServer(projectRoot) {
|
|
|
2139
2140
|
if (!existsSync(join$1(stateDir, ".dolt"))) return null;
|
|
2140
2141
|
try {
|
|
2141
2142
|
await access$1(socketPath);
|
|
2142
|
-
logger$
|
|
2143
|
+
logger$25.debug("Dolt socket already exists at %s — using existing server", socketPath);
|
|
2143
2144
|
return null;
|
|
2144
2145
|
} catch {}
|
|
2145
2146
|
try {
|
|
@@ -2148,10 +2149,10 @@ async function startDoltServer(projectRoot) {
|
|
|
2148
2149
|
stdio: "pipe"
|
|
2149
2150
|
});
|
|
2150
2151
|
} catch {
|
|
2151
|
-
logger$
|
|
2152
|
+
logger$25.debug("dolt binary not on PATH — cannot start server");
|
|
2152
2153
|
return null;
|
|
2153
2154
|
}
|
|
2154
|
-
logger$
|
|
2155
|
+
logger$25.debug("Starting dolt sql-server at %s", socketPath);
|
|
2155
2156
|
let proc$1;
|
|
2156
2157
|
try {
|
|
2157
2158
|
proc$1 = spawn("dolt", [
|
|
@@ -2172,26 +2173,26 @@ async function startDoltServer(projectRoot) {
|
|
|
2172
2173
|
detached: false
|
|
2173
2174
|
});
|
|
2174
2175
|
} catch (err) {
|
|
2175
|
-
logger$
|
|
2176
|
+
logger$25.debug("Failed to spawn dolt sql-server: %s", err instanceof Error ? err.message : String(err));
|
|
2176
2177
|
return null;
|
|
2177
2178
|
}
|
|
2178
2179
|
let failed = false;
|
|
2179
2180
|
proc$1.on("error", (err) => {
|
|
2180
|
-
logger$
|
|
2181
|
+
logger$25.debug("dolt sql-server error: %s", err.message);
|
|
2181
2182
|
failed = true;
|
|
2182
2183
|
});
|
|
2183
2184
|
proc$1.on("exit", (code) => {
|
|
2184
|
-
if (code !== null && code !== 0) logger$
|
|
2185
|
+
if (code !== null && code !== 0) logger$25.debug("dolt sql-server exited with code %d", code);
|
|
2185
2186
|
});
|
|
2186
2187
|
proc$1.stderr?.on("data", (chunk) => {
|
|
2187
2188
|
const line = chunk.toString().trim();
|
|
2188
|
-
if (line) logger$
|
|
2189
|
+
if (line) logger$25.debug("dolt-server: %s", line);
|
|
2189
2190
|
});
|
|
2190
2191
|
const deadline = Date.now() + 5e3;
|
|
2191
2192
|
while (Date.now() < deadline && !failed) try {
|
|
2192
2193
|
await access$1(socketPath);
|
|
2193
2194
|
const pid = proc$1.pid ?? 0;
|
|
2194
|
-
logger$
|
|
2195
|
+
logger$25.info("Auto-started dolt sql-server (pid=%d, socket=%s)", pid, socketPath);
|
|
2195
2196
|
let stopped = false;
|
|
2196
2197
|
return {
|
|
2197
2198
|
pid,
|
|
@@ -2199,14 +2200,14 @@ async function startDoltServer(projectRoot) {
|
|
|
2199
2200
|
stop: () => {
|
|
2200
2201
|
if (stopped) return;
|
|
2201
2202
|
stopped = true;
|
|
2202
|
-
logger$
|
|
2203
|
+
logger$25.debug("Stopping dolt sql-server (pid=%d)", pid);
|
|
2203
2204
|
proc$1.kill("SIGTERM");
|
|
2204
2205
|
}
|
|
2205
2206
|
};
|
|
2206
2207
|
} catch {
|
|
2207
2208
|
await new Promise((resolve$6) => setTimeout(resolve$6, 100));
|
|
2208
2209
|
}
|
|
2209
|
-
logger$
|
|
2210
|
+
logger$25.debug("dolt sql-server did not start within 5s — killing");
|
|
2210
2211
|
proc$1.kill("SIGTERM");
|
|
2211
2212
|
return null;
|
|
2212
2213
|
}
|
|
@@ -2276,7 +2277,7 @@ function truncateToTokens(text, maxTokens) {
|
|
|
2276
2277
|
|
|
2277
2278
|
//#endregion
|
|
2278
2279
|
//#region src/modules/context-compiler/context-compiler-impl.ts
|
|
2279
|
-
const logger$
|
|
2280
|
+
const logger$24 = createLogger("context-compiler");
|
|
2280
2281
|
/**
|
|
2281
2282
|
* Fraction of the original token budget that must remain (after required +
|
|
2282
2283
|
* important sections) before an optional section is included.
|
|
@@ -2337,7 +2338,7 @@ var ContextCompilerImpl = class {
|
|
|
2337
2338
|
}
|
|
2338
2339
|
_applyExclusionFilter(text, sectionName) {
|
|
2339
2340
|
for (const excludedPath of this._excludedPaths) if (text.includes(excludedPath)) {
|
|
2340
|
-
logger$
|
|
2341
|
+
logger$24.warn({
|
|
2341
2342
|
sectionName,
|
|
2342
2343
|
excludedPath
|
|
2343
2344
|
}, "ContextCompiler: section excluded — contains path from exclusion list");
|
|
@@ -2395,7 +2396,7 @@ var ContextCompilerImpl = class {
|
|
|
2395
2396
|
includedParts.push(truncated);
|
|
2396
2397
|
remainingBudget -= truncatedTokens;
|
|
2397
2398
|
anyTruncated = true;
|
|
2398
|
-
logger$
|
|
2399
|
+
logger$24.warn({
|
|
2399
2400
|
section: section.name,
|
|
2400
2401
|
originalTokens: tokens,
|
|
2401
2402
|
budgetTokens: truncatedTokens
|
|
@@ -2409,7 +2410,7 @@ var ContextCompilerImpl = class {
|
|
|
2409
2410
|
});
|
|
2410
2411
|
} else {
|
|
2411
2412
|
anyTruncated = true;
|
|
2412
|
-
logger$
|
|
2413
|
+
logger$24.warn({
|
|
2413
2414
|
section: section.name,
|
|
2414
2415
|
tokens
|
|
2415
2416
|
}, "Context compiler: omitted \"important\" section — no budget remaining");
|
|
@@ -2436,7 +2437,7 @@ var ContextCompilerImpl = class {
|
|
|
2436
2437
|
} else {
|
|
2437
2438
|
if (tokens > 0) {
|
|
2438
2439
|
anyTruncated = true;
|
|
2439
|
-
logger$
|
|
2440
|
+
logger$24.warn({
|
|
2440
2441
|
section: section.name,
|
|
2441
2442
|
tokens,
|
|
2442
2443
|
budgetFractionRemaining: budgetFractionRemaining.toFixed(2)
|
|
@@ -2530,8 +2531,8 @@ var GrammarLoader = class {
|
|
|
2530
2531
|
_extensionMap;
|
|
2531
2532
|
_cache = new Map();
|
|
2532
2533
|
_unavailable = false;
|
|
2533
|
-
constructor(logger$
|
|
2534
|
-
this._logger = logger$
|
|
2534
|
+
constructor(logger$26) {
|
|
2535
|
+
this._logger = logger$26;
|
|
2535
2536
|
this._extensionMap = new Map([
|
|
2536
2537
|
[".ts", "tree-sitter-typescript/typescript"],
|
|
2537
2538
|
[".tsx", "tree-sitter-typescript/tsx"],
|
|
@@ -2568,8 +2569,8 @@ var GrammarLoader = class {
|
|
|
2568
2569
|
throw err;
|
|
2569
2570
|
}
|
|
2570
2571
|
}
|
|
2571
|
-
_loadModule(path$
|
|
2572
|
-
return __require(path$
|
|
2572
|
+
_loadModule(path$4) {
|
|
2573
|
+
return __require(path$4);
|
|
2573
2574
|
}
|
|
2574
2575
|
};
|
|
2575
2576
|
|
|
@@ -2617,9 +2618,9 @@ const ERR_REPO_MAP_GIT_FAILED = "ERR_REPO_MAP_GIT_FAILED";
|
|
|
2617
2618
|
var SymbolParser = class {
|
|
2618
2619
|
_grammarLoader;
|
|
2619
2620
|
_logger;
|
|
2620
|
-
constructor(grammarLoader, logger$
|
|
2621
|
+
constructor(grammarLoader, logger$26) {
|
|
2621
2622
|
this._grammarLoader = grammarLoader;
|
|
2622
|
-
this._logger = logger$
|
|
2623
|
+
this._logger = logger$26;
|
|
2623
2624
|
}
|
|
2624
2625
|
async parseFile(filePath) {
|
|
2625
2626
|
const ext$2 = extname$1(filePath);
|
|
@@ -2764,9 +2765,9 @@ async function computeFileHash(filePath) {
|
|
|
2764
2765
|
var DoltSymbolRepository = class {
|
|
2765
2766
|
_client;
|
|
2766
2767
|
_logger;
|
|
2767
|
-
constructor(client, logger$
|
|
2768
|
+
constructor(client, logger$26) {
|
|
2768
2769
|
this._client = client;
|
|
2769
|
-
this._logger = logger$
|
|
2770
|
+
this._logger = logger$26;
|
|
2770
2771
|
}
|
|
2771
2772
|
/**
|
|
2772
2773
|
* Atomically replace all symbols for filePath.
|
|
@@ -2972,11 +2973,11 @@ var RepoMapStorage = class {
|
|
|
2972
2973
|
_metaRepo;
|
|
2973
2974
|
_gitClient;
|
|
2974
2975
|
_logger;
|
|
2975
|
-
constructor(symbolRepo, metaRepo, gitClient, logger$
|
|
2976
|
+
constructor(symbolRepo, metaRepo, gitClient, logger$26) {
|
|
2976
2977
|
this._symbolRepo = symbolRepo;
|
|
2977
2978
|
this._metaRepo = metaRepo;
|
|
2978
2979
|
this._gitClient = gitClient;
|
|
2979
|
-
this._logger = logger$
|
|
2980
|
+
this._logger = logger$26;
|
|
2980
2981
|
}
|
|
2981
2982
|
/**
|
|
2982
2983
|
* Returns true if the file's current content hash differs from the stored hash.
|
|
@@ -3093,8 +3094,8 @@ function runGit(args, cwd) {
|
|
|
3093
3094
|
*/
|
|
3094
3095
|
var GitClient = class {
|
|
3095
3096
|
_logger;
|
|
3096
|
-
constructor(logger$
|
|
3097
|
-
this._logger = logger$
|
|
3097
|
+
constructor(logger$26) {
|
|
3098
|
+
this._logger = logger$26;
|
|
3098
3099
|
}
|
|
3099
3100
|
/**
|
|
3100
3101
|
* Returns the current HEAD commit SHA.
|
|
@@ -3926,12 +3927,12 @@ const qmarksTestNoExtDot$1 = ([$0]) => {
|
|
|
3926
3927
|
};
|
|
3927
3928
|
/* c8 ignore start */
|
|
3928
3929
|
const defaultPlatform$3 = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
3929
|
-
const path$
|
|
3930
|
+
const path$3 = {
|
|
3930
3931
|
win32: { sep: "\\" },
|
|
3931
3932
|
posix: { sep: "/" }
|
|
3932
3933
|
};
|
|
3933
3934
|
/* c8 ignore stop */
|
|
3934
|
-
const sep$1 = defaultPlatform$3 === "win32" ? path$
|
|
3935
|
+
const sep$1 = defaultPlatform$3 === "win32" ? path$3.win32.sep : path$3.posix.sep;
|
|
3935
3936
|
minimatch$1.sep = sep$1;
|
|
3936
3937
|
const GLOBSTAR$1 = Symbol("globstar **");
|
|
3937
3938
|
minimatch$1.GLOBSTAR = GLOBSTAR$1;
|
|
@@ -4450,9 +4451,9 @@ var RepoMapQueryEngine = class {
|
|
|
4450
4451
|
repo;
|
|
4451
4452
|
logger;
|
|
4452
4453
|
telemetry;
|
|
4453
|
-
constructor(repo, logger$
|
|
4454
|
+
constructor(repo, logger$26, telemetry) {
|
|
4454
4455
|
this.repo = repo;
|
|
4455
|
-
this.logger = logger$
|
|
4456
|
+
this.logger = logger$26;
|
|
4456
4457
|
this.telemetry = telemetry;
|
|
4457
4458
|
}
|
|
4458
4459
|
async query(q) {
|
|
@@ -4672,9 +4673,9 @@ var RepoMapFormatter = class {
|
|
|
4672
4673
|
var RepoMapTelemetry = class {
|
|
4673
4674
|
_telemetry;
|
|
4674
4675
|
_logger;
|
|
4675
|
-
constructor(telemetry, logger$
|
|
4676
|
+
constructor(telemetry, logger$26) {
|
|
4676
4677
|
this._telemetry = telemetry;
|
|
4677
|
-
this._logger = logger$
|
|
4678
|
+
this._logger = logger$26;
|
|
4678
4679
|
}
|
|
4679
4680
|
/**
|
|
4680
4681
|
* Emit a `repo_map.query` span.
|
|
@@ -4699,9 +4700,9 @@ var RepoMapTelemetry = class {
|
|
|
4699
4700
|
var RepoMapModule = class {
|
|
4700
4701
|
_metaRepo;
|
|
4701
4702
|
_logger;
|
|
4702
|
-
constructor(metaRepo, logger$
|
|
4703
|
+
constructor(metaRepo, logger$26) {
|
|
4703
4704
|
this._metaRepo = metaRepo;
|
|
4704
|
-
this._logger = logger$
|
|
4705
|
+
this._logger = logger$26;
|
|
4705
4706
|
}
|
|
4706
4707
|
/**
|
|
4707
4708
|
* Check whether the stored repo-map is stale relative to the current HEAD commit.
|
|
@@ -4745,9 +4746,9 @@ var RepoMapModule = class {
|
|
|
4745
4746
|
var RepoMapInjector = class {
|
|
4746
4747
|
_queryEngine;
|
|
4747
4748
|
_logger;
|
|
4748
|
-
constructor(queryEngine, logger$
|
|
4749
|
+
constructor(queryEngine, logger$26) {
|
|
4749
4750
|
this._queryEngine = queryEngine;
|
|
4750
|
-
this._logger = logger$
|
|
4751
|
+
this._logger = logger$26;
|
|
4751
4752
|
}
|
|
4752
4753
|
/**
|
|
4753
4754
|
* Build repo-map context by extracting file references from the story content,
|
|
@@ -4823,12 +4824,13 @@ const DEFAULT_TIMEOUTS = {
|
|
|
4823
4824
|
"arch-decisions": 24e4,
|
|
4824
4825
|
"arch-patterns": 24e4,
|
|
4825
4826
|
"story-epics": 24e4,
|
|
4826
|
-
"story-stories": 6e5
|
|
4827
|
+
"story-stories": 6e5,
|
|
4828
|
+
"probe-author": 3e5
|
|
4827
4829
|
};
|
|
4828
4830
|
|
|
4829
4831
|
//#endregion
|
|
4830
4832
|
//#region src/modules/agent-dispatch/dispatcher-impl.ts
|
|
4831
|
-
const logger$
|
|
4833
|
+
const logger$23 = createLogger("agent-dispatch");
|
|
4832
4834
|
/**
|
|
4833
4835
|
* Create a new Dispatcher instance.
|
|
4834
4836
|
*
|
|
@@ -4972,7 +4974,7 @@ function runBuildVerification(options) {
|
|
|
4972
4974
|
let cmd;
|
|
4973
4975
|
if (verifyCommand === void 0) {
|
|
4974
4976
|
const detection = detectPackageManager(projectRoot);
|
|
4975
|
-
logger$
|
|
4977
|
+
logger$23.info({
|
|
4976
4978
|
packageManager: detection.packageManager,
|
|
4977
4979
|
lockfile: detection.lockfile,
|
|
4978
4980
|
resolvedCommand: detection.command
|
|
@@ -4984,7 +4986,7 @@ function runBuildVerification(options) {
|
|
|
4984
4986
|
const filters = deriveTurboFilters(changedFiles, projectRoot);
|
|
4985
4987
|
if (filters.length > 0) {
|
|
4986
4988
|
cmd = `${cmd} ${filters.join(" ")}`;
|
|
4987
|
-
logger$
|
|
4989
|
+
logger$23.info({
|
|
4988
4990
|
filters,
|
|
4989
4991
|
originalCmd: options.verifyCommand ?? "(auto-detected)"
|
|
4990
4992
|
}, "Build verification: scoped turbo build to affected packages");
|
|
@@ -5027,7 +5029,7 @@ function runBuildVerification(options) {
|
|
|
5027
5029
|
};
|
|
5028
5030
|
const missingScriptPattern = /Missing script[:\s]|No script found|Command "build" not found/i;
|
|
5029
5031
|
if (missingScriptPattern.test(combinedOutput)) {
|
|
5030
|
-
logger$
|
|
5032
|
+
logger$23.warn("Build script not found — skipping pre-flight (greenfield repo)");
|
|
5031
5033
|
return {
|
|
5032
5034
|
status: "skipped",
|
|
5033
5035
|
exitCode,
|
|
@@ -5037,7 +5039,7 @@ function runBuildVerification(options) {
|
|
|
5037
5039
|
}
|
|
5038
5040
|
const pep668Pattern = /externally-managed-environment|This environment is externally managed/i;
|
|
5039
5041
|
if (pep668Pattern.test(combinedOutput)) {
|
|
5040
|
-
logger$
|
|
5042
|
+
logger$23.warn("PEP 668: pip blocked by externally-managed-environment — skipping pre-flight. Create a .venv to resolve.");
|
|
5041
5043
|
return {
|
|
5042
5044
|
status: "skipped",
|
|
5043
5045
|
exitCode,
|
|
@@ -5221,7 +5223,7 @@ function pickRecommendation(distribution, profile, totalIssues, reviewCycles, la
|
|
|
5221
5223
|
|
|
5222
5224
|
//#endregion
|
|
5223
5225
|
//#region src/modules/implementation-orchestrator/project-findings.ts
|
|
5224
|
-
const logger$
|
|
5226
|
+
const logger$22 = createLogger("project-findings");
|
|
5225
5227
|
/** Maximum character length for the findings summary */
|
|
5226
5228
|
const MAX_CHARS = 2e3;
|
|
5227
5229
|
/**
|
|
@@ -5294,7 +5296,7 @@ async function getProjectFindings(db) {
|
|
|
5294
5296
|
if (summary.length > MAX_CHARS) summary = summary.slice(0, MAX_CHARS - 3) + "...";
|
|
5295
5297
|
return summary;
|
|
5296
5298
|
} catch (err) {
|
|
5297
|
-
logger$
|
|
5299
|
+
logger$22.warn({ err }, "Failed to query project findings (graceful fallback)");
|
|
5298
5300
|
return "";
|
|
5299
5301
|
}
|
|
5300
5302
|
}
|
|
@@ -5317,7 +5319,7 @@ function extractRecurringPatterns(outcomes) {
|
|
|
5317
5319
|
|
|
5318
5320
|
//#endregion
|
|
5319
5321
|
//#region src/modules/compiled-workflows/prompt-assembler.ts
|
|
5320
|
-
const logger$
|
|
5322
|
+
const logger$21 = createLogger("compiled-workflows:prompt-assembler");
|
|
5321
5323
|
/**
|
|
5322
5324
|
* Assemble a final prompt from a template and sections map.
|
|
5323
5325
|
*
|
|
@@ -5342,7 +5344,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5342
5344
|
tokenCount,
|
|
5343
5345
|
truncated: false
|
|
5344
5346
|
};
|
|
5345
|
-
logger$
|
|
5347
|
+
logger$21.warn({
|
|
5346
5348
|
tokenCount,
|
|
5347
5349
|
ceiling: tokenCeiling
|
|
5348
5350
|
}, "Prompt exceeds token ceiling — truncating optional sections");
|
|
@@ -5358,10 +5360,10 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5358
5360
|
const targetSectionTokens = Math.max(0, currentSectionTokens - overBy);
|
|
5359
5361
|
if (targetSectionTokens === 0) {
|
|
5360
5362
|
contentMap[section.name] = "";
|
|
5361
|
-
logger$
|
|
5363
|
+
logger$21.warn({ sectionName: section.name }, "Section eliminated to fit token budget");
|
|
5362
5364
|
} else {
|
|
5363
5365
|
contentMap[section.name] = truncateToTokens(section.content, targetSectionTokens);
|
|
5364
|
-
logger$
|
|
5366
|
+
logger$21.warn({
|
|
5365
5367
|
sectionName: section.name,
|
|
5366
5368
|
targetSectionTokens
|
|
5367
5369
|
}, "Section truncated to fit token budget");
|
|
@@ -5372,7 +5374,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5372
5374
|
}
|
|
5373
5375
|
if (tokenCount <= tokenCeiling) break;
|
|
5374
5376
|
}
|
|
5375
|
-
if (tokenCount > tokenCeiling) logger$
|
|
5377
|
+
if (tokenCount > tokenCeiling) logger$21.warn({
|
|
5376
5378
|
tokenCount,
|
|
5377
5379
|
ceiling: tokenCeiling
|
|
5378
5380
|
}, "Required sections alone exceed token ceiling — returning over-budget prompt");
|
|
@@ -5633,6 +5635,43 @@ const TestExpansionResultSchema = z.object({
|
|
|
5633
5635
|
suggested_tests: z.array(SuggestedTestSchema).default([]),
|
|
5634
5636
|
notes: z.string().optional()
|
|
5635
5637
|
});
|
|
5638
|
+
/**
|
|
5639
|
+
* Inline mirror of RuntimeProbeSchema from @substrate-ai/sdlc.
|
|
5640
|
+
*
|
|
5641
|
+
* Inlined here instead of imported to avoid triggering Vitest's mock validation
|
|
5642
|
+
* error in orchestrator tests that mock @substrate-ai/sdlc without including
|
|
5643
|
+
* RuntimeProbeListSchema. The canonical definition lives in
|
|
5644
|
+
* packages/sdlc/src/verification/probes/types.ts — keep in sync when that
|
|
5645
|
+
* schema changes.
|
|
5646
|
+
*/
|
|
5647
|
+
const InlineRuntimeProbeSchema = z.object({
|
|
5648
|
+
name: z.string().min(1, "probe name is required"),
|
|
5649
|
+
sandbox: z.enum(["host", "twin"]),
|
|
5650
|
+
command: z.string().min(1, "probe command is required"),
|
|
5651
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
5652
|
+
description: z.string().optional(),
|
|
5653
|
+
expect_stdout_no_regex: z.array(z.string().min(1)).optional(),
|
|
5654
|
+
expect_stdout_regex: z.array(z.string().min(1)).optional()
|
|
5655
|
+
});
|
|
5656
|
+
const InlineRuntimeProbeListSchema = z.array(InlineRuntimeProbeSchema);
|
|
5657
|
+
/**
|
|
5658
|
+
* Schema for the YAML output contract of the probe-author sub-agent.
|
|
5659
|
+
*
|
|
5660
|
+
* The agent emits a yaml block containing result and probes list.
|
|
5661
|
+
* The probes field is validated against the RuntimeProbe shape from @substrate-ai/sdlc
|
|
5662
|
+
* (inlined to avoid module mock conflicts in orchestrator unit tests).
|
|
5663
|
+
*
|
|
5664
|
+
* Example:
|
|
5665
|
+
* result: success
|
|
5666
|
+
* probes:
|
|
5667
|
+
* - name: my-probe
|
|
5668
|
+
* sandbox: host
|
|
5669
|
+
* command: echo "hello"
|
|
5670
|
+
*/
|
|
5671
|
+
const ProbeAuthorResultSchema = z.object({
|
|
5672
|
+
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
5673
|
+
probes: InlineRuntimeProbeListSchema
|
|
5674
|
+
});
|
|
5636
5675
|
|
|
5637
5676
|
//#endregion
|
|
5638
5677
|
//#region src/modules/compiled-workflows/token-ceiling.ts
|
|
@@ -5645,7 +5684,8 @@ const TOKEN_CEILING_DEFAULTS = {
|
|
|
5645
5684
|
"dev-story": 4e5,
|
|
5646
5685
|
"code-review": 5e5,
|
|
5647
5686
|
"test-plan": 1e5,
|
|
5648
|
-
"test-expansion": 2e5
|
|
5687
|
+
"test-expansion": 2e5,
|
|
5688
|
+
"probe-author": 5e4
|
|
5649
5689
|
};
|
|
5650
5690
|
/**
|
|
5651
5691
|
* Resolve the effective token ceiling for a workflow type.
|
|
@@ -5674,7 +5714,7 @@ function getTokenCeiling(workflowType, tokenCeilings) {
|
|
|
5674
5714
|
|
|
5675
5715
|
//#endregion
|
|
5676
5716
|
//#region src/modules/compiled-workflows/create-story.ts
|
|
5677
|
-
const logger$
|
|
5717
|
+
const logger$20 = createLogger("compiled-workflows:create-story");
|
|
5678
5718
|
/**
|
|
5679
5719
|
* Compute a hex SHA-256 of the normalized source AC section text.
|
|
5680
5720
|
*
|
|
@@ -5709,13 +5749,13 @@ function hashSourceAcSection(section) {
|
|
|
5709
5749
|
*/
|
|
5710
5750
|
async function runCreateStory(deps, params) {
|
|
5711
5751
|
const { epicId, storyKey, pipelineRunId, source_ac_hash, priorDriftFeedback } = params;
|
|
5712
|
-
logger$
|
|
5752
|
+
logger$20.debug({
|
|
5713
5753
|
epicId,
|
|
5714
5754
|
storyKey,
|
|
5715
5755
|
pipelineRunId
|
|
5716
5756
|
}, "Starting create-story workflow");
|
|
5717
5757
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("create-story", deps.tokenCeilings);
|
|
5718
|
-
logger$
|
|
5758
|
+
logger$20.info({
|
|
5719
5759
|
workflow: "create-story",
|
|
5720
5760
|
ceiling: TOKEN_CEILING,
|
|
5721
5761
|
source: tokenCeilingSource
|
|
@@ -5725,7 +5765,7 @@ async function runCreateStory(deps, params) {
|
|
|
5725
5765
|
template = await deps.pack.getPrompt("create-story");
|
|
5726
5766
|
} catch (err) {
|
|
5727
5767
|
const error = err instanceof Error ? err.message : String(err);
|
|
5728
|
-
logger$
|
|
5768
|
+
logger$20.error({ error }, "Failed to retrieve create-story prompt template");
|
|
5729
5769
|
return {
|
|
5730
5770
|
result: "failed",
|
|
5731
5771
|
error: `Failed to retrieve prompt template: ${error}`,
|
|
@@ -5742,7 +5782,7 @@ async function runCreateStory(deps, params) {
|
|
|
5742
5782
|
const storySection = extractStorySection(epicShardContent, storyKey);
|
|
5743
5783
|
if (storySection !== null) {
|
|
5744
5784
|
const computedHash = hashSourceAcSection(storySection);
|
|
5745
|
-
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$
|
|
5785
|
+
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$20.debug({
|
|
5746
5786
|
storyKey,
|
|
5747
5787
|
suppliedHash: source_ac_hash,
|
|
5748
5788
|
computedHash
|
|
@@ -5757,7 +5797,7 @@ async function runCreateStory(deps, params) {
|
|
|
5757
5797
|
const storyDef = storyDecisions.find((d) => d.category === "stories" && d.key === storyKey);
|
|
5758
5798
|
if (storyDef) {
|
|
5759
5799
|
storyDefinitionContent = storyDef.value;
|
|
5760
|
-
logger$
|
|
5800
|
+
logger$20.debug({ storyKey }, "Injected story definition from solutioning decisions");
|
|
5761
5801
|
}
|
|
5762
5802
|
} catch {}
|
|
5763
5803
|
const archConstraintsContent = await getArchConstraints$3(deps);
|
|
@@ -5808,7 +5848,7 @@ async function runCreateStory(deps, params) {
|
|
|
5808
5848
|
priority: "optional"
|
|
5809
5849
|
}]
|
|
5810
5850
|
], TOKEN_CEILING);
|
|
5811
|
-
logger$
|
|
5851
|
+
logger$20.debug({
|
|
5812
5852
|
tokenCount,
|
|
5813
5853
|
truncated,
|
|
5814
5854
|
tokenCeiling: TOKEN_CEILING
|
|
@@ -5828,7 +5868,7 @@ async function runCreateStory(deps, params) {
|
|
|
5828
5868
|
dispatchResult = await handle.result;
|
|
5829
5869
|
} catch (err) {
|
|
5830
5870
|
const error = err instanceof Error ? err.message : String(err);
|
|
5831
|
-
logger$
|
|
5871
|
+
logger$20.error({
|
|
5832
5872
|
epicId,
|
|
5833
5873
|
storyKey,
|
|
5834
5874
|
error
|
|
@@ -5849,7 +5889,7 @@ async function runCreateStory(deps, params) {
|
|
|
5849
5889
|
if (dispatchResult.status === "failed") {
|
|
5850
5890
|
const errorMsg = dispatchResult.parseError ?? `Dispatch failed with exit code ${dispatchResult.exitCode}`;
|
|
5851
5891
|
const stderrDetail = dispatchResult.output ? ` Output: ${dispatchResult.output}` : "";
|
|
5852
|
-
logger$
|
|
5892
|
+
logger$20.warn({
|
|
5853
5893
|
epicId,
|
|
5854
5894
|
storyKey,
|
|
5855
5895
|
exitCode: dispatchResult.exitCode,
|
|
@@ -5862,7 +5902,7 @@ async function runCreateStory(deps, params) {
|
|
|
5862
5902
|
};
|
|
5863
5903
|
}
|
|
5864
5904
|
if (dispatchResult.status === "timeout") {
|
|
5865
|
-
logger$
|
|
5905
|
+
logger$20.warn({
|
|
5866
5906
|
epicId,
|
|
5867
5907
|
storyKey
|
|
5868
5908
|
}, "Create-story dispatch timed out");
|
|
@@ -5875,7 +5915,7 @@ async function runCreateStory(deps, params) {
|
|
|
5875
5915
|
if (dispatchResult.parsed === null) {
|
|
5876
5916
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
5877
5917
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
5878
|
-
logger$
|
|
5918
|
+
logger$20.warn({
|
|
5879
5919
|
epicId,
|
|
5880
5920
|
storyKey,
|
|
5881
5921
|
details,
|
|
@@ -5891,7 +5931,7 @@ async function runCreateStory(deps, params) {
|
|
|
5891
5931
|
const parseResult = CreateStoryResultSchema.safeParse(dispatchResult.parsed);
|
|
5892
5932
|
if (!parseResult.success) {
|
|
5893
5933
|
const details = parseResult.error.message;
|
|
5894
|
-
logger$
|
|
5934
|
+
logger$20.warn({
|
|
5895
5935
|
epicId,
|
|
5896
5936
|
storyKey,
|
|
5897
5937
|
details
|
|
@@ -5904,7 +5944,7 @@ async function runCreateStory(deps, params) {
|
|
|
5904
5944
|
};
|
|
5905
5945
|
}
|
|
5906
5946
|
const parsed = parseResult.data;
|
|
5907
|
-
logger$
|
|
5947
|
+
logger$20.info({
|
|
5908
5948
|
epicId,
|
|
5909
5949
|
storyKey,
|
|
5910
5950
|
storyFile: parsed.story_file,
|
|
@@ -5932,7 +5972,7 @@ async function getImplementationDecisions(deps, pipelineRunId) {
|
|
|
5932
5972
|
}
|
|
5933
5973
|
return await getDecisionsByPhase(deps.db, "implementation");
|
|
5934
5974
|
} catch (err) {
|
|
5935
|
-
logger$
|
|
5975
|
+
logger$20.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve implementation decisions");
|
|
5936
5976
|
return [];
|
|
5937
5977
|
}
|
|
5938
5978
|
}
|
|
@@ -6019,10 +6059,10 @@ function computeStoryFileFidelity(storyFileContent, namedPaths) {
|
|
|
6019
6059
|
};
|
|
6020
6060
|
const missing = [];
|
|
6021
6061
|
const present = [];
|
|
6022
|
-
for (const path$
|
|
6023
|
-
const basename$2 = path$
|
|
6024
|
-
if (storyFileContent.includes(path$
|
|
6025
|
-
else missing.push(path$
|
|
6062
|
+
for (const path$4 of namedPaths) {
|
|
6063
|
+
const basename$2 = path$4.includes("/") ? path$4.slice(path$4.lastIndexOf("/") + 1) : path$4;
|
|
6064
|
+
if (storyFileContent.includes(path$4) || storyFileContent.includes(basename$2)) present.push(path$4);
|
|
6065
|
+
else missing.push(path$4);
|
|
6026
6066
|
}
|
|
6027
6067
|
return {
|
|
6028
6068
|
missing,
|
|
@@ -6134,7 +6174,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6134
6174
|
if (storyKey) {
|
|
6135
6175
|
const perStoryShard = decisions.find((d) => d.category === "epic-shard" && d.key === storyKey);
|
|
6136
6176
|
if (perStoryShard?.value) {
|
|
6137
|
-
logger$
|
|
6177
|
+
logger$20.debug({
|
|
6138
6178
|
epicId,
|
|
6139
6179
|
storyKey
|
|
6140
6180
|
}, "Found per-story epic shard (direct lookup)");
|
|
@@ -6146,13 +6186,13 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6146
6186
|
if (shardContent && storyKey) {
|
|
6147
6187
|
const storySection = extractStorySection(shardContent, storyKey);
|
|
6148
6188
|
if (storySection) {
|
|
6149
|
-
logger$
|
|
6189
|
+
logger$20.debug({
|
|
6150
6190
|
epicId,
|
|
6151
6191
|
storyKey
|
|
6152
6192
|
}, "Extracted per-story section from epic shard (pre-37-0 fallback)");
|
|
6153
6193
|
return storySection;
|
|
6154
6194
|
}
|
|
6155
|
-
logger$
|
|
6195
|
+
logger$20.info({
|
|
6156
6196
|
epicId,
|
|
6157
6197
|
storyKey
|
|
6158
6198
|
}, "Story section absent in decisions-store shard — attempting file-based fallback before returning stale shard");
|
|
@@ -6160,11 +6200,11 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6160
6200
|
if (projectRoot) {
|
|
6161
6201
|
const fallback = readEpicShardFromFile(projectRoot, epicId);
|
|
6162
6202
|
if (fallback) {
|
|
6163
|
-
logger$
|
|
6203
|
+
logger$20.info({ epicId }, "Using file-based fallback for epic shard");
|
|
6164
6204
|
if (storyKey) {
|
|
6165
6205
|
const storySection = extractStorySection(fallback, storyKey);
|
|
6166
6206
|
if (storySection) {
|
|
6167
|
-
logger$
|
|
6207
|
+
logger$20.debug({
|
|
6168
6208
|
epicId,
|
|
6169
6209
|
storyKey
|
|
6170
6210
|
}, "Extracted per-story section from file-based epic shard");
|
|
@@ -6177,7 +6217,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6177
6217
|
if (shardContent) return shardContent;
|
|
6178
6218
|
return "";
|
|
6179
6219
|
} catch (err) {
|
|
6180
|
-
logger$
|
|
6220
|
+
logger$20.warn({
|
|
6181
6221
|
epicId,
|
|
6182
6222
|
error: err instanceof Error ? err.message : String(err)
|
|
6183
6223
|
}, "Failed to retrieve epic shard");
|
|
@@ -6194,7 +6234,7 @@ function getPrevDevNotes(decisions, epicId) {
|
|
|
6194
6234
|
if (devNotes.length === 0) return "";
|
|
6195
6235
|
return devNotes[devNotes.length - 1].value;
|
|
6196
6236
|
} catch (err) {
|
|
6197
|
-
logger$
|
|
6237
|
+
logger$20.warn({
|
|
6198
6238
|
epicId,
|
|
6199
6239
|
error: err instanceof Error ? err.message : String(err)
|
|
6200
6240
|
}, "Failed to retrieve prev dev notes");
|
|
@@ -6227,7 +6267,7 @@ async function getArchConstraints$3(deps) {
|
|
|
6227
6267
|
const truncatedBody = body.length > 300 ? body.slice(0, 297) + "..." : body;
|
|
6228
6268
|
return `${header}\n${truncatedBody}`;
|
|
6229
6269
|
}).join("\n\n");
|
|
6230
|
-
logger$
|
|
6270
|
+
logger$20.info({
|
|
6231
6271
|
fullLength: full.length,
|
|
6232
6272
|
summarizedLength: summarized.length,
|
|
6233
6273
|
decisions: constraints.length
|
|
@@ -6237,13 +6277,13 @@ async function getArchConstraints$3(deps) {
|
|
|
6237
6277
|
if (deps.projectRoot) {
|
|
6238
6278
|
const fallback = readArchConstraintsFromFile(deps.projectRoot);
|
|
6239
6279
|
if (fallback) {
|
|
6240
|
-
logger$
|
|
6280
|
+
logger$20.info("Using file-based fallback for architecture constraints (decisions table empty)");
|
|
6241
6281
|
return fallback.length > ARCH_CONSTRAINT_MAX_CHARS ? fallback.slice(0, ARCH_CONSTRAINT_MAX_CHARS) + "\n\n[truncated for token budget]" : fallback;
|
|
6242
6282
|
}
|
|
6243
6283
|
}
|
|
6244
6284
|
return "";
|
|
6245
6285
|
} catch (err) {
|
|
6246
|
-
logger$
|
|
6286
|
+
logger$20.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
6247
6287
|
return "";
|
|
6248
6288
|
}
|
|
6249
6289
|
}
|
|
@@ -6296,7 +6336,7 @@ function readEpicShardFromFile(projectRoot, epicId) {
|
|
|
6296
6336
|
} catch {}
|
|
6297
6337
|
return "";
|
|
6298
6338
|
} catch (err) {
|
|
6299
|
-
logger$
|
|
6339
|
+
logger$20.warn({
|
|
6300
6340
|
epicId,
|
|
6301
6341
|
error: err instanceof Error ? err.message : String(err)
|
|
6302
6342
|
}, "File-based epic shard fallback failed");
|
|
@@ -6319,7 +6359,7 @@ function readArchConstraintsFromFile(projectRoot) {
|
|
|
6319
6359
|
const content = readFileSync(archPath, "utf-8");
|
|
6320
6360
|
return content.slice(0, 1500);
|
|
6321
6361
|
} catch (err) {
|
|
6322
|
-
logger$
|
|
6362
|
+
logger$20.warn({ error: err instanceof Error ? err.message : String(err) }, "File-based architecture fallback failed");
|
|
6323
6363
|
return "";
|
|
6324
6364
|
}
|
|
6325
6365
|
}
|
|
@@ -6332,7 +6372,7 @@ async function getStoryTemplate(deps) {
|
|
|
6332
6372
|
try {
|
|
6333
6373
|
return await deps.pack.getTemplate("story");
|
|
6334
6374
|
} catch (err) {
|
|
6335
|
-
logger$
|
|
6375
|
+
logger$20.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve story template from pack");
|
|
6336
6376
|
return "";
|
|
6337
6377
|
}
|
|
6338
6378
|
}
|
|
@@ -6369,7 +6409,7 @@ async function isValidStoryFile(filePath) {
|
|
|
6369
6409
|
|
|
6370
6410
|
//#endregion
|
|
6371
6411
|
//#region src/modules/compiled-workflows/git-helpers.ts
|
|
6372
|
-
const logger$
|
|
6412
|
+
const logger$19 = createLogger("compiled-workflows:git-helpers");
|
|
6373
6413
|
/**
|
|
6374
6414
|
* Check whether the repo at `cwd` has at least one commit (HEAD resolves).
|
|
6375
6415
|
* Returns false for fresh repos with no commits, avoiding `fatal: bad revision 'HEAD'`.
|
|
@@ -6406,7 +6446,7 @@ function hasCommits(cwd) {
|
|
|
6406
6446
|
*/
|
|
6407
6447
|
async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
6408
6448
|
if (!hasCommits(workingDirectory)) {
|
|
6409
|
-
logger$
|
|
6449
|
+
logger$19.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff");
|
|
6410
6450
|
return "";
|
|
6411
6451
|
}
|
|
6412
6452
|
return runGitCommand(["diff", "HEAD"], workingDirectory, "git-diff-summary");
|
|
@@ -6423,7 +6463,7 @@ async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
|
6423
6463
|
*/
|
|
6424
6464
|
async function getGitDiffStatSummary(workingDirectory = process.cwd()) {
|
|
6425
6465
|
if (!hasCommits(workingDirectory)) {
|
|
6426
|
-
logger$
|
|
6466
|
+
logger$19.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat");
|
|
6427
6467
|
return "";
|
|
6428
6468
|
}
|
|
6429
6469
|
return runGitCommand([
|
|
@@ -6472,7 +6512,7 @@ async function getGitDiffStatBetweenCommits(baseCommit, endCommit = "HEAD", work
|
|
|
6472
6512
|
async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
6473
6513
|
if (files.length === 0) return "";
|
|
6474
6514
|
if (!hasCommits(workingDirectory)) {
|
|
6475
|
-
logger$
|
|
6515
|
+
logger$19.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff for files");
|
|
6476
6516
|
return "";
|
|
6477
6517
|
}
|
|
6478
6518
|
await stageIntentToAdd(files, workingDirectory);
|
|
@@ -6499,7 +6539,7 @@ async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
|
6499
6539
|
async function getGitDiffStatForFiles(files, workingDirectory = process.cwd()) {
|
|
6500
6540
|
if (files.length === 0) return "";
|
|
6501
6541
|
if (!hasCommits(workingDirectory)) {
|
|
6502
|
-
logger$
|
|
6542
|
+
logger$19.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat for files");
|
|
6503
6543
|
return "";
|
|
6504
6544
|
}
|
|
6505
6545
|
return runGitCommand([
|
|
@@ -6548,7 +6588,7 @@ async function stageIntentToAdd(files, workingDirectory) {
|
|
|
6548
6588
|
if (files.length === 0) return;
|
|
6549
6589
|
const existing = files.filter((f$1) => {
|
|
6550
6590
|
const exists = existsSync(f$1);
|
|
6551
|
-
if (!exists) logger$
|
|
6591
|
+
if (!exists) logger$19.debug({ file: f$1 }, "Skipping nonexistent file in stageIntentToAdd");
|
|
6552
6592
|
return exists;
|
|
6553
6593
|
});
|
|
6554
6594
|
if (existing.length === 0) return;
|
|
@@ -6582,7 +6622,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6582
6622
|
stderr += chunk.toString("utf-8");
|
|
6583
6623
|
});
|
|
6584
6624
|
proc$1.on("error", (err) => {
|
|
6585
|
-
logger$
|
|
6625
|
+
logger$19.warn({
|
|
6586
6626
|
label: logLabel,
|
|
6587
6627
|
cwd,
|
|
6588
6628
|
error: err.message
|
|
@@ -6591,7 +6631,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6591
6631
|
});
|
|
6592
6632
|
proc$1.on("close", (code) => {
|
|
6593
6633
|
if (code !== 0) {
|
|
6594
|
-
logger$
|
|
6634
|
+
logger$19.warn({
|
|
6595
6635
|
label: logLabel,
|
|
6596
6636
|
cwd,
|
|
6597
6637
|
code,
|
|
@@ -6607,7 +6647,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6607
6647
|
|
|
6608
6648
|
//#endregion
|
|
6609
6649
|
//#region src/modules/compiled-workflows/story-complexity.ts
|
|
6610
|
-
const logger$
|
|
6650
|
+
const logger$18 = createLogger("compiled-workflows:story-complexity");
|
|
6611
6651
|
/**
|
|
6612
6652
|
* Compute a complexity score from story markdown content.
|
|
6613
6653
|
*
|
|
@@ -6659,7 +6699,7 @@ function resolveFixStoryMaxTurns(complexityScore) {
|
|
|
6659
6699
|
* @param resolvedMaxTurns - Turn limit resolved for this dispatch
|
|
6660
6700
|
*/
|
|
6661
6701
|
function logComplexityResult(storyKey, complexity, resolvedMaxTurns) {
|
|
6662
|
-
logger$
|
|
6702
|
+
logger$18.info({
|
|
6663
6703
|
storyKey,
|
|
6664
6704
|
taskCount: complexity.taskCount,
|
|
6665
6705
|
subtaskCount: complexity.subtaskCount,
|
|
@@ -6915,9 +6955,9 @@ function resolveInstallCommand(projectRoot) {
|
|
|
6915
6955
|
|
|
6916
6956
|
//#endregion
|
|
6917
6957
|
//#region src/modules/compiled-workflows/dev-story.ts
|
|
6918
|
-
const logger$
|
|
6958
|
+
const logger$17 = createLogger("compiled-workflows:dev-story");
|
|
6919
6959
|
/** Default timeout for dev-story dispatches in milliseconds (30 min) */
|
|
6920
|
-
const DEFAULT_TIMEOUT_MS$
|
|
6960
|
+
const DEFAULT_TIMEOUT_MS$2 = 18e5;
|
|
6921
6961
|
/**
|
|
6922
6962
|
* Execute the compiled dev-story workflow.
|
|
6923
6963
|
*
|
|
@@ -6927,12 +6967,12 @@ const DEFAULT_TIMEOUT_MS$1 = 18e5;
|
|
|
6927
6967
|
*/
|
|
6928
6968
|
async function runDevStory(deps, params) {
|
|
6929
6969
|
const { storyKey, storyFilePath, taskScope, priorFiles, findingsPrompt: handlerFindingsPrompt } = params;
|
|
6930
|
-
logger$
|
|
6970
|
+
logger$17.info({
|
|
6931
6971
|
storyKey,
|
|
6932
6972
|
storyFilePath
|
|
6933
6973
|
}, "Starting compiled dev-story workflow");
|
|
6934
6974
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("dev-story", deps.tokenCeilings);
|
|
6935
|
-
logger$
|
|
6975
|
+
logger$17.info({
|
|
6936
6976
|
workflow: "dev-story",
|
|
6937
6977
|
ceiling: TOKEN_CEILING,
|
|
6938
6978
|
source: tokenCeilingSource
|
|
@@ -6975,10 +7015,10 @@ async function runDevStory(deps, params) {
|
|
|
6975
7015
|
let template;
|
|
6976
7016
|
try {
|
|
6977
7017
|
template = await deps.pack.getPrompt("dev-story");
|
|
6978
|
-
logger$
|
|
7018
|
+
logger$17.debug({ storyKey }, "Retrieved dev-story prompt template from pack");
|
|
6979
7019
|
} catch (err) {
|
|
6980
7020
|
const error = err instanceof Error ? err.message : String(err);
|
|
6981
|
-
logger$
|
|
7021
|
+
logger$17.error({
|
|
6982
7022
|
storyKey,
|
|
6983
7023
|
error
|
|
6984
7024
|
}, "Failed to retrieve dev-story prompt template");
|
|
@@ -6989,14 +7029,14 @@ async function runDevStory(deps, params) {
|
|
|
6989
7029
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
6990
7030
|
} catch (err) {
|
|
6991
7031
|
if (err.code === "ENOENT") {
|
|
6992
|
-
logger$
|
|
7032
|
+
logger$17.error({
|
|
6993
7033
|
storyKey,
|
|
6994
7034
|
storyFilePath
|
|
6995
7035
|
}, "Story file not found");
|
|
6996
7036
|
return makeFailureResult("story_file_not_found");
|
|
6997
7037
|
}
|
|
6998
7038
|
const error = err instanceof Error ? err.message : String(err);
|
|
6999
|
-
logger$
|
|
7039
|
+
logger$17.error({
|
|
7000
7040
|
storyKey,
|
|
7001
7041
|
storyFilePath,
|
|
7002
7042
|
error
|
|
@@ -7004,7 +7044,7 @@ async function runDevStory(deps, params) {
|
|
|
7004
7044
|
return makeFailureResult(`story_file_read_error: ${error}`);
|
|
7005
7045
|
}
|
|
7006
7046
|
if (storyContent.trim().length === 0) {
|
|
7007
|
-
logger$
|
|
7047
|
+
logger$17.error({
|
|
7008
7048
|
storyKey,
|
|
7009
7049
|
storyFilePath
|
|
7010
7050
|
}, "Story file is empty");
|
|
@@ -7012,7 +7052,7 @@ async function runDevStory(deps, params) {
|
|
|
7012
7052
|
}
|
|
7013
7053
|
const staleStatus = detectDeprecatedStatusField(storyContent);
|
|
7014
7054
|
if (staleStatus !== null) {
|
|
7015
|
-
logger$
|
|
7055
|
+
logger$17.warn({
|
|
7016
7056
|
storyFilePath,
|
|
7017
7057
|
staleStatus
|
|
7018
7058
|
}, "Story spec contains deprecated Status field — stripped before dispatch (status is managed by Dolt work graph)");
|
|
@@ -7027,17 +7067,17 @@ async function runDevStory(deps, params) {
|
|
|
7027
7067
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
7028
7068
|
if (testPatternDecisions.length > 0) {
|
|
7029
7069
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
7030
|
-
logger$
|
|
7070
|
+
logger$17.debug({
|
|
7031
7071
|
storyKey,
|
|
7032
7072
|
count: testPatternDecisions.length
|
|
7033
7073
|
}, "Loaded test patterns from decision store");
|
|
7034
7074
|
} else {
|
|
7035
7075
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
7036
|
-
logger$
|
|
7076
|
+
logger$17.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
7037
7077
|
}
|
|
7038
7078
|
} catch (err) {
|
|
7039
7079
|
const error = err instanceof Error ? err.message : String(err);
|
|
7040
|
-
logger$
|
|
7080
|
+
logger$17.warn({
|
|
7041
7081
|
storyKey,
|
|
7042
7082
|
error
|
|
7043
7083
|
}, "Failed to load test patterns — using defaults");
|
|
@@ -7051,7 +7091,7 @@ async function runDevStory(deps, params) {
|
|
|
7051
7091
|
if (deps.repoMapInjector !== void 0) {
|
|
7052
7092
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
7053
7093
|
repoContextContent = injection.text;
|
|
7054
|
-
logger$
|
|
7094
|
+
logger$17.info({
|
|
7055
7095
|
storyKey,
|
|
7056
7096
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
7057
7097
|
symbolCount: injection.symbolCount,
|
|
@@ -7061,7 +7101,7 @@ async function runDevStory(deps, params) {
|
|
|
7061
7101
|
let priorFindingsContent = "";
|
|
7062
7102
|
if (handlerFindingsPrompt !== void 0 && handlerFindingsPrompt.length > 0) {
|
|
7063
7103
|
priorFindingsContent = handlerFindingsPrompt;
|
|
7064
|
-
logger$
|
|
7104
|
+
logger$17.debug({
|
|
7065
7105
|
storyKey,
|
|
7066
7106
|
findingsLen: handlerFindingsPrompt.length
|
|
7067
7107
|
}, "Using pre-computed findings from handler (Story 53-8 AC2)");
|
|
@@ -7073,7 +7113,7 @@ async function runDevStory(deps, params) {
|
|
|
7073
7113
|
});
|
|
7074
7114
|
if (findings.length > 0) {
|
|
7075
7115
|
priorFindingsContent = findings;
|
|
7076
|
-
logger$
|
|
7116
|
+
logger$17.debug({
|
|
7077
7117
|
storyKey,
|
|
7078
7118
|
findingsLen: findings.length
|
|
7079
7119
|
}, "Injecting relevance-scored findings into dev-story prompt");
|
|
@@ -7093,7 +7133,7 @@ async function runDevStory(deps, params) {
|
|
|
7093
7133
|
if (plan.test_categories && plan.test_categories.length > 0) parts.push(`\n### Categories: ${plan.test_categories.join(", ")}`);
|
|
7094
7134
|
if (plan.coverage_notes) parts.push(`\n### Coverage Notes\n${plan.coverage_notes}`);
|
|
7095
7135
|
testPlanContent = parts.join("\n");
|
|
7096
|
-
logger$
|
|
7136
|
+
logger$17.debug({ storyKey }, "Injecting test plan into dev-story prompt");
|
|
7097
7137
|
}
|
|
7098
7138
|
} catch {}
|
|
7099
7139
|
const sections = [
|
|
@@ -7154,7 +7194,7 @@ async function runDevStory(deps, params) {
|
|
|
7154
7194
|
}
|
|
7155
7195
|
];
|
|
7156
7196
|
const { prompt, tokenCount, truncated } = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
7157
|
-
logger$
|
|
7197
|
+
logger$17.info({
|
|
7158
7198
|
storyKey,
|
|
7159
7199
|
tokenCount,
|
|
7160
7200
|
ceiling: TOKEN_CEILING,
|
|
@@ -7166,7 +7206,7 @@ async function runDevStory(deps, params) {
|
|
|
7166
7206
|
prompt,
|
|
7167
7207
|
agent: deps.agentId ?? "claude-code",
|
|
7168
7208
|
taskType: "dev-story",
|
|
7169
|
-
timeout: DEFAULT_TIMEOUT_MS$
|
|
7209
|
+
timeout: DEFAULT_TIMEOUT_MS$2,
|
|
7170
7210
|
outputSchema: DevStoryResultSchema,
|
|
7171
7211
|
maxTurns: resolvedMaxTurns,
|
|
7172
7212
|
...deps.projectRoot !== void 0 ? { workingDirectory: deps.projectRoot } : {},
|
|
@@ -7178,7 +7218,7 @@ async function runDevStory(deps, params) {
|
|
|
7178
7218
|
dispatchResult = await handle.result;
|
|
7179
7219
|
} catch (err) {
|
|
7180
7220
|
const error = err instanceof Error ? err.message : String(err);
|
|
7181
|
-
logger$
|
|
7221
|
+
logger$17.error({
|
|
7182
7222
|
storyKey,
|
|
7183
7223
|
error
|
|
7184
7224
|
}, "Dispatch threw an unexpected error");
|
|
@@ -7189,11 +7229,11 @@ async function runDevStory(deps, params) {
|
|
|
7189
7229
|
output: dispatchResult.tokenEstimate.output
|
|
7190
7230
|
};
|
|
7191
7231
|
if (dispatchResult.status === "timeout") {
|
|
7192
|
-
logger$
|
|
7232
|
+
logger$17.error({
|
|
7193
7233
|
storyKey,
|
|
7194
7234
|
durationMs: dispatchResult.durationMs
|
|
7195
7235
|
}, "Dev-story dispatch timed out");
|
|
7196
|
-
if (dispatchResult.output.length > 0) logger$
|
|
7236
|
+
if (dispatchResult.output.length > 0) logger$17.info({
|
|
7197
7237
|
storyKey,
|
|
7198
7238
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
7199
7239
|
}, "Partial output before timeout");
|
|
@@ -7203,12 +7243,12 @@ async function runDevStory(deps, params) {
|
|
|
7203
7243
|
};
|
|
7204
7244
|
}
|
|
7205
7245
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
7206
|
-
logger$
|
|
7246
|
+
logger$17.error({
|
|
7207
7247
|
storyKey,
|
|
7208
7248
|
exitCode: dispatchResult.exitCode,
|
|
7209
7249
|
status: dispatchResult.status
|
|
7210
7250
|
}, "Dev-story dispatch failed");
|
|
7211
|
-
if (dispatchResult.output.length > 0) logger$
|
|
7251
|
+
if (dispatchResult.output.length > 0) logger$17.info({
|
|
7212
7252
|
storyKey,
|
|
7213
7253
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
7214
7254
|
}, "Partial output from failed dispatch");
|
|
@@ -7220,7 +7260,7 @@ async function runDevStory(deps, params) {
|
|
|
7220
7260
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
7221
7261
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
7222
7262
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
7223
|
-
logger$
|
|
7263
|
+
logger$17.error({
|
|
7224
7264
|
storyKey,
|
|
7225
7265
|
parseError: details,
|
|
7226
7266
|
rawOutputSnippet: rawSnippet
|
|
@@ -7228,12 +7268,12 @@ async function runDevStory(deps, params) {
|
|
|
7228
7268
|
let filesModified = [];
|
|
7229
7269
|
try {
|
|
7230
7270
|
filesModified = await getGitChangedFiles(deps.projectRoot ?? process.cwd());
|
|
7231
|
-
if (filesModified.length > 0) logger$
|
|
7271
|
+
if (filesModified.length > 0) logger$17.info({
|
|
7232
7272
|
storyKey,
|
|
7233
7273
|
fileCount: filesModified.length
|
|
7234
7274
|
}, "Recovered files_modified from git status (YAML fallback)");
|
|
7235
7275
|
} catch (err) {
|
|
7236
|
-
logger$
|
|
7276
|
+
logger$17.warn({
|
|
7237
7277
|
storyKey,
|
|
7238
7278
|
error: err instanceof Error ? err.message : String(err)
|
|
7239
7279
|
}, "Failed to recover files_modified from git");
|
|
@@ -7250,7 +7290,7 @@ async function runDevStory(deps, params) {
|
|
|
7250
7290
|
};
|
|
7251
7291
|
}
|
|
7252
7292
|
const parsed = dispatchResult.parsed;
|
|
7253
|
-
logger$
|
|
7293
|
+
logger$17.info({
|
|
7254
7294
|
storyKey,
|
|
7255
7295
|
result: parsed.result,
|
|
7256
7296
|
acMet: parsed.ac_met.length
|
|
@@ -7366,7 +7406,7 @@ function extractReferencedFiles(storyContent) {
|
|
|
7366
7406
|
const matches = storyContent.match(filePathRegex) ?? [];
|
|
7367
7407
|
const freq = new Map();
|
|
7368
7408
|
for (const m of matches) freq.set(m, (freq.get(m) ?? 0) + 1);
|
|
7369
|
-
const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([path$
|
|
7409
|
+
const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([path$4]) => path$4);
|
|
7370
7410
|
return sorted.filter((p) => !p.includes(".test."));
|
|
7371
7411
|
}
|
|
7372
7412
|
function extractFilesInScope(storyContent) {
|
|
@@ -7390,19 +7430,6 @@ function extractFilesInScope(storyContent) {
|
|
|
7390
7430
|
//#endregion
|
|
7391
7431
|
//#region src/modules/compiled-workflows/scope-guardrail.ts
|
|
7392
7432
|
/**
|
|
7393
|
-
* ScopeGuardrail — utility for detecting out-of-scope file modifications in code review.
|
|
7394
|
-
*
|
|
7395
|
-
* Parses the expected file set from a story spec and compares it against the
|
|
7396
|
-
* actual files modified by the dev agent. Returns a pre-computed scope analysis
|
|
7397
|
-
* markdown string that can be injected into the code-review prompt so the LLM
|
|
7398
|
-
* reviewer does not need to re-parse the spec sections manually.
|
|
7399
|
-
*
|
|
7400
|
-
* Architecture constraints:
|
|
7401
|
-
* - Pure utility: no imports from packages/sdlc/, packages/core/, or persistence layer
|
|
7402
|
-
* - Takes plain strings in, returns plain strings out
|
|
7403
|
-
* - Test-file exemption patterns must match countTestMetrics() in code-review.ts
|
|
7404
|
-
*/
|
|
7405
|
-
/**
|
|
7406
7433
|
* File extensions that qualify a token as a "path-like" string in task bullets.
|
|
7407
7434
|
* Any token containing `/` and one of these extensions is treated as a file path.
|
|
7408
7435
|
*/
|
|
@@ -7495,13 +7522,17 @@ var ScopeGuardrail = class ScopeGuardrail {
|
|
|
7495
7522
|
*
|
|
7496
7523
|
* @param storyContent - Raw story spec markdown text
|
|
7497
7524
|
* @param filesModified - List of file paths from the git diff
|
|
7525
|
+
* @param fileDiffs - Optional per-file diff map. When provided, transitive
|
|
7526
|
+
* re-exports (Story 61-5) whose `from` source IS in
|
|
7527
|
+
* expectedFiles are excluded from the out-of-scope set.
|
|
7498
7528
|
* @returns Markdown string listing expected/actual/delta file sets,
|
|
7499
7529
|
* or empty string if no violations found
|
|
7500
7530
|
*/
|
|
7501
|
-
static buildAnalysis(storyContent, filesModified) {
|
|
7531
|
+
static buildAnalysis(storyContent, filesModified, fileDiffs) {
|
|
7502
7532
|
const expectedFiles = ScopeGuardrail.parseExpectedFiles(storyContent);
|
|
7503
7533
|
const nonTestFiles = filesModified.filter((f$1) => !isTestFile(f$1));
|
|
7504
|
-
|
|
7534
|
+
let outOfScope = nonTestFiles.filter((f$1) => !expectedFiles.has(f$1));
|
|
7535
|
+
if (fileDiffs !== void 0) outOfScope = outOfScope.filter((filePath) => !isPureTransitiveReExport(filePath, fileDiffs.get(filePath), expectedFiles));
|
|
7505
7536
|
if (outOfScope.length === 0) return "";
|
|
7506
7537
|
const expectedList = expectedFiles.size > 0 ? Array.from(expectedFiles).map((f$1) => ` - ${f$1}`).join("\n") : " (none specified)";
|
|
7507
7538
|
const actualList = nonTestFiles.length > 0 ? nonTestFiles.map((f$1) => ` - ${f$1}`).join("\n") : " (none)";
|
|
@@ -7571,10 +7602,108 @@ function isFilePath(candidate) {
|
|
|
7571
7602
|
if (/\s/.test(candidate)) return false;
|
|
7572
7603
|
return RECOGNIZED_EXTENSIONS.some((ext$2) => candidate.endsWith(ext$2));
|
|
7573
7604
|
}
|
|
7605
|
+
/**
|
|
7606
|
+
* Split a combined `git diff` output into per-file diff sections, keyed by
|
|
7607
|
+
* the post-image (`b/`) path. Returns an empty map if the input is empty.
|
|
7608
|
+
*
|
|
7609
|
+
* Used by callers that need to feed per-file diffs into
|
|
7610
|
+
* `ScopeGuardrail.buildAnalysis` for transitive re-export detection.
|
|
7611
|
+
*/
|
|
7612
|
+
function parseDiffByFile(combinedDiff) {
|
|
7613
|
+
const result = new Map();
|
|
7614
|
+
if (combinedDiff.trim() === "") return result;
|
|
7615
|
+
let currentPath = null;
|
|
7616
|
+
let currentLines = [];
|
|
7617
|
+
for (const line of combinedDiff.split("\n")) {
|
|
7618
|
+
const headerMatch = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
7619
|
+
if (headerMatch !== null) {
|
|
7620
|
+
if (currentPath !== null) result.set(currentPath, currentLines.join("\n"));
|
|
7621
|
+
currentPath = headerMatch[2] ?? null;
|
|
7622
|
+
currentLines = [line];
|
|
7623
|
+
continue;
|
|
7624
|
+
}
|
|
7625
|
+
if (currentPath !== null) currentLines.push(line);
|
|
7626
|
+
}
|
|
7627
|
+
if (currentPath !== null) result.set(currentPath, currentLines.join("\n"));
|
|
7628
|
+
return result;
|
|
7629
|
+
}
|
|
7630
|
+
/**
|
|
7631
|
+
* Single-line re-export pattern. Matches:
|
|
7632
|
+
* export { Foo } from './bar.js'
|
|
7633
|
+
* export { Foo, Bar as Baz } from './bar'
|
|
7634
|
+
* export type { Foo } from './bar.js'
|
|
7635
|
+
* export { type Foo, Bar } from './bar.js'
|
|
7636
|
+
*
|
|
7637
|
+
* Captures the relative `from` path (group 1). Path must start with `./`
|
|
7638
|
+
* (downward re-exports only — the canonical pattern is package barrel files
|
|
7639
|
+
* re-exporting submodule symbols). `../` paths are not tolerated; those
|
|
7640
|
+
* suggest cross-package coupling that warrants real review.
|
|
7641
|
+
*/
|
|
7642
|
+
const REEXPORT_LINE_RE = /^\s*export\s+(?:type\s+)?\{[^}]+\}\s+from\s+['"](\.\/[^'"]+)['"]\s*;?\s*$/;
|
|
7643
|
+
/**
|
|
7644
|
+
* Returns true if `diffContent` represents a pure transitive re-export
|
|
7645
|
+
* change for `modifiedFilePath` — meaning every added/removed line is a
|
|
7646
|
+
* re-export whose `from` source resolves to a file in `expectedFiles`.
|
|
7647
|
+
*
|
|
7648
|
+
* Story 61-5: surfaced by 60-13 dispatch where dev added a 2-line re-export
|
|
7649
|
+
* of `detectsEventDrivenAC` to `verification/index.ts` (an `index.ts`
|
|
7650
|
+
* re-export hop required for cross-package access via `@substrate-ai/sdlc`).
|
|
7651
|
+
* scope-guardrail flagged it as out-of-scope, reviewer admitted "the change
|
|
7652
|
+
* is clearly required" but flagged anyway, story timed out → escalated.
|
|
7653
|
+
*
|
|
7654
|
+
* Returns false when:
|
|
7655
|
+
* - diff content unavailable
|
|
7656
|
+
* - any non-re-export, non-comment, non-blank change exists
|
|
7657
|
+
* - any re-export's resolved `from` source is NOT in expectedFiles
|
|
7658
|
+
* - diff is empty (no changes — preserve existing behavior)
|
|
7659
|
+
*/
|
|
7660
|
+
function isPureTransitiveReExport(modifiedFilePath, diffContent, expectedFiles) {
|
|
7661
|
+
if (diffContent === void 0 || diffContent.trim() === "") return false;
|
|
7662
|
+
let sawChange = false;
|
|
7663
|
+
for (const line of diffContent.split("\n")) {
|
|
7664
|
+
if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("similarity ") || line.startsWith("rename ") || line.startsWith("new file ") || line.startsWith("deleted file ") || line.startsWith("Binary ") || line.startsWith("\\ No newline")) continue;
|
|
7665
|
+
if (!line.startsWith("+") && !line.startsWith("-")) continue;
|
|
7666
|
+
const content = line.slice(1);
|
|
7667
|
+
const trimmed = content.trim();
|
|
7668
|
+
if (trimmed === "") continue;
|
|
7669
|
+
if (trimmed.startsWith("//")) continue;
|
|
7670
|
+
sawChange = true;
|
|
7671
|
+
const match$2 = trimmed.match(REEXPORT_LINE_RE);
|
|
7672
|
+
if (match$2 === null) return false;
|
|
7673
|
+
const fromPath = match$2[1] ?? "";
|
|
7674
|
+
if (!resolvesIntoExpected(modifiedFilePath, fromPath, expectedFiles)) return false;
|
|
7675
|
+
}
|
|
7676
|
+
return sawChange;
|
|
7677
|
+
}
|
|
7678
|
+
/**
|
|
7679
|
+
* Resolve a `from './x.js'` path relative to `modifiedFilePath`'s directory
|
|
7680
|
+
* and check if the resolved path (or its `.ts` sibling) is in `expectedFiles`.
|
|
7681
|
+
*
|
|
7682
|
+
* ESM convention: source files are `.ts`, but imports use `.js` extensions.
|
|
7683
|
+
* We accept either extension when matching against expectedFiles.
|
|
7684
|
+
*/
|
|
7685
|
+
function resolvesIntoExpected(modifiedFilePath, relativePath, expectedFiles) {
|
|
7686
|
+
const dir = path$2.posix.dirname(modifiedFilePath);
|
|
7687
|
+
const resolved = path$2.posix.normalize(path$2.posix.join(dir, relativePath));
|
|
7688
|
+
const candidates = new Set([resolved]);
|
|
7689
|
+
if (resolved.endsWith(".js")) {
|
|
7690
|
+
candidates.add(resolved.slice(0, -3) + ".ts");
|
|
7691
|
+
candidates.add(resolved.slice(0, -3) + ".tsx");
|
|
7692
|
+
}
|
|
7693
|
+
if (resolved.endsWith(".ts")) candidates.add(resolved.slice(0, -3) + ".js");
|
|
7694
|
+
if (!/\.(t|j)sx?$/.test(resolved)) {
|
|
7695
|
+
candidates.add(resolved + ".ts");
|
|
7696
|
+
candidates.add(resolved + ".tsx");
|
|
7697
|
+
candidates.add(resolved + ".js");
|
|
7698
|
+
candidates.add(resolved + "/index.ts");
|
|
7699
|
+
}
|
|
7700
|
+
for (const candidate of candidates) if (expectedFiles.has(candidate)) return true;
|
|
7701
|
+
return false;
|
|
7702
|
+
}
|
|
7574
7703
|
|
|
7575
7704
|
//#endregion
|
|
7576
7705
|
//#region src/modules/compiled-workflows/code-review.ts
|
|
7577
|
-
const logger$
|
|
7706
|
+
const logger$16 = createLogger("compiled-workflows:code-review");
|
|
7578
7707
|
/**
|
|
7579
7708
|
* Default fallback result when dispatch fails or times out.
|
|
7580
7709
|
* Uses NEEDS_MINOR_FIXES (not NEEDS_MAJOR_REWORK) so a parse/schema failure
|
|
@@ -7649,14 +7778,14 @@ async function countTestMetrics(filesModified, cwd) {
|
|
|
7649
7778
|
async function runCodeReview(deps, params) {
|
|
7650
7779
|
const { storyKey, storyFilePath, workingDirectory, pipelineRunId, filesModified, previousIssues, buildPassed, baselineCommit } = params;
|
|
7651
7780
|
const cwd = workingDirectory ?? process.cwd();
|
|
7652
|
-
logger$
|
|
7781
|
+
logger$16.debug({
|
|
7653
7782
|
storyKey,
|
|
7654
7783
|
storyFilePath,
|
|
7655
7784
|
cwd,
|
|
7656
7785
|
pipelineRunId
|
|
7657
7786
|
}, "Starting code-review workflow");
|
|
7658
7787
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("code-review", deps.tokenCeilings);
|
|
7659
|
-
logger$
|
|
7788
|
+
logger$16.info({
|
|
7660
7789
|
workflow: "code-review",
|
|
7661
7790
|
ceiling: TOKEN_CEILING,
|
|
7662
7791
|
source: tokenCeilingSource
|
|
@@ -7666,7 +7795,7 @@ async function runCodeReview(deps, params) {
|
|
|
7666
7795
|
template = await deps.pack.getPrompt("code-review");
|
|
7667
7796
|
} catch (err) {
|
|
7668
7797
|
const error = err instanceof Error ? err.message : String(err);
|
|
7669
|
-
logger$
|
|
7798
|
+
logger$16.error({ error }, "Failed to retrieve code-review prompt template");
|
|
7670
7799
|
return defaultFailResult(`Failed to retrieve prompt template: ${error}`, {
|
|
7671
7800
|
input: 0,
|
|
7672
7801
|
output: 0
|
|
@@ -7677,7 +7806,7 @@ async function runCodeReview(deps, params) {
|
|
|
7677
7806
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
7678
7807
|
} catch (err) {
|
|
7679
7808
|
const error = err instanceof Error ? err.message : String(err);
|
|
7680
|
-
logger$
|
|
7809
|
+
logger$16.error({
|
|
7681
7810
|
storyFilePath,
|
|
7682
7811
|
error
|
|
7683
7812
|
}, "Failed to read story file");
|
|
@@ -7697,12 +7826,12 @@ async function runCodeReview(deps, params) {
|
|
|
7697
7826
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
7698
7827
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
7699
7828
|
gitDiffContent = scopedDiff;
|
|
7700
|
-
logger$
|
|
7829
|
+
logger$16.debug({
|
|
7701
7830
|
fileCount: filesModified.length,
|
|
7702
7831
|
tokenCount: scopedTotal
|
|
7703
7832
|
}, "Using scoped file diff");
|
|
7704
7833
|
} else {
|
|
7705
|
-
logger$
|
|
7834
|
+
logger$16.warn({
|
|
7706
7835
|
estimatedTotal: scopedTotal,
|
|
7707
7836
|
ceiling: TOKEN_CEILING,
|
|
7708
7837
|
fileCount: filesModified.length
|
|
@@ -7716,7 +7845,7 @@ async function runCodeReview(deps, params) {
|
|
|
7716
7845
|
const fullTotal = nonDiffTokens + countTokens(fullDiff);
|
|
7717
7846
|
if (fullTotal <= TOKEN_CEILING) gitDiffContent = fullDiff;
|
|
7718
7847
|
else {
|
|
7719
|
-
logger$
|
|
7848
|
+
logger$16.warn({
|
|
7720
7849
|
estimatedTotal: fullTotal,
|
|
7721
7850
|
ceiling: TOKEN_CEILING
|
|
7722
7851
|
}, "Full git diff would exceed token ceiling — using stat-only summary");
|
|
@@ -7724,7 +7853,7 @@ async function runCodeReview(deps, params) {
|
|
|
7724
7853
|
}
|
|
7725
7854
|
}
|
|
7726
7855
|
if (gitDiffContent.trim().length === 0 && baselineCommit) {
|
|
7727
|
-
logger$
|
|
7856
|
+
logger$16.info({
|
|
7728
7857
|
storyKey,
|
|
7729
7858
|
baselineCommit
|
|
7730
7859
|
}, "Working tree diff empty — diffing against baseline commit");
|
|
@@ -7732,7 +7861,7 @@ async function runCodeReview(deps, params) {
|
|
|
7732
7861
|
const commitTotal = nonDiffTokens + countTokens(commitDiff);
|
|
7733
7862
|
if (commitDiff.trim().length > 0) if (commitTotal <= TOKEN_CEILING) gitDiffContent = commitDiff;
|
|
7734
7863
|
else {
|
|
7735
|
-
logger$
|
|
7864
|
+
logger$16.warn({
|
|
7736
7865
|
estimatedTotal: commitTotal,
|
|
7737
7866
|
ceiling: TOKEN_CEILING
|
|
7738
7867
|
}, "Baseline..HEAD diff exceeds token ceiling — using stat-only summary");
|
|
@@ -7740,7 +7869,7 @@ async function runCodeReview(deps, params) {
|
|
|
7740
7869
|
}
|
|
7741
7870
|
}
|
|
7742
7871
|
if (gitDiffContent.trim().length === 0) {
|
|
7743
|
-
logger$
|
|
7872
|
+
logger$16.info({ storyKey }, "Empty git diff — skipping review with SHIP_IT");
|
|
7744
7873
|
return {
|
|
7745
7874
|
verdict: "SHIP_IT",
|
|
7746
7875
|
issues: 0,
|
|
@@ -7756,7 +7885,7 @@ async function runCodeReview(deps, params) {
|
|
|
7756
7885
|
if (deps.repoMapInjector !== void 0) {
|
|
7757
7886
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
7758
7887
|
repoContextContent = injection.text;
|
|
7759
|
-
logger$
|
|
7888
|
+
logger$16.info({
|
|
7760
7889
|
storyKey,
|
|
7761
7890
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
7762
7891
|
symbolCount: injection.symbolCount,
|
|
@@ -7776,16 +7905,17 @@ async function runCodeReview(deps, params) {
|
|
|
7776
7905
|
const findings = await getProjectFindings(deps.db);
|
|
7777
7906
|
if (findings.length > 0) {
|
|
7778
7907
|
priorFindingsContent = "Previous reviews found these recurring patterns — pay special attention:\n\n" + findings;
|
|
7779
|
-
logger$
|
|
7908
|
+
logger$16.debug({
|
|
7780
7909
|
storyKey,
|
|
7781
7910
|
findingsLen: findings.length
|
|
7782
7911
|
}, "Injecting prior findings into code-review prompt");
|
|
7783
7912
|
}
|
|
7784
7913
|
} catch {}
|
|
7785
7914
|
const testMetricsContent = await countTestMetrics(filesModified, cwd);
|
|
7786
|
-
if (testMetricsContent) logger$
|
|
7787
|
-
const
|
|
7788
|
-
|
|
7915
|
+
if (testMetricsContent) logger$16.debug({ storyKey }, "Injecting verified test-count metrics into code-review context");
|
|
7916
|
+
const fileDiffs = gitDiffContent ? parseDiffByFile(gitDiffContent) : void 0;
|
|
7917
|
+
const scopeAnalysisContent = storyContent && filesModified ? ScopeGuardrail.buildAnalysis(storyContent, filesModified, fileDiffs) : "";
|
|
7918
|
+
if (scopeAnalysisContent) logger$16.debug({ storyKey }, "Scope analysis detected out-of-scope files");
|
|
7789
7919
|
const buildStatusPrefix = buildPassed === true ? "BUILD STATUS: PASSED — code compiles and passes build verification. Focus on logic correctness, style, and acceptance criteria rather than compilation errors.\n\n" : "";
|
|
7790
7920
|
const sections = [
|
|
7791
7921
|
{
|
|
@@ -7830,11 +7960,11 @@ async function runCodeReview(deps, params) {
|
|
|
7830
7960
|
}
|
|
7831
7961
|
];
|
|
7832
7962
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
7833
|
-
if (assembleResult.truncated) logger$
|
|
7963
|
+
if (assembleResult.truncated) logger$16.warn({
|
|
7834
7964
|
storyKey,
|
|
7835
7965
|
tokenCount: assembleResult.tokenCount
|
|
7836
7966
|
}, "Code-review prompt truncated to fit token ceiling");
|
|
7837
|
-
logger$
|
|
7967
|
+
logger$16.debug({
|
|
7838
7968
|
storyKey,
|
|
7839
7969
|
tokenCount: assembleResult.tokenCount,
|
|
7840
7970
|
truncated: assembleResult.truncated
|
|
@@ -7855,7 +7985,7 @@ async function runCodeReview(deps, params) {
|
|
|
7855
7985
|
dispatchResult = await handle.result;
|
|
7856
7986
|
} catch (err) {
|
|
7857
7987
|
const error = err instanceof Error ? err.message : String(err);
|
|
7858
|
-
logger$
|
|
7988
|
+
logger$16.error({
|
|
7859
7989
|
storyKey,
|
|
7860
7990
|
error
|
|
7861
7991
|
}, "Code-review dispatch threw unexpected error");
|
|
@@ -7871,7 +8001,7 @@ async function runCodeReview(deps, params) {
|
|
|
7871
8001
|
const rawOutput = dispatchResult.output ?? void 0;
|
|
7872
8002
|
if (dispatchResult.status === "failed") {
|
|
7873
8003
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""} ${dispatchResult.output ? `Stderr: ${dispatchResult.output}` : ""}`.trim();
|
|
7874
|
-
logger$
|
|
8004
|
+
logger$16.warn({
|
|
7875
8005
|
storyKey,
|
|
7876
8006
|
exitCode: dispatchResult.exitCode
|
|
7877
8007
|
}, "Code-review dispatch failed");
|
|
@@ -7881,7 +8011,7 @@ async function runCodeReview(deps, params) {
|
|
|
7881
8011
|
};
|
|
7882
8012
|
}
|
|
7883
8013
|
if (dispatchResult.status === "timeout") {
|
|
7884
|
-
logger$
|
|
8014
|
+
logger$16.warn({ storyKey }, "Code-review dispatch timed out");
|
|
7885
8015
|
return {
|
|
7886
8016
|
...defaultFailResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage),
|
|
7887
8017
|
rawOutput
|
|
@@ -7889,7 +8019,7 @@ async function runCodeReview(deps, params) {
|
|
|
7889
8019
|
}
|
|
7890
8020
|
if (dispatchResult.parsed === null) {
|
|
7891
8021
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
7892
|
-
logger$
|
|
8022
|
+
logger$16.warn({
|
|
7893
8023
|
storyKey,
|
|
7894
8024
|
details
|
|
7895
8025
|
}, "Code-review output schema validation failed");
|
|
@@ -7907,7 +8037,7 @@ async function runCodeReview(deps, params) {
|
|
|
7907
8037
|
const parseResult = CodeReviewResultSchema.safeParse(dispatchResult.parsed);
|
|
7908
8038
|
if (!parseResult.success) {
|
|
7909
8039
|
const details = parseResult.error.message;
|
|
7910
|
-
logger$
|
|
8040
|
+
logger$16.warn({
|
|
7911
8041
|
storyKey,
|
|
7912
8042
|
details
|
|
7913
8043
|
}, "Code-review output failed schema validation");
|
|
@@ -7923,13 +8053,13 @@ async function runCodeReview(deps, params) {
|
|
|
7923
8053
|
};
|
|
7924
8054
|
}
|
|
7925
8055
|
const parsed = parseResult.data;
|
|
7926
|
-
if (parsed.agentVerdict !== parsed.verdict) logger$
|
|
8056
|
+
if (parsed.agentVerdict !== parsed.verdict) logger$16.info({
|
|
7927
8057
|
storyKey,
|
|
7928
8058
|
agentVerdict: parsed.agentVerdict,
|
|
7929
8059
|
pipelineVerdict: parsed.verdict,
|
|
7930
8060
|
issues: parsed.issues
|
|
7931
8061
|
}, "Pipeline overrode agent verdict based on issue severities");
|
|
7932
|
-
logger$
|
|
8062
|
+
logger$16.info({
|
|
7933
8063
|
storyKey,
|
|
7934
8064
|
verdict: parsed.verdict,
|
|
7935
8065
|
issues: parsed.issues
|
|
@@ -7954,16 +8084,16 @@ async function getArchConstraints$2(deps) {
|
|
|
7954
8084
|
if (constraints.length === 0) return "";
|
|
7955
8085
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
7956
8086
|
} catch (err) {
|
|
7957
|
-
logger$
|
|
8087
|
+
logger$16.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
7958
8088
|
return "";
|
|
7959
8089
|
}
|
|
7960
8090
|
}
|
|
7961
8091
|
|
|
7962
8092
|
//#endregion
|
|
7963
8093
|
//#region src/modules/compiled-workflows/test-plan.ts
|
|
7964
|
-
const logger$
|
|
8094
|
+
const logger$15 = createLogger("compiled-workflows:test-plan");
|
|
7965
8095
|
/** Default timeout for test-plan dispatches in milliseconds (5 min — lightweight call) */
|
|
7966
|
-
const DEFAULT_TIMEOUT_MS = 3e5;
|
|
8096
|
+
const DEFAULT_TIMEOUT_MS$1 = 3e5;
|
|
7967
8097
|
/**
|
|
7968
8098
|
* Execute the compiled test-plan workflow.
|
|
7969
8099
|
*
|
|
@@ -7973,12 +8103,12 @@ const DEFAULT_TIMEOUT_MS = 3e5;
|
|
|
7973
8103
|
*/
|
|
7974
8104
|
async function runTestPlan(deps, params) {
|
|
7975
8105
|
const { storyKey, storyFilePath, pipelineRunId } = params;
|
|
7976
|
-
logger$
|
|
8106
|
+
logger$15.info({
|
|
7977
8107
|
storyKey,
|
|
7978
8108
|
storyFilePath
|
|
7979
8109
|
}, "Starting compiled test-plan workflow");
|
|
7980
8110
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("test-plan", deps.tokenCeilings);
|
|
7981
|
-
logger$
|
|
8111
|
+
logger$15.info({
|
|
7982
8112
|
workflow: "test-plan",
|
|
7983
8113
|
ceiling: TOKEN_CEILING,
|
|
7984
8114
|
source: tokenCeilingSource
|
|
@@ -7986,10 +8116,10 @@ async function runTestPlan(deps, params) {
|
|
|
7986
8116
|
let template;
|
|
7987
8117
|
try {
|
|
7988
8118
|
template = await deps.pack.getPrompt("test-plan");
|
|
7989
|
-
logger$
|
|
8119
|
+
logger$15.debug({ storyKey }, "Retrieved test-plan prompt template from pack");
|
|
7990
8120
|
} catch (err) {
|
|
7991
8121
|
const error = err instanceof Error ? err.message : String(err);
|
|
7992
|
-
logger$
|
|
8122
|
+
logger$15.warn({
|
|
7993
8123
|
storyKey,
|
|
7994
8124
|
error
|
|
7995
8125
|
}, "Failed to retrieve test-plan prompt template");
|
|
@@ -8000,14 +8130,14 @@ async function runTestPlan(deps, params) {
|
|
|
8000
8130
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
8001
8131
|
} catch (err) {
|
|
8002
8132
|
if (err.code === "ENOENT") {
|
|
8003
|
-
logger$
|
|
8133
|
+
logger$15.warn({
|
|
8004
8134
|
storyKey,
|
|
8005
8135
|
storyFilePath
|
|
8006
8136
|
}, "Story file not found for test planning");
|
|
8007
8137
|
return makeTestPlanFailureResult("story_file_not_found");
|
|
8008
8138
|
}
|
|
8009
8139
|
const error = err instanceof Error ? err.message : String(err);
|
|
8010
|
-
logger$
|
|
8140
|
+
logger$15.warn({
|
|
8011
8141
|
storyKey,
|
|
8012
8142
|
storyFilePath,
|
|
8013
8143
|
error
|
|
@@ -8021,13 +8151,13 @@ async function runTestPlan(deps, params) {
|
|
|
8021
8151
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
8022
8152
|
if (testPatternDecisions.length > 0) {
|
|
8023
8153
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
8024
|
-
logger$
|
|
8154
|
+
logger$15.debug({
|
|
8025
8155
|
storyKey,
|
|
8026
8156
|
count: testPatternDecisions.length
|
|
8027
8157
|
}, "Loaded test patterns from decision store");
|
|
8028
8158
|
} else {
|
|
8029
8159
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
8030
|
-
logger$
|
|
8160
|
+
logger$15.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
8031
8161
|
}
|
|
8032
8162
|
} catch {
|
|
8033
8163
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
@@ -8049,7 +8179,7 @@ async function runTestPlan(deps, params) {
|
|
|
8049
8179
|
priority: "optional"
|
|
8050
8180
|
}
|
|
8051
8181
|
], TOKEN_CEILING);
|
|
8052
|
-
logger$
|
|
8182
|
+
logger$15.info({
|
|
8053
8183
|
storyKey,
|
|
8054
8184
|
tokenCount,
|
|
8055
8185
|
ceiling: TOKEN_CEILING,
|
|
@@ -8061,7 +8191,7 @@ async function runTestPlan(deps, params) {
|
|
|
8061
8191
|
prompt,
|
|
8062
8192
|
agent: deps.agentId ?? "claude-code",
|
|
8063
8193
|
taskType: "test-plan",
|
|
8064
|
-
timeout: DEFAULT_TIMEOUT_MS,
|
|
8194
|
+
timeout: DEFAULT_TIMEOUT_MS$1,
|
|
8065
8195
|
outputSchema: TestPlanResultSchema,
|
|
8066
8196
|
...deps.projectRoot !== void 0 ? { workingDirectory: deps.projectRoot } : {},
|
|
8067
8197
|
...deps.otlpEndpoint !== void 0 ? { otlpEndpoint: deps.otlpEndpoint } : {},
|
|
@@ -8070,7 +8200,7 @@ async function runTestPlan(deps, params) {
|
|
|
8070
8200
|
dispatchResult = await handle.result;
|
|
8071
8201
|
} catch (err) {
|
|
8072
8202
|
const error = err instanceof Error ? err.message : String(err);
|
|
8073
|
-
logger$
|
|
8203
|
+
logger$15.warn({
|
|
8074
8204
|
storyKey,
|
|
8075
8205
|
error
|
|
8076
8206
|
}, "Test-plan dispatch threw an unexpected error");
|
|
@@ -8081,7 +8211,7 @@ async function runTestPlan(deps, params) {
|
|
|
8081
8211
|
output: dispatchResult.tokenEstimate.output
|
|
8082
8212
|
};
|
|
8083
8213
|
if (dispatchResult.status === "timeout") {
|
|
8084
|
-
logger$
|
|
8214
|
+
logger$15.warn({
|
|
8085
8215
|
storyKey,
|
|
8086
8216
|
durationMs: dispatchResult.durationMs
|
|
8087
8217
|
}, "Test-plan dispatch timed out");
|
|
@@ -8091,7 +8221,7 @@ async function runTestPlan(deps, params) {
|
|
|
8091
8221
|
};
|
|
8092
8222
|
}
|
|
8093
8223
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
8094
|
-
logger$
|
|
8224
|
+
logger$15.warn({
|
|
8095
8225
|
storyKey,
|
|
8096
8226
|
exitCode: dispatchResult.exitCode,
|
|
8097
8227
|
status: dispatchResult.status
|
|
@@ -8103,7 +8233,7 @@ async function runTestPlan(deps, params) {
|
|
|
8103
8233
|
}
|
|
8104
8234
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
8105
8235
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
8106
|
-
logger$
|
|
8236
|
+
logger$15.warn({
|
|
8107
8237
|
storyKey,
|
|
8108
8238
|
parseError: details
|
|
8109
8239
|
}, "Test-plan YAML schema validation failed");
|
|
@@ -8126,19 +8256,19 @@ async function runTestPlan(deps, params) {
|
|
|
8126
8256
|
}),
|
|
8127
8257
|
rationale: `Test plan for ${storyKey}: ${parsed.test_files.length} test files, categories: ${parsed.test_categories.join(", ")}`
|
|
8128
8258
|
});
|
|
8129
|
-
logger$
|
|
8259
|
+
logger$15.info({
|
|
8130
8260
|
storyKey,
|
|
8131
8261
|
fileCount: parsed.test_files.length,
|
|
8132
8262
|
categories: parsed.test_categories
|
|
8133
8263
|
}, "Test plan stored in decision store");
|
|
8134
8264
|
} catch (err) {
|
|
8135
8265
|
const error = err instanceof Error ? err.message : String(err);
|
|
8136
|
-
logger$
|
|
8266
|
+
logger$15.warn({
|
|
8137
8267
|
storyKey,
|
|
8138
8268
|
error
|
|
8139
8269
|
}, "Failed to store test plan in decision store — proceeding anyway");
|
|
8140
8270
|
}
|
|
8141
|
-
logger$
|
|
8271
|
+
logger$15.info({
|
|
8142
8272
|
storyKey,
|
|
8143
8273
|
result: parsed.result
|
|
8144
8274
|
}, "Test-plan workflow completed");
|
|
@@ -8178,14 +8308,312 @@ async function getArchConstraints$1(deps) {
|
|
|
8178
8308
|
if (constraints.length === 0) return "";
|
|
8179
8309
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
8180
8310
|
} catch (err) {
|
|
8181
|
-
logger$
|
|
8311
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints for test-plan — proceeding without them");
|
|
8182
8312
|
return "";
|
|
8183
8313
|
}
|
|
8184
8314
|
}
|
|
8185
8315
|
|
|
8316
|
+
//#endregion
|
|
8317
|
+
//#region src/modules/implementation-orchestrator/probe-author-integration.ts
|
|
8318
|
+
const logger$14 = createLogger("implementation-orchestrator:probe-author");
|
|
8319
|
+
/** Default timeout for probe-author dispatches (5 min) */
|
|
8320
|
+
const DEFAULT_TIMEOUT_MS = 3e5;
|
|
8321
|
+
/** Timeout multiplier for the single retry after a timeout failure */
|
|
8322
|
+
const TIMEOUT_RETRY_MULTIPLIER = 1.5;
|
|
8323
|
+
/**
|
|
8324
|
+
* Execute the probe-author integration phase.
|
|
8325
|
+
*
|
|
8326
|
+
* Gate 1 — Event-driven AC check: calls `detectsEventDrivenAC(epicContent)`.
|
|
8327
|
+
* Skip if the source AC does not describe a hook, timer, signal, or webhook.
|
|
8328
|
+
*
|
|
8329
|
+
* Gate 2 — Idempotency check: reads storyFilePath and checks for an existing
|
|
8330
|
+
* `## Runtime Probes` section. Skip if present (probes already authored).
|
|
8331
|
+
*
|
|
8332
|
+
* Dispatch: assembles the probe-author prompt and dispatches via WorkflowDeps.
|
|
8333
|
+
* Uses ProbeAuthorResultSchema (result + probes) as outputSchema so the
|
|
8334
|
+
* existing YAML-parser anchor-key detection works correctly.
|
|
8335
|
+
*
|
|
8336
|
+
* Retry policy:
|
|
8337
|
+
* - Timeout → single retry at TIMEOUT_RETRY_MULTIPLIER × DEFAULT_TIMEOUT_MS.
|
|
8338
|
+
* Fall through if second attempt also times out.
|
|
8339
|
+
* - Invalid YAML → single retry with augmented prompt that includes the parse
|
|
8340
|
+
* error and the first 500 chars of bad output. Fall through if retry fails.
|
|
8341
|
+
* - Dispatch error (process crash, network failure) → fall through immediately.
|
|
8342
|
+
* - Empty probes list → emit `probe-author:no-probes-authored`, fall through.
|
|
8343
|
+
*
|
|
8344
|
+
* All failure paths are non-fatal — returns result: 'failed' instead of
|
|
8345
|
+
* throwing so the caller can unconditionally fall through to dev-story.
|
|
8346
|
+
*/
|
|
8347
|
+
async function runProbeAuthor(deps, params) {
|
|
8348
|
+
const start = Date.now();
|
|
8349
|
+
const { storyKey, storyFilePath, pipelineRunId, sourceAcContent, epicContent, emitEvent } = params;
|
|
8350
|
+
const tokenUsage = {
|
|
8351
|
+
input: 0,
|
|
8352
|
+
output: 0
|
|
8353
|
+
};
|
|
8354
|
+
if (!detectsEventDrivenAC(epicContent)) {
|
|
8355
|
+
logger$14.debug({ storyKey }, "probe-author: source AC not event-driven — skipping");
|
|
8356
|
+
return makeSkippedResult(tokenUsage, start);
|
|
8357
|
+
}
|
|
8358
|
+
let storyContent;
|
|
8359
|
+
try {
|
|
8360
|
+
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
8361
|
+
if (/^## Runtime Probes/m.test(storyContent)) {
|
|
8362
|
+
logger$14.info({ storyKey }, "probe-author: story artifact already has ## Runtime Probes — skipping");
|
|
8363
|
+
return makeSkippedResult(tokenUsage, start);
|
|
8364
|
+
}
|
|
8365
|
+
} catch (err) {
|
|
8366
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
8367
|
+
logger$14.warn({
|
|
8368
|
+
storyKey,
|
|
8369
|
+
error
|
|
8370
|
+
}, "probe-author: failed to read story file — falling through");
|
|
8371
|
+
emitEvent?.("probe-author:dispatch-error", {
|
|
8372
|
+
storyKey,
|
|
8373
|
+
runId: pipelineRunId,
|
|
8374
|
+
error
|
|
8375
|
+
});
|
|
8376
|
+
return makeFailedResult(`story_file_read_error: ${error}`, tokenUsage, start);
|
|
8377
|
+
}
|
|
8378
|
+
const { ceiling: TOKEN_CEILING } = getTokenCeiling("probe-author", deps.tokenCeilings);
|
|
8379
|
+
let template;
|
|
8380
|
+
try {
|
|
8381
|
+
template = await deps.pack.getPrompt("probe-author");
|
|
8382
|
+
logger$14.debug({ storyKey }, "probe-author: retrieved prompt template");
|
|
8383
|
+
} catch (err) {
|
|
8384
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
8385
|
+
logger$14.warn({
|
|
8386
|
+
storyKey,
|
|
8387
|
+
error
|
|
8388
|
+
}, "probe-author: failed to get prompt template — falling through");
|
|
8389
|
+
emitEvent?.("probe-author:dispatch-error", {
|
|
8390
|
+
storyKey,
|
|
8391
|
+
runId: pipelineRunId,
|
|
8392
|
+
error
|
|
8393
|
+
});
|
|
8394
|
+
return makeFailedResult(`template_load_failed: ${error}`, tokenUsage, start);
|
|
8395
|
+
}
|
|
8396
|
+
const { prompt: basePrompt } = assemblePrompt(template, [{
|
|
8397
|
+
name: "rendered_ac_section",
|
|
8398
|
+
content: storyContent,
|
|
8399
|
+
priority: "required"
|
|
8400
|
+
}, {
|
|
8401
|
+
name: "source_epic_ac_section",
|
|
8402
|
+
content: sourceAcContent,
|
|
8403
|
+
priority: "required"
|
|
8404
|
+
}], TOKEN_CEILING);
|
|
8405
|
+
const doDispatch = async (promptText, timeoutMs) => {
|
|
8406
|
+
const handle = deps.dispatcher.dispatch({
|
|
8407
|
+
prompt: promptText,
|
|
8408
|
+
agent: deps.agentId ?? "claude-code",
|
|
8409
|
+
taskType: "probe-author",
|
|
8410
|
+
timeout: timeoutMs,
|
|
8411
|
+
outputSchema: ProbeAuthorResultSchema,
|
|
8412
|
+
...deps.projectRoot !== void 0 ? { workingDirectory: deps.projectRoot } : {},
|
|
8413
|
+
...deps.otlpEndpoint !== void 0 ? { otlpEndpoint: deps.otlpEndpoint } : {},
|
|
8414
|
+
storyKey
|
|
8415
|
+
});
|
|
8416
|
+
return await handle.result;
|
|
8417
|
+
};
|
|
8418
|
+
let dispatchResult;
|
|
8419
|
+
try {
|
|
8420
|
+
logger$14.info({ storyKey }, "probe-author: dispatching probe-author agent");
|
|
8421
|
+
dispatchResult = await doDispatch(basePrompt, DEFAULT_TIMEOUT_MS);
|
|
8422
|
+
tokenUsage.input += dispatchResult.tokenEstimate.input;
|
|
8423
|
+
tokenUsage.output += dispatchResult.tokenEstimate.output;
|
|
8424
|
+
} catch (err) {
|
|
8425
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
8426
|
+
logger$14.warn({
|
|
8427
|
+
storyKey,
|
|
8428
|
+
error
|
|
8429
|
+
}, "probe-author: dispatch error — falling through to dev-story");
|
|
8430
|
+
emitEvent?.("probe-author:dispatch-error", {
|
|
8431
|
+
storyKey,
|
|
8432
|
+
runId: pipelineRunId,
|
|
8433
|
+
error
|
|
8434
|
+
});
|
|
8435
|
+
return makeFailedResult(`dispatch_error: ${error}`, tokenUsage, start);
|
|
8436
|
+
}
|
|
8437
|
+
if (dispatchResult.status === "timeout") {
|
|
8438
|
+
const elapsedMs = Date.now() - start;
|
|
8439
|
+
logger$14.warn({
|
|
8440
|
+
storyKey,
|
|
8441
|
+
elapsedMs
|
|
8442
|
+
}, "probe-author: dispatch timed out — retrying with 1.5× timeout");
|
|
8443
|
+
emitEvent?.("probe-author:timeout", {
|
|
8444
|
+
storyKey,
|
|
8445
|
+
runId: pipelineRunId,
|
|
8446
|
+
elapsedMs
|
|
8447
|
+
});
|
|
8448
|
+
try {
|
|
8449
|
+
const retryResult = await doDispatch(basePrompt, Math.round(DEFAULT_TIMEOUT_MS * TIMEOUT_RETRY_MULTIPLIER));
|
|
8450
|
+
tokenUsage.input += retryResult.tokenEstimate.input;
|
|
8451
|
+
tokenUsage.output += retryResult.tokenEstimate.output;
|
|
8452
|
+
if (retryResult.status === "timeout") {
|
|
8453
|
+
logger$14.warn({ storyKey }, "probe-author: retry also timed out — falling through to dev-story");
|
|
8454
|
+
return makeFailedResult("dispatch_timeout", tokenUsage, start);
|
|
8455
|
+
}
|
|
8456
|
+
dispatchResult = retryResult;
|
|
8457
|
+
} catch (retryErr) {
|
|
8458
|
+
const error = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
8459
|
+
logger$14.warn({
|
|
8460
|
+
storyKey,
|
|
8461
|
+
error
|
|
8462
|
+
}, "probe-author: retry dispatch error — falling through to dev-story");
|
|
8463
|
+
return makeFailedResult(`retry_dispatch_error: ${error}`, tokenUsage, start);
|
|
8464
|
+
}
|
|
8465
|
+
}
|
|
8466
|
+
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
8467
|
+
const error = `dispatch_failed with exit_code=${dispatchResult.exitCode}`;
|
|
8468
|
+
logger$14.warn({ storyKey }, `probe-author: ${error} — falling through to dev-story`);
|
|
8469
|
+
emitEvent?.("probe-author:dispatch-error", {
|
|
8470
|
+
storyKey,
|
|
8471
|
+
runId: pipelineRunId,
|
|
8472
|
+
error
|
|
8473
|
+
});
|
|
8474
|
+
return makeFailedResult(error, tokenUsage, start);
|
|
8475
|
+
}
|
|
8476
|
+
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
8477
|
+
const parseError = dispatchResult.parseError ?? "parsed result was null";
|
|
8478
|
+
const rawOutputSnippet = dispatchResult.output.slice(0, 500);
|
|
8479
|
+
logger$14.warn({
|
|
8480
|
+
storyKey,
|
|
8481
|
+
parseError,
|
|
8482
|
+
rawOutputSnippet
|
|
8483
|
+
}, "probe-author: YAML parse failure — retrying with augmented prompt");
|
|
8484
|
+
emitEvent?.("probe-author:invalid-output", {
|
|
8485
|
+
storyKey,
|
|
8486
|
+
runId: pipelineRunId,
|
|
8487
|
+
parseError,
|
|
8488
|
+
rawOutputSnippet
|
|
8489
|
+
});
|
|
8490
|
+
const augmentedPrompt = `${basePrompt}\n\n---\n\nPrevious output failed parsing with: ${parseError}; produce a single yaml block conforming to RuntimeProbeListSchema`;
|
|
8491
|
+
try {
|
|
8492
|
+
const retryResult = await doDispatch(augmentedPrompt, DEFAULT_TIMEOUT_MS);
|
|
8493
|
+
tokenUsage.input += retryResult.tokenEstimate.input;
|
|
8494
|
+
tokenUsage.output += retryResult.tokenEstimate.output;
|
|
8495
|
+
if (retryResult.parseError !== null || retryResult.parsed === null) {
|
|
8496
|
+
logger$14.warn({ storyKey }, "probe-author: retry still produced invalid YAML — falling through");
|
|
8497
|
+
return makeFailedResult("invalid_yaml_after_retry", tokenUsage, start);
|
|
8498
|
+
}
|
|
8499
|
+
dispatchResult = retryResult;
|
|
8500
|
+
} catch (retryErr) {
|
|
8501
|
+
const error = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
8502
|
+
logger$14.warn({
|
|
8503
|
+
storyKey,
|
|
8504
|
+
error
|
|
8505
|
+
}, "probe-author: retry error after invalid YAML — falling through");
|
|
8506
|
+
return makeFailedResult(`retry_error_after_invalid_yaml: ${error}`, tokenUsage, start);
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
const parsedOutput = dispatchResult.parsed;
|
|
8510
|
+
const probeValidation = RuntimeProbeListSchema.safeParse(parsedOutput.probes);
|
|
8511
|
+
if (!probeValidation.success) {
|
|
8512
|
+
const validationError = probeValidation.error.message;
|
|
8513
|
+
logger$14.warn({
|
|
8514
|
+
storyKey,
|
|
8515
|
+
validationError
|
|
8516
|
+
}, "probe-author: probes failed RuntimeProbeListSchema — falling through");
|
|
8517
|
+
return makeFailedResult(`schema_validation_failed: ${validationError}`, tokenUsage, start);
|
|
8518
|
+
}
|
|
8519
|
+
const probes = probeValidation.data;
|
|
8520
|
+
if (probes.length === 0) {
|
|
8521
|
+
logger$14.info({ storyKey }, "probe-author: authored empty probes list — no probes needed");
|
|
8522
|
+
emitEvent?.("probe-author:no-probes-authored", {
|
|
8523
|
+
storyKey,
|
|
8524
|
+
runId: pipelineRunId
|
|
8525
|
+
});
|
|
8526
|
+
return {
|
|
8527
|
+
result: "success",
|
|
8528
|
+
probesAuthoredCount: 0,
|
|
8529
|
+
tokenUsage,
|
|
8530
|
+
durationMs: Date.now() - start
|
|
8531
|
+
};
|
|
8532
|
+
}
|
|
8533
|
+
try {
|
|
8534
|
+
const refreshedContent = await readFile$1(storyFilePath, "utf-8");
|
|
8535
|
+
if (/^## Runtime Probes/m.test(refreshedContent)) {
|
|
8536
|
+
logger$14.info({ storyKey }, "probe-author: ## Runtime Probes section appeared after dispatch — skipping append (idempotent)");
|
|
8537
|
+
const dispatchDurationMs$1 = Date.now() - start;
|
|
8538
|
+
emitEvent?.("probe-author:dispatched", {
|
|
8539
|
+
storyKey,
|
|
8540
|
+
runId: pipelineRunId,
|
|
8541
|
+
probesAuthoredCount: 0,
|
|
8542
|
+
dispatchDurationMs: dispatchDurationMs$1,
|
|
8543
|
+
costUsd: estimateDispatchCost$1(tokenUsage.input, tokenUsage.output)
|
|
8544
|
+
});
|
|
8545
|
+
return makeSkippedResult(tokenUsage, start);
|
|
8546
|
+
}
|
|
8547
|
+
const probesYaml = yaml.dump(probes, { lineWidth: 120 }).trimEnd();
|
|
8548
|
+
const probesSection = `\n## Runtime Probes\n\n\`\`\`yaml\n${probesYaml}\n\`\`\`\n`;
|
|
8549
|
+
const newContent = refreshedContent + probesSection;
|
|
8550
|
+
const targetDir = dirname$1(storyFilePath);
|
|
8551
|
+
const tmpPath = join$1(targetDir, `.probe-author-${Date.now()}.tmp.md`);
|
|
8552
|
+
await writeFile$1(tmpPath, newContent, "utf-8");
|
|
8553
|
+
await rename(tmpPath, storyFilePath);
|
|
8554
|
+
logger$14.info({
|
|
8555
|
+
storyKey,
|
|
8556
|
+
probesCount: probes.length
|
|
8557
|
+
}, "probe-author: appended ## Runtime Probes section");
|
|
8558
|
+
} catch (err) {
|
|
8559
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
8560
|
+
logger$14.warn({
|
|
8561
|
+
storyKey,
|
|
8562
|
+
error
|
|
8563
|
+
}, "probe-author: failed to append probes — falling through to dev-story");
|
|
8564
|
+
return {
|
|
8565
|
+
result: "failed",
|
|
8566
|
+
probesAuthoredCount: probes.length,
|
|
8567
|
+
error: `append_error: ${error}`,
|
|
8568
|
+
tokenUsage,
|
|
8569
|
+
durationMs: Date.now() - start
|
|
8570
|
+
};
|
|
8571
|
+
}
|
|
8572
|
+
const dispatchDurationMs = Date.now() - start;
|
|
8573
|
+
const costUsd = estimateDispatchCost$1(tokenUsage.input, tokenUsage.output);
|
|
8574
|
+
emitEvent?.("probe-author:dispatched", {
|
|
8575
|
+
storyKey,
|
|
8576
|
+
runId: pipelineRunId,
|
|
8577
|
+
probesAuthoredCount: probes.length,
|
|
8578
|
+
dispatchDurationMs,
|
|
8579
|
+
costUsd
|
|
8580
|
+
});
|
|
8581
|
+
logger$14.info({
|
|
8582
|
+
storyKey,
|
|
8583
|
+
probesAuthoredCount: probes.length
|
|
8584
|
+
}, "probe-author: phase complete");
|
|
8585
|
+
return {
|
|
8586
|
+
result: "success",
|
|
8587
|
+
probesAuthoredCount: probes.length,
|
|
8588
|
+
tokenUsage,
|
|
8589
|
+
durationMs: Date.now() - start
|
|
8590
|
+
};
|
|
8591
|
+
}
|
|
8592
|
+
function makeSkippedResult(tokenUsage, start) {
|
|
8593
|
+
return {
|
|
8594
|
+
result: "skipped",
|
|
8595
|
+
probesAuthoredCount: 0,
|
|
8596
|
+
tokenUsage,
|
|
8597
|
+
durationMs: Date.now() - start
|
|
8598
|
+
};
|
|
8599
|
+
}
|
|
8600
|
+
function makeFailedResult(error, tokenUsage, start) {
|
|
8601
|
+
return {
|
|
8602
|
+
result: "failed",
|
|
8603
|
+
probesAuthoredCount: 0,
|
|
8604
|
+
error,
|
|
8605
|
+
tokenUsage,
|
|
8606
|
+
durationMs: Date.now() - start
|
|
8607
|
+
};
|
|
8608
|
+
}
|
|
8609
|
+
/** Claude pricing: $3/1M input, $15/1M output */
|
|
8610
|
+
function estimateDispatchCost$1(input, output) {
|
|
8611
|
+
return (input * 3 + output * 15) / 1e6;
|
|
8612
|
+
}
|
|
8613
|
+
|
|
8186
8614
|
//#endregion
|
|
8187
8615
|
//#region src/modules/compiled-workflows/test-expansion.ts
|
|
8188
|
-
const logger$
|
|
8616
|
+
const logger$13 = createLogger("compiled-workflows:test-expansion");
|
|
8189
8617
|
function defaultFallbackResult(error, tokenUsage) {
|
|
8190
8618
|
return {
|
|
8191
8619
|
expansion_priority: "low",
|
|
@@ -8215,14 +8643,14 @@ function defaultFallbackResult(error, tokenUsage) {
|
|
|
8215
8643
|
async function runTestExpansion(deps, params) {
|
|
8216
8644
|
const { storyKey, storyFilePath, pipelineRunId, filesModified, workingDirectory } = params;
|
|
8217
8645
|
const cwd = workingDirectory ?? process.cwd();
|
|
8218
|
-
logger$
|
|
8646
|
+
logger$13.debug({
|
|
8219
8647
|
storyKey,
|
|
8220
8648
|
storyFilePath,
|
|
8221
8649
|
cwd,
|
|
8222
8650
|
pipelineRunId
|
|
8223
8651
|
}, "Starting test-expansion workflow");
|
|
8224
8652
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("test-expansion", deps.tokenCeilings);
|
|
8225
|
-
logger$
|
|
8653
|
+
logger$13.info({
|
|
8226
8654
|
workflow: "test-expansion",
|
|
8227
8655
|
ceiling: TOKEN_CEILING,
|
|
8228
8656
|
source: tokenCeilingSource
|
|
@@ -8232,7 +8660,7 @@ async function runTestExpansion(deps, params) {
|
|
|
8232
8660
|
template = await deps.pack.getPrompt("test-expansion");
|
|
8233
8661
|
} catch (err) {
|
|
8234
8662
|
const error = err instanceof Error ? err.message : String(err);
|
|
8235
|
-
logger$
|
|
8663
|
+
logger$13.warn({ error }, "Failed to retrieve test-expansion prompt template");
|
|
8236
8664
|
return defaultFallbackResult(`Failed to retrieve prompt template: ${error}`, {
|
|
8237
8665
|
input: 0,
|
|
8238
8666
|
output: 0
|
|
@@ -8243,7 +8671,7 @@ async function runTestExpansion(deps, params) {
|
|
|
8243
8671
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
8244
8672
|
} catch (err) {
|
|
8245
8673
|
const error = err instanceof Error ? err.message : String(err);
|
|
8246
|
-
logger$
|
|
8674
|
+
logger$13.warn({
|
|
8247
8675
|
storyFilePath,
|
|
8248
8676
|
error
|
|
8249
8677
|
}, "Failed to read story file");
|
|
@@ -8259,13 +8687,13 @@ async function runTestExpansion(deps, params) {
|
|
|
8259
8687
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
8260
8688
|
if (testPatternDecisions.length > 0) {
|
|
8261
8689
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
8262
|
-
logger$
|
|
8690
|
+
logger$13.debug({
|
|
8263
8691
|
storyKey,
|
|
8264
8692
|
count: testPatternDecisions.length
|
|
8265
8693
|
}, "Loaded test patterns from decision store");
|
|
8266
8694
|
} else {
|
|
8267
8695
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
8268
|
-
logger$
|
|
8696
|
+
logger$13.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
8269
8697
|
}
|
|
8270
8698
|
} catch {
|
|
8271
8699
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
@@ -8280,12 +8708,12 @@ async function runTestExpansion(deps, params) {
|
|
|
8280
8708
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
8281
8709
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
8282
8710
|
gitDiffContent = scopedDiff;
|
|
8283
|
-
logger$
|
|
8711
|
+
logger$13.debug({
|
|
8284
8712
|
fileCount: filesModified.length,
|
|
8285
8713
|
tokenCount: scopedTotal
|
|
8286
8714
|
}, "Using scoped file diff");
|
|
8287
8715
|
} else {
|
|
8288
|
-
logger$
|
|
8716
|
+
logger$13.warn({
|
|
8289
8717
|
estimatedTotal: scopedTotal,
|
|
8290
8718
|
ceiling: TOKEN_CEILING,
|
|
8291
8719
|
fileCount: filesModified.length
|
|
@@ -8293,7 +8721,7 @@ async function runTestExpansion(deps, params) {
|
|
|
8293
8721
|
gitDiffContent = await getGitDiffStatForFiles(filesModified, cwd);
|
|
8294
8722
|
}
|
|
8295
8723
|
} catch (err) {
|
|
8296
|
-
logger$
|
|
8724
|
+
logger$13.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to get git diff — proceeding with empty diff");
|
|
8297
8725
|
}
|
|
8298
8726
|
const sections = [
|
|
8299
8727
|
{
|
|
@@ -8318,11 +8746,11 @@ async function runTestExpansion(deps, params) {
|
|
|
8318
8746
|
}
|
|
8319
8747
|
];
|
|
8320
8748
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
8321
|
-
if (assembleResult.truncated) logger$
|
|
8749
|
+
if (assembleResult.truncated) logger$13.warn({
|
|
8322
8750
|
storyKey,
|
|
8323
8751
|
tokenCount: assembleResult.tokenCount
|
|
8324
8752
|
}, "Test-expansion prompt truncated to fit token ceiling");
|
|
8325
|
-
logger$
|
|
8753
|
+
logger$13.debug({
|
|
8326
8754
|
storyKey,
|
|
8327
8755
|
tokenCount: assembleResult.tokenCount,
|
|
8328
8756
|
truncated: assembleResult.truncated
|
|
@@ -8342,7 +8770,7 @@ async function runTestExpansion(deps, params) {
|
|
|
8342
8770
|
dispatchResult = await handle.result;
|
|
8343
8771
|
} catch (err) {
|
|
8344
8772
|
const error = err instanceof Error ? err.message : String(err);
|
|
8345
|
-
logger$
|
|
8773
|
+
logger$13.warn({
|
|
8346
8774
|
storyKey,
|
|
8347
8775
|
error
|
|
8348
8776
|
}, "Test-expansion dispatch threw unexpected error");
|
|
@@ -8357,19 +8785,19 @@ async function runTestExpansion(deps, params) {
|
|
|
8357
8785
|
};
|
|
8358
8786
|
if (dispatchResult.status === "failed") {
|
|
8359
8787
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""}`.trim();
|
|
8360
|
-
logger$
|
|
8788
|
+
logger$13.warn({
|
|
8361
8789
|
storyKey,
|
|
8362
8790
|
exitCode: dispatchResult.exitCode
|
|
8363
8791
|
}, "Test-expansion dispatch failed");
|
|
8364
8792
|
return defaultFallbackResult(errorMsg, tokenUsage);
|
|
8365
8793
|
}
|
|
8366
8794
|
if (dispatchResult.status === "timeout") {
|
|
8367
|
-
logger$
|
|
8795
|
+
logger$13.warn({ storyKey }, "Test-expansion dispatch timed out");
|
|
8368
8796
|
return defaultFallbackResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage);
|
|
8369
8797
|
}
|
|
8370
8798
|
if (dispatchResult.parsed === null) {
|
|
8371
8799
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
8372
|
-
logger$
|
|
8800
|
+
logger$13.warn({
|
|
8373
8801
|
storyKey,
|
|
8374
8802
|
details
|
|
8375
8803
|
}, "Test-expansion output has no parseable YAML");
|
|
@@ -8378,14 +8806,14 @@ async function runTestExpansion(deps, params) {
|
|
|
8378
8806
|
const parseResult = TestExpansionResultSchema.safeParse(dispatchResult.parsed);
|
|
8379
8807
|
if (!parseResult.success) {
|
|
8380
8808
|
const details = parseResult.error.message;
|
|
8381
|
-
logger$
|
|
8809
|
+
logger$13.warn({
|
|
8382
8810
|
storyKey,
|
|
8383
8811
|
details
|
|
8384
8812
|
}, "Test-expansion output failed schema validation");
|
|
8385
8813
|
return defaultFallbackResult(`schema_validation_failed: ${details}`, tokenUsage);
|
|
8386
8814
|
}
|
|
8387
8815
|
const parsed = parseResult.data;
|
|
8388
|
-
logger$
|
|
8816
|
+
logger$13.info({
|
|
8389
8817
|
storyKey,
|
|
8390
8818
|
expansion_priority: parsed.expansion_priority,
|
|
8391
8819
|
coverage_gaps: parsed.coverage_gaps.length,
|
|
@@ -8410,11 +8838,15 @@ async function getArchConstraints(deps) {
|
|
|
8410
8838
|
if (constraints.length === 0) return "";
|
|
8411
8839
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
8412
8840
|
} catch (err) {
|
|
8413
|
-
logger$
|
|
8841
|
+
logger$13.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
8414
8842
|
return "";
|
|
8415
8843
|
}
|
|
8416
8844
|
}
|
|
8417
8845
|
|
|
8846
|
+
//#endregion
|
|
8847
|
+
//#region src/modules/compiled-workflows/probe-author.ts
|
|
8848
|
+
const logger$12 = createLogger("compiled-workflows:probe-author");
|
|
8849
|
+
|
|
8418
8850
|
//#endregion
|
|
8419
8851
|
//#region src/modules/compiled-workflows/story-analyzer.ts
|
|
8420
8852
|
/**
|
|
@@ -11707,7 +12139,7 @@ function checkProfileStaleness(projectRoot) {
|
|
|
11707
12139
|
*/
|
|
11708
12140
|
function createImplementationOrchestrator(deps) {
|
|
11709
12141
|
const { db, pack, contextCompiler, dispatcher, eventBus, config, projectRoot, tokenCeilings, stateStore, telemetryPersistence, ingestionServer, repoMapInjector, maxRepoMapTokens, agentId, runManifest = null } = deps;
|
|
11710
|
-
const logger$
|
|
12142
|
+
const logger$26 = createLogger("implementation-orchestrator");
|
|
11711
12143
|
const telemetryAdvisor = db !== void 0 ? createTelemetryAdvisor({ db }) : void 0;
|
|
11712
12144
|
const wgRepo = new WorkGraphRepository(db);
|
|
11713
12145
|
const _wgInProgressWritten = new Set();
|
|
@@ -11790,7 +12222,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11790
12222
|
const existingCount = storyState?.retry_count ?? 0;
|
|
11791
12223
|
_storyRetryCount.set(storyKey, existingCount);
|
|
11792
12224
|
} catch (err) {
|
|
11793
|
-
logger$
|
|
12225
|
+
logger$26.warn({
|
|
11794
12226
|
err,
|
|
11795
12227
|
storyKey
|
|
11796
12228
|
}, "initRetryCount: failed to read manifest — starting at 0");
|
|
@@ -11804,7 +12236,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11804
12236
|
const current = _storyRetryCount.get(storyKey) ?? 0;
|
|
11805
12237
|
const next = current + 1;
|
|
11806
12238
|
_storyRetryCount.set(storyKey, next);
|
|
11807
|
-
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$
|
|
12239
|
+
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$26.warn({
|
|
11808
12240
|
err,
|
|
11809
12241
|
storyKey
|
|
11810
12242
|
}, "patchStoryState(retry_count) failed — pipeline continues"));
|
|
@@ -11817,7 +12249,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11817
12249
|
const nowMs = Date.now();
|
|
11818
12250
|
for (const [phase, startMs] of starts) {
|
|
11819
12251
|
const endMs = ends?.get(phase);
|
|
11820
|
-
if (endMs === void 0) logger$
|
|
12252
|
+
if (endMs === void 0) logger$26.warn({
|
|
11821
12253
|
storyKey,
|
|
11822
12254
|
phase
|
|
11823
12255
|
}, "Phase has no end time — story may have errored mid-phase. Duration capped to now() and may be inflated.");
|
|
@@ -11834,7 +12266,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11834
12266
|
const wallClockSeconds = startedAt ? Math.round((new Date(completedAt).getTime() - new Date(startedAt).getTime()) / 1e3) : 0;
|
|
11835
12267
|
const wallClockMs = startedAt ? new Date(completedAt).getTime() - new Date(startedAt).getTime() : 0;
|
|
11836
12268
|
const tokenAgg = await aggregateTokenUsageForStory(db, config.pipelineRunId, storyKey);
|
|
11837
|
-
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$
|
|
12269
|
+
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$26.warn({
|
|
11838
12270
|
err,
|
|
11839
12271
|
storyKey
|
|
11840
12272
|
}, "patchStoryState(cost_usd) failed — pipeline continues"));
|
|
@@ -11870,7 +12302,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11870
12302
|
recordedAt: completedAt,
|
|
11871
12303
|
timestamp: completedAt
|
|
11872
12304
|
}).catch((storeErr) => {
|
|
11873
|
-
logger$
|
|
12305
|
+
logger$26.warn({
|
|
11874
12306
|
err: storeErr,
|
|
11875
12307
|
storyKey
|
|
11876
12308
|
}, "Failed to record metric to StateStore (best-effort)");
|
|
@@ -11892,7 +12324,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11892
12324
|
rationale: `Story ${storyKey} completed with result=${result} in ${wallClockSeconds}s. Tokens: ${tokenAgg.input}+${tokenAgg.output}. Review cycles: ${reviewCycles}.`
|
|
11893
12325
|
});
|
|
11894
12326
|
} catch (decisionErr) {
|
|
11895
|
-
logger$
|
|
12327
|
+
logger$26.warn({
|
|
11896
12328
|
err: decisionErr,
|
|
11897
12329
|
storyKey
|
|
11898
12330
|
}, "Failed to write story-metrics decision (best-effort)");
|
|
@@ -11971,7 +12403,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
11971
12403
|
const LOW_OUTPUT_TOKEN_THRESHOLD = 100;
|
|
11972
12404
|
const unverified = tokenAgg.output < LOW_OUTPUT_TOKEN_THRESHOLD;
|
|
11973
12405
|
if (unverified) {
|
|
11974
|
-
logger$
|
|
12406
|
+
logger$26.warn({
|
|
11975
12407
|
storyKey,
|
|
11976
12408
|
outputTokens: tokenAgg.output,
|
|
11977
12409
|
threshold: LOW_OUTPUT_TOKEN_THRESHOLD
|
|
@@ -11995,13 +12427,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
11995
12427
|
...unverified ? { unverified: true } : {}
|
|
11996
12428
|
});
|
|
11997
12429
|
} catch (emitErr) {
|
|
11998
|
-
logger$
|
|
12430
|
+
logger$26.warn({
|
|
11999
12431
|
err: emitErr,
|
|
12000
12432
|
storyKey
|
|
12001
12433
|
}, "Failed to emit story:metrics event (best-effort)");
|
|
12002
12434
|
}
|
|
12003
12435
|
} catch (err) {
|
|
12004
|
-
logger$
|
|
12436
|
+
logger$26.warn({
|
|
12005
12437
|
err,
|
|
12006
12438
|
storyKey
|
|
12007
12439
|
}, "Failed to write story metrics (best-effort)");
|
|
@@ -12030,7 +12462,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12030
12462
|
rationale: `Story ${storyKey} ${outcome} after ${reviewCycles} review cycle(s).`
|
|
12031
12463
|
});
|
|
12032
12464
|
} catch (err) {
|
|
12033
|
-
logger$
|
|
12465
|
+
logger$26.warn({
|
|
12034
12466
|
err,
|
|
12035
12467
|
storyKey
|
|
12036
12468
|
}, "Failed to write story-outcome decision (best-effort)");
|
|
@@ -12068,7 +12500,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12068
12500
|
rationale: `Escalation diagnosis for ${payload.storyKey}: ${diagnosis.recommendedAction} — ${diagnosis.rationale}`
|
|
12069
12501
|
});
|
|
12070
12502
|
} catch (err) {
|
|
12071
|
-
logger$
|
|
12503
|
+
logger$26.warn({
|
|
12072
12504
|
err,
|
|
12073
12505
|
storyKey: payload.storyKey
|
|
12074
12506
|
}, "Failed to persist escalation diagnosis (best-effort)");
|
|
@@ -12118,7 +12550,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12118
12550
|
const existing = _stories.get(storyKey);
|
|
12119
12551
|
if (existing !== void 0) {
|
|
12120
12552
|
Object.assign(existing, updates);
|
|
12121
|
-
persistStoryState(storyKey, existing).catch((err) => logger$
|
|
12553
|
+
persistStoryState(storyKey, existing).catch((err) => logger$26.warn({
|
|
12122
12554
|
err,
|
|
12123
12555
|
storyKey
|
|
12124
12556
|
}, "StateStore write failed after updateStory"));
|
|
@@ -12127,12 +12559,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
12127
12559
|
storyKey,
|
|
12128
12560
|
conflict: err
|
|
12129
12561
|
});
|
|
12130
|
-
else logger$
|
|
12562
|
+
else logger$26.warn({
|
|
12131
12563
|
err,
|
|
12132
12564
|
storyKey
|
|
12133
12565
|
}, "mergeStory failed");
|
|
12134
12566
|
});
|
|
12135
|
-
else if (updates.phase === "ESCALATED" || updates.phase === "VERIFICATION_FAILED") stateStore?.rollbackStory(storyKey).catch((err) => logger$
|
|
12567
|
+
else if (updates.phase === "ESCALATED" || updates.phase === "VERIFICATION_FAILED") stateStore?.rollbackStory(storyKey).catch((err) => logger$26.warn({
|
|
12136
12568
|
err,
|
|
12137
12569
|
storyKey
|
|
12138
12570
|
}, "rollbackStory failed — branch may persist"));
|
|
@@ -12144,7 +12576,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12144
12576
|
...updates
|
|
12145
12577
|
};
|
|
12146
12578
|
const opts = targetStatus === "complete" || targetStatus === "escalated" ? { completedAt: fullUpdated.completedAt } : void 0;
|
|
12147
|
-
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$
|
|
12579
|
+
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$26.warn({
|
|
12148
12580
|
err,
|
|
12149
12581
|
storyKey
|
|
12150
12582
|
}, "wg_stories status update failed (best-effort)"));
|
|
@@ -12160,7 +12592,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12160
12592
|
status: "dispatched",
|
|
12161
12593
|
phase: String(updates.phase),
|
|
12162
12594
|
started_at: fullUpdated.startedAt ?? new Date().toISOString()
|
|
12163
|
-
}).catch((err) => logger$
|
|
12595
|
+
}).catch((err) => logger$26.warn({
|
|
12164
12596
|
err,
|
|
12165
12597
|
storyKey
|
|
12166
12598
|
}, "patchStoryState(dispatched) failed — pipeline continues"));
|
|
@@ -12172,7 +12604,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12172
12604
|
completed_at: fullUpdated.completedAt ?? new Date().toISOString(),
|
|
12173
12605
|
review_cycles: fullUpdated.reviewCycles ?? 0,
|
|
12174
12606
|
dispatches: _storyDispatches.get(storyKey) ?? 0
|
|
12175
|
-
}).catch((err) => logger$
|
|
12607
|
+
}).catch((err) => logger$26.warn({
|
|
12176
12608
|
err,
|
|
12177
12609
|
storyKey
|
|
12178
12610
|
}, `patchStoryState(${manifestStatus}) failed — pipeline continues`));
|
|
@@ -12202,7 +12634,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12202
12634
|
};
|
|
12203
12635
|
await stateStore.setStoryState(storyKey, record);
|
|
12204
12636
|
} catch (err) {
|
|
12205
|
-
logger$
|
|
12637
|
+
logger$26.warn({
|
|
12206
12638
|
err,
|
|
12207
12639
|
storyKey
|
|
12208
12640
|
}, "StateStore.setStoryState failed (best-effort)");
|
|
@@ -12218,7 +12650,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12218
12650
|
token_usage_json: serialized
|
|
12219
12651
|
});
|
|
12220
12652
|
} catch (err) {
|
|
12221
|
-
logger$
|
|
12653
|
+
logger$26.warn({ err }, "Failed to persist orchestrator state");
|
|
12222
12654
|
}
|
|
12223
12655
|
}
|
|
12224
12656
|
function recordProgress() {
|
|
@@ -12244,7 +12676,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12244
12676
|
queuedDispatches: queued
|
|
12245
12677
|
});
|
|
12246
12678
|
if (config.pipelineRunId !== void 0) updatePipelineRun(db, config.pipelineRunId, { current_phase: "implementation" }).catch((err) => {
|
|
12247
|
-
logger$
|
|
12679
|
+
logger$26.debug({ err }, "Heartbeat: failed to touch updated_at (non-fatal)");
|
|
12248
12680
|
});
|
|
12249
12681
|
const elapsed = Date.now() - _lastProgressTs;
|
|
12250
12682
|
let childPids = [];
|
|
@@ -12266,7 +12698,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12266
12698
|
}
|
|
12267
12699
|
if (childActive) {
|
|
12268
12700
|
_lastProgressTs = Date.now();
|
|
12269
|
-
logger$
|
|
12701
|
+
logger$26.debug({
|
|
12270
12702
|
storyKey: key,
|
|
12271
12703
|
phase: s$1.phase,
|
|
12272
12704
|
childPids
|
|
@@ -12275,7 +12707,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12275
12707
|
}
|
|
12276
12708
|
_stalledStories.add(key);
|
|
12277
12709
|
_storiesWithStall.add(key);
|
|
12278
|
-
logger$
|
|
12710
|
+
logger$26.warn({
|
|
12279
12711
|
storyKey: key,
|
|
12280
12712
|
phase: s$1.phase,
|
|
12281
12713
|
elapsedMs: elapsed,
|
|
@@ -12320,7 +12752,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12320
12752
|
for (let attempt = 0; attempt < MEMORY_PRESSURE_BACKOFF_MS.length; attempt++) {
|
|
12321
12753
|
const memState = dispatcher.getMemoryState();
|
|
12322
12754
|
if (!memState.isPressured) return true;
|
|
12323
|
-
logger$
|
|
12755
|
+
logger$26.warn({
|
|
12324
12756
|
storyKey,
|
|
12325
12757
|
freeMB: memState.freeMB,
|
|
12326
12758
|
thresholdMB: memState.thresholdMB,
|
|
@@ -12340,12 +12772,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
12340
12772
|
* exhausted retries the story is ESCALATED.
|
|
12341
12773
|
*/
|
|
12342
12774
|
async function processStory(storyKey, storyOptions) {
|
|
12343
|
-
logger$
|
|
12775
|
+
logger$26.info({ storyKey }, "Processing story");
|
|
12344
12776
|
await initRetryCount(storyKey);
|
|
12345
12777
|
{
|
|
12346
12778
|
const memoryOk = await checkMemoryPressure(storyKey);
|
|
12347
12779
|
if (!memoryOk) {
|
|
12348
|
-
logger$
|
|
12780
|
+
logger$26.warn({ storyKey }, "Memory pressure exhausted — escalating story without dispatch");
|
|
12349
12781
|
const memPressureState = {
|
|
12350
12782
|
phase: "ESCALATED",
|
|
12351
12783
|
reviewCycles: 0,
|
|
@@ -12354,7 +12786,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12354
12786
|
completedAt: new Date().toISOString()
|
|
12355
12787
|
};
|
|
12356
12788
|
_stories.set(storyKey, memPressureState);
|
|
12357
|
-
persistStoryState(storyKey, memPressureState).catch((err) => logger$
|
|
12789
|
+
persistStoryState(storyKey, memPressureState).catch((err) => logger$26.warn({
|
|
12358
12790
|
err,
|
|
12359
12791
|
storyKey
|
|
12360
12792
|
}, "StateStore write failed after memory-pressure escalation"));
|
|
@@ -12371,7 +12803,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12371
12803
|
}
|
|
12372
12804
|
await waitIfPaused();
|
|
12373
12805
|
if (_state !== "RUNNING") return;
|
|
12374
|
-
stateStore?.branchForStory(storyKey).catch((err) => logger$
|
|
12806
|
+
stateStore?.branchForStory(storyKey).catch((err) => logger$26.warn({
|
|
12375
12807
|
err,
|
|
12376
12808
|
storyKey
|
|
12377
12809
|
}, "branchForStory failed — continuing without branch isolation"));
|
|
@@ -12390,7 +12822,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12390
12822
|
if (match$2) {
|
|
12391
12823
|
const candidatePath = join$1(artifactsDir, match$2);
|
|
12392
12824
|
const validation = await isValidStoryFile(candidatePath);
|
|
12393
|
-
if (!validation.valid) logger$
|
|
12825
|
+
if (!validation.valid) logger$26.warn({
|
|
12394
12826
|
storyKey,
|
|
12395
12827
|
storyFilePath: candidatePath,
|
|
12396
12828
|
reason: validation.reason
|
|
@@ -12415,7 +12847,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12415
12847
|
storedHash,
|
|
12416
12848
|
currentHash
|
|
12417
12849
|
});
|
|
12418
|
-
logger$
|
|
12850
|
+
logger$26.info({
|
|
12419
12851
|
storyKey,
|
|
12420
12852
|
storedHash,
|
|
12421
12853
|
currentHash
|
|
@@ -12426,7 +12858,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12426
12858
|
} catch {}
|
|
12427
12859
|
if (!isDrift) {
|
|
12428
12860
|
storyFilePath = candidatePath;
|
|
12429
|
-
logger$
|
|
12861
|
+
logger$26.info({
|
|
12430
12862
|
storyKey,
|
|
12431
12863
|
storyFilePath
|
|
12432
12864
|
}, "Found existing story file — skipping create-story");
|
|
@@ -12446,12 +12878,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
12446
12878
|
const staleName = match$2.replace(/\.md$/, `.stale-${ts}.md`);
|
|
12447
12879
|
const stalePath = join$1(artifactsDir, staleName);
|
|
12448
12880
|
renameSync(candidatePath, stalePath);
|
|
12449
|
-
logger$
|
|
12881
|
+
logger$26.info({
|
|
12450
12882
|
storyKey,
|
|
12451
12883
|
staleName
|
|
12452
12884
|
}, `[orchestrator] story ${storyKey}: renamed drifted artifact to ${staleName} before re-dispatch`);
|
|
12453
12885
|
} catch (renameErr) {
|
|
12454
|
-
logger$
|
|
12886
|
+
logger$26.warn({
|
|
12455
12887
|
storyKey,
|
|
12456
12888
|
err: renameErr
|
|
12457
12889
|
}, "Failed to rename stale artifact before create-story re-dispatch; relying on 58-9d fraud-guard");
|
|
@@ -12460,7 +12892,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12460
12892
|
}
|
|
12461
12893
|
} catch {}
|
|
12462
12894
|
if (storyFilePath === void 0 && projectRoot && isImplicitlyCovered(storyKey, projectRoot)) {
|
|
12463
|
-
logger$
|
|
12895
|
+
logger$26.info({ storyKey }, `Story ${storyKey} appears implicitly covered — all expected new files already exist. Skipping create-story.`);
|
|
12464
12896
|
endPhase(storyKey, "create-story");
|
|
12465
12897
|
eventBus.emit("orchestrator:story-phase-complete", {
|
|
12466
12898
|
storyKey,
|
|
@@ -12513,7 +12945,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12513
12945
|
output_tokens: createResult.tokenUsage.output,
|
|
12514
12946
|
cost_usd: estimateDispatchCost(createResult.tokenUsage.input, createResult.tokenUsage.output),
|
|
12515
12947
|
metadata: JSON.stringify({ storyKey })
|
|
12516
|
-
})).catch((tokenErr) => logger$
|
|
12948
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
12517
12949
|
storyKey,
|
|
12518
12950
|
err: tokenErr
|
|
12519
12951
|
}, "Failed to record create-story token usage"));
|
|
@@ -12521,7 +12953,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12521
12953
|
if (createResult.result === "failed") {
|
|
12522
12954
|
const errMsg = createResult.error ?? "create-story failed";
|
|
12523
12955
|
const stderrSnippet = errMsg.includes("--- stderr ---") ? errMsg.slice(errMsg.indexOf("--- stderr ---") + 15, errMsg.indexOf("--- stderr ---") + 515) : errMsg.slice(0, 500);
|
|
12524
|
-
logger$
|
|
12956
|
+
logger$26.error({
|
|
12525
12957
|
storyKey,
|
|
12526
12958
|
stderrSnippet
|
|
12527
12959
|
}, `Create-story failed: ${stderrSnippet.split("\n")[0]}`);
|
|
@@ -12563,7 +12995,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12563
12995
|
let claimedPath = createResult.story_file;
|
|
12564
12996
|
if (claimedPath.startsWith(escapedExpectedDir)) {
|
|
12565
12997
|
claimedPath = claimedPath.replace("/\\_bmad-output/", "/_bmad-output/");
|
|
12566
|
-
logger$
|
|
12998
|
+
logger$26.warn({
|
|
12567
12999
|
storyKey,
|
|
12568
13000
|
originalClaim: createResult.story_file,
|
|
12569
13001
|
normalizedClaim: claimedPath
|
|
@@ -12581,7 +13013,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12581
13013
|
if (escapedVariant !== claimedPath && existsSync(escapedVariant)) try {
|
|
12582
13014
|
renameSync(escapedVariant, claimedPath);
|
|
12583
13015
|
actualPath = claimedPath;
|
|
12584
|
-
logger$
|
|
13016
|
+
logger$26.warn({
|
|
12585
13017
|
storyKey,
|
|
12586
13018
|
escapedVariant,
|
|
12587
13019
|
canonicalPath: claimedPath
|
|
@@ -12592,7 +13024,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12592
13024
|
});
|
|
12593
13025
|
} catch (renameErr) {
|
|
12594
13026
|
actualPath = escapedVariant;
|
|
12595
|
-
logger$
|
|
13027
|
+
logger$26.warn({
|
|
12596
13028
|
storyKey,
|
|
12597
13029
|
escapedVariant,
|
|
12598
13030
|
canonicalPath: claimedPath,
|
|
@@ -12607,7 +13039,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12607
13039
|
if (actualPath === null) {
|
|
12608
13040
|
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
12609
13041
|
const errMsg = `create-story claimed success (story_file: ${createResult.story_file}) but the file does not exist on disk (output tokens: ${outputTokens})`;
|
|
12610
|
-
logger$
|
|
13042
|
+
logger$26.error({
|
|
12611
13043
|
storyKey,
|
|
12612
13044
|
claimedPath: createResult.story_file,
|
|
12613
13045
|
outputTokens
|
|
@@ -12634,7 +13066,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12634
13066
|
const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
|
|
12635
13067
|
const dispatchStartISO = new Date(dispatchStartMs).toISOString();
|
|
12636
13068
|
const errMsg = `create-story claimed success but did not rewrite ${actualPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
|
|
12637
|
-
logger$
|
|
13069
|
+
logger$26.error({
|
|
12638
13070
|
storyKey,
|
|
12639
13071
|
claimedPath: actualPath,
|
|
12640
13072
|
mtimeISO,
|
|
@@ -12657,7 +13089,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12657
13089
|
return;
|
|
12658
13090
|
}
|
|
12659
13091
|
} catch (verifyErr) {
|
|
12660
|
-
logger$
|
|
13092
|
+
logger$26.warn({
|
|
12661
13093
|
storyKey,
|
|
12662
13094
|
err: verifyErr
|
|
12663
13095
|
}, "create-story post-dispatch file verification threw; proceeding with claimed path");
|
|
@@ -12680,7 +13112,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12680
13112
|
const overlap = computeTitleOverlap(expectedTitle, createResult.story_title);
|
|
12681
13113
|
if (overlap < TITLE_OVERLAP_WARNING_THRESHOLD) {
|
|
12682
13114
|
const msg = `Story title mismatch: expected "${expectedTitle}" but got "${createResult.story_title}" (word overlap: ${Math.round(overlap * 100)}%). This may indicate the create-story agent received truncated context.`;
|
|
12683
|
-
logger$
|
|
13115
|
+
logger$26.warn({
|
|
12684
13116
|
storyKey,
|
|
12685
13117
|
expectedTitle,
|
|
12686
13118
|
generatedTitle: createResult.story_title,
|
|
@@ -12690,7 +13122,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12690
13122
|
storyKey,
|
|
12691
13123
|
msg
|
|
12692
13124
|
});
|
|
12693
|
-
} else logger$
|
|
13125
|
+
} else logger$26.debug({
|
|
12694
13126
|
storyKey,
|
|
12695
13127
|
expectedTitle,
|
|
12696
13128
|
generatedTitle: createResult.story_title,
|
|
@@ -12699,7 +13131,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12699
13131
|
}
|
|
12700
13132
|
}
|
|
12701
13133
|
} catch (titleValidationErr) {
|
|
12702
|
-
logger$
|
|
13134
|
+
logger$26.debug({
|
|
12703
13135
|
storyKey,
|
|
12704
13136
|
err: titleValidationErr
|
|
12705
13137
|
}, "Story title validation skipped due to error");
|
|
@@ -12740,7 +13172,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12740
13172
|
const pathDrift = pathFidelity?.drift ?? 0;
|
|
12741
13173
|
const clauseDrift = clauseFidelity.drift;
|
|
12742
13174
|
const overallDrift = Math.max(pathDrift, clauseDrift);
|
|
12743
|
-
logger$
|
|
13175
|
+
logger$26.debug({
|
|
12744
13176
|
storyKey,
|
|
12745
13177
|
pathDrift,
|
|
12746
13178
|
clauseDrift,
|
|
@@ -12762,7 +13194,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12762
13194
|
if (pathMissing.length > 0) reasons.push(`${pathMissing.length} named path(s) missing`);
|
|
12763
13195
|
if (numericMismatches.length > 0) reasons.push(`${numericMismatches.length} numeric quantifier mismatch(es) (e.g., "${numericMismatches[0].noun}" source=${numericMismatches[0].sourceCount} rendered=${numericMismatches[0].renderedCount})`);
|
|
12764
13196
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall (rendered ${clauseFidelity.renderedClauseCount}/${clauseFidelity.sourceClauseCount} = ${Math.round(clauseFidelity.clauseRatio * 100)}%)`);
|
|
12765
|
-
logger$
|
|
13197
|
+
logger$26.warn({
|
|
12766
13198
|
storyKey,
|
|
12767
13199
|
pathDrift,
|
|
12768
13200
|
clauseDrift,
|
|
@@ -12805,7 +13237,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12805
13237
|
storyFilePath = void 0;
|
|
12806
13238
|
continue;
|
|
12807
13239
|
} catch (renameErr) {
|
|
12808
|
-
logger$
|
|
13240
|
+
logger$26.warn({
|
|
12809
13241
|
storyKey,
|
|
12810
13242
|
err: renameErr,
|
|
12811
13243
|
stalePath
|
|
@@ -12819,7 +13251,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12819
13251
|
if (numericMismatches.length > 0) reasons.push(`numeric mismatches: ${numericMismatches.map((m) => `${m.noun} (source=${m.sourceCount}, rendered=${m.renderedCount})`).join("; ")}`);
|
|
12820
13252
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall: source=${clauseFidelity.sourceClauseCount}, rendered=${clauseFidelity.renderedClauseCount}`);
|
|
12821
13253
|
const errMsg = `create-story output drifted from source AC after ${MAX_FIDELITY_RETRIES} retries; ` + reasons.join("; ");
|
|
12822
|
-
logger$
|
|
13254
|
+
logger$26.error({
|
|
12823
13255
|
storyKey,
|
|
12824
13256
|
pathDrift,
|
|
12825
13257
|
clauseDrift,
|
|
@@ -12846,7 +13278,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12846
13278
|
}
|
|
12847
13279
|
}
|
|
12848
13280
|
} catch (fidelityErr) {
|
|
12849
|
-
logger$
|
|
13281
|
+
logger$26.warn({
|
|
12850
13282
|
storyKey,
|
|
12851
13283
|
err: fidelityErr
|
|
12852
13284
|
}, "fidelity gate threw; proceeding without retry");
|
|
@@ -12877,18 +13309,79 @@ function createImplementationOrchestrator(deps) {
|
|
|
12877
13309
|
...contract.transport !== void 0 ? { transport: contract.transport } : {}
|
|
12878
13310
|
})
|
|
12879
13311
|
});
|
|
12880
|
-
logger$
|
|
13312
|
+
logger$26.info({
|
|
12881
13313
|
storyKey,
|
|
12882
13314
|
contractCount: contracts.length,
|
|
12883
13315
|
contracts
|
|
12884
13316
|
}, "Stored interface contract declarations");
|
|
12885
13317
|
}
|
|
12886
13318
|
} catch (err) {
|
|
12887
|
-
logger$
|
|
13319
|
+
logger$26.warn({
|
|
12888
13320
|
storyKey,
|
|
12889
13321
|
error: err instanceof Error ? err.message : String(err)
|
|
12890
13322
|
}, "Failed to parse interface contracts — continuing without contract declarations");
|
|
12891
13323
|
}
|
|
13324
|
+
if (storyFilePath) try {
|
|
13325
|
+
let probeAuthorEpicContent = "";
|
|
13326
|
+
const probeAuthorEpicsPath = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
|
|
13327
|
+
if (probeAuthorEpicsPath) try {
|
|
13328
|
+
const epicFull = readFileSync(probeAuthorEpicsPath, "utf-8");
|
|
13329
|
+
const section = extractStorySection(epicFull, storyKey);
|
|
13330
|
+
probeAuthorEpicContent = section ?? epicFull;
|
|
13331
|
+
} catch {}
|
|
13332
|
+
if (detectsEventDrivenAC(probeAuthorEpicContent)) {
|
|
13333
|
+
let artifactHasProbes = false;
|
|
13334
|
+
try {
|
|
13335
|
+
const artifactContent = readFileSync(storyFilePath, "utf-8");
|
|
13336
|
+
artifactHasProbes = /^## Runtime Probes/m.test(artifactContent);
|
|
13337
|
+
} catch {}
|
|
13338
|
+
if (!artifactHasProbes) {
|
|
13339
|
+
const probeAuthorResult = await runProbeAuthor({
|
|
13340
|
+
db,
|
|
13341
|
+
pack,
|
|
13342
|
+
contextCompiler,
|
|
13343
|
+
dispatcher,
|
|
13344
|
+
projectRoot,
|
|
13345
|
+
tokenCeilings,
|
|
13346
|
+
otlpEndpoint: _otlpEndpoint,
|
|
13347
|
+
agentId
|
|
13348
|
+
}, {
|
|
13349
|
+
storyKey,
|
|
13350
|
+
storyFilePath,
|
|
13351
|
+
pipelineRunId: config.pipelineRunId ?? "",
|
|
13352
|
+
sourceAcContent: probeAuthorEpicContent,
|
|
13353
|
+
epicContent: probeAuthorEpicContent,
|
|
13354
|
+
emitEvent: (name, payload) => {
|
|
13355
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
13356
|
+
storyKey,
|
|
13357
|
+
msg: `probe-author:${name.replace("probe-author:", "")} ${JSON.stringify(payload)}`
|
|
13358
|
+
});
|
|
13359
|
+
}
|
|
13360
|
+
});
|
|
13361
|
+
logger$26.info({
|
|
13362
|
+
storyKey,
|
|
13363
|
+
result: probeAuthorResult.result,
|
|
13364
|
+
probesAuthoredCount: probeAuthorResult.probesAuthoredCount
|
|
13365
|
+
}, "probe-author phase complete");
|
|
13366
|
+
if (config.pipelineRunId !== void 0 && probeAuthorResult.tokenUsage.input + probeAuthorResult.tokenUsage.output > 0) Promise.resolve().then(() => addTokenUsage(db, config.pipelineRunId, {
|
|
13367
|
+
phase: "probe-author",
|
|
13368
|
+
agent: "probe-author",
|
|
13369
|
+
input_tokens: probeAuthorResult.tokenUsage.input,
|
|
13370
|
+
output_tokens: probeAuthorResult.tokenUsage.output,
|
|
13371
|
+
cost_usd: estimateDispatchCost(probeAuthorResult.tokenUsage.input, probeAuthorResult.tokenUsage.output),
|
|
13372
|
+
metadata: JSON.stringify({ storyKey })
|
|
13373
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
13374
|
+
storyKey,
|
|
13375
|
+
err: tokenErr
|
|
13376
|
+
}, "Failed to record probe-author token usage"));
|
|
13377
|
+
} else logger$26.debug({ storyKey }, "probe-author: story artifact already has ## Runtime Probes — skipping gate");
|
|
13378
|
+
} else logger$26.debug({ storyKey }, "probe-author: source AC not event-driven — skipping gate");
|
|
13379
|
+
} catch (probeAuthorErr) {
|
|
13380
|
+
logger$26.warn({
|
|
13381
|
+
storyKey,
|
|
13382
|
+
err: probeAuthorErr
|
|
13383
|
+
}, "probe-author gate threw unexpectedly; proceeding to test-plan without authored probes");
|
|
13384
|
+
}
|
|
12892
13385
|
await waitIfPaused();
|
|
12893
13386
|
if (_state !== "RUNNING") return;
|
|
12894
13387
|
startPhase(storyKey, "test-plan");
|
|
@@ -12913,10 +13406,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
12913
13406
|
});
|
|
12914
13407
|
testPlanPhaseResult = testPlanResult.result;
|
|
12915
13408
|
testPlanTokenUsage = testPlanResult.tokenUsage;
|
|
12916
|
-
if (testPlanResult.result === "success") logger$
|
|
12917
|
-
else logger$
|
|
13409
|
+
if (testPlanResult.result === "success") logger$26.info({ storyKey }, "Test plan generated successfully");
|
|
13410
|
+
else logger$26.warn({ storyKey }, "Test planning returned failed result — proceeding to dev-story without test plan");
|
|
12918
13411
|
} catch (err) {
|
|
12919
|
-
logger$
|
|
13412
|
+
logger$26.warn({
|
|
12920
13413
|
storyKey,
|
|
12921
13414
|
err
|
|
12922
13415
|
}, "Test planning failed — proceeding to dev-story without test plan");
|
|
@@ -12929,7 +13422,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12929
13422
|
output_tokens: testPlanTokenUsage.output,
|
|
12930
13423
|
cost_usd: estimateDispatchCost(testPlanTokenUsage.input, testPlanTokenUsage.output),
|
|
12931
13424
|
metadata: JSON.stringify({ storyKey })
|
|
12932
|
-
})).catch((tokenErr) => logger$
|
|
13425
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
12933
13426
|
storyKey,
|
|
12934
13427
|
err: tokenErr
|
|
12935
13428
|
}, "Failed to record test-plan token usage"));
|
|
@@ -12997,7 +13490,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12997
13490
|
storyContentForAnalysis = await readFile$1(storyFilePath ?? "", "utf-8");
|
|
12998
13491
|
storyContentForVerification = storyContentForAnalysis;
|
|
12999
13492
|
} catch (err) {
|
|
13000
|
-
logger$
|
|
13493
|
+
logger$26.error({
|
|
13001
13494
|
storyKey,
|
|
13002
13495
|
storyFilePath,
|
|
13003
13496
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -13005,7 +13498,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13005
13498
|
}
|
|
13006
13499
|
const analysis = analyzeStoryComplexity(storyContentForAnalysis);
|
|
13007
13500
|
const batches = planTaskBatches(analysis);
|
|
13008
|
-
logger$
|
|
13501
|
+
logger$26.info({
|
|
13009
13502
|
storyKey,
|
|
13010
13503
|
estimatedScope: analysis.estimatedScope,
|
|
13011
13504
|
batchCount: batches.length,
|
|
@@ -13023,7 +13516,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13023
13516
|
if (_state !== "RUNNING") break;
|
|
13024
13517
|
const taskScope = batch.taskIds.map((id, i) => `T${id}: ${batch.taskTitles[i] ?? ""}`).join("\n");
|
|
13025
13518
|
const priorFiles = allFilesModified.size > 0 ? Array.from(allFilesModified) : void 0;
|
|
13026
|
-
logger$
|
|
13519
|
+
logger$26.info({
|
|
13027
13520
|
storyKey,
|
|
13028
13521
|
batchIndex: batch.batchIndex,
|
|
13029
13522
|
taskCount: batch.taskIds.length
|
|
@@ -13054,7 +13547,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13054
13547
|
});
|
|
13055
13548
|
} catch (batchErr) {
|
|
13056
13549
|
const errMsg = batchErr instanceof Error ? batchErr.message : String(batchErr);
|
|
13057
|
-
logger$
|
|
13550
|
+
logger$26.warn({
|
|
13058
13551
|
storyKey,
|
|
13059
13552
|
batchIndex: batch.batchIndex,
|
|
13060
13553
|
error: errMsg
|
|
@@ -13075,7 +13568,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13075
13568
|
filesModified: batchFilesModified,
|
|
13076
13569
|
result: batchResult.result === "success" ? "success" : "failed"
|
|
13077
13570
|
};
|
|
13078
|
-
logger$
|
|
13571
|
+
logger$26.info(batchMetrics, "Batch dev-story metrics");
|
|
13079
13572
|
for (const f$1 of batchFilesModified) allFilesModified.add(f$1);
|
|
13080
13573
|
if (batchFilesModified.length > 0) batchFileGroups.push({
|
|
13081
13574
|
batchIndex: batch.batchIndex,
|
|
@@ -13094,13 +13587,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
13094
13587
|
durationMs: batchDurationMs,
|
|
13095
13588
|
result: batchMetrics.result
|
|
13096
13589
|
})
|
|
13097
|
-
})).catch((tokenErr) => logger$
|
|
13590
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
13098
13591
|
storyKey,
|
|
13099
13592
|
batchIndex: batch.batchIndex,
|
|
13100
13593
|
err: tokenErr
|
|
13101
13594
|
}, "Failed to record batch token usage"));
|
|
13102
13595
|
if (batchResult.tokenUsage?.output !== void 0) devOutputTokenCount = (devOutputTokenCount ?? 0) + batchResult.tokenUsage.output;
|
|
13103
|
-
if (batchResult.result === "failed") logger$
|
|
13596
|
+
if (batchResult.result === "failed") logger$26.warn({
|
|
13104
13597
|
storyKey,
|
|
13105
13598
|
batchIndex: batch.batchIndex,
|
|
13106
13599
|
error: batchResult.error
|
|
@@ -13143,7 +13636,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13143
13636
|
output_tokens: devResult.tokenUsage.output,
|
|
13144
13637
|
cost_usd: estimateDispatchCost(devResult.tokenUsage.input, devResult.tokenUsage.output),
|
|
13145
13638
|
metadata: JSON.stringify({ storyKey })
|
|
13146
|
-
})).catch((tokenErr) => logger$
|
|
13639
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
13147
13640
|
storyKey,
|
|
13148
13641
|
err: tokenErr
|
|
13149
13642
|
}, "Failed to record dev-story token usage"));
|
|
@@ -13158,7 +13651,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13158
13651
|
endPhase(storyKey, "dev-story");
|
|
13159
13652
|
const timeoutFiles = checkGitDiffFiles(projectRoot ?? process.cwd());
|
|
13160
13653
|
if (timeoutFiles.length === 0) {
|
|
13161
|
-
logger$
|
|
13654
|
+
logger$26.warn({ storyKey }, "Dev-story timeout with zero modified files — escalating immediately (no checkpoint)");
|
|
13162
13655
|
updateStory(storyKey, {
|
|
13163
13656
|
phase: "ESCALATED",
|
|
13164
13657
|
error: "timeout-no-files",
|
|
@@ -13174,7 +13667,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13174
13667
|
await persistState();
|
|
13175
13668
|
return;
|
|
13176
13669
|
}
|
|
13177
|
-
logger$
|
|
13670
|
+
logger$26.info({
|
|
13178
13671
|
storyKey,
|
|
13179
13672
|
filesCount: timeoutFiles.length
|
|
13180
13673
|
}, "Dev-story timeout with partial files — capturing checkpoint");
|
|
@@ -13191,7 +13684,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13191
13684
|
]
|
|
13192
13685
|
}).trim();
|
|
13193
13686
|
} catch (diffErr) {
|
|
13194
|
-
logger$
|
|
13687
|
+
logger$26.warn({
|
|
13195
13688
|
storyKey,
|
|
13196
13689
|
error: diffErr instanceof Error ? diffErr.message : String(diffErr)
|
|
13197
13690
|
}, "Failed to capture git diff for checkpoint — proceeding with empty diff");
|
|
@@ -13218,7 +13711,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13218
13711
|
recordedAt: new Date().toISOString(),
|
|
13219
13712
|
sprint: config.sprint
|
|
13220
13713
|
}).catch((storeErr) => {
|
|
13221
|
-
logger$
|
|
13714
|
+
logger$26.warn({
|
|
13222
13715
|
err: storeErr,
|
|
13223
13716
|
storyKey
|
|
13224
13717
|
}, "Failed to record timeout metric to StateStore (best-effort)");
|
|
@@ -13277,9 +13770,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
13277
13770
|
checkpointRetryPrompt = assembled.prompt;
|
|
13278
13771
|
} catch {
|
|
13279
13772
|
checkpointRetryPrompt = `Continue story ${storyKey} from checkpoint. Your prior attempt timed out. Do not redo completed work.`;
|
|
13280
|
-
logger$
|
|
13773
|
+
logger$26.warn({ storyKey }, "Failed to assemble checkpoint retry prompt — using fallback");
|
|
13281
13774
|
}
|
|
13282
|
-
logger$
|
|
13775
|
+
logger$26.info({
|
|
13283
13776
|
storyKey,
|
|
13284
13777
|
filesCount: checkpointData.filesModified.length
|
|
13285
13778
|
}, "Dispatching checkpoint retry for timed-out story");
|
|
@@ -13308,7 +13801,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13308
13801
|
} : void 0 }
|
|
13309
13802
|
});
|
|
13310
13803
|
if (checkpointRetryResult.status === "timeout") {
|
|
13311
|
-
logger$
|
|
13804
|
+
logger$26.warn({ storyKey }, "Checkpoint retry dispatch timed out — escalating story");
|
|
13312
13805
|
updateStory(storyKey, {
|
|
13313
13806
|
phase: "ESCALATED",
|
|
13314
13807
|
error: "checkpoint-retry-timeout",
|
|
@@ -13328,7 +13821,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13328
13821
|
replaceDevStorySignals(retryParsed);
|
|
13329
13822
|
devFilesModified = retryParsed?.files_modified ?? checkGitDiffFiles(projectRoot ?? process.cwd());
|
|
13330
13823
|
if (checkpointRetryResult.status === "completed" && retryParsed?.result === "success") devStoryWasSuccess = true;
|
|
13331
|
-
else logger$
|
|
13824
|
+
else logger$26.warn({
|
|
13332
13825
|
storyKey,
|
|
13333
13826
|
status: checkpointRetryResult.status
|
|
13334
13827
|
}, "Checkpoint retry completed with failure — proceeding to code review");
|
|
@@ -13338,13 +13831,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
13338
13831
|
replaceDevStorySignals(devResult);
|
|
13339
13832
|
if (devResult.result === "success") devStoryWasSuccess = true;
|
|
13340
13833
|
else {
|
|
13341
|
-
logger$
|
|
13834
|
+
logger$26.warn({
|
|
13342
13835
|
storyKey,
|
|
13343
13836
|
error: devResult.error,
|
|
13344
13837
|
filesModified: devFilesModified.length
|
|
13345
13838
|
}, "Dev-story reported failure, proceeding to code review");
|
|
13346
13839
|
if (!devResult.error?.startsWith("dispatch_timeout")) {
|
|
13347
|
-
logger$
|
|
13840
|
+
logger$26.warn({
|
|
13348
13841
|
storyKey,
|
|
13349
13842
|
error: devResult.error
|
|
13350
13843
|
}, "Agent process failure (non-timeout) — story will proceed to code review with partial work");
|
|
@@ -13406,13 +13899,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
13406
13899
|
}).trim();
|
|
13407
13900
|
if (committedFiles.length > 0) gitDiffFiles = committedFiles.split("\n").filter(Boolean);
|
|
13408
13901
|
} catch {}
|
|
13409
|
-
logger$
|
|
13902
|
+
logger$26.info({
|
|
13410
13903
|
storyKey,
|
|
13411
13904
|
baselineHeadSha,
|
|
13412
13905
|
committedFileCount: gitDiffFiles?.length ?? 0
|
|
13413
13906
|
}, "Working tree clean but new commits detected since dispatch — skipping zero-diff escalation");
|
|
13414
13907
|
} else {
|
|
13415
|
-
logger$
|
|
13908
|
+
logger$26.warn({ storyKey }, "Zero-diff detected after COMPLETE dev-story — no file changes and no new commits");
|
|
13416
13909
|
eventBus.emit("orchestrator:zero-diff-escalation", {
|
|
13417
13910
|
storyKey,
|
|
13418
13911
|
reason: "zero-diff-on-complete"
|
|
@@ -13462,10 +13955,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
13462
13955
|
"pipe"
|
|
13463
13956
|
]
|
|
13464
13957
|
});
|
|
13465
|
-
logger$
|
|
13958
|
+
logger$26.info({ storyKey }, "Secondary typecheck (tsc --noEmit) passed");
|
|
13466
13959
|
} catch (tscErr) {
|
|
13467
13960
|
const tscOutput = tscErr instanceof Error && "stdout" in tscErr ? String(tscErr.stdout ?? "").slice(0, 2e3) : "";
|
|
13468
|
-
logger$
|
|
13961
|
+
logger$26.warn({
|
|
13469
13962
|
storyKey,
|
|
13470
13963
|
tscOutput
|
|
13471
13964
|
}, "Secondary typecheck (tsc --noEmit) failed — treating as build failure");
|
|
@@ -13480,7 +13973,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13480
13973
|
if (buildVerifyResult.status === "passed") {
|
|
13481
13974
|
_buildPassed = true;
|
|
13482
13975
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
13483
|
-
logger$
|
|
13976
|
+
logger$26.info({ storyKey }, "Build verification passed");
|
|
13484
13977
|
} else if (buildVerifyResult.status === "failed" || buildVerifyResult.status === "timeout") {
|
|
13485
13978
|
const truncatedOutput = (buildVerifyResult.output ?? "").slice(0, 2e3);
|
|
13486
13979
|
const reason = buildVerifyResult.reason ?? "build-verification-failed";
|
|
@@ -13489,7 +13982,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13489
13982
|
const resolvedRoot = projectRoot ?? process.cwd();
|
|
13490
13983
|
const hasChanges = detectPackageChanges(_packageSnapshot, resolvedRoot);
|
|
13491
13984
|
if (hasChanges) {
|
|
13492
|
-
logger$
|
|
13985
|
+
logger$26.warn({ storyKey }, "Package files changed since snapshot — restoring to prevent cascade");
|
|
13493
13986
|
const restoreResult = restorePackageSnapshot(_packageSnapshot, { projectRoot: resolvedRoot });
|
|
13494
13987
|
if (restoreResult.restored) {
|
|
13495
13988
|
const retryAfterRestore = runBuildVerification({
|
|
@@ -13502,11 +13995,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
13502
13995
|
retryPassed = true;
|
|
13503
13996
|
_buildPassed = true;
|
|
13504
13997
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
13505
|
-
logger$
|
|
13998
|
+
logger$26.warn({
|
|
13506
13999
|
storyKey,
|
|
13507
14000
|
filesRestored: restoreResult.filesRestored
|
|
13508
14001
|
}, "Build passed after package snapshot restore — cross-story pollution detected and cleaned");
|
|
13509
|
-
} else logger$
|
|
14002
|
+
} else logger$26.warn({
|
|
13510
14003
|
storyKey,
|
|
13511
14004
|
filesRestored: restoreResult.filesRestored
|
|
13512
14005
|
}, "Build still fails after snapshot restore — story has its own build errors");
|
|
@@ -13518,7 +14011,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13518
14011
|
if (missingPkgMatch && buildVerifyResult.status !== "timeout") {
|
|
13519
14012
|
const missingPkg = missingPkgMatch[1].replace(/^(@[^/]+\/[^/]+)\/.*$/, "$1").replace(/^([^@][^/]*)\/.*$/, "$1");
|
|
13520
14013
|
const resolvedRoot = projectRoot ?? process.cwd();
|
|
13521
|
-
logger$
|
|
14014
|
+
logger$26.warn({
|
|
13522
14015
|
storyKey,
|
|
13523
14016
|
missingPkg
|
|
13524
14017
|
}, "Build-fix retry: detected missing npm package — attempting npm install");
|
|
@@ -13529,7 +14022,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13529
14022
|
encoding: "utf-8",
|
|
13530
14023
|
stdio: "pipe"
|
|
13531
14024
|
});
|
|
13532
|
-
logger$
|
|
14025
|
+
logger$26.warn({
|
|
13533
14026
|
storyKey,
|
|
13534
14027
|
missingPkg
|
|
13535
14028
|
}, "Build-fix retry: npm install succeeded — retrying build verification");
|
|
@@ -13543,18 +14036,18 @@ function createImplementationOrchestrator(deps) {
|
|
|
13543
14036
|
retryPassed = true;
|
|
13544
14037
|
_buildPassed = true;
|
|
13545
14038
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
13546
|
-
logger$
|
|
14039
|
+
logger$26.warn({
|
|
13547
14040
|
storyKey,
|
|
13548
14041
|
missingPkg
|
|
13549
14042
|
}, "Build-fix retry: build verification passed after installing missing package");
|
|
13550
|
-
} else logger$
|
|
14043
|
+
} else logger$26.warn({
|
|
13551
14044
|
storyKey,
|
|
13552
14045
|
missingPkg,
|
|
13553
14046
|
retryStatus: retryResult.status
|
|
13554
14047
|
}, "Build-fix retry: build still fails after installing missing package — escalating");
|
|
13555
14048
|
} catch (installErr) {
|
|
13556
14049
|
const installMsg = installErr instanceof Error ? installErr.message : String(installErr);
|
|
13557
|
-
logger$
|
|
14050
|
+
logger$26.warn({
|
|
13558
14051
|
storyKey,
|
|
13559
14052
|
missingPkg,
|
|
13560
14053
|
error: installMsg
|
|
@@ -13564,7 +14057,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13564
14057
|
if (!retryPassed) {
|
|
13565
14058
|
let buildFixPassed = false;
|
|
13566
14059
|
if (buildVerifyResult.status === "failed" && storyFilePath !== void 0) try {
|
|
13567
|
-
logger$
|
|
14060
|
+
logger$26.info({ storyKey }, "Dispatching build-fix agent");
|
|
13568
14061
|
startPhase(storyKey, "build-fix");
|
|
13569
14062
|
const storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
13570
14063
|
let buildFixTemplate;
|
|
@@ -13601,11 +14094,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
13601
14094
|
buildFixPassed = true;
|
|
13602
14095
|
_buildPassed = true;
|
|
13603
14096
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
13604
|
-
logger$
|
|
13605
|
-
} else logger$
|
|
14097
|
+
logger$26.info({ storyKey }, "Build passed after build-fix dispatch");
|
|
14098
|
+
} else logger$26.warn({ storyKey }, "Build still fails after build-fix dispatch — escalating");
|
|
13606
14099
|
} catch (fixErr) {
|
|
13607
14100
|
const fixMsg = fixErr instanceof Error ? fixErr.message : String(fixErr);
|
|
13608
|
-
logger$
|
|
14101
|
+
logger$26.warn({
|
|
13609
14102
|
storyKey,
|
|
13610
14103
|
error: fixMsg
|
|
13611
14104
|
}, "Build-fix dispatch failed — escalating");
|
|
@@ -13616,7 +14109,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13616
14109
|
exitCode: buildVerifyResult.exitCode ?? 1,
|
|
13617
14110
|
output: truncatedOutput
|
|
13618
14111
|
});
|
|
13619
|
-
logger$
|
|
14112
|
+
logger$26.warn({
|
|
13620
14113
|
storyKey,
|
|
13621
14114
|
reason,
|
|
13622
14115
|
exitCode: buildVerifyResult.exitCode
|
|
@@ -13648,7 +14141,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13648
14141
|
storyKey
|
|
13649
14142
|
});
|
|
13650
14143
|
if (icResult.potentiallyAffectedTests.length > 0) {
|
|
13651
|
-
logger$
|
|
14144
|
+
logger$26.warn({
|
|
13652
14145
|
storyKey,
|
|
13653
14146
|
modifiedInterfaces: icResult.modifiedInterfaces,
|
|
13654
14147
|
potentiallyAffectedTests: icResult.potentiallyAffectedTests
|
|
@@ -13729,7 +14222,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13729
14222
|
"NEEDS_MAJOR_REWORK": 2
|
|
13730
14223
|
};
|
|
13731
14224
|
for (const group of batchFileGroups) {
|
|
13732
|
-
logger$
|
|
14225
|
+
logger$26.info({
|
|
13733
14226
|
storyKey,
|
|
13734
14227
|
batchIndex: group.batchIndex,
|
|
13735
14228
|
fileCount: group.files.length
|
|
@@ -13774,7 +14267,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13774
14267
|
rawOutput: lastRawOutput,
|
|
13775
14268
|
tokenUsage: aggregateTokens
|
|
13776
14269
|
};
|
|
13777
|
-
logger$
|
|
14270
|
+
logger$26.info({
|
|
13778
14271
|
storyKey,
|
|
13779
14272
|
batchCount: batchFileGroups.length,
|
|
13780
14273
|
verdict: worstVerdict,
|
|
@@ -13817,7 +14310,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13817
14310
|
storyKey,
|
|
13818
14311
|
reviewCycle: reviewCycles
|
|
13819
14312
|
})
|
|
13820
|
-
})).catch((tokenErr) => logger$
|
|
14313
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
13821
14314
|
storyKey,
|
|
13822
14315
|
err: tokenErr
|
|
13823
14316
|
}, "Failed to record code-review token usage"));
|
|
@@ -13825,7 +14318,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13825
14318
|
const isPhantomReview = reviewResult.dispatchFailed === true || reviewResult.verdict !== "SHIP_IT" && reviewResult.verdict !== "LGTM_WITH_NOTES" && (reviewResult.issue_list === void 0 || reviewResult.issue_list.length === 0) && reviewResult.error !== void 0;
|
|
13826
14319
|
if (isPhantomReview && !timeoutRetried) {
|
|
13827
14320
|
timeoutRetried = true;
|
|
13828
|
-
logger$
|
|
14321
|
+
logger$26.warn({
|
|
13829
14322
|
storyKey,
|
|
13830
14323
|
reviewCycles,
|
|
13831
14324
|
error: reviewResult.error
|
|
@@ -13833,7 +14326,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13833
14326
|
continue;
|
|
13834
14327
|
}
|
|
13835
14328
|
if (isPhantomReview && timeoutRetried) {
|
|
13836
|
-
logger$
|
|
14329
|
+
logger$26.warn({
|
|
13837
14330
|
storyKey,
|
|
13838
14331
|
reviewCycles,
|
|
13839
14332
|
error: reviewResult.error
|
|
@@ -13857,7 +14350,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13857
14350
|
verdict = reviewResult.verdict;
|
|
13858
14351
|
issueList = reviewResult.issue_list ?? [];
|
|
13859
14352
|
if (verdict === "NEEDS_MAJOR_REWORK" && reviewCycles > 0 && previousIssueList.length > 0 && issueList.length < previousIssueList.length) {
|
|
13860
|
-
logger$
|
|
14353
|
+
logger$26.info({
|
|
13861
14354
|
storyKey,
|
|
13862
14355
|
originalVerdict: verdict,
|
|
13863
14356
|
issuesBefore: previousIssueList.length,
|
|
@@ -13893,7 +14386,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13893
14386
|
if (_decomposition !== void 0) parts.push(`decomposed: ${_decomposition.batchCount} batches`);
|
|
13894
14387
|
parts.push(`${fileCount} files`);
|
|
13895
14388
|
parts.push(`${totalTokensK} tokens`);
|
|
13896
|
-
logger$
|
|
14389
|
+
logger$26.info({
|
|
13897
14390
|
storyKey,
|
|
13898
14391
|
verdict,
|
|
13899
14392
|
agentVerdict: reviewResult.agentVerdict
|
|
@@ -13950,7 +14443,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13950
14443
|
phase: "VERIFICATION_FAILED",
|
|
13951
14444
|
completedAt: new Date().toISOString()
|
|
13952
14445
|
});
|
|
13953
|
-
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$
|
|
14446
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
|
|
13954
14447
|
err,
|
|
13955
14448
|
storyKey
|
|
13956
14449
|
}, "StateStore write failed after verification-failed"));
|
|
@@ -13964,7 +14457,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13964
14457
|
completedAt: new Date().toISOString()
|
|
13965
14458
|
});
|
|
13966
14459
|
if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
|
|
13967
|
-
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$
|
|
14460
|
+
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
|
|
13968
14461
|
storyKey,
|
|
13969
14462
|
category: "verification-result-missing"
|
|
13970
14463
|
}, "post-COMPLETE invariant: verification_result absent in manifest");
|
|
@@ -13989,9 +14482,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
13989
14482
|
}),
|
|
13990
14483
|
rationale: `Advisory notes from LGTM_WITH_NOTES review of ${storyKey}`
|
|
13991
14484
|
});
|
|
13992
|
-
logger$
|
|
14485
|
+
logger$26.info({ storyKey }, "Advisory notes persisted to decision store");
|
|
13993
14486
|
} catch (advisoryErr) {
|
|
13994
|
-
logger$
|
|
14487
|
+
logger$26.warn({
|
|
13995
14488
|
storyKey,
|
|
13996
14489
|
error: advisoryErr instanceof Error ? advisoryErr.message : String(advisoryErr)
|
|
13997
14490
|
}, "Failed to persist advisory notes (best-effort)");
|
|
@@ -13999,27 +14492,27 @@ function createImplementationOrchestrator(deps) {
|
|
|
13999
14492
|
if (telemetryPersistence !== void 0) try {
|
|
14000
14493
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
14001
14494
|
if (turns.length > 0) {
|
|
14002
|
-
const scorer = new EfficiencyScorer(logger$
|
|
14495
|
+
const scorer = new EfficiencyScorer(logger$26);
|
|
14003
14496
|
const effScore = scorer.score(storyKey, turns);
|
|
14004
14497
|
await telemetryPersistence.storeEfficiencyScore(effScore);
|
|
14005
|
-
logger$
|
|
14498
|
+
logger$26.info({
|
|
14006
14499
|
storyKey,
|
|
14007
14500
|
compositeScore: effScore.compositeScore,
|
|
14008
14501
|
modelCount: effScore.perModelBreakdown.length
|
|
14009
14502
|
}, "Efficiency score computed and persisted");
|
|
14010
|
-
} else logger$
|
|
14503
|
+
} else logger$26.debug({ storyKey }, "No turn analysis data available — skipping efficiency scoring");
|
|
14011
14504
|
} catch (effErr) {
|
|
14012
|
-
logger$
|
|
14505
|
+
logger$26.warn({
|
|
14013
14506
|
storyKey,
|
|
14014
14507
|
error: effErr instanceof Error ? effErr.message : String(effErr)
|
|
14015
14508
|
}, "Efficiency scoring failed — story verdict unchanged");
|
|
14016
14509
|
}
|
|
14017
14510
|
if (telemetryPersistence !== void 0) try {
|
|
14018
14511
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
14019
|
-
if (turns.length === 0) logger$
|
|
14512
|
+
if (turns.length === 0) logger$26.debug({ storyKey }, "No turn analysis data for telemetry categorization — skipping");
|
|
14020
14513
|
else {
|
|
14021
|
-
const categorizer = new Categorizer(logger$
|
|
14022
|
-
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$
|
|
14514
|
+
const categorizer = new Categorizer(logger$26);
|
|
14515
|
+
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$26);
|
|
14023
14516
|
const categoryStats = categorizer.computeCategoryStatsFromTurns(turns);
|
|
14024
14517
|
const consumerStats = consumerAnalyzer.analyzeFromTurns(turns);
|
|
14025
14518
|
await telemetryPersistence.storeCategoryStats(storyKey, categoryStats);
|
|
@@ -14027,7 +14520,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14027
14520
|
const growingCount = categoryStats.filter((c) => c.trend === "growing").length;
|
|
14028
14521
|
const topCategory = categoryStats[0]?.category ?? "none";
|
|
14029
14522
|
const topConsumer = consumerStats[0]?.consumerKey ?? "none";
|
|
14030
|
-
logger$
|
|
14523
|
+
logger$26.info({
|
|
14031
14524
|
storyKey,
|
|
14032
14525
|
topCategory,
|
|
14033
14526
|
topConsumer,
|
|
@@ -14035,7 +14528,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14035
14528
|
}, "Semantic categorization and consumer analysis complete");
|
|
14036
14529
|
}
|
|
14037
14530
|
} catch (catErr) {
|
|
14038
|
-
logger$
|
|
14531
|
+
logger$26.warn({
|
|
14039
14532
|
storyKey,
|
|
14040
14533
|
error: catErr instanceof Error ? catErr.message : String(catErr)
|
|
14041
14534
|
}, "Semantic categorization failed — story verdict unchanged");
|
|
@@ -14057,7 +14550,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14057
14550
|
filesModified: devFilesModified,
|
|
14058
14551
|
workingDirectory: projectRoot
|
|
14059
14552
|
});
|
|
14060
|
-
logger$
|
|
14553
|
+
logger$26.debug({
|
|
14061
14554
|
storyKey,
|
|
14062
14555
|
expansion_priority: expansionResult.expansion_priority,
|
|
14063
14556
|
coverage_gaps: expansionResult.coverage_gaps.length
|
|
@@ -14070,7 +14563,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14070
14563
|
value: JSON.stringify(expansionResult)
|
|
14071
14564
|
});
|
|
14072
14565
|
} catch (expansionErr) {
|
|
14073
|
-
logger$
|
|
14566
|
+
logger$26.warn({
|
|
14074
14567
|
storyKey,
|
|
14075
14568
|
error: expansionErr instanceof Error ? expansionErr.message : String(expansionErr)
|
|
14076
14569
|
}, "Test expansion failed — story verdict unchanged");
|
|
@@ -14097,7 +14590,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14097
14590
|
await persistState();
|
|
14098
14591
|
return;
|
|
14099
14592
|
}
|
|
14100
|
-
logger$
|
|
14593
|
+
logger$26.info({
|
|
14101
14594
|
storyKey,
|
|
14102
14595
|
reviewCycles: finalReviewCycles,
|
|
14103
14596
|
issueCount: issueList.length
|
|
@@ -14163,7 +14656,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14163
14656
|
fixPrompt = assembled.prompt;
|
|
14164
14657
|
} catch {
|
|
14165
14658
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, minor fixes needed`;
|
|
14166
|
-
logger$
|
|
14659
|
+
logger$26.warn({ storyKey }, "Failed to assemble auto-approve fix prompt, using fallback");
|
|
14167
14660
|
}
|
|
14168
14661
|
const handle = dispatcher.dispatch({
|
|
14169
14662
|
prompt: fixPrompt,
|
|
@@ -14184,9 +14677,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
14184
14677
|
output: fixResult.tokenEstimate.output
|
|
14185
14678
|
} : void 0 }
|
|
14186
14679
|
});
|
|
14187
|
-
if (fixResult.status === "timeout") logger$
|
|
14680
|
+
if (fixResult.status === "timeout") logger$26.warn({ storyKey }, "Auto-approve fix timed out — approving anyway (issues were minor)");
|
|
14188
14681
|
} catch (err) {
|
|
14189
|
-
logger$
|
|
14682
|
+
logger$26.warn({
|
|
14190
14683
|
storyKey,
|
|
14191
14684
|
err
|
|
14192
14685
|
}, "Auto-approve fix dispatch failed — approving anyway (issues were minor)");
|
|
@@ -14223,7 +14716,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14223
14716
|
phase: "VERIFICATION_FAILED",
|
|
14224
14717
|
completedAt: new Date().toISOString()
|
|
14225
14718
|
});
|
|
14226
|
-
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$
|
|
14719
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
|
|
14227
14720
|
err,
|
|
14228
14721
|
storyKey
|
|
14229
14722
|
}, "StateStore write failed after verification-failed"));
|
|
@@ -14246,7 +14739,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14246
14739
|
completedAt: new Date().toISOString()
|
|
14247
14740
|
});
|
|
14248
14741
|
if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
|
|
14249
|
-
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$
|
|
14742
|
+
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
|
|
14250
14743
|
storyKey,
|
|
14251
14744
|
category: "verification-result-missing"
|
|
14252
14745
|
}, "post-COMPLETE invariant: verification_result absent in manifest");
|
|
@@ -14271,7 +14764,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14271
14764
|
outcome: "retried",
|
|
14272
14765
|
cost_usd: 0,
|
|
14273
14766
|
timestamp: new Date().toISOString()
|
|
14274
|
-
}).catch((err) => logger$
|
|
14767
|
+
}).catch((err) => logger$26.warn({
|
|
14275
14768
|
err,
|
|
14276
14769
|
storyKey
|
|
14277
14770
|
}, "appendRecoveryEntry failed — pipeline continues"));
|
|
@@ -14411,7 +14904,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14411
14904
|
fixPrompt = assembled.prompt;
|
|
14412
14905
|
} catch {
|
|
14413
14906
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, taskType=${taskType}`;
|
|
14414
|
-
logger$
|
|
14907
|
+
logger$26.warn({
|
|
14415
14908
|
storyKey,
|
|
14416
14909
|
taskType
|
|
14417
14910
|
}, "Failed to assemble fix prompt, using fallback");
|
|
@@ -14448,7 +14941,86 @@ function createImplementationOrchestrator(deps) {
|
|
|
14448
14941
|
} : void 0 }
|
|
14449
14942
|
});
|
|
14450
14943
|
if (fixResult.status === "timeout") {
|
|
14451
|
-
|
|
14944
|
+
if (taskType === "minor-fixes") {
|
|
14945
|
+
const finalReviewCycles = reviewCycles + 1;
|
|
14946
|
+
const downgradedVerdict = "LGTM_WITH_NOTES";
|
|
14947
|
+
logger$26.warn({
|
|
14948
|
+
storyKey,
|
|
14949
|
+
reviewCycles: finalReviewCycles,
|
|
14950
|
+
issueCount: issueList.length
|
|
14951
|
+
}, "Minor-fixes dispatch timed out — auto-approving as LGTM_WITH_NOTES (original findings retained as warnings)");
|
|
14952
|
+
endPhase(storyKey, "code-review");
|
|
14953
|
+
if (config.skipVerification !== true) {
|
|
14954
|
+
const latestReviewSignals = reviewResult != null ? {
|
|
14955
|
+
dispatchFailed: reviewResult.dispatchFailed,
|
|
14956
|
+
error: reviewResult.error,
|
|
14957
|
+
rawOutput: reviewResult.rawOutput
|
|
14958
|
+
} : void 0;
|
|
14959
|
+
let sourceEpicContent3;
|
|
14960
|
+
const epicsPath3 = findEpicFileForStory(projectRoot ?? process.cwd(), storyKey);
|
|
14961
|
+
if (epicsPath3) try {
|
|
14962
|
+
const epicFull3 = readFileSync(epicsPath3, "utf-8");
|
|
14963
|
+
const section3 = extractStorySection(epicFull3, storyKey);
|
|
14964
|
+
if (section3) sourceEpicContent3 = section3;
|
|
14965
|
+
} catch {}
|
|
14966
|
+
await persistDevStorySignals(storyKey, devStorySignals, runManifest);
|
|
14967
|
+
const verifContext = assembleVerificationContext({
|
|
14968
|
+
storyKey,
|
|
14969
|
+
workingDir: projectRoot ?? process.cwd(),
|
|
14970
|
+
reviewResult: latestReviewSignals,
|
|
14971
|
+
storyContent: storyContentForVerification,
|
|
14972
|
+
devStoryResult: devStorySignals,
|
|
14973
|
+
outputTokenCount: devOutputTokenCount,
|
|
14974
|
+
sourceEpicContent: sourceEpicContent3
|
|
14975
|
+
});
|
|
14976
|
+
const verifSummary = await verificationPipeline.run(verifContext, "A");
|
|
14977
|
+
verificationStore.set(storyKey, verifSummary);
|
|
14978
|
+
await persistVerificationResult(storyKey, verifSummary, runManifest);
|
|
14979
|
+
if (verifSummary.status === "fail") {
|
|
14980
|
+
updateStory(storyKey, {
|
|
14981
|
+
phase: "VERIFICATION_FAILED",
|
|
14982
|
+
completedAt: new Date().toISOString()
|
|
14983
|
+
});
|
|
14984
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$26.warn({
|
|
14985
|
+
err,
|
|
14986
|
+
storyKey
|
|
14987
|
+
}, "StateStore write failed after verification-failed"));
|
|
14988
|
+
await writeStoryMetricsBestEffort(storyKey, "verification-failed", finalReviewCycles);
|
|
14989
|
+
await persistState();
|
|
14990
|
+
return;
|
|
14991
|
+
}
|
|
14992
|
+
}
|
|
14993
|
+
eventBus.emit("story:auto-approved", {
|
|
14994
|
+
storyKey,
|
|
14995
|
+
verdict: downgradedVerdict,
|
|
14996
|
+
reviewCycles: finalReviewCycles,
|
|
14997
|
+
maxReviewCycles: config.maxReviewCycles,
|
|
14998
|
+
issueCount: issueList.length,
|
|
14999
|
+
reason: `Minor-fixes dispatch timed out (cycle ${finalReviewCycles}) — auto-approving as LGTM_WITH_NOTES with original findings retained as warnings`
|
|
15000
|
+
});
|
|
15001
|
+
updateStory(storyKey, {
|
|
15002
|
+
phase: "COMPLETE",
|
|
15003
|
+
reviewCycles: finalReviewCycles,
|
|
15004
|
+
lastVerdict: downgradedVerdict,
|
|
15005
|
+
completedAt: new Date().toISOString()
|
|
15006
|
+
});
|
|
15007
|
+
if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
|
|
15008
|
+
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
|
|
15009
|
+
storyKey,
|
|
15010
|
+
category: "verification-result-missing"
|
|
15011
|
+
}, "post-COMPLETE invariant: verification_result absent in manifest");
|
|
15012
|
+
}).catch(() => {});
|
|
15013
|
+
await writeStoryMetricsBestEffort(storyKey, downgradedVerdict, finalReviewCycles);
|
|
15014
|
+
await writeStoryOutcomeBestEffort(storyKey, "complete", finalReviewCycles);
|
|
15015
|
+
eventBus.emit("orchestrator:story-complete", {
|
|
15016
|
+
storyKey,
|
|
15017
|
+
reviewCycles: finalReviewCycles
|
|
15018
|
+
});
|
|
15019
|
+
await persistState();
|
|
15020
|
+
keepReviewing = false;
|
|
15021
|
+
return;
|
|
15022
|
+
}
|
|
15023
|
+
logger$26.warn({
|
|
14452
15024
|
storyKey,
|
|
14453
15025
|
taskType
|
|
14454
15026
|
}, "Fix dispatch timed out — escalating story");
|
|
@@ -14470,7 +15042,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14470
15042
|
}
|
|
14471
15043
|
if (fixResult.status === "failed") {
|
|
14472
15044
|
if (isMajorRework) {
|
|
14473
|
-
logger$
|
|
15045
|
+
logger$26.warn({
|
|
14474
15046
|
storyKey,
|
|
14475
15047
|
exitCode: fixResult.exitCode
|
|
14476
15048
|
}, "Major rework dispatch failed — escalating story");
|
|
@@ -14490,7 +15062,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14490
15062
|
await persistState();
|
|
14491
15063
|
return;
|
|
14492
15064
|
}
|
|
14493
|
-
logger$
|
|
15065
|
+
logger$26.warn({
|
|
14494
15066
|
storyKey,
|
|
14495
15067
|
taskType,
|
|
14496
15068
|
exitCode: fixResult.exitCode
|
|
@@ -14498,7 +15070,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14498
15070
|
}
|
|
14499
15071
|
if (isMajorRework) replaceDevStorySignals(fixResult.parsed);
|
|
14500
15072
|
} catch (err) {
|
|
14501
|
-
logger$
|
|
15073
|
+
logger$26.warn({
|
|
14502
15074
|
storyKey,
|
|
14503
15075
|
taskType,
|
|
14504
15076
|
err
|
|
@@ -14549,7 +15121,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14549
15121
|
...haltOn !== "none" ? { severity: "critical" } : {}
|
|
14550
15122
|
});
|
|
14551
15123
|
_budgetExhausted = true;
|
|
14552
|
-
logger$
|
|
15124
|
+
logger$26.warn({
|
|
14553
15125
|
skipped: allSkipped.length,
|
|
14554
15126
|
cumulative: result.cumulative,
|
|
14555
15127
|
ceiling: result.ceiling
|
|
@@ -14566,7 +15138,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14566
15138
|
const completedStoryKeys = [];
|
|
14567
15139
|
for (const storyKey of group) {
|
|
14568
15140
|
if (_shutdownRequested) {
|
|
14569
|
-
logger$
|
|
15141
|
+
logger$26.info({ storyKey }, "shutdown requested — skipping dispatch");
|
|
14570
15142
|
return;
|
|
14571
15143
|
}
|
|
14572
15144
|
if (runManifest !== null && runManifest !== void 0) try {
|
|
@@ -14589,7 +15161,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14589
15161
|
}
|
|
14590
15162
|
}
|
|
14591
15163
|
} catch (err) {
|
|
14592
|
-
logger$
|
|
15164
|
+
logger$26.debug({ err }, "Cost ceiling check failed — proceeding without enforcement");
|
|
14593
15165
|
}
|
|
14594
15166
|
let optimizationDirectives;
|
|
14595
15167
|
if (telemetryAdvisor !== void 0 && completedStoryKeys.length > 0) try {
|
|
@@ -14597,13 +15169,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14597
15169
|
const directives = telemetryAdvisor.formatOptimizationDirectives(recs);
|
|
14598
15170
|
if (directives.length > 0) {
|
|
14599
15171
|
optimizationDirectives = directives;
|
|
14600
|
-
logger$
|
|
15172
|
+
logger$26.debug({
|
|
14601
15173
|
storyKey,
|
|
14602
15174
|
directiveCount: recs.filter((r) => r.severity !== "info").length
|
|
14603
15175
|
}, "Optimization directives ready for dispatch");
|
|
14604
15176
|
}
|
|
14605
15177
|
} catch (err) {
|
|
14606
|
-
logger$
|
|
15178
|
+
logger$26.debug({
|
|
14607
15179
|
err,
|
|
14608
15180
|
storyKey
|
|
14609
15181
|
}, "Failed to fetch optimization directives — proceeding without");
|
|
@@ -14658,7 +15230,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14658
15230
|
async function shutdownGracefully(reason, signal) {
|
|
14659
15231
|
if (_shutdownRequested) return;
|
|
14660
15232
|
_shutdownRequested = true;
|
|
14661
|
-
logger$
|
|
15233
|
+
logger$26.info({
|
|
14662
15234
|
reason,
|
|
14663
15235
|
signal
|
|
14664
15236
|
}, "Graceful shutdown initiated — stopping new dispatches");
|
|
@@ -14668,8 +15240,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
14668
15240
|
run_status: "stopped",
|
|
14669
15241
|
stopped_reason: reason,
|
|
14670
15242
|
stopped_at: new Date().toISOString()
|
|
14671
|
-
}).catch((err) => logger$
|
|
14672
|
-
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$
|
|
15243
|
+
}).catch((err) => logger$26.warn({ err }, "patchRunStatus failed during shutdown (best-effort)"));
|
|
15244
|
+
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$26.warn({ err }, "updatePipelineRun(stopped) failed during shutdown (best-effort)"));
|
|
14673
15245
|
const activePhases = [
|
|
14674
15246
|
"PENDING",
|
|
14675
15247
|
"IN_STORY_CREATION",
|
|
@@ -14680,7 +15252,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14680
15252
|
"CHECKPOINT"
|
|
14681
15253
|
];
|
|
14682
15254
|
const cancellations = [];
|
|
14683
|
-
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$
|
|
15255
|
+
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$26.warn({
|
|
14684
15256
|
err,
|
|
14685
15257
|
storyKey
|
|
14686
15258
|
}, "wg_stories → cancelled failed during shutdown (best-effort)")));
|
|
@@ -14689,11 +15261,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
14689
15261
|
}
|
|
14690
15262
|
async function run(storyKeys) {
|
|
14691
15263
|
if (_state === "RUNNING" || _state === "PAUSED") {
|
|
14692
|
-
logger$
|
|
15264
|
+
logger$26.warn({ state: _state }, "run() called while orchestrator is already running or paused — ignoring");
|
|
14693
15265
|
return getStatus();
|
|
14694
15266
|
}
|
|
14695
15267
|
if (_state === "COMPLETE") {
|
|
14696
|
-
logger$
|
|
15268
|
+
logger$26.warn({ state: _state }, "run() called on a COMPLETE orchestrator — ignoring");
|
|
14697
15269
|
return getStatus();
|
|
14698
15270
|
}
|
|
14699
15271
|
_state = "RUNNING";
|
|
@@ -14717,7 +15289,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14717
15289
|
const seedStart = Date.now();
|
|
14718
15290
|
const seedResult = await seedMethodologyContext(db, projectRoot);
|
|
14719
15291
|
_startupTimings.seedMethodologyMs = Date.now() - seedStart;
|
|
14720
|
-
if (seedResult.decisionsCreated > 0) logger$
|
|
15292
|
+
if (seedResult.decisionsCreated > 0) logger$26.info({
|
|
14721
15293
|
decisionsCreated: seedResult.decisionsCreated,
|
|
14722
15294
|
skippedCategories: seedResult.skippedCategories,
|
|
14723
15295
|
durationMs: _startupTimings.seedMethodologyMs
|
|
@@ -14727,12 +15299,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14727
15299
|
const ingestStart = Date.now();
|
|
14728
15300
|
try {
|
|
14729
15301
|
const ingestResult = await autoIngestEpicsDependencies(db, projectRoot);
|
|
14730
|
-
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$
|
|
15302
|
+
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$26.info({
|
|
14731
15303
|
...ingestResult,
|
|
14732
15304
|
durationMs: Date.now() - ingestStart
|
|
14733
15305
|
}, "Auto-ingested stories and dependencies from epics document");
|
|
14734
15306
|
} catch (err) {
|
|
14735
|
-
logger$
|
|
15307
|
+
logger$26.debug({ err }, "Auto-ingest from epics document skipped — work graph may be unavailable");
|
|
14736
15308
|
}
|
|
14737
15309
|
}
|
|
14738
15310
|
const sigtermHandler = () => {
|
|
@@ -14750,7 +15322,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14750
15322
|
_startupTimings.stateStoreInitMs = Date.now() - stateStoreInitStart;
|
|
14751
15323
|
for (const key of storyKeys) {
|
|
14752
15324
|
const pendingState = _stories.get(key);
|
|
14753
|
-
if (pendingState !== void 0) persistStoryState(key, pendingState).catch((err) => logger$
|
|
15325
|
+
if (pendingState !== void 0) persistStoryState(key, pendingState).catch((err) => logger$26.warn({
|
|
14754
15326
|
err,
|
|
14755
15327
|
storyKey: key
|
|
14756
15328
|
}, "StateStore write failed during PENDING init"));
|
|
@@ -14761,12 +15333,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14761
15333
|
_startupTimings.queryStoriesMs = Date.now() - queryStoriesStart;
|
|
14762
15334
|
for (const record of existingRecords) _stateStoreCache.set(record.storyKey, record);
|
|
14763
15335
|
} catch (err) {
|
|
14764
|
-
logger$
|
|
15336
|
+
logger$26.warn({ err }, "StateStore.queryStories() failed during init — status merge will be empty (best-effort)");
|
|
14765
15337
|
}
|
|
14766
15338
|
}
|
|
14767
15339
|
if (ingestionServer !== void 0) {
|
|
14768
15340
|
if (telemetryPersistence !== void 0) try {
|
|
14769
|
-
const pipelineLogger = logger$
|
|
15341
|
+
const pipelineLogger = logger$26;
|
|
14770
15342
|
const telemetryPipeline = new TelemetryPipeline({
|
|
14771
15343
|
normalizer: new TelemetryNormalizer(pipelineLogger),
|
|
14772
15344
|
turnAnalyzer: new TurnAnalyzer(pipelineLogger),
|
|
@@ -14778,14 +15350,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
14778
15350
|
persistence: telemetryPersistence
|
|
14779
15351
|
});
|
|
14780
15352
|
ingestionServer.setPipeline(telemetryPipeline);
|
|
14781
|
-
logger$
|
|
15353
|
+
logger$26.info("TelemetryPipeline wired to IngestionServer");
|
|
14782
15354
|
} catch (pipelineErr) {
|
|
14783
|
-
logger$
|
|
15355
|
+
logger$26.warn({ err: pipelineErr }, "Failed to create TelemetryPipeline — continuing without analysis pipeline");
|
|
14784
15356
|
}
|
|
14785
|
-
await ingestionServer.start().catch((err) => logger$
|
|
15357
|
+
await ingestionServer.start().catch((err) => logger$26.warn({ err }, "IngestionServer.start() failed — continuing without telemetry (best-effort)"));
|
|
14786
15358
|
try {
|
|
14787
15359
|
_otlpEndpoint = ingestionServer.getOtlpEnvVars().OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
14788
|
-
logger$
|
|
15360
|
+
logger$26.info({ otlpEndpoint: _otlpEndpoint }, "OTLP telemetry ingestion active");
|
|
14789
15361
|
} catch {}
|
|
14790
15362
|
}
|
|
14791
15363
|
let contractDeclarations = [];
|
|
@@ -14825,12 +15397,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14825
15397
|
const conflictDetectStart = Date.now();
|
|
14826
15398
|
const { batches, edges: contractEdges } = detectConflictGroupsWithContracts(storyKeys, { moduleMap: pack.manifest.conflictGroups }, contractDeclarations);
|
|
14827
15399
|
_startupTimings.conflictDetectMs = Date.now() - conflictDetectStart;
|
|
14828
|
-
if (contractEdges.length > 0) logger$
|
|
15400
|
+
if (contractEdges.length > 0) logger$26.info({
|
|
14829
15401
|
contractEdges,
|
|
14830
15402
|
edgeCount: contractEdges.length
|
|
14831
15403
|
}, "Contract dependency edges detected — applying contract-aware dispatch ordering");
|
|
14832
|
-
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$
|
|
14833
|
-
logger$
|
|
15404
|
+
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$26.warn({ err }, "contract dep persistence failed (best-effort)"));
|
|
15405
|
+
logger$26.info({
|
|
14834
15406
|
storyCount: storyKeys.length,
|
|
14835
15407
|
groupCount: batches.reduce((sum, b) => sum + b.length, 0),
|
|
14836
15408
|
batchCount: batches.length,
|
|
@@ -14840,7 +15412,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14840
15412
|
groups: batch.map((g) => g.join(","))
|
|
14841
15413
|
}))
|
|
14842
15414
|
}, "Orchestrator starting");
|
|
14843
|
-
logger$
|
|
15415
|
+
logger$26.info({
|
|
14844
15416
|
storyCount: storyKeys.length,
|
|
14845
15417
|
conflictGroups: batches.length,
|
|
14846
15418
|
maxConcurrency: config.maxConcurrency
|
|
@@ -14861,7 +15433,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14861
15433
|
exitCode,
|
|
14862
15434
|
output: truncatedOutput
|
|
14863
15435
|
});
|
|
14864
|
-
logger$
|
|
15436
|
+
logger$26.error({
|
|
14865
15437
|
exitCode,
|
|
14866
15438
|
reason: preFlightResult.reason
|
|
14867
15439
|
}, "Pre-flight build check failed — aborting pipeline before any story dispatch");
|
|
@@ -14870,19 +15442,19 @@ function createImplementationOrchestrator(deps) {
|
|
|
14870
15442
|
await persistState();
|
|
14871
15443
|
return getStatus();
|
|
14872
15444
|
}
|
|
14873
|
-
if (preFlightResult.status !== "skipped") logger$
|
|
15445
|
+
if (preFlightResult.status !== "skipped") logger$26.info("Pre-flight build check passed");
|
|
14874
15446
|
}
|
|
14875
|
-
logger$
|
|
15447
|
+
logger$26.info(_startupTimings, "Orchestrator startup timings (ms)");
|
|
14876
15448
|
const totalGroups = batches.reduce((sum, b) => sum + b.length, 0);
|
|
14877
15449
|
const actualConcurrency = Math.min(config.maxConcurrency, totalGroups);
|
|
14878
15450
|
if (actualConcurrency > 1 && projectRoot !== void 0) try {
|
|
14879
15451
|
_packageSnapshot = capturePackageSnapshot({ projectRoot });
|
|
14880
|
-
logger$
|
|
15452
|
+
logger$26.info({
|
|
14881
15453
|
fileCount: _packageSnapshot.files.size,
|
|
14882
15454
|
installCommand: _packageSnapshot.installCommand
|
|
14883
15455
|
}, "Package snapshot captured for concurrent story protection");
|
|
14884
15456
|
} catch (snapErr) {
|
|
14885
|
-
logger$
|
|
15457
|
+
logger$26.warn({ err: snapErr }, "Failed to capture package snapshot — continuing without protection");
|
|
14886
15458
|
}
|
|
14887
15459
|
try {
|
|
14888
15460
|
for (const batchGroups of batches) await runWithConcurrency(batchGroups, config.maxConcurrency);
|
|
@@ -14891,7 +15463,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14891
15463
|
_state = "FAILED";
|
|
14892
15464
|
_completedAt = new Date().toISOString();
|
|
14893
15465
|
await persistState();
|
|
14894
|
-
logger$
|
|
15466
|
+
logger$26.error({ err }, "Orchestrator failed with unhandled error");
|
|
14895
15467
|
return getStatus();
|
|
14896
15468
|
}
|
|
14897
15469
|
stopHeartbeat();
|
|
@@ -14901,7 +15473,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14901
15473
|
const totalDeclarations = contractDeclarations.length;
|
|
14902
15474
|
const currentSprintDeclarations = contractDeclarations.filter((d) => storyKeys.includes(d.storyKey));
|
|
14903
15475
|
const stalePruned = totalDeclarations - currentSprintDeclarations.length;
|
|
14904
|
-
if (stalePruned > 0) logger$
|
|
15476
|
+
if (stalePruned > 0) logger$26.info({
|
|
14905
15477
|
stalePruned,
|
|
14906
15478
|
remaining: currentSprintDeclarations.length
|
|
14907
15479
|
}, "Pruned stale contract declarations from previous epics");
|
|
@@ -14915,11 +15487,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
14915
15487
|
contractName: mismatch.contractName,
|
|
14916
15488
|
mismatchDescription: mismatch.mismatchDescription
|
|
14917
15489
|
});
|
|
14918
|
-
logger$
|
|
15490
|
+
logger$26.warn({
|
|
14919
15491
|
mismatchCount: mismatches.length,
|
|
14920
15492
|
mismatches
|
|
14921
15493
|
}, "Post-sprint contract verification found mismatches — manual review required");
|
|
14922
|
-
} else if (currentSprintDeclarations.length > 0) logger$
|
|
15494
|
+
} else if (currentSprintDeclarations.length > 0) logger$26.info("Post-sprint contract verification passed — all declared contracts satisfied");
|
|
14923
15495
|
eventBus.emit("pipeline:contract-verification-summary", {
|
|
14924
15496
|
verified: currentSprintDeclarations.length,
|
|
14925
15497
|
stalePruned,
|
|
@@ -14954,12 +15526,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14954
15526
|
});
|
|
14955
15527
|
await stateStore.setContractVerification(sk, records);
|
|
14956
15528
|
}
|
|
14957
|
-
logger$
|
|
15529
|
+
logger$26.info({ storyCount: contractsByStory.size }, "Contract verification results persisted to StateStore");
|
|
14958
15530
|
} catch (persistErr) {
|
|
14959
|
-
logger$
|
|
15531
|
+
logger$26.warn({ err: persistErr }, "Failed to persist contract verification results to StateStore");
|
|
14960
15532
|
}
|
|
14961
15533
|
} catch (err) {
|
|
14962
|
-
logger$
|
|
15534
|
+
logger$26.error({ err }, "Post-sprint contract verification threw an error — skipping");
|
|
14963
15535
|
}
|
|
14964
15536
|
if (projectRoot !== void 0) try {
|
|
14965
15537
|
const indicators = checkProfileStaleness(projectRoot);
|
|
@@ -14969,10 +15541,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
14969
15541
|
message,
|
|
14970
15542
|
indicators
|
|
14971
15543
|
});
|
|
14972
|
-
logger$
|
|
15544
|
+
logger$26.warn({ indicators }, message);
|
|
14973
15545
|
}
|
|
14974
15546
|
} catch (err) {
|
|
14975
|
-
logger$
|
|
15547
|
+
logger$26.debug({ err }, "Profile staleness check failed (best-effort)");
|
|
14976
15548
|
}
|
|
14977
15549
|
let completed = 0;
|
|
14978
15550
|
let escalated = 0;
|
|
@@ -14991,8 +15563,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
14991
15563
|
} finally {
|
|
14992
15564
|
process.off("SIGTERM", sigtermHandler);
|
|
14993
15565
|
process.off("SIGINT", sigintHandler);
|
|
14994
|
-
if (stateStore !== void 0) await stateStore.close().catch((err) => logger$
|
|
14995
|
-
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$
|
|
15566
|
+
if (stateStore !== void 0) await stateStore.close().catch((err) => logger$26.warn({ err }, "StateStore.close() failed (best-effort)"));
|
|
15567
|
+
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$26.warn({ err }, "IngestionServer.stop() failed (best-effort)"));
|
|
14996
15568
|
}
|
|
14997
15569
|
}
|
|
14998
15570
|
function pause() {
|
|
@@ -15001,7 +15573,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15001
15573
|
_pauseGate = createPauseGate();
|
|
15002
15574
|
_state = "PAUSED";
|
|
15003
15575
|
eventBus.emit("orchestrator:paused", {});
|
|
15004
|
-
logger$
|
|
15576
|
+
logger$26.info("Orchestrator paused");
|
|
15005
15577
|
}
|
|
15006
15578
|
function resume() {
|
|
15007
15579
|
if (_state !== "PAUSED") return;
|
|
@@ -15012,7 +15584,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15012
15584
|
}
|
|
15013
15585
|
_state = "RUNNING";
|
|
15014
15586
|
eventBus.emit("orchestrator:resumed", {});
|
|
15015
|
-
logger$
|
|
15587
|
+
logger$26.info("Orchestrator resumed");
|
|
15016
15588
|
}
|
|
15017
15589
|
return {
|
|
15018
15590
|
run,
|
|
@@ -16428,8 +17000,8 @@ async function resolveContext(ref, deps, runId, params, stepOutputs) {
|
|
|
16428
17000
|
return params[key] ?? "";
|
|
16429
17001
|
}
|
|
16430
17002
|
if (source.startsWith("decision:")) {
|
|
16431
|
-
const path$
|
|
16432
|
-
const [phase, category] = path$
|
|
17003
|
+
const path$4 = source.slice(9);
|
|
17004
|
+
const [phase, category] = path$4.split(".");
|
|
16433
17005
|
if (!phase || !category) return "";
|
|
16434
17006
|
const decisions = await getDecisionsByPhaseForRun(deps.db, runId, phase);
|
|
16435
17007
|
const filtered = decisions.filter((d) => d.category === category);
|
|
@@ -16500,8 +17072,8 @@ async function runSteps(steps, deps, runId, phase, params) {
|
|
|
16500
17072
|
for (const ref of step.context) {
|
|
16501
17073
|
let value;
|
|
16502
17074
|
if (ref.source.startsWith("decision:")) {
|
|
16503
|
-
const path$
|
|
16504
|
-
const [decPhase, decCategory] = path$
|
|
17075
|
+
const path$4 = ref.source.slice(9);
|
|
17076
|
+
const [decPhase, decCategory] = path$4.split(".");
|
|
16505
17077
|
if (decPhase && decCategory) {
|
|
16506
17078
|
const decisions = await getDecisionsByPhaseForRun(deps.db, runId, decPhase);
|
|
16507
17079
|
const filtered = decisions.filter((d) => d.category === decCategory);
|
|
@@ -27548,8 +28120,8 @@ var require_uri_all = __commonJS({ "node_modules/uri-js/dist/es5/uri.all.js"(exp
|
|
|
27548
28120
|
wsComponents.secure = void 0;
|
|
27549
28121
|
}
|
|
27550
28122
|
if (wsComponents.resourceName) {
|
|
27551
|
-
var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path$
|
|
27552
|
-
wsComponents.path = path$
|
|
28123
|
+
var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path$4 = _wsComponents$resourc2[0], query = _wsComponents$resourc2[1];
|
|
28124
|
+
wsComponents.path = path$4 && path$4 !== "/" ? path$4 : void 0;
|
|
27553
28125
|
wsComponents.query = query;
|
|
27554
28126
|
wsComponents.resourceName = void 0;
|
|
27555
28127
|
}
|
|
@@ -27890,12 +28462,12 @@ var require_util = __commonJS({ "node_modules/ajv/lib/compile/util.js"(exports,
|
|
|
27890
28462
|
return "'" + escapeQuotes(str) + "'";
|
|
27891
28463
|
}
|
|
27892
28464
|
function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
|
|
27893
|
-
var path$
|
|
27894
|
-
return joinPaths(currentPath, path$
|
|
28465
|
+
var path$4 = jsonPointers ? "'/' + " + expr + (isNumber ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'";
|
|
28466
|
+
return joinPaths(currentPath, path$4);
|
|
27895
28467
|
}
|
|
27896
28468
|
function getPath(currentPath, prop, jsonPointers) {
|
|
27897
|
-
var path$
|
|
27898
|
-
return joinPaths(currentPath, path$
|
|
28469
|
+
var path$4 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop));
|
|
28470
|
+
return joinPaths(currentPath, path$4);
|
|
27899
28471
|
}
|
|
27900
28472
|
var JSON_POINTER$1 = /^\/(?:[^~]|~0|~1)*$/;
|
|
27901
28473
|
var RELATIVE_JSON_POINTER$1 = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
|
@@ -32063,16 +32635,16 @@ var require_ajv = __commonJS({ "node_modules/ajv/lib/ajv.js"(exports, module) {
|
|
|
32063
32635
|
return metaOpts;
|
|
32064
32636
|
}
|
|
32065
32637
|
function setLogger(self) {
|
|
32066
|
-
var logger$
|
|
32067
|
-
if (logger$
|
|
32638
|
+
var logger$26 = self._opts.logger;
|
|
32639
|
+
if (logger$26 === false) self.logger = {
|
|
32068
32640
|
log: noop,
|
|
32069
32641
|
warn: noop,
|
|
32070
32642
|
error: noop
|
|
32071
32643
|
};
|
|
32072
32644
|
else {
|
|
32073
|
-
if (logger$
|
|
32074
|
-
if (!(typeof logger$
|
|
32075
|
-
self.logger = logger$
|
|
32645
|
+
if (logger$26 === void 0) logger$26 = console;
|
|
32646
|
+
if (!(typeof logger$26 == "object" && logger$26.log && logger$26.warn && logger$26.error)) throw new Error("logger must implement log, warn and error methods");
|
|
32647
|
+
self.logger = logger$26;
|
|
32076
32648
|
}
|
|
32077
32649
|
}
|
|
32078
32650
|
function noop() {}
|
|
@@ -32104,8 +32676,8 @@ var ToolRegistry = class {
|
|
|
32104
32676
|
if (!valid) {
|
|
32105
32677
|
const errors = validate$1.errors ?? [];
|
|
32106
32678
|
const messages = errors.map((e) => {
|
|
32107
|
-
const path$
|
|
32108
|
-
return `${path$
|
|
32679
|
+
const path$4 = e.instancePath ?? e.dataPath ?? "";
|
|
32680
|
+
return `${path$4} ${e.message ?? ""}`.trim();
|
|
32109
32681
|
}).join(", ");
|
|
32110
32682
|
return {
|
|
32111
32683
|
content: `Validation failed for tool '${name}': ${messages}`,
|
|
@@ -38709,10 +39281,10 @@ var PathBase = class {
|
|
|
38709
39281
|
/**
|
|
38710
39282
|
* Get the Path object referenced by the string path, resolved from this Path
|
|
38711
39283
|
*/
|
|
38712
|
-
resolve(path$
|
|
38713
|
-
if (!path$
|
|
38714
|
-
const rootPath = this.getRootString(path$
|
|
38715
|
-
const dir = path$
|
|
39284
|
+
resolve(path$4) {
|
|
39285
|
+
if (!path$4) return this;
|
|
39286
|
+
const rootPath = this.getRootString(path$4);
|
|
39287
|
+
const dir = path$4.substring(rootPath.length);
|
|
38716
39288
|
const dirParts = dir.split(this.splitSep);
|
|
38717
39289
|
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
|
|
38718
39290
|
return result;
|
|
@@ -39367,8 +39939,8 @@ var PathWin32 = class PathWin32 extends PathBase {
|
|
|
39367
39939
|
/**
|
|
39368
39940
|
* @internal
|
|
39369
39941
|
*/
|
|
39370
|
-
getRootString(path$
|
|
39371
|
-
return win32.parse(path$
|
|
39942
|
+
getRootString(path$4) {
|
|
39943
|
+
return win32.parse(path$4).root;
|
|
39372
39944
|
}
|
|
39373
39945
|
/**
|
|
39374
39946
|
* @internal
|
|
@@ -39413,8 +39985,8 @@ var PathPosix = class PathPosix extends PathBase {
|
|
|
39413
39985
|
/**
|
|
39414
39986
|
* @internal
|
|
39415
39987
|
*/
|
|
39416
|
-
getRootString(path$
|
|
39417
|
-
return path$
|
|
39988
|
+
getRootString(path$4) {
|
|
39989
|
+
return path$4.startsWith("/") ? "/" : "";
|
|
39418
39990
|
}
|
|
39419
39991
|
/**
|
|
39420
39992
|
* @internal
|
|
@@ -39507,9 +40079,9 @@ var PathScurryBase = class {
|
|
|
39507
40079
|
/**
|
|
39508
40080
|
* Get the depth of a provided path, string, or the cwd
|
|
39509
40081
|
*/
|
|
39510
|
-
depth(path$
|
|
39511
|
-
if (typeof path$
|
|
39512
|
-
return path$
|
|
40082
|
+
depth(path$4 = this.cwd) {
|
|
40083
|
+
if (typeof path$4 === "string") path$4 = this.cwd.resolve(path$4);
|
|
40084
|
+
return path$4.depth();
|
|
39513
40085
|
}
|
|
39514
40086
|
/**
|
|
39515
40087
|
* Return the cache of child entries. Exposed so subclasses can create
|
|
@@ -39890,9 +40462,9 @@ var PathScurryBase = class {
|
|
|
39890
40462
|
process$1();
|
|
39891
40463
|
return results;
|
|
39892
40464
|
}
|
|
39893
|
-
chdir(path$
|
|
40465
|
+
chdir(path$4 = this.cwd) {
|
|
39894
40466
|
const oldCwd = this.cwd;
|
|
39895
|
-
this.cwd = typeof path$
|
|
40467
|
+
this.cwd = typeof path$4 === "string" ? this.cwd.resolve(path$4) : path$4;
|
|
39896
40468
|
this.cwd[setAsCwd](oldCwd);
|
|
39897
40469
|
}
|
|
39898
40470
|
};
|
|
@@ -40276,8 +40848,8 @@ var MatchRecord = class {
|
|
|
40276
40848
|
this.store.set(target, current === void 0 ? n$1 : n$1 & current);
|
|
40277
40849
|
}
|
|
40278
40850
|
entries() {
|
|
40279
|
-
return [...this.store.entries()].map(([path$
|
|
40280
|
-
path$
|
|
40851
|
+
return [...this.store.entries()].map(([path$4, n$1]) => [
|
|
40852
|
+
path$4,
|
|
40281
40853
|
!!(n$1 & 2),
|
|
40282
40854
|
!!(n$1 & 1)
|
|
40283
40855
|
]);
|
|
@@ -40453,9 +41025,9 @@ var GlobUtil = class {
|
|
|
40453
41025
|
signal;
|
|
40454
41026
|
maxDepth;
|
|
40455
41027
|
includeChildMatches;
|
|
40456
|
-
constructor(patterns, path$
|
|
41028
|
+
constructor(patterns, path$4, opts) {
|
|
40457
41029
|
this.patterns = patterns;
|
|
40458
|
-
this.path = path$
|
|
41030
|
+
this.path = path$4;
|
|
40459
41031
|
this.opts = opts;
|
|
40460
41032
|
this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
|
|
40461
41033
|
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
@@ -40476,11 +41048,11 @@ var GlobUtil = class {
|
|
|
40476
41048
|
});
|
|
40477
41049
|
}
|
|
40478
41050
|
}
|
|
40479
|
-
#ignored(path$
|
|
40480
|
-
return this.seen.has(path$
|
|
41051
|
+
#ignored(path$4) {
|
|
41052
|
+
return this.seen.has(path$4) || !!this.#ignore?.ignored?.(path$4);
|
|
40481
41053
|
}
|
|
40482
|
-
#childrenIgnored(path$
|
|
40483
|
-
return !!this.#ignore?.childrenIgnored?.(path$
|
|
41054
|
+
#childrenIgnored(path$4) {
|
|
41055
|
+
return !!this.#ignore?.childrenIgnored?.(path$4);
|
|
40484
41056
|
}
|
|
40485
41057
|
pause() {
|
|
40486
41058
|
this.paused = true;
|
|
@@ -40662,8 +41234,8 @@ var GlobUtil = class {
|
|
|
40662
41234
|
};
|
|
40663
41235
|
var GlobWalker = class extends GlobUtil {
|
|
40664
41236
|
matches = new Set();
|
|
40665
|
-
constructor(patterns, path$
|
|
40666
|
-
super(patterns, path$
|
|
41237
|
+
constructor(patterns, path$4, opts) {
|
|
41238
|
+
super(patterns, path$4, opts);
|
|
40667
41239
|
}
|
|
40668
41240
|
matchEmit(e) {
|
|
40669
41241
|
this.matches.add(e);
|
|
@@ -40690,8 +41262,8 @@ var GlobWalker = class extends GlobUtil {
|
|
|
40690
41262
|
};
|
|
40691
41263
|
var GlobStream = class extends GlobUtil {
|
|
40692
41264
|
results;
|
|
40693
|
-
constructor(patterns, path$
|
|
40694
|
-
super(patterns, path$
|
|
41265
|
+
constructor(patterns, path$4, opts) {
|
|
41266
|
+
super(patterns, path$4, opts);
|
|
40695
41267
|
this.results = new Minipass({
|
|
40696
41268
|
signal: this.signal,
|
|
40697
41269
|
objectMode: true
|
|
@@ -44583,4 +45155,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
44583
45155
|
|
|
44584
45156
|
//#endregion
|
|
44585
45157
|
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
44586
|
-
//# sourceMappingURL=run-
|
|
45158
|
+
//# sourceMappingURL=run-DGyWCmcu.js.map
|