substrate-ai 0.20.78 → 0.20.81
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/README.md +7 -0
- package/dist/adapter-registry-BgfwxcSY.js +4 -0
- package/dist/cli/index.js +40 -641
- package/dist/cli/templates/agents-md-substrate-section.md +5 -0
- package/dist/cli/templates/claude-md-substrate-section.md +5 -0
- package/dist/cli/templates/gemini-md-substrate-section.md +5 -0
- package/dist/{health-EyALt_76.js → health-CuKzY0Fn.js} +2 -2
- package/dist/{health-CUPkzJ8b.js → health-D_2Tesme.js} +2 -2
- package/dist/index.d.ts +34 -1
- package/dist/index.js +1 -1
- package/dist/{interactive-prompt-DqvUvzPv.js → interactive-prompt-CsvMelhG.js} +2 -2
- package/dist/{manifest-read-DP4lBymM.js → manifest-read-Boipz5aP.js} +7 -3
- package/dist/modules/interactive-prompt/index.js +2 -2
- package/dist/{run-5R5ZPgSw.js → run-CElciHC1.js} +1413 -435
- package/dist/{run-E6tr8jf3.js → run-DWIVzH_N.js} +4 -4
- package/dist/src/modules/recovery-engine/index.d.ts +12 -1
- package/package.json +1 -1
- package/dist/adapter-registry-B42bBpfj.js +0 -4
- /package/dist/{adapter-registry-DXLMTmfD.js → adapter-registry-DIcrxjH8.js} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-CuKzY0Fn.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, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-DCBSXUiX.js";
|
|
5
|
-
import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-
|
|
5
|
+
import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-Boipz5aP.js";
|
|
6
6
|
import { WorkGraphRepository, detectCycles } from "./work-graph-repository-DZyJv5pV.js";
|
|
7
7
|
import { deriveExitCode, routeDecision } from "./decision-router-DblHY8se.js";
|
|
8
|
-
import { runInteractivePrompt } from "./interactive-prompt-
|
|
8
|
+
import { runInteractivePrompt } from "./interactive-prompt-CsvMelhG.js";
|
|
9
9
|
import { runRecoveryEngine } from "./recovery-engine-BKGBeBnW.js";
|
|
10
10
|
import { basename, dirname, extname, join } from "path";
|
|
11
11
|
import { access, readFile, readdir, stat } from "fs/promises";
|
|
@@ -14,12 +14,14 @@ import yaml from "js-yaml";
|
|
|
14
14
|
import * as actualFS from "node:fs";
|
|
15
15
|
import { accessSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
|
|
16
16
|
import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
|
|
17
|
+
import * as path$5 from "node:path";
|
|
18
|
+
import * as path$4 from "node:path";
|
|
17
19
|
import * as path$2 from "node:path";
|
|
18
20
|
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";
|
|
19
21
|
import { tmpdir } from "node:os";
|
|
20
22
|
import { createHash, randomUUID } from "node:crypto";
|
|
21
23
|
import { z } from "zod";
|
|
22
|
-
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 as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
|
|
24
|
+
import { access as access$1, lstat, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, readlink, realpath, rename, rm, stat as stat$1, unlink as unlink$1, writeFile as writeFile$1 } from "node:fs/promises";
|
|
23
25
|
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";
|
|
24
26
|
import { promisify } from "node:util";
|
|
25
27
|
import { fileURLToPath } from "node:url";
|
|
@@ -31,6 +33,623 @@ import { channel, tracingChannel } from "node:diagnostics_channel";
|
|
|
31
33
|
import Stream from "node:stream";
|
|
32
34
|
import { StringDecoder } from "node:string_decoder";
|
|
33
35
|
|
|
36
|
+
//#region packages/core/dist/git/git-utils.js
|
|
37
|
+
const MIN_GIT_MAJOR = 2;
|
|
38
|
+
const MIN_GIT_MINOR = 20;
|
|
39
|
+
/**
|
|
40
|
+
* Spawn a git subprocess with the given args.
|
|
41
|
+
*
|
|
42
|
+
* @param args - Arguments to pass to git (e.g., ['worktree', 'add', ...])
|
|
43
|
+
* @param options - Optional spawn options (cwd, env)
|
|
44
|
+
* @returns - Object with stdout, stderr, and exit code
|
|
45
|
+
*/
|
|
46
|
+
function spawnGit(args, options) {
|
|
47
|
+
return new Promise((resolve$6) => {
|
|
48
|
+
const proc$1 = spawn("git", args, {
|
|
49
|
+
cwd: options?.cwd,
|
|
50
|
+
env: options?.env ?? process.env,
|
|
51
|
+
stdio: [
|
|
52
|
+
"ignore",
|
|
53
|
+
"pipe",
|
|
54
|
+
"pipe"
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
let stdout = "";
|
|
58
|
+
let stderr = "";
|
|
59
|
+
proc$1.stdout?.on("data", (chunk) => {
|
|
60
|
+
stdout += chunk.toString();
|
|
61
|
+
});
|
|
62
|
+
proc$1.stderr?.on("data", (chunk) => {
|
|
63
|
+
stderr += chunk.toString();
|
|
64
|
+
});
|
|
65
|
+
proc$1.on("close", (code) => {
|
|
66
|
+
resolve$6({
|
|
67
|
+
stdout: stdout.trim(),
|
|
68
|
+
stderr: stderr.trim(),
|
|
69
|
+
code: code ?? 1
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
proc$1.on("error", (err) => {
|
|
73
|
+
resolve$6({
|
|
74
|
+
stdout: "",
|
|
75
|
+
stderr: err.message,
|
|
76
|
+
code: 1
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the installed git version string.
|
|
83
|
+
*
|
|
84
|
+
* @returns Version string like "2.42.0"
|
|
85
|
+
* @throws Error if git is not installed or version cannot be parsed
|
|
86
|
+
*/
|
|
87
|
+
async function getGitVersion() {
|
|
88
|
+
const result = await spawnGit(["--version"]);
|
|
89
|
+
if (result.code !== 0) throw new Error(`git --version failed: ${result.stderr}`);
|
|
90
|
+
const match$2 = /git version\s+(\d+\.\d+(?:\.\d+)?)/.exec(result.stdout);
|
|
91
|
+
if (match$2 === null || match$2[1] === void 0) throw new Error(`Unable to parse git version from output: "${result.stdout}"`);
|
|
92
|
+
return match$2[1];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Parse a git version string into major/minor/patch components.
|
|
96
|
+
*
|
|
97
|
+
* @param versionString - Version string like "2.42.0" or "2.20"
|
|
98
|
+
* @returns - Parsed version components
|
|
99
|
+
*/
|
|
100
|
+
function parseGitVersion(versionString) {
|
|
101
|
+
const parts = versionString.split(".").map(Number);
|
|
102
|
+
return {
|
|
103
|
+
major: parts[0] ?? 0,
|
|
104
|
+
minor: parts[1] ?? 0,
|
|
105
|
+
patch: parts[2] ?? 0
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if the given git version string is >= 2.20.0.
|
|
110
|
+
*
|
|
111
|
+
* @param version - Version string like "2.42.0"
|
|
112
|
+
* @returns - true if version >= 2.20.0
|
|
113
|
+
*/
|
|
114
|
+
function isGitVersionSupported(version) {
|
|
115
|
+
const { major, minor } = parseGitVersion(version);
|
|
116
|
+
if (major > MIN_GIT_MAJOR) return true;
|
|
117
|
+
if (major === MIN_GIT_MAJOR && minor >= MIN_GIT_MINOR) return true;
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Verify that git is installed and version >= 2.20.
|
|
122
|
+
*
|
|
123
|
+
* @throws Error with clear message if git is not installed or too old
|
|
124
|
+
*/
|
|
125
|
+
async function verifyGitVersion() {
|
|
126
|
+
let version;
|
|
127
|
+
try {
|
|
128
|
+
version = await getGitVersion();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
throw new Error(`git is not installed or could not be executed. Please install git 2.20 or newer. Details: ${String(err)}`);
|
|
131
|
+
}
|
|
132
|
+
if (!isGitVersionSupported(version)) {
|
|
133
|
+
const { major, minor, patch } = parseGitVersion(version);
|
|
134
|
+
throw new Error(`Git version ${major}.${minor}.${patch} is too old. Substrate requires git 2.20 or newer. Please upgrade git: https://git-scm.com/downloads`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create a git worktree and its associated branch.
|
|
139
|
+
*
|
|
140
|
+
* Uses a single `git worktree add {worktreePath} -b {branchName} {baseBranch}`
|
|
141
|
+
* command to create the worktree with a new branch in one step.
|
|
142
|
+
*
|
|
143
|
+
* @param projectRoot - Absolute path to the git repository root
|
|
144
|
+
* @param taskId - Task identifier (used in path derivation)
|
|
145
|
+
* @param branchName - Branch name to create (e.g., "substrate/task-abc123")
|
|
146
|
+
* @param baseBranch - Branch to base the worktree on (e.g., "main")
|
|
147
|
+
* @returns - Object with the worktreePath
|
|
148
|
+
* @throws - Error if git command fails
|
|
149
|
+
*/
|
|
150
|
+
async function createWorktree(projectRoot, taskId, branchName, baseBranch) {
|
|
151
|
+
const worktreePath = path$5.join(projectRoot, ".substrate-worktrees", taskId);
|
|
152
|
+
const worktreeExists = await access$1(worktreePath).then(() => true).catch((err) => {
|
|
153
|
+
if (err.code === "ENOENT") return false;
|
|
154
|
+
throw err;
|
|
155
|
+
});
|
|
156
|
+
if (worktreeExists) {
|
|
157
|
+
const listResult = await spawnGit([
|
|
158
|
+
"worktree",
|
|
159
|
+
"list",
|
|
160
|
+
"--porcelain"
|
|
161
|
+
], { cwd: projectRoot });
|
|
162
|
+
const registeredPaths = listResult.stdout.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice(9).trim());
|
|
163
|
+
const isRegistered = registeredPaths.includes(worktreePath);
|
|
164
|
+
if (!isRegistered) await rm(worktreePath, {
|
|
165
|
+
recursive: true,
|
|
166
|
+
force: true
|
|
167
|
+
});
|
|
168
|
+
else throw new Error(`Worktree at ${worktreePath} is already registered. Run \`substrate worktrees --cleanup\` to remove it.`);
|
|
169
|
+
}
|
|
170
|
+
const addResult = await spawnGit([
|
|
171
|
+
"worktree",
|
|
172
|
+
"add",
|
|
173
|
+
worktreePath,
|
|
174
|
+
"-b",
|
|
175
|
+
branchName,
|
|
176
|
+
baseBranch
|
|
177
|
+
], { cwd: projectRoot });
|
|
178
|
+
if (addResult.code !== 0) throw new Error(`git worktree add failed for task "${taskId}": ${addResult.stderr || addResult.stdout}`);
|
|
179
|
+
return { worktreePath };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Remove a git worktree by path.
|
|
183
|
+
*
|
|
184
|
+
* Uses `git worktree remove --force` to handle unclean worktrees.
|
|
185
|
+
*
|
|
186
|
+
* @param worktreePath - Absolute path to the worktree directory
|
|
187
|
+
* @param projectRoot - Absolute path to the git repository root
|
|
188
|
+
* @throws - Error if git command fails
|
|
189
|
+
*/
|
|
190
|
+
async function removeWorktree(worktreePath, projectRoot) {
|
|
191
|
+
const spawnOpts = {};
|
|
192
|
+
if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
|
|
193
|
+
const result = await spawnGit([
|
|
194
|
+
"worktree",
|
|
195
|
+
"remove",
|
|
196
|
+
"--force",
|
|
197
|
+
worktreePath
|
|
198
|
+
], spawnOpts);
|
|
199
|
+
if (result.code !== 0) throw new Error(`git worktree remove failed for "${worktreePath}": ${result.stderr || result.stdout}`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Delete a git branch using `git branch -D`.
|
|
203
|
+
*
|
|
204
|
+
* @param branchName - Branch name to delete (e.g., "substrate/task-abc123")
|
|
205
|
+
* @param projectRoot - Absolute path to the git repository root
|
|
206
|
+
* @returns - true if branch was successfully deleted, false otherwise
|
|
207
|
+
*/
|
|
208
|
+
async function removeBranch(branchName, projectRoot) {
|
|
209
|
+
const spawnOpts = {};
|
|
210
|
+
if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
|
|
211
|
+
const result = await spawnGit([
|
|
212
|
+
"branch",
|
|
213
|
+
"-D",
|
|
214
|
+
branchName
|
|
215
|
+
], spawnOpts);
|
|
216
|
+
if (result.code !== 0) return false;
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Scan the worktrees base directory and return paths of all found worktree directories.
|
|
221
|
+
*
|
|
222
|
+
* @param projectRoot - Absolute path to the git repository root
|
|
223
|
+
* @param baseDirectory - Relative directory name for worktrees (default: '.substrate-worktrees')
|
|
224
|
+
* @returns - Array of absolute worktree directory paths
|
|
225
|
+
*/
|
|
226
|
+
async function getOrphanedWorktrees(projectRoot, baseDirectory = ".substrate-worktrees") {
|
|
227
|
+
const worktreesDir = path$5.join(projectRoot, baseDirectory);
|
|
228
|
+
try {
|
|
229
|
+
await access$1(worktreesDir);
|
|
230
|
+
} catch {
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
let entries;
|
|
234
|
+
try {
|
|
235
|
+
entries = await readdir$1(worktreesDir, { withFileTypes: true });
|
|
236
|
+
} catch {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => path$5.join(worktreesDir, entry.name));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Simulate a merge using git merge --no-commit --no-ff without committing.
|
|
243
|
+
*
|
|
244
|
+
* This runs in the target branch's working directory (the project root or
|
|
245
|
+
* worktree path). The simulation must be aborted after checking conflicts
|
|
246
|
+
* via abortMerge().
|
|
247
|
+
*
|
|
248
|
+
* @param branchName - The source branch to simulate merging
|
|
249
|
+
* @param cwd - Working directory (must be on the target branch)
|
|
250
|
+
* @returns - true if merge would be clean, false if there are conflicts
|
|
251
|
+
*/
|
|
252
|
+
async function simulateMerge(branchName, cwd) {
|
|
253
|
+
const result = await spawnGit([
|
|
254
|
+
"merge",
|
|
255
|
+
"--no-commit",
|
|
256
|
+
"--no-ff",
|
|
257
|
+
branchName
|
|
258
|
+
], { cwd });
|
|
259
|
+
if (result.code === 0) return true;
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Abort a merge in progress using git merge --abort.
|
|
264
|
+
*
|
|
265
|
+
* Should be called after simulateMerge() to clean up the merge state,
|
|
266
|
+
* regardless of whether conflicts were found.
|
|
267
|
+
*
|
|
268
|
+
* @param cwd - Working directory (same as used for simulateMerge)
|
|
269
|
+
*/
|
|
270
|
+
async function abortMerge(cwd) {
|
|
271
|
+
await spawnGit(["merge", "--abort"], { cwd });
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get a list of files with conflicts during a merge.
|
|
275
|
+
*
|
|
276
|
+
* Must be called while a merge is in progress (after simulateMerge() and
|
|
277
|
+
* before abortMerge()).
|
|
278
|
+
*
|
|
279
|
+
* @param cwd - Working directory of the repository
|
|
280
|
+
* @returns - Array of conflicting file paths
|
|
281
|
+
*/
|
|
282
|
+
async function getConflictingFiles(cwd) {
|
|
283
|
+
const result = await spawnGit([
|
|
284
|
+
"diff",
|
|
285
|
+
"--name-only",
|
|
286
|
+
"--diff-filter=U"
|
|
287
|
+
], { cwd });
|
|
288
|
+
if (result.code !== 0) return [];
|
|
289
|
+
if (result.stdout.trim() === "") return [];
|
|
290
|
+
return result.stdout.trim().split("\n").filter((f$1) => f$1.trim().length > 0);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Perform an actual merge using git merge --no-ff.
|
|
294
|
+
*
|
|
295
|
+
* Should only be called after detectConflicts() confirms there are no conflicts.
|
|
296
|
+
* Creates a merge commit even if fast-forward is possible (--no-ff ensures history).
|
|
297
|
+
*
|
|
298
|
+
* @param branchName - The source branch to merge
|
|
299
|
+
* @param cwd - Working directory (must be on the target branch)
|
|
300
|
+
* @returns - true if merge succeeded, false otherwise
|
|
301
|
+
*/
|
|
302
|
+
async function performMerge(branchName, cwd) {
|
|
303
|
+
const result = await spawnGit([
|
|
304
|
+
"merge",
|
|
305
|
+
"--no-ff",
|
|
306
|
+
branchName
|
|
307
|
+
], { cwd });
|
|
308
|
+
if (result.code !== 0) return false;
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get a list of files changed in the most recent merge.
|
|
313
|
+
*
|
|
314
|
+
* Uses git diff --name-only HEAD~1..HEAD to find files in the merge commit.
|
|
315
|
+
* Falls back to empty array if commit history is insufficient.
|
|
316
|
+
*
|
|
317
|
+
* @param cwd - Working directory of the repository
|
|
318
|
+
* @returns - Array of file paths that were merged
|
|
319
|
+
*/
|
|
320
|
+
async function getMergedFiles(cwd) {
|
|
321
|
+
const result = await spawnGit([
|
|
322
|
+
"diff",
|
|
323
|
+
"--name-only",
|
|
324
|
+
"HEAD~1..HEAD"
|
|
325
|
+
], { cwd });
|
|
326
|
+
if (result.code !== 0) {
|
|
327
|
+
const altResult = await spawnGit([
|
|
328
|
+
"show",
|
|
329
|
+
"--name-only",
|
|
330
|
+
"--format=",
|
|
331
|
+
"HEAD"
|
|
332
|
+
], { cwd });
|
|
333
|
+
if (altResult.code !== 0) return [];
|
|
334
|
+
return altResult.stdout.trim().split("\n").filter((f$1) => f$1.trim().length > 0);
|
|
335
|
+
}
|
|
336
|
+
if (result.stdout.trim() === "") return [];
|
|
337
|
+
return result.stdout.trim().split("\n").filter((f$1) => f$1.trim().length > 0);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region packages/core/dist/git/git-worktree-manager-impl.js
|
|
342
|
+
const BRANCH_PREFIX = "substrate/task-";
|
|
343
|
+
const DEFAULT_WORKTREE_BASE = ".substrate-worktrees";
|
|
344
|
+
var GitWorktreeManagerImpl = class {
|
|
345
|
+
_eventBus;
|
|
346
|
+
_projectRoot;
|
|
347
|
+
_baseDirectory;
|
|
348
|
+
_db;
|
|
349
|
+
_logger;
|
|
350
|
+
/** Bound listener references for cleanup in shutdown() */
|
|
351
|
+
_onTaskReady;
|
|
352
|
+
_onTaskComplete;
|
|
353
|
+
_onTaskFailed;
|
|
354
|
+
constructor(eventBus, projectRoot, baseDirectory = DEFAULT_WORKTREE_BASE, db = null, logger$27) {
|
|
355
|
+
this._eventBus = eventBus;
|
|
356
|
+
this._projectRoot = projectRoot;
|
|
357
|
+
this._baseDirectory = baseDirectory;
|
|
358
|
+
this._db = db;
|
|
359
|
+
this._logger = logger$27 ?? console;
|
|
360
|
+
this._onTaskReady = ({ taskId }) => {
|
|
361
|
+
this._handleTaskReady(taskId).catch((err) => {
|
|
362
|
+
this._logger.error({
|
|
363
|
+
taskId,
|
|
364
|
+
err
|
|
365
|
+
}, "Unhandled error in _handleTaskReady");
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
this._onTaskComplete = ({ taskId }) => {
|
|
369
|
+
this._handleTaskDone(taskId);
|
|
370
|
+
};
|
|
371
|
+
this._onTaskFailed = ({ taskId }) => {
|
|
372
|
+
this._handleTaskDone(taskId);
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
async initialize() {
|
|
376
|
+
this._logger.info({ projectRoot: this._projectRoot }, "GitWorktreeManager.initialize()");
|
|
377
|
+
await this.verifyGitVersion();
|
|
378
|
+
const cleaned = await this.cleanupAllWorktrees();
|
|
379
|
+
if (cleaned > 0) this._logger.info({ cleaned }, "Recovered orphaned worktrees on startup");
|
|
380
|
+
this._eventBus.on("task:ready", this._onTaskReady);
|
|
381
|
+
this._eventBus.on("task:complete", this._onTaskComplete);
|
|
382
|
+
this._eventBus.on("task:failed", this._onTaskFailed);
|
|
383
|
+
this._logger.info("GitWorktreeManager initialized");
|
|
384
|
+
}
|
|
385
|
+
async shutdown() {
|
|
386
|
+
this._logger.info("GitWorktreeManager.shutdown()");
|
|
387
|
+
this._eventBus.off("task:ready", this._onTaskReady);
|
|
388
|
+
this._eventBus.off("task:complete", this._onTaskComplete);
|
|
389
|
+
this._eventBus.off("task:failed", this._onTaskFailed);
|
|
390
|
+
await this.cleanupAllWorktrees();
|
|
391
|
+
this._logger.info("GitWorktreeManager shutdown complete");
|
|
392
|
+
}
|
|
393
|
+
async _handleTaskReady(taskId) {
|
|
394
|
+
this._logger.debug({ taskId }, "task:ready — creating worktree");
|
|
395
|
+
try {
|
|
396
|
+
await this.createWorktree(taskId);
|
|
397
|
+
} catch (err) {
|
|
398
|
+
this._logger.error({
|
|
399
|
+
taskId,
|
|
400
|
+
err
|
|
401
|
+
}, "Failed to create worktree for task");
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async _handleTaskDone(taskId) {
|
|
405
|
+
this._logger.debug({ taskId }, "task done — cleaning up worktree");
|
|
406
|
+
try {
|
|
407
|
+
await this.cleanupWorktree(taskId);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
this._logger.warn({
|
|
410
|
+
taskId,
|
|
411
|
+
err
|
|
412
|
+
}, "Failed to cleanup worktree for task");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
async createWorktree(taskId, baseBranch = "main") {
|
|
416
|
+
if (!taskId || taskId.trim().length === 0) throw new Error("createWorktree: taskId must be a non-empty string");
|
|
417
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
418
|
+
const worktreePath = this.getWorktreePath(taskId);
|
|
419
|
+
this._logger.debug({
|
|
420
|
+
taskId,
|
|
421
|
+
branchName,
|
|
422
|
+
worktreePath,
|
|
423
|
+
baseBranch
|
|
424
|
+
}, "createWorktree");
|
|
425
|
+
await createWorktree(this._projectRoot, taskId, branchName, baseBranch);
|
|
426
|
+
const createdAt = new Date();
|
|
427
|
+
this._eventBus.emit("worktree:created", {
|
|
428
|
+
taskId,
|
|
429
|
+
branchName,
|
|
430
|
+
worktreePath,
|
|
431
|
+
createdAt
|
|
432
|
+
});
|
|
433
|
+
const info = {
|
|
434
|
+
taskId,
|
|
435
|
+
branchName,
|
|
436
|
+
worktreePath,
|
|
437
|
+
createdAt
|
|
438
|
+
};
|
|
439
|
+
this._logger.info({
|
|
440
|
+
taskId,
|
|
441
|
+
branchName,
|
|
442
|
+
worktreePath
|
|
443
|
+
}, "Worktree created");
|
|
444
|
+
return info;
|
|
445
|
+
}
|
|
446
|
+
async cleanupWorktree(taskId) {
|
|
447
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
448
|
+
const worktreePath = this.getWorktreePath(taskId);
|
|
449
|
+
this._logger.debug({
|
|
450
|
+
taskId,
|
|
451
|
+
branchName,
|
|
452
|
+
worktreePath
|
|
453
|
+
}, "cleanupWorktree");
|
|
454
|
+
let worktreeExists = false;
|
|
455
|
+
try {
|
|
456
|
+
await access$1(worktreePath);
|
|
457
|
+
worktreeExists = true;
|
|
458
|
+
} catch {
|
|
459
|
+
this._logger.debug({
|
|
460
|
+
taskId,
|
|
461
|
+
worktreePath
|
|
462
|
+
}, "cleanupWorktree: worktree does not exist, skipping removal");
|
|
463
|
+
}
|
|
464
|
+
if (worktreeExists) try {
|
|
465
|
+
await removeWorktree(worktreePath, this._projectRoot);
|
|
466
|
+
} catch (err) {
|
|
467
|
+
this._logger.warn({
|
|
468
|
+
taskId,
|
|
469
|
+
worktreePath,
|
|
470
|
+
err
|
|
471
|
+
}, "removeWorktree failed during cleanup");
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
await removeBranch(branchName, this._projectRoot);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
this._logger.warn({
|
|
477
|
+
taskId,
|
|
478
|
+
branchName,
|
|
479
|
+
err
|
|
480
|
+
}, "removeBranch failed during cleanup");
|
|
481
|
+
}
|
|
482
|
+
this._eventBus.emit("worktree:removed", {
|
|
483
|
+
taskId,
|
|
484
|
+
branchName
|
|
485
|
+
});
|
|
486
|
+
this._logger.info({
|
|
487
|
+
taskId,
|
|
488
|
+
branchName
|
|
489
|
+
}, "Worktree cleaned up");
|
|
490
|
+
}
|
|
491
|
+
async cleanupAllWorktrees() {
|
|
492
|
+
this._logger.debug({ projectRoot: this._projectRoot }, "cleanupAllWorktrees");
|
|
493
|
+
const orphanedPaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
|
|
494
|
+
let cleaned = 0;
|
|
495
|
+
for (const worktreePath of orphanedPaths) {
|
|
496
|
+
const taskId = path$4.basename(worktreePath);
|
|
497
|
+
let worktreeRemoved = false;
|
|
498
|
+
try {
|
|
499
|
+
await removeWorktree(worktreePath, this._projectRoot);
|
|
500
|
+
worktreeRemoved = true;
|
|
501
|
+
this._logger.debug({
|
|
502
|
+
taskId,
|
|
503
|
+
worktreePath
|
|
504
|
+
}, "cleanupAllWorktrees: removed orphaned worktree");
|
|
505
|
+
} catch (err) {
|
|
506
|
+
this._logger.warn({
|
|
507
|
+
taskId,
|
|
508
|
+
worktreePath,
|
|
509
|
+
err
|
|
510
|
+
}, "cleanupAllWorktrees: failed to remove worktree");
|
|
511
|
+
}
|
|
512
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
513
|
+
try {
|
|
514
|
+
const branchRemoved = await removeBranch(branchName, this._projectRoot);
|
|
515
|
+
if (branchRemoved) this._logger.debug({
|
|
516
|
+
taskId,
|
|
517
|
+
branchName
|
|
518
|
+
}, "cleanupAllWorktrees: removed orphaned branch");
|
|
519
|
+
} catch (err) {
|
|
520
|
+
this._logger.warn({
|
|
521
|
+
taskId,
|
|
522
|
+
branchName,
|
|
523
|
+
err
|
|
524
|
+
}, "cleanupAllWorktrees: failed to remove branch");
|
|
525
|
+
}
|
|
526
|
+
if (worktreeRemoved) cleaned++;
|
|
527
|
+
}
|
|
528
|
+
if (cleaned > 0) this._logger.info({ cleaned }, "cleanupAllWorktrees: recovered orphaned worktrees");
|
|
529
|
+
return cleaned;
|
|
530
|
+
}
|
|
531
|
+
async detectConflicts(taskId, targetBranch = "main") {
|
|
532
|
+
if (!taskId || taskId.trim().length === 0) throw new Error("detectConflicts: taskId must be a non-empty string");
|
|
533
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
534
|
+
const worktreePath = this.getWorktreePath(taskId);
|
|
535
|
+
this._logger.debug({
|
|
536
|
+
taskId,
|
|
537
|
+
branchName,
|
|
538
|
+
targetBranch
|
|
539
|
+
}, "detectConflicts");
|
|
540
|
+
try {
|
|
541
|
+
await access$1(worktreePath);
|
|
542
|
+
} catch {
|
|
543
|
+
throw new Error(`detectConflicts: Worktree for task "${taskId}" not found at "${worktreePath}". The worktree may have already been cleaned up.`);
|
|
544
|
+
}
|
|
545
|
+
const mergeClean = await simulateMerge(branchName, this._projectRoot);
|
|
546
|
+
let conflictingFiles = [];
|
|
547
|
+
try {
|
|
548
|
+
if (!mergeClean) conflictingFiles = await getConflictingFiles(this._projectRoot);
|
|
549
|
+
} finally {
|
|
550
|
+
await abortMerge(this._projectRoot);
|
|
551
|
+
}
|
|
552
|
+
const report = {
|
|
553
|
+
hasConflicts: !mergeClean || conflictingFiles.length > 0,
|
|
554
|
+
conflictingFiles,
|
|
555
|
+
taskId,
|
|
556
|
+
targetBranch
|
|
557
|
+
};
|
|
558
|
+
if (report.hasConflicts) this._eventBus.emit("worktree:conflict", {
|
|
559
|
+
taskId,
|
|
560
|
+
branch: branchName,
|
|
561
|
+
conflictingFiles: report.conflictingFiles
|
|
562
|
+
});
|
|
563
|
+
this._logger.info({
|
|
564
|
+
taskId,
|
|
565
|
+
hasConflicts: report.hasConflicts,
|
|
566
|
+
conflictCount: conflictingFiles.length
|
|
567
|
+
}, "Conflict detection complete");
|
|
568
|
+
return report;
|
|
569
|
+
}
|
|
570
|
+
async mergeWorktree(taskId, targetBranch = "main") {
|
|
571
|
+
if (!taskId || taskId.trim().length === 0) throw new Error("mergeWorktree: taskId must be a non-empty string");
|
|
572
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
573
|
+
this._logger.debug({
|
|
574
|
+
taskId,
|
|
575
|
+
branchName,
|
|
576
|
+
targetBranch
|
|
577
|
+
}, "mergeWorktree");
|
|
578
|
+
const conflictReport = await this.detectConflicts(taskId, targetBranch);
|
|
579
|
+
if (conflictReport.hasConflicts) {
|
|
580
|
+
this._logger.info({
|
|
581
|
+
taskId,
|
|
582
|
+
conflictCount: conflictReport.conflictingFiles.length
|
|
583
|
+
}, "Merge skipped due to conflicts");
|
|
584
|
+
return {
|
|
585
|
+
success: false,
|
|
586
|
+
mergedFiles: [],
|
|
587
|
+
conflicts: conflictReport
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
const mergeSuccess = await performMerge(branchName, this._projectRoot);
|
|
591
|
+
if (!mergeSuccess) throw new Error(`mergeWorktree: git merge --no-ff failed for task "${taskId}" branch "${branchName}"`);
|
|
592
|
+
const mergedFiles = await getMergedFiles(this._projectRoot);
|
|
593
|
+
this._eventBus.emit("worktree:merged", {
|
|
594
|
+
taskId,
|
|
595
|
+
branch: branchName,
|
|
596
|
+
mergedFiles
|
|
597
|
+
});
|
|
598
|
+
const result = {
|
|
599
|
+
success: true,
|
|
600
|
+
mergedFiles
|
|
601
|
+
};
|
|
602
|
+
this._logger.info({
|
|
603
|
+
taskId,
|
|
604
|
+
branchName,
|
|
605
|
+
mergedFileCount: mergedFiles.length
|
|
606
|
+
}, "Worktree merged successfully");
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
async listWorktrees() {
|
|
610
|
+
this._logger.debug({
|
|
611
|
+
projectRoot: this._projectRoot,
|
|
612
|
+
baseDirectory: this._baseDirectory
|
|
613
|
+
}, "listWorktrees");
|
|
614
|
+
const worktreePaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
|
|
615
|
+
const results = [];
|
|
616
|
+
for (const worktreePath of worktreePaths) {
|
|
617
|
+
const taskId = path$4.basename(worktreePath);
|
|
618
|
+
const branchName = BRANCH_PREFIX + taskId;
|
|
619
|
+
let createdAt;
|
|
620
|
+
try {
|
|
621
|
+
const { stat: stat$2 } = await import("node:fs/promises");
|
|
622
|
+
const stats = await stat$2(worktreePath);
|
|
623
|
+
createdAt = stats.birthtime ?? stats.ctime;
|
|
624
|
+
} catch {
|
|
625
|
+
createdAt = new Date();
|
|
626
|
+
}
|
|
627
|
+
results.push({
|
|
628
|
+
taskId,
|
|
629
|
+
branchName,
|
|
630
|
+
worktreePath,
|
|
631
|
+
createdAt
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
this._logger.debug({ count: results.length }, "listWorktrees: found worktrees");
|
|
635
|
+
return results;
|
|
636
|
+
}
|
|
637
|
+
getWorktreePath(taskId) {
|
|
638
|
+
return path$4.join(this._projectRoot, this._baseDirectory, taskId);
|
|
639
|
+
}
|
|
640
|
+
async verifyGitVersion() {
|
|
641
|
+
try {
|
|
642
|
+
await verifyGitVersion();
|
|
643
|
+
} catch (err) {
|
|
644
|
+
throw new Error(`GitWorktreeManager: git version check failed: ${String(err)}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
function createGitWorktreeManager(options) {
|
|
649
|
+
return new GitWorktreeManagerImpl(options.eventBus, options.projectRoot, options.baseDirectory, options.db ?? null, options.logger);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
//#endregion
|
|
34
653
|
//#region src/modules/methodology-pack/schemas.ts
|
|
35
654
|
/**
|
|
36
655
|
* A reference to a context value to inject into a step prompt.
|
|
@@ -1820,6 +2439,33 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
1820
2439
|
description: "Human-readable reason for skipping."
|
|
1821
2440
|
}
|
|
1822
2441
|
]
|
|
2442
|
+
},
|
|
2443
|
+
{
|
|
2444
|
+
type: "pipeline:merge-conflict-detected",
|
|
2445
|
+
description: "A story branch could not be merged into the base branch — both branches edited the same lines. The story is marked ESCALATED. The worktree and branch are preserved for operator inspection.",
|
|
2446
|
+
when: "Emitted during the merge-to-main phase when a 3-way merge fails due to conflicts. Story 75-2.",
|
|
2447
|
+
fields: [
|
|
2448
|
+
{
|
|
2449
|
+
name: "ts",
|
|
2450
|
+
type: "string",
|
|
2451
|
+
description: "Timestamp."
|
|
2452
|
+
},
|
|
2453
|
+
{
|
|
2454
|
+
name: "storyKey",
|
|
2455
|
+
type: "string",
|
|
2456
|
+
description: "Story key whose branch could not be merged."
|
|
2457
|
+
},
|
|
2458
|
+
{
|
|
2459
|
+
name: "branchName",
|
|
2460
|
+
type: "string",
|
|
2461
|
+
description: "Branch name being merged (e.g., \"substrate/story-75-2\")."
|
|
2462
|
+
},
|
|
2463
|
+
{
|
|
2464
|
+
name: "conflictingFiles",
|
|
2465
|
+
type: "string[]",
|
|
2466
|
+
description: "Files with unresolved merge conflicts."
|
|
2467
|
+
}
|
|
2468
|
+
]
|
|
1823
2469
|
}
|
|
1824
2470
|
];
|
|
1825
2471
|
/**
|
|
@@ -1899,6 +2545,7 @@ Options:
|
|
|
1899
2545
|
- \`--research\` — Enable the research phase even if not set in the pack config
|
|
1900
2546
|
- \`--skip-research\` — Skip the research phase even if enabled in the pack config
|
|
1901
2547
|
- \`--skip-ux\` — Skip the UX design phase even if enabled in the pack config
|
|
2548
|
+
- \`--no-worktree\` — Disable per-story git worktrees; all implementation runs in the main working tree (use for submodule repos or bare repos that don't support worktrees)
|
|
1902
2549
|
- \`--help-agent\` — Print this agent instruction fragment and exit
|
|
1903
2550
|
|
|
1904
2551
|
Examples:
|
|
@@ -2064,6 +2711,7 @@ These on-disk files back the new autonomy commands. External monitors (dashboard
|
|
|
2064
2711
|
- \`.substrate/current-run-id\` — plain text file containing the latest run ID; consulted by the canonical run-discovery chain.
|
|
2065
2712
|
- \`.substrate/notifications/<run-id>-<timestamp>.json\` — operator halt notifications written by the Recovery Engine when \`--halt-on\` triggers; deleted by \`substrate report\` after read.
|
|
2066
2713
|
- \`pending_proposals[]\` field in the run manifest — Recovery Engine Tier B re-scope proposals collected here for next-morning operator review. Back-pressure pauses dispatching at \`>= 2\` proposals (work-graph-aware) or \`>= 5\` (safety valve).
|
|
2714
|
+
- \`.substrate-worktrees/story-<key>/\` — per-story git worktree directories created during dispatch. Removed on successful merge; preserved on failure for \`substrate reconcile-from-disk\` inspection. Use \`--no-worktree\` to disable.
|
|
2067
2715
|
|
|
2068
2716
|
## Environment Variables
|
|
2069
2717
|
|
|
@@ -2230,7 +2878,7 @@ async function runHelpAgent() {
|
|
|
2230
2878
|
|
|
2231
2879
|
//#endregion
|
|
2232
2880
|
//#region src/persistence/dolt-server.ts
|
|
2233
|
-
const logger$
|
|
2881
|
+
const logger$26 = createLogger("dolt-server");
|
|
2234
2882
|
/**
|
|
2235
2883
|
* Start a dolt sql-server for the given project, if Dolt is available and no
|
|
2236
2884
|
* server is already running (socket already exists).
|
|
@@ -2247,7 +2895,7 @@ async function startDoltServer(projectRoot) {
|
|
|
2247
2895
|
if (!existsSync(join$1(stateDir, ".dolt"))) return null;
|
|
2248
2896
|
try {
|
|
2249
2897
|
await access$1(socketPath);
|
|
2250
|
-
logger$
|
|
2898
|
+
logger$26.debug("Dolt socket already exists at %s — using existing server", socketPath);
|
|
2251
2899
|
return null;
|
|
2252
2900
|
} catch {}
|
|
2253
2901
|
try {
|
|
@@ -2256,10 +2904,10 @@ async function startDoltServer(projectRoot) {
|
|
|
2256
2904
|
stdio: "pipe"
|
|
2257
2905
|
});
|
|
2258
2906
|
} catch {
|
|
2259
|
-
logger$
|
|
2907
|
+
logger$26.debug("dolt binary not on PATH — cannot start server");
|
|
2260
2908
|
return null;
|
|
2261
2909
|
}
|
|
2262
|
-
logger$
|
|
2910
|
+
logger$26.debug("Starting dolt sql-server at %s", socketPath);
|
|
2263
2911
|
let proc$1;
|
|
2264
2912
|
try {
|
|
2265
2913
|
proc$1 = spawn("dolt", [
|
|
@@ -2280,26 +2928,26 @@ async function startDoltServer(projectRoot) {
|
|
|
2280
2928
|
detached: false
|
|
2281
2929
|
});
|
|
2282
2930
|
} catch (err) {
|
|
2283
|
-
logger$
|
|
2931
|
+
logger$26.debug("Failed to spawn dolt sql-server: %s", err instanceof Error ? err.message : String(err));
|
|
2284
2932
|
return null;
|
|
2285
2933
|
}
|
|
2286
2934
|
let failed = false;
|
|
2287
2935
|
proc$1.on("error", (err) => {
|
|
2288
|
-
logger$
|
|
2936
|
+
logger$26.debug("dolt sql-server error: %s", err.message);
|
|
2289
2937
|
failed = true;
|
|
2290
2938
|
});
|
|
2291
2939
|
proc$1.on("exit", (code) => {
|
|
2292
|
-
if (code !== null && code !== 0) logger$
|
|
2940
|
+
if (code !== null && code !== 0) logger$26.debug("dolt sql-server exited with code %d", code);
|
|
2293
2941
|
});
|
|
2294
2942
|
proc$1.stderr?.on("data", (chunk) => {
|
|
2295
2943
|
const line = chunk.toString().trim();
|
|
2296
|
-
if (line) logger$
|
|
2944
|
+
if (line) logger$26.debug("dolt-server: %s", line);
|
|
2297
2945
|
});
|
|
2298
2946
|
const deadline = Date.now() + 5e3;
|
|
2299
2947
|
while (Date.now() < deadline && !failed) try {
|
|
2300
2948
|
await access$1(socketPath);
|
|
2301
2949
|
const pid = proc$1.pid ?? 0;
|
|
2302
|
-
logger$
|
|
2950
|
+
logger$26.info("Auto-started dolt sql-server (pid=%d, socket=%s)", pid, socketPath);
|
|
2303
2951
|
let stopped = false;
|
|
2304
2952
|
return {
|
|
2305
2953
|
pid,
|
|
@@ -2307,14 +2955,14 @@ async function startDoltServer(projectRoot) {
|
|
|
2307
2955
|
stop: () => {
|
|
2308
2956
|
if (stopped) return;
|
|
2309
2957
|
stopped = true;
|
|
2310
|
-
logger$
|
|
2958
|
+
logger$26.debug("Stopping dolt sql-server (pid=%d)", pid);
|
|
2311
2959
|
proc$1.kill("SIGTERM");
|
|
2312
2960
|
}
|
|
2313
2961
|
};
|
|
2314
2962
|
} catch {
|
|
2315
2963
|
await new Promise((resolve$6) => setTimeout(resolve$6, 100));
|
|
2316
2964
|
}
|
|
2317
|
-
logger$
|
|
2965
|
+
logger$26.debug("dolt sql-server did not start within 5s — killing");
|
|
2318
2966
|
proc$1.kill("SIGTERM");
|
|
2319
2967
|
return null;
|
|
2320
2968
|
}
|
|
@@ -2384,7 +3032,7 @@ function truncateToTokens(text, maxTokens) {
|
|
|
2384
3032
|
|
|
2385
3033
|
//#endregion
|
|
2386
3034
|
//#region src/modules/context-compiler/context-compiler-impl.ts
|
|
2387
|
-
const logger$
|
|
3035
|
+
const logger$25 = createLogger("context-compiler");
|
|
2388
3036
|
/**
|
|
2389
3037
|
* Fraction of the original token budget that must remain (after required +
|
|
2390
3038
|
* important sections) before an optional section is included.
|
|
@@ -2445,7 +3093,7 @@ var ContextCompilerImpl = class {
|
|
|
2445
3093
|
}
|
|
2446
3094
|
_applyExclusionFilter(text, sectionName) {
|
|
2447
3095
|
for (const excludedPath of this._excludedPaths) if (text.includes(excludedPath)) {
|
|
2448
|
-
logger$
|
|
3096
|
+
logger$25.warn({
|
|
2449
3097
|
sectionName,
|
|
2450
3098
|
excludedPath
|
|
2451
3099
|
}, "ContextCompiler: section excluded — contains path from exclusion list");
|
|
@@ -2503,7 +3151,7 @@ var ContextCompilerImpl = class {
|
|
|
2503
3151
|
includedParts.push(truncated);
|
|
2504
3152
|
remainingBudget -= truncatedTokens;
|
|
2505
3153
|
anyTruncated = true;
|
|
2506
|
-
logger$
|
|
3154
|
+
logger$25.warn({
|
|
2507
3155
|
section: section.name,
|
|
2508
3156
|
originalTokens: tokens,
|
|
2509
3157
|
budgetTokens: truncatedTokens
|
|
@@ -2517,7 +3165,7 @@ var ContextCompilerImpl = class {
|
|
|
2517
3165
|
});
|
|
2518
3166
|
} else {
|
|
2519
3167
|
anyTruncated = true;
|
|
2520
|
-
logger$
|
|
3168
|
+
logger$25.warn({
|
|
2521
3169
|
section: section.name,
|
|
2522
3170
|
tokens
|
|
2523
3171
|
}, "Context compiler: omitted \"important\" section — no budget remaining");
|
|
@@ -2544,7 +3192,7 @@ var ContextCompilerImpl = class {
|
|
|
2544
3192
|
} else {
|
|
2545
3193
|
if (tokens > 0) {
|
|
2546
3194
|
anyTruncated = true;
|
|
2547
|
-
logger$
|
|
3195
|
+
logger$25.warn({
|
|
2548
3196
|
section: section.name,
|
|
2549
3197
|
tokens,
|
|
2550
3198
|
budgetFractionRemaining: budgetFractionRemaining.toFixed(2)
|
|
@@ -2638,8 +3286,8 @@ var GrammarLoader = class {
|
|
|
2638
3286
|
_extensionMap;
|
|
2639
3287
|
_cache = new Map();
|
|
2640
3288
|
_unavailable = false;
|
|
2641
|
-
constructor(logger$
|
|
2642
|
-
this._logger = logger$
|
|
3289
|
+
constructor(logger$27) {
|
|
3290
|
+
this._logger = logger$27;
|
|
2643
3291
|
this._extensionMap = new Map([
|
|
2644
3292
|
[".ts", "tree-sitter-typescript/typescript"],
|
|
2645
3293
|
[".tsx", "tree-sitter-typescript/tsx"],
|
|
@@ -2676,8 +3324,8 @@ var GrammarLoader = class {
|
|
|
2676
3324
|
throw err;
|
|
2677
3325
|
}
|
|
2678
3326
|
}
|
|
2679
|
-
_loadModule(path$
|
|
2680
|
-
return __require(path$
|
|
3327
|
+
_loadModule(path$6) {
|
|
3328
|
+
return __require(path$6);
|
|
2681
3329
|
}
|
|
2682
3330
|
};
|
|
2683
3331
|
|
|
@@ -2725,9 +3373,9 @@ const ERR_REPO_MAP_GIT_FAILED = "ERR_REPO_MAP_GIT_FAILED";
|
|
|
2725
3373
|
var SymbolParser = class {
|
|
2726
3374
|
_grammarLoader;
|
|
2727
3375
|
_logger;
|
|
2728
|
-
constructor(grammarLoader, logger$
|
|
3376
|
+
constructor(grammarLoader, logger$27) {
|
|
2729
3377
|
this._grammarLoader = grammarLoader;
|
|
2730
|
-
this._logger = logger$
|
|
3378
|
+
this._logger = logger$27;
|
|
2731
3379
|
}
|
|
2732
3380
|
async parseFile(filePath) {
|
|
2733
3381
|
const ext$2 = extname$1(filePath);
|
|
@@ -2872,9 +3520,9 @@ async function computeFileHash(filePath) {
|
|
|
2872
3520
|
var DoltSymbolRepository = class {
|
|
2873
3521
|
_client;
|
|
2874
3522
|
_logger;
|
|
2875
|
-
constructor(client, logger$
|
|
3523
|
+
constructor(client, logger$27) {
|
|
2876
3524
|
this._client = client;
|
|
2877
|
-
this._logger = logger$
|
|
3525
|
+
this._logger = logger$27;
|
|
2878
3526
|
}
|
|
2879
3527
|
/**
|
|
2880
3528
|
* Atomically replace all symbols for filePath.
|
|
@@ -3080,11 +3728,11 @@ var RepoMapStorage = class {
|
|
|
3080
3728
|
_metaRepo;
|
|
3081
3729
|
_gitClient;
|
|
3082
3730
|
_logger;
|
|
3083
|
-
constructor(symbolRepo, metaRepo, gitClient, logger$
|
|
3731
|
+
constructor(symbolRepo, metaRepo, gitClient, logger$27) {
|
|
3084
3732
|
this._symbolRepo = symbolRepo;
|
|
3085
3733
|
this._metaRepo = metaRepo;
|
|
3086
3734
|
this._gitClient = gitClient;
|
|
3087
|
-
this._logger = logger$
|
|
3735
|
+
this._logger = logger$27;
|
|
3088
3736
|
}
|
|
3089
3737
|
/**
|
|
3090
3738
|
* Returns true if the file's current content hash differs from the stored hash.
|
|
@@ -3201,8 +3849,8 @@ function runGit(args, cwd) {
|
|
|
3201
3849
|
*/
|
|
3202
3850
|
var GitClient = class {
|
|
3203
3851
|
_logger;
|
|
3204
|
-
constructor(logger$
|
|
3205
|
-
this._logger = logger$
|
|
3852
|
+
constructor(logger$27) {
|
|
3853
|
+
this._logger = logger$27;
|
|
3206
3854
|
}
|
|
3207
3855
|
/**
|
|
3208
3856
|
* Returns the current HEAD commit SHA.
|
|
@@ -4558,9 +5206,9 @@ var RepoMapQueryEngine = class {
|
|
|
4558
5206
|
repo;
|
|
4559
5207
|
logger;
|
|
4560
5208
|
telemetry;
|
|
4561
|
-
constructor(repo, logger$
|
|
5209
|
+
constructor(repo, logger$27, telemetry) {
|
|
4562
5210
|
this.repo = repo;
|
|
4563
|
-
this.logger = logger$
|
|
5211
|
+
this.logger = logger$27;
|
|
4564
5212
|
this.telemetry = telemetry;
|
|
4565
5213
|
}
|
|
4566
5214
|
async query(q) {
|
|
@@ -4780,9 +5428,9 @@ var RepoMapFormatter = class {
|
|
|
4780
5428
|
var RepoMapTelemetry = class {
|
|
4781
5429
|
_telemetry;
|
|
4782
5430
|
_logger;
|
|
4783
|
-
constructor(telemetry, logger$
|
|
5431
|
+
constructor(telemetry, logger$27) {
|
|
4784
5432
|
this._telemetry = telemetry;
|
|
4785
|
-
this._logger = logger$
|
|
5433
|
+
this._logger = logger$27;
|
|
4786
5434
|
}
|
|
4787
5435
|
/**
|
|
4788
5436
|
* Emit a `repo_map.query` span.
|
|
@@ -4807,9 +5455,9 @@ var RepoMapTelemetry = class {
|
|
|
4807
5455
|
var RepoMapModule = class {
|
|
4808
5456
|
_metaRepo;
|
|
4809
5457
|
_logger;
|
|
4810
|
-
constructor(metaRepo, logger$
|
|
5458
|
+
constructor(metaRepo, logger$27) {
|
|
4811
5459
|
this._metaRepo = metaRepo;
|
|
4812
|
-
this._logger = logger$
|
|
5460
|
+
this._logger = logger$27;
|
|
4813
5461
|
}
|
|
4814
5462
|
/**
|
|
4815
5463
|
* Check whether the stored repo-map is stale relative to the current HEAD commit.
|
|
@@ -4853,9 +5501,9 @@ var RepoMapModule = class {
|
|
|
4853
5501
|
var RepoMapInjector = class {
|
|
4854
5502
|
_queryEngine;
|
|
4855
5503
|
_logger;
|
|
4856
|
-
constructor(queryEngine, logger$
|
|
5504
|
+
constructor(queryEngine, logger$27) {
|
|
4857
5505
|
this._queryEngine = queryEngine;
|
|
4858
|
-
this._logger = logger$
|
|
5506
|
+
this._logger = logger$27;
|
|
4859
5507
|
}
|
|
4860
5508
|
/**
|
|
4861
5509
|
* Build repo-map context by extracting file references from the story content,
|
|
@@ -4937,7 +5585,7 @@ const DEFAULT_TIMEOUTS = {
|
|
|
4937
5585
|
|
|
4938
5586
|
//#endregion
|
|
4939
5587
|
//#region src/modules/agent-dispatch/dispatcher-impl.ts
|
|
4940
|
-
const logger$
|
|
5588
|
+
const logger$24 = createLogger("agent-dispatch");
|
|
4941
5589
|
/**
|
|
4942
5590
|
* Create a new Dispatcher instance.
|
|
4943
5591
|
*
|
|
@@ -5081,7 +5729,7 @@ function runBuildVerification(options) {
|
|
|
5081
5729
|
let cmd;
|
|
5082
5730
|
if (verifyCommand === void 0) {
|
|
5083
5731
|
const detection = detectPackageManager(projectRoot);
|
|
5084
|
-
logger$
|
|
5732
|
+
logger$24.info({
|
|
5085
5733
|
packageManager: detection.packageManager,
|
|
5086
5734
|
lockfile: detection.lockfile,
|
|
5087
5735
|
resolvedCommand: detection.command
|
|
@@ -5093,7 +5741,7 @@ function runBuildVerification(options) {
|
|
|
5093
5741
|
const filters = deriveTurboFilters(changedFiles, projectRoot);
|
|
5094
5742
|
if (filters.length > 0) {
|
|
5095
5743
|
cmd = `${cmd} ${filters.join(" ")}`;
|
|
5096
|
-
logger$
|
|
5744
|
+
logger$24.info({
|
|
5097
5745
|
filters,
|
|
5098
5746
|
originalCmd: options.verifyCommand ?? "(auto-detected)"
|
|
5099
5747
|
}, "Build verification: scoped turbo build to affected packages");
|
|
@@ -5136,7 +5784,7 @@ function runBuildVerification(options) {
|
|
|
5136
5784
|
};
|
|
5137
5785
|
const missingScriptPattern = /Missing script[:\s]|No script found|Command "build" not found/i;
|
|
5138
5786
|
if (missingScriptPattern.test(combinedOutput)) {
|
|
5139
|
-
logger$
|
|
5787
|
+
logger$24.warn("Build script not found — skipping pre-flight (greenfield repo)");
|
|
5140
5788
|
return {
|
|
5141
5789
|
status: "skipped",
|
|
5142
5790
|
exitCode,
|
|
@@ -5146,7 +5794,7 @@ function runBuildVerification(options) {
|
|
|
5146
5794
|
}
|
|
5147
5795
|
const pep668Pattern = /externally-managed-environment|This environment is externally managed/i;
|
|
5148
5796
|
if (pep668Pattern.test(combinedOutput)) {
|
|
5149
|
-
logger$
|
|
5797
|
+
logger$24.warn("PEP 668: pip blocked by externally-managed-environment — skipping pre-flight. Create a .venv to resolve.");
|
|
5150
5798
|
return {
|
|
5151
5799
|
status: "skipped",
|
|
5152
5800
|
exitCode,
|
|
@@ -5330,7 +5978,7 @@ function pickRecommendation(distribution, profile, totalIssues, reviewCycles, la
|
|
|
5330
5978
|
|
|
5331
5979
|
//#endregion
|
|
5332
5980
|
//#region src/modules/implementation-orchestrator/project-findings.ts
|
|
5333
|
-
const logger$
|
|
5981
|
+
const logger$23 = createLogger("project-findings");
|
|
5334
5982
|
/** Maximum character length for the findings summary */
|
|
5335
5983
|
const MAX_CHARS = 2e3;
|
|
5336
5984
|
/**
|
|
@@ -5403,7 +6051,7 @@ async function getProjectFindings(db) {
|
|
|
5403
6051
|
if (summary.length > MAX_CHARS) summary = summary.slice(0, MAX_CHARS - 3) + "...";
|
|
5404
6052
|
return summary;
|
|
5405
6053
|
} catch (err) {
|
|
5406
|
-
logger$
|
|
6054
|
+
logger$23.warn({ err }, "Failed to query project findings (graceful fallback)");
|
|
5407
6055
|
return "";
|
|
5408
6056
|
}
|
|
5409
6057
|
}
|
|
@@ -5426,7 +6074,7 @@ function extractRecurringPatterns(outcomes) {
|
|
|
5426
6074
|
|
|
5427
6075
|
//#endregion
|
|
5428
6076
|
//#region src/modules/compiled-workflows/prompt-assembler.ts
|
|
5429
|
-
const logger$
|
|
6077
|
+
const logger$22 = createLogger("compiled-workflows:prompt-assembler");
|
|
5430
6078
|
/**
|
|
5431
6079
|
* Assemble a final prompt from a template and sections map.
|
|
5432
6080
|
*
|
|
@@ -5451,7 +6099,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5451
6099
|
tokenCount,
|
|
5452
6100
|
truncated: false
|
|
5453
6101
|
};
|
|
5454
|
-
logger$
|
|
6102
|
+
logger$22.warn({
|
|
5455
6103
|
tokenCount,
|
|
5456
6104
|
ceiling: tokenCeiling
|
|
5457
6105
|
}, "Prompt exceeds token ceiling — truncating optional sections");
|
|
@@ -5467,10 +6115,10 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5467
6115
|
const targetSectionTokens = Math.max(0, currentSectionTokens - overBy);
|
|
5468
6116
|
if (targetSectionTokens === 0) {
|
|
5469
6117
|
contentMap[section.name] = "";
|
|
5470
|
-
logger$
|
|
6118
|
+
logger$22.warn({ sectionName: section.name }, "Section eliminated to fit token budget");
|
|
5471
6119
|
} else {
|
|
5472
6120
|
contentMap[section.name] = truncateToTokens(section.content, targetSectionTokens);
|
|
5473
|
-
logger$
|
|
6121
|
+
logger$22.warn({
|
|
5474
6122
|
sectionName: section.name,
|
|
5475
6123
|
targetSectionTokens
|
|
5476
6124
|
}, "Section truncated to fit token budget");
|
|
@@ -5481,7 +6129,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
5481
6129
|
}
|
|
5482
6130
|
if (tokenCount <= tokenCeiling) break;
|
|
5483
6131
|
}
|
|
5484
|
-
if (tokenCount > tokenCeiling) logger$
|
|
6132
|
+
if (tokenCount > tokenCeiling) logger$22.warn({
|
|
5485
6133
|
tokenCount,
|
|
5486
6134
|
ceiling: tokenCeiling
|
|
5487
6135
|
}, "Required sections alone exceed token ceiling — returning over-budget prompt");
|
|
@@ -5821,7 +6469,7 @@ function getTokenCeiling(workflowType, tokenCeilings) {
|
|
|
5821
6469
|
|
|
5822
6470
|
//#endregion
|
|
5823
6471
|
//#region src/modules/compiled-workflows/create-story.ts
|
|
5824
|
-
const logger$
|
|
6472
|
+
const logger$21 = createLogger("compiled-workflows:create-story");
|
|
5825
6473
|
/**
|
|
5826
6474
|
* Compute a hex SHA-256 of the normalized source AC section text.
|
|
5827
6475
|
*
|
|
@@ -5856,13 +6504,13 @@ function hashSourceAcSection(section) {
|
|
|
5856
6504
|
*/
|
|
5857
6505
|
async function runCreateStory(deps, params) {
|
|
5858
6506
|
const { epicId, storyKey, pipelineRunId, source_ac_hash, priorDriftFeedback } = params;
|
|
5859
|
-
logger$
|
|
6507
|
+
logger$21.debug({
|
|
5860
6508
|
epicId,
|
|
5861
6509
|
storyKey,
|
|
5862
6510
|
pipelineRunId
|
|
5863
6511
|
}, "Starting create-story workflow");
|
|
5864
6512
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("create-story", deps.tokenCeilings);
|
|
5865
|
-
logger$
|
|
6513
|
+
logger$21.info({
|
|
5866
6514
|
workflow: "create-story",
|
|
5867
6515
|
ceiling: TOKEN_CEILING,
|
|
5868
6516
|
source: tokenCeilingSource
|
|
@@ -5872,7 +6520,7 @@ async function runCreateStory(deps, params) {
|
|
|
5872
6520
|
template = await deps.pack.getPrompt("create-story");
|
|
5873
6521
|
} catch (err) {
|
|
5874
6522
|
const error = err instanceof Error ? err.message : String(err);
|
|
5875
|
-
logger$
|
|
6523
|
+
logger$21.error({ error }, "Failed to retrieve create-story prompt template");
|
|
5876
6524
|
return {
|
|
5877
6525
|
result: "failed",
|
|
5878
6526
|
error: `Failed to retrieve prompt template: ${error}`,
|
|
@@ -5889,7 +6537,7 @@ async function runCreateStory(deps, params) {
|
|
|
5889
6537
|
const storySection = extractStorySection(epicShardContent, storyKey);
|
|
5890
6538
|
if (storySection !== null) {
|
|
5891
6539
|
const computedHash = hashSourceAcSection(storySection);
|
|
5892
|
-
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$
|
|
6540
|
+
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$21.debug({
|
|
5893
6541
|
storyKey,
|
|
5894
6542
|
suppliedHash: source_ac_hash,
|
|
5895
6543
|
computedHash
|
|
@@ -5904,7 +6552,7 @@ async function runCreateStory(deps, params) {
|
|
|
5904
6552
|
const storyDef = storyDecisions.find((d) => d.category === "stories" && d.key === storyKey);
|
|
5905
6553
|
if (storyDef) {
|
|
5906
6554
|
storyDefinitionContent = storyDef.value;
|
|
5907
|
-
logger$
|
|
6555
|
+
logger$21.debug({ storyKey }, "Injected story definition from solutioning decisions");
|
|
5908
6556
|
}
|
|
5909
6557
|
} catch {}
|
|
5910
6558
|
const archConstraintsContent = await getArchConstraints$3(deps);
|
|
@@ -5955,7 +6603,7 @@ async function runCreateStory(deps, params) {
|
|
|
5955
6603
|
priority: "optional"
|
|
5956
6604
|
}]
|
|
5957
6605
|
], TOKEN_CEILING);
|
|
5958
|
-
logger$
|
|
6606
|
+
logger$21.debug({
|
|
5959
6607
|
tokenCount,
|
|
5960
6608
|
truncated,
|
|
5961
6609
|
tokenCeiling: TOKEN_CEILING
|
|
@@ -5975,7 +6623,7 @@ async function runCreateStory(deps, params) {
|
|
|
5975
6623
|
dispatchResult = await handle.result;
|
|
5976
6624
|
} catch (err) {
|
|
5977
6625
|
const error = err instanceof Error ? err.message : String(err);
|
|
5978
|
-
logger$
|
|
6626
|
+
logger$21.error({
|
|
5979
6627
|
epicId,
|
|
5980
6628
|
storyKey,
|
|
5981
6629
|
error
|
|
@@ -5996,7 +6644,7 @@ async function runCreateStory(deps, params) {
|
|
|
5996
6644
|
if (dispatchResult.status === "failed") {
|
|
5997
6645
|
const errorMsg = dispatchResult.parseError ?? `Dispatch failed with exit code ${dispatchResult.exitCode}`;
|
|
5998
6646
|
const stderrDetail = dispatchResult.output ? ` Output: ${dispatchResult.output}` : "";
|
|
5999
|
-
logger$
|
|
6647
|
+
logger$21.warn({
|
|
6000
6648
|
epicId,
|
|
6001
6649
|
storyKey,
|
|
6002
6650
|
exitCode: dispatchResult.exitCode,
|
|
@@ -6009,7 +6657,7 @@ async function runCreateStory(deps, params) {
|
|
|
6009
6657
|
};
|
|
6010
6658
|
}
|
|
6011
6659
|
if (dispatchResult.status === "timeout") {
|
|
6012
|
-
logger$
|
|
6660
|
+
logger$21.warn({
|
|
6013
6661
|
epicId,
|
|
6014
6662
|
storyKey
|
|
6015
6663
|
}, "Create-story dispatch timed out");
|
|
@@ -6022,7 +6670,7 @@ async function runCreateStory(deps, params) {
|
|
|
6022
6670
|
if (dispatchResult.parsed === null) {
|
|
6023
6671
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
6024
6672
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
6025
|
-
logger$
|
|
6673
|
+
logger$21.warn({
|
|
6026
6674
|
epicId,
|
|
6027
6675
|
storyKey,
|
|
6028
6676
|
details,
|
|
@@ -6038,7 +6686,7 @@ async function runCreateStory(deps, params) {
|
|
|
6038
6686
|
const parseResult = CreateStoryResultSchema.safeParse(dispatchResult.parsed);
|
|
6039
6687
|
if (!parseResult.success) {
|
|
6040
6688
|
const details = parseResult.error.message;
|
|
6041
|
-
logger$
|
|
6689
|
+
logger$21.warn({
|
|
6042
6690
|
epicId,
|
|
6043
6691
|
storyKey,
|
|
6044
6692
|
details
|
|
@@ -6051,7 +6699,7 @@ async function runCreateStory(deps, params) {
|
|
|
6051
6699
|
};
|
|
6052
6700
|
}
|
|
6053
6701
|
const parsed = parseResult.data;
|
|
6054
|
-
logger$
|
|
6702
|
+
logger$21.info({
|
|
6055
6703
|
epicId,
|
|
6056
6704
|
storyKey,
|
|
6057
6705
|
storyFile: parsed.story_file,
|
|
@@ -6079,7 +6727,7 @@ async function getImplementationDecisions(deps, pipelineRunId) {
|
|
|
6079
6727
|
}
|
|
6080
6728
|
return await getDecisionsByPhase(deps.db, "implementation");
|
|
6081
6729
|
} catch (err) {
|
|
6082
|
-
logger$
|
|
6730
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve implementation decisions");
|
|
6083
6731
|
return [];
|
|
6084
6732
|
}
|
|
6085
6733
|
}
|
|
@@ -6166,10 +6814,10 @@ function computeStoryFileFidelity(storyFileContent, namedPaths) {
|
|
|
6166
6814
|
};
|
|
6167
6815
|
const missing = [];
|
|
6168
6816
|
const present = [];
|
|
6169
|
-
for (const path$
|
|
6170
|
-
const basename$2 = path$
|
|
6171
|
-
if (storyFileContent.includes(path$
|
|
6172
|
-
else missing.push(path$
|
|
6817
|
+
for (const path$6 of namedPaths) {
|
|
6818
|
+
const basename$2 = path$6.includes("/") ? path$6.slice(path$6.lastIndexOf("/") + 1) : path$6;
|
|
6819
|
+
if (storyFileContent.includes(path$6) || storyFileContent.includes(basename$2)) present.push(path$6);
|
|
6820
|
+
else missing.push(path$6);
|
|
6173
6821
|
}
|
|
6174
6822
|
return {
|
|
6175
6823
|
missing,
|
|
@@ -6370,7 +7018,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6370
7018
|
if (storyKey) {
|
|
6371
7019
|
const perStoryShard = decisions.find((d) => d.category === "epic-shard" && d.key === storyKey);
|
|
6372
7020
|
if (perStoryShard?.value) {
|
|
6373
|
-
logger$
|
|
7021
|
+
logger$21.debug({
|
|
6374
7022
|
epicId,
|
|
6375
7023
|
storyKey
|
|
6376
7024
|
}, "Found per-story epic shard (direct lookup)");
|
|
@@ -6382,13 +7030,13 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6382
7030
|
if (shardContent && storyKey) {
|
|
6383
7031
|
const storySection = extractStorySection(shardContent, storyKey);
|
|
6384
7032
|
if (storySection) {
|
|
6385
|
-
logger$
|
|
7033
|
+
logger$21.debug({
|
|
6386
7034
|
epicId,
|
|
6387
7035
|
storyKey
|
|
6388
7036
|
}, "Extracted per-story section from epic shard (pre-37-0 fallback)");
|
|
6389
7037
|
return storySection;
|
|
6390
7038
|
}
|
|
6391
|
-
logger$
|
|
7039
|
+
logger$21.info({
|
|
6392
7040
|
epicId,
|
|
6393
7041
|
storyKey
|
|
6394
7042
|
}, "Story section absent in decisions-store shard — attempting file-based fallback before returning stale shard");
|
|
@@ -6396,11 +7044,11 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6396
7044
|
if (projectRoot) {
|
|
6397
7045
|
const fallback = readEpicShardFromFile(projectRoot, epicId);
|
|
6398
7046
|
if (fallback) {
|
|
6399
|
-
logger$
|
|
7047
|
+
logger$21.info({ epicId }, "Using file-based fallback for epic shard");
|
|
6400
7048
|
if (storyKey) {
|
|
6401
7049
|
const storySection = extractStorySection(fallback, storyKey);
|
|
6402
7050
|
if (storySection) {
|
|
6403
|
-
logger$
|
|
7051
|
+
logger$21.debug({
|
|
6404
7052
|
epicId,
|
|
6405
7053
|
storyKey
|
|
6406
7054
|
}, "Extracted per-story section from file-based epic shard");
|
|
@@ -6413,7 +7061,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6413
7061
|
if (shardContent) return shardContent;
|
|
6414
7062
|
return "";
|
|
6415
7063
|
} catch (err) {
|
|
6416
|
-
logger$
|
|
7064
|
+
logger$21.warn({
|
|
6417
7065
|
epicId,
|
|
6418
7066
|
error: err instanceof Error ? err.message : String(err)
|
|
6419
7067
|
}, "Failed to retrieve epic shard");
|
|
@@ -6430,7 +7078,7 @@ function getPrevDevNotes(decisions, epicId) {
|
|
|
6430
7078
|
if (devNotes.length === 0) return "";
|
|
6431
7079
|
return devNotes[devNotes.length - 1].value;
|
|
6432
7080
|
} catch (err) {
|
|
6433
|
-
logger$
|
|
7081
|
+
logger$21.warn({
|
|
6434
7082
|
epicId,
|
|
6435
7083
|
error: err instanceof Error ? err.message : String(err)
|
|
6436
7084
|
}, "Failed to retrieve prev dev notes");
|
|
@@ -6463,7 +7111,7 @@ async function getArchConstraints$3(deps) {
|
|
|
6463
7111
|
const truncatedBody = body.length > 300 ? body.slice(0, 297) + "..." : body;
|
|
6464
7112
|
return `${header}\n${truncatedBody}`;
|
|
6465
7113
|
}).join("\n\n");
|
|
6466
|
-
logger$
|
|
7114
|
+
logger$21.info({
|
|
6467
7115
|
fullLength: full.length,
|
|
6468
7116
|
summarizedLength: summarized.length,
|
|
6469
7117
|
decisions: constraints.length
|
|
@@ -6473,13 +7121,13 @@ async function getArchConstraints$3(deps) {
|
|
|
6473
7121
|
if (deps.projectRoot) {
|
|
6474
7122
|
const fallback = readArchConstraintsFromFile(deps.projectRoot);
|
|
6475
7123
|
if (fallback) {
|
|
6476
|
-
logger$
|
|
7124
|
+
logger$21.info("Using file-based fallback for architecture constraints (decisions table empty)");
|
|
6477
7125
|
return fallback.length > ARCH_CONSTRAINT_MAX_CHARS ? fallback.slice(0, ARCH_CONSTRAINT_MAX_CHARS) + "\n\n[truncated for token budget]" : fallback;
|
|
6478
7126
|
}
|
|
6479
7127
|
}
|
|
6480
7128
|
return "";
|
|
6481
7129
|
} catch (err) {
|
|
6482
|
-
logger$
|
|
7130
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
6483
7131
|
return "";
|
|
6484
7132
|
}
|
|
6485
7133
|
}
|
|
@@ -6532,7 +7180,7 @@ function readEpicShardFromFile(projectRoot, epicId) {
|
|
|
6532
7180
|
} catch {}
|
|
6533
7181
|
return "";
|
|
6534
7182
|
} catch (err) {
|
|
6535
|
-
logger$
|
|
7183
|
+
logger$21.warn({
|
|
6536
7184
|
epicId,
|
|
6537
7185
|
error: err instanceof Error ? err.message : String(err)
|
|
6538
7186
|
}, "File-based epic shard fallback failed");
|
|
@@ -6555,7 +7203,7 @@ function readArchConstraintsFromFile(projectRoot) {
|
|
|
6555
7203
|
const content = readFileSync(archPath, "utf-8");
|
|
6556
7204
|
return content.slice(0, 1500);
|
|
6557
7205
|
} catch (err) {
|
|
6558
|
-
logger$
|
|
7206
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "File-based architecture fallback failed");
|
|
6559
7207
|
return "";
|
|
6560
7208
|
}
|
|
6561
7209
|
}
|
|
@@ -6568,7 +7216,7 @@ async function getStoryTemplate(deps) {
|
|
|
6568
7216
|
try {
|
|
6569
7217
|
return await deps.pack.getTemplate("story");
|
|
6570
7218
|
} catch (err) {
|
|
6571
|
-
logger$
|
|
7219
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve story template from pack");
|
|
6572
7220
|
return "";
|
|
6573
7221
|
}
|
|
6574
7222
|
}
|
|
@@ -6605,7 +7253,7 @@ async function isValidStoryFile(filePath) {
|
|
|
6605
7253
|
|
|
6606
7254
|
//#endregion
|
|
6607
7255
|
//#region src/modules/compiled-workflows/git-helpers.ts
|
|
6608
|
-
const logger$
|
|
7256
|
+
const logger$20 = createLogger("compiled-workflows:git-helpers");
|
|
6609
7257
|
/**
|
|
6610
7258
|
* Check whether the repo at `cwd` has at least one commit (HEAD resolves).
|
|
6611
7259
|
* Returns false for fresh repos with no commits, avoiding `fatal: bad revision 'HEAD'`.
|
|
@@ -6642,7 +7290,7 @@ function hasCommits(cwd) {
|
|
|
6642
7290
|
*/
|
|
6643
7291
|
async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
6644
7292
|
if (!hasCommits(workingDirectory)) {
|
|
6645
|
-
logger$
|
|
7293
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff");
|
|
6646
7294
|
return "";
|
|
6647
7295
|
}
|
|
6648
7296
|
return runGitCommand(["diff", "HEAD"], workingDirectory, "git-diff-summary");
|
|
@@ -6659,7 +7307,7 @@ async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
|
6659
7307
|
*/
|
|
6660
7308
|
async function getGitDiffStatSummary(workingDirectory = process.cwd()) {
|
|
6661
7309
|
if (!hasCommits(workingDirectory)) {
|
|
6662
|
-
logger$
|
|
7310
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat");
|
|
6663
7311
|
return "";
|
|
6664
7312
|
}
|
|
6665
7313
|
return runGitCommand([
|
|
@@ -6708,7 +7356,7 @@ async function getGitDiffStatBetweenCommits(baseCommit, endCommit = "HEAD", work
|
|
|
6708
7356
|
async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
6709
7357
|
if (files.length === 0) return "";
|
|
6710
7358
|
if (!hasCommits(workingDirectory)) {
|
|
6711
|
-
logger$
|
|
7359
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff for files");
|
|
6712
7360
|
return "";
|
|
6713
7361
|
}
|
|
6714
7362
|
await stageIntentToAdd(files, workingDirectory);
|
|
@@ -6735,7 +7383,7 @@ async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
|
6735
7383
|
async function getGitDiffStatForFiles(files, workingDirectory = process.cwd()) {
|
|
6736
7384
|
if (files.length === 0) return "";
|
|
6737
7385
|
if (!hasCommits(workingDirectory)) {
|
|
6738
|
-
logger$
|
|
7386
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat for files");
|
|
6739
7387
|
return "";
|
|
6740
7388
|
}
|
|
6741
7389
|
return runGitCommand([
|
|
@@ -6784,7 +7432,7 @@ async function stageIntentToAdd(files, workingDirectory) {
|
|
|
6784
7432
|
if (files.length === 0) return;
|
|
6785
7433
|
const existing = files.filter((f$1) => {
|
|
6786
7434
|
const exists = existsSync(f$1);
|
|
6787
|
-
if (!exists) logger$
|
|
7435
|
+
if (!exists) logger$20.debug({ file: f$1 }, "Skipping nonexistent file in stageIntentToAdd");
|
|
6788
7436
|
return exists;
|
|
6789
7437
|
});
|
|
6790
7438
|
if (existing.length === 0) return;
|
|
@@ -6818,7 +7466,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6818
7466
|
stderr += chunk.toString("utf-8");
|
|
6819
7467
|
});
|
|
6820
7468
|
proc$1.on("error", (err) => {
|
|
6821
|
-
logger$
|
|
7469
|
+
logger$20.warn({
|
|
6822
7470
|
label: logLabel,
|
|
6823
7471
|
cwd,
|
|
6824
7472
|
error: err.message
|
|
@@ -6827,7 +7475,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6827
7475
|
});
|
|
6828
7476
|
proc$1.on("close", (code) => {
|
|
6829
7477
|
if (code !== 0) {
|
|
6830
|
-
logger$
|
|
7478
|
+
logger$20.warn({
|
|
6831
7479
|
label: logLabel,
|
|
6832
7480
|
cwd,
|
|
6833
7481
|
code,
|
|
@@ -6843,7 +7491,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
6843
7491
|
|
|
6844
7492
|
//#endregion
|
|
6845
7493
|
//#region src/modules/compiled-workflows/story-complexity.ts
|
|
6846
|
-
const logger$
|
|
7494
|
+
const logger$19 = createLogger("compiled-workflows:story-complexity");
|
|
6847
7495
|
/**
|
|
6848
7496
|
* Compute a complexity score from story markdown content.
|
|
6849
7497
|
*
|
|
@@ -6895,7 +7543,7 @@ function resolveFixStoryMaxTurns(complexityScore) {
|
|
|
6895
7543
|
* @param resolvedMaxTurns - Turn limit resolved for this dispatch
|
|
6896
7544
|
*/
|
|
6897
7545
|
function logComplexityResult(storyKey, complexity, resolvedMaxTurns) {
|
|
6898
|
-
logger$
|
|
7546
|
+
logger$19.info({
|
|
6899
7547
|
storyKey,
|
|
6900
7548
|
taskCount: complexity.taskCount,
|
|
6901
7549
|
subtaskCount: complexity.subtaskCount,
|
|
@@ -7151,7 +7799,7 @@ function resolveInstallCommand(projectRoot) {
|
|
|
7151
7799
|
|
|
7152
7800
|
//#endregion
|
|
7153
7801
|
//#region src/modules/compiled-workflows/dev-story.ts
|
|
7154
|
-
const logger$
|
|
7802
|
+
const logger$18 = createLogger("compiled-workflows:dev-story");
|
|
7155
7803
|
/** Default timeout for dev-story dispatches in milliseconds (30 min) */
|
|
7156
7804
|
const DEFAULT_TIMEOUT_MS$2 = 18e5;
|
|
7157
7805
|
/**
|
|
@@ -7163,12 +7811,12 @@ const DEFAULT_TIMEOUT_MS$2 = 18e5;
|
|
|
7163
7811
|
*/
|
|
7164
7812
|
async function runDevStory(deps, params) {
|
|
7165
7813
|
const { storyKey, storyFilePath, taskScope, priorFiles, findingsPrompt: handlerFindingsPrompt } = params;
|
|
7166
|
-
logger$
|
|
7814
|
+
logger$18.info({
|
|
7167
7815
|
storyKey,
|
|
7168
7816
|
storyFilePath
|
|
7169
7817
|
}, "Starting compiled dev-story workflow");
|
|
7170
7818
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("dev-story", deps.tokenCeilings);
|
|
7171
|
-
logger$
|
|
7819
|
+
logger$18.info({
|
|
7172
7820
|
workflow: "dev-story",
|
|
7173
7821
|
ceiling: TOKEN_CEILING,
|
|
7174
7822
|
source: tokenCeilingSource
|
|
@@ -7211,10 +7859,10 @@ async function runDevStory(deps, params) {
|
|
|
7211
7859
|
let template;
|
|
7212
7860
|
try {
|
|
7213
7861
|
template = await deps.pack.getPrompt("dev-story");
|
|
7214
|
-
logger$
|
|
7862
|
+
logger$18.debug({ storyKey }, "Retrieved dev-story prompt template from pack");
|
|
7215
7863
|
} catch (err) {
|
|
7216
7864
|
const error = err instanceof Error ? err.message : String(err);
|
|
7217
|
-
logger$
|
|
7865
|
+
logger$18.error({
|
|
7218
7866
|
storyKey,
|
|
7219
7867
|
error
|
|
7220
7868
|
}, "Failed to retrieve dev-story prompt template");
|
|
@@ -7225,14 +7873,14 @@ async function runDevStory(deps, params) {
|
|
|
7225
7873
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
7226
7874
|
} catch (err) {
|
|
7227
7875
|
if (err.code === "ENOENT") {
|
|
7228
|
-
logger$
|
|
7876
|
+
logger$18.error({
|
|
7229
7877
|
storyKey,
|
|
7230
7878
|
storyFilePath
|
|
7231
7879
|
}, "Story file not found");
|
|
7232
7880
|
return makeFailureResult("story_file_not_found");
|
|
7233
7881
|
}
|
|
7234
7882
|
const error = err instanceof Error ? err.message : String(err);
|
|
7235
|
-
logger$
|
|
7883
|
+
logger$18.error({
|
|
7236
7884
|
storyKey,
|
|
7237
7885
|
storyFilePath,
|
|
7238
7886
|
error
|
|
@@ -7240,7 +7888,7 @@ async function runDevStory(deps, params) {
|
|
|
7240
7888
|
return makeFailureResult(`story_file_read_error: ${error}`);
|
|
7241
7889
|
}
|
|
7242
7890
|
if (storyContent.trim().length === 0) {
|
|
7243
|
-
logger$
|
|
7891
|
+
logger$18.error({
|
|
7244
7892
|
storyKey,
|
|
7245
7893
|
storyFilePath
|
|
7246
7894
|
}, "Story file is empty");
|
|
@@ -7248,7 +7896,7 @@ async function runDevStory(deps, params) {
|
|
|
7248
7896
|
}
|
|
7249
7897
|
const staleStatus = detectDeprecatedStatusField(storyContent);
|
|
7250
7898
|
if (staleStatus !== null) {
|
|
7251
|
-
logger$
|
|
7899
|
+
logger$18.warn({
|
|
7252
7900
|
storyFilePath,
|
|
7253
7901
|
staleStatus
|
|
7254
7902
|
}, "Story spec contains deprecated Status field — stripped before dispatch (status is managed by Dolt work graph)");
|
|
@@ -7263,17 +7911,17 @@ async function runDevStory(deps, params) {
|
|
|
7263
7911
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
7264
7912
|
if (testPatternDecisions.length > 0) {
|
|
7265
7913
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
7266
|
-
logger$
|
|
7914
|
+
logger$18.debug({
|
|
7267
7915
|
storyKey,
|
|
7268
7916
|
count: testPatternDecisions.length
|
|
7269
7917
|
}, "Loaded test patterns from decision store");
|
|
7270
7918
|
} else {
|
|
7271
7919
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
7272
|
-
logger$
|
|
7920
|
+
logger$18.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
7273
7921
|
}
|
|
7274
7922
|
} catch (err) {
|
|
7275
7923
|
const error = err instanceof Error ? err.message : String(err);
|
|
7276
|
-
logger$
|
|
7924
|
+
logger$18.warn({
|
|
7277
7925
|
storyKey,
|
|
7278
7926
|
error
|
|
7279
7927
|
}, "Failed to load test patterns — using defaults");
|
|
@@ -7287,7 +7935,7 @@ async function runDevStory(deps, params) {
|
|
|
7287
7935
|
if (deps.repoMapInjector !== void 0) {
|
|
7288
7936
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
7289
7937
|
repoContextContent = injection.text;
|
|
7290
|
-
logger$
|
|
7938
|
+
logger$18.info({
|
|
7291
7939
|
storyKey,
|
|
7292
7940
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
7293
7941
|
symbolCount: injection.symbolCount,
|
|
@@ -7297,7 +7945,7 @@ async function runDevStory(deps, params) {
|
|
|
7297
7945
|
let priorFindingsContent = "";
|
|
7298
7946
|
if (handlerFindingsPrompt !== void 0 && handlerFindingsPrompt.length > 0) {
|
|
7299
7947
|
priorFindingsContent = handlerFindingsPrompt;
|
|
7300
|
-
logger$
|
|
7948
|
+
logger$18.debug({
|
|
7301
7949
|
storyKey,
|
|
7302
7950
|
findingsLen: handlerFindingsPrompt.length
|
|
7303
7951
|
}, "Using pre-computed findings from handler (Story 53-8 AC2)");
|
|
@@ -7309,7 +7957,7 @@ async function runDevStory(deps, params) {
|
|
|
7309
7957
|
});
|
|
7310
7958
|
if (findings.length > 0) {
|
|
7311
7959
|
priorFindingsContent = findings;
|
|
7312
|
-
logger$
|
|
7960
|
+
logger$18.debug({
|
|
7313
7961
|
storyKey,
|
|
7314
7962
|
findingsLen: findings.length
|
|
7315
7963
|
}, "Injecting relevance-scored findings into dev-story prompt");
|
|
@@ -7329,7 +7977,7 @@ async function runDevStory(deps, params) {
|
|
|
7329
7977
|
if (plan.test_categories && plan.test_categories.length > 0) parts.push(`\n### Categories: ${plan.test_categories.join(", ")}`);
|
|
7330
7978
|
if (plan.coverage_notes) parts.push(`\n### Coverage Notes\n${plan.coverage_notes}`);
|
|
7331
7979
|
testPlanContent = parts.join("\n");
|
|
7332
|
-
logger$
|
|
7980
|
+
logger$18.debug({ storyKey }, "Injecting test plan into dev-story prompt");
|
|
7333
7981
|
}
|
|
7334
7982
|
} catch {}
|
|
7335
7983
|
const sections = [
|
|
@@ -7390,7 +8038,7 @@ async function runDevStory(deps, params) {
|
|
|
7390
8038
|
}
|
|
7391
8039
|
];
|
|
7392
8040
|
const { prompt, tokenCount, truncated } = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
7393
|
-
logger$
|
|
8041
|
+
logger$18.info({
|
|
7394
8042
|
storyKey,
|
|
7395
8043
|
tokenCount,
|
|
7396
8044
|
ceiling: TOKEN_CEILING,
|
|
@@ -7414,7 +8062,7 @@ async function runDevStory(deps, params) {
|
|
|
7414
8062
|
dispatchResult = await handle.result;
|
|
7415
8063
|
} catch (err) {
|
|
7416
8064
|
const error = err instanceof Error ? err.message : String(err);
|
|
7417
|
-
logger$
|
|
8065
|
+
logger$18.error({
|
|
7418
8066
|
storyKey,
|
|
7419
8067
|
error
|
|
7420
8068
|
}, "Dispatch threw an unexpected error");
|
|
@@ -7425,11 +8073,11 @@ async function runDevStory(deps, params) {
|
|
|
7425
8073
|
output: dispatchResult.tokenEstimate.output
|
|
7426
8074
|
};
|
|
7427
8075
|
if (dispatchResult.status === "timeout") {
|
|
7428
|
-
logger$
|
|
8076
|
+
logger$18.error({
|
|
7429
8077
|
storyKey,
|
|
7430
8078
|
durationMs: dispatchResult.durationMs
|
|
7431
8079
|
}, "Dev-story dispatch timed out");
|
|
7432
|
-
if (dispatchResult.output.length > 0) logger$
|
|
8080
|
+
if (dispatchResult.output.length > 0) logger$18.info({
|
|
7433
8081
|
storyKey,
|
|
7434
8082
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
7435
8083
|
}, "Partial output before timeout");
|
|
@@ -7439,12 +8087,12 @@ async function runDevStory(deps, params) {
|
|
|
7439
8087
|
};
|
|
7440
8088
|
}
|
|
7441
8089
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
7442
|
-
logger$
|
|
8090
|
+
logger$18.error({
|
|
7443
8091
|
storyKey,
|
|
7444
8092
|
exitCode: dispatchResult.exitCode,
|
|
7445
8093
|
status: dispatchResult.status
|
|
7446
8094
|
}, "Dev-story dispatch failed");
|
|
7447
|
-
if (dispatchResult.output.length > 0) logger$
|
|
8095
|
+
if (dispatchResult.output.length > 0) logger$18.info({
|
|
7448
8096
|
storyKey,
|
|
7449
8097
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
7450
8098
|
}, "Partial output from failed dispatch");
|
|
@@ -7456,7 +8104,7 @@ async function runDevStory(deps, params) {
|
|
|
7456
8104
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
7457
8105
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
7458
8106
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
7459
|
-
logger$
|
|
8107
|
+
logger$18.error({
|
|
7460
8108
|
storyKey,
|
|
7461
8109
|
parseError: details,
|
|
7462
8110
|
rawOutputSnippet: rawSnippet
|
|
@@ -7464,12 +8112,12 @@ async function runDevStory(deps, params) {
|
|
|
7464
8112
|
let filesModified = [];
|
|
7465
8113
|
try {
|
|
7466
8114
|
filesModified = await getGitChangedFiles(deps.projectRoot ?? process.cwd());
|
|
7467
|
-
if (filesModified.length > 0) logger$
|
|
8115
|
+
if (filesModified.length > 0) logger$18.info({
|
|
7468
8116
|
storyKey,
|
|
7469
8117
|
fileCount: filesModified.length
|
|
7470
8118
|
}, "Recovered files_modified from git status (YAML fallback)");
|
|
7471
8119
|
} catch (err) {
|
|
7472
|
-
logger$
|
|
8120
|
+
logger$18.warn({
|
|
7473
8121
|
storyKey,
|
|
7474
8122
|
error: err instanceof Error ? err.message : String(err)
|
|
7475
8123
|
}, "Failed to recover files_modified from git");
|
|
@@ -7486,7 +8134,7 @@ async function runDevStory(deps, params) {
|
|
|
7486
8134
|
};
|
|
7487
8135
|
}
|
|
7488
8136
|
const parsed = dispatchResult.parsed;
|
|
7489
|
-
logger$
|
|
8137
|
+
logger$18.info({
|
|
7490
8138
|
storyKey,
|
|
7491
8139
|
result: parsed.result,
|
|
7492
8140
|
acMet: parsed.ac_met.length
|
|
@@ -7602,7 +8250,7 @@ function extractReferencedFiles(storyContent) {
|
|
|
7602
8250
|
const matches = storyContent.match(filePathRegex) ?? [];
|
|
7603
8251
|
const freq = new Map();
|
|
7604
8252
|
for (const m of matches) freq.set(m, (freq.get(m) ?? 0) + 1);
|
|
7605
|
-
const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([path$
|
|
8253
|
+
const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([path$6]) => path$6);
|
|
7606
8254
|
return sorted.filter((p) => !p.includes(".test."));
|
|
7607
8255
|
}
|
|
7608
8256
|
function extractFilesInScope(storyContent) {
|
|
@@ -7899,7 +8547,7 @@ function resolvesIntoExpected(modifiedFilePath, relativePath, expectedFiles) {
|
|
|
7899
8547
|
|
|
7900
8548
|
//#endregion
|
|
7901
8549
|
//#region src/modules/compiled-workflows/code-review.ts
|
|
7902
|
-
const logger$
|
|
8550
|
+
const logger$17 = createLogger("compiled-workflows:code-review");
|
|
7903
8551
|
/**
|
|
7904
8552
|
* Default fallback result when dispatch fails or times out.
|
|
7905
8553
|
* Uses NEEDS_MINOR_FIXES (not NEEDS_MAJOR_REWORK) so a parse/schema failure
|
|
@@ -7974,14 +8622,14 @@ async function countTestMetrics(filesModified, cwd) {
|
|
|
7974
8622
|
async function runCodeReview(deps, params) {
|
|
7975
8623
|
const { storyKey, storyFilePath, workingDirectory, pipelineRunId, filesModified, previousIssues, buildPassed, baselineCommit } = params;
|
|
7976
8624
|
const cwd = workingDirectory ?? process.cwd();
|
|
7977
|
-
logger$
|
|
8625
|
+
logger$17.debug({
|
|
7978
8626
|
storyKey,
|
|
7979
8627
|
storyFilePath,
|
|
7980
8628
|
cwd,
|
|
7981
8629
|
pipelineRunId
|
|
7982
8630
|
}, "Starting code-review workflow");
|
|
7983
8631
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("code-review", deps.tokenCeilings);
|
|
7984
|
-
logger$
|
|
8632
|
+
logger$17.info({
|
|
7985
8633
|
workflow: "code-review",
|
|
7986
8634
|
ceiling: TOKEN_CEILING,
|
|
7987
8635
|
source: tokenCeilingSource
|
|
@@ -7991,7 +8639,7 @@ async function runCodeReview(deps, params) {
|
|
|
7991
8639
|
template = await deps.pack.getPrompt("code-review");
|
|
7992
8640
|
} catch (err) {
|
|
7993
8641
|
const error = err instanceof Error ? err.message : String(err);
|
|
7994
|
-
logger$
|
|
8642
|
+
logger$17.error({ error }, "Failed to retrieve code-review prompt template");
|
|
7995
8643
|
return defaultFailResult(`Failed to retrieve prompt template: ${error}`, {
|
|
7996
8644
|
input: 0,
|
|
7997
8645
|
output: 0
|
|
@@ -8002,7 +8650,7 @@ async function runCodeReview(deps, params) {
|
|
|
8002
8650
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
8003
8651
|
} catch (err) {
|
|
8004
8652
|
const error = err instanceof Error ? err.message : String(err);
|
|
8005
|
-
logger$
|
|
8653
|
+
logger$17.error({
|
|
8006
8654
|
storyFilePath,
|
|
8007
8655
|
error
|
|
8008
8656
|
}, "Failed to read story file");
|
|
@@ -8022,12 +8670,12 @@ async function runCodeReview(deps, params) {
|
|
|
8022
8670
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
8023
8671
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
8024
8672
|
gitDiffContent = scopedDiff;
|
|
8025
|
-
logger$
|
|
8673
|
+
logger$17.debug({
|
|
8026
8674
|
fileCount: filesModified.length,
|
|
8027
8675
|
tokenCount: scopedTotal
|
|
8028
8676
|
}, "Using scoped file diff");
|
|
8029
8677
|
} else {
|
|
8030
|
-
logger$
|
|
8678
|
+
logger$17.warn({
|
|
8031
8679
|
estimatedTotal: scopedTotal,
|
|
8032
8680
|
ceiling: TOKEN_CEILING,
|
|
8033
8681
|
fileCount: filesModified.length
|
|
@@ -8041,7 +8689,7 @@ async function runCodeReview(deps, params) {
|
|
|
8041
8689
|
const fullTotal = nonDiffTokens + countTokens(fullDiff);
|
|
8042
8690
|
if (fullTotal <= TOKEN_CEILING) gitDiffContent = fullDiff;
|
|
8043
8691
|
else {
|
|
8044
|
-
logger$
|
|
8692
|
+
logger$17.warn({
|
|
8045
8693
|
estimatedTotal: fullTotal,
|
|
8046
8694
|
ceiling: TOKEN_CEILING
|
|
8047
8695
|
}, "Full git diff would exceed token ceiling — using stat-only summary");
|
|
@@ -8049,7 +8697,7 @@ async function runCodeReview(deps, params) {
|
|
|
8049
8697
|
}
|
|
8050
8698
|
}
|
|
8051
8699
|
if (gitDiffContent.trim().length === 0 && baselineCommit) {
|
|
8052
|
-
logger$
|
|
8700
|
+
logger$17.info({
|
|
8053
8701
|
storyKey,
|
|
8054
8702
|
baselineCommit
|
|
8055
8703
|
}, "Working tree diff empty — diffing against baseline commit");
|
|
@@ -8057,7 +8705,7 @@ async function runCodeReview(deps, params) {
|
|
|
8057
8705
|
const commitTotal = nonDiffTokens + countTokens(commitDiff);
|
|
8058
8706
|
if (commitDiff.trim().length > 0) if (commitTotal <= TOKEN_CEILING) gitDiffContent = commitDiff;
|
|
8059
8707
|
else {
|
|
8060
|
-
logger$
|
|
8708
|
+
logger$17.warn({
|
|
8061
8709
|
estimatedTotal: commitTotal,
|
|
8062
8710
|
ceiling: TOKEN_CEILING
|
|
8063
8711
|
}, "Baseline..HEAD diff exceeds token ceiling — using stat-only summary");
|
|
@@ -8065,7 +8713,7 @@ async function runCodeReview(deps, params) {
|
|
|
8065
8713
|
}
|
|
8066
8714
|
}
|
|
8067
8715
|
if (gitDiffContent.trim().length === 0) {
|
|
8068
|
-
logger$
|
|
8716
|
+
logger$17.info({ storyKey }, "Empty git diff — skipping review with SHIP_IT");
|
|
8069
8717
|
return {
|
|
8070
8718
|
verdict: "SHIP_IT",
|
|
8071
8719
|
issues: 0,
|
|
@@ -8081,7 +8729,7 @@ async function runCodeReview(deps, params) {
|
|
|
8081
8729
|
if (deps.repoMapInjector !== void 0) {
|
|
8082
8730
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
8083
8731
|
repoContextContent = injection.text;
|
|
8084
|
-
logger$
|
|
8732
|
+
logger$17.info({
|
|
8085
8733
|
storyKey,
|
|
8086
8734
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
8087
8735
|
symbolCount: injection.symbolCount,
|
|
@@ -8101,17 +8749,17 @@ async function runCodeReview(deps, params) {
|
|
|
8101
8749
|
const findings = await getProjectFindings(deps.db);
|
|
8102
8750
|
if (findings.length > 0) {
|
|
8103
8751
|
priorFindingsContent = "Previous reviews found these recurring patterns — pay special attention:\n\n" + findings;
|
|
8104
|
-
logger$
|
|
8752
|
+
logger$17.debug({
|
|
8105
8753
|
storyKey,
|
|
8106
8754
|
findingsLen: findings.length
|
|
8107
8755
|
}, "Injecting prior findings into code-review prompt");
|
|
8108
8756
|
}
|
|
8109
8757
|
} catch {}
|
|
8110
8758
|
const testMetricsContent = await countTestMetrics(filesModified, cwd);
|
|
8111
|
-
if (testMetricsContent) logger$
|
|
8759
|
+
if (testMetricsContent) logger$17.debug({ storyKey }, "Injecting verified test-count metrics into code-review context");
|
|
8112
8760
|
const fileDiffs = gitDiffContent ? parseDiffByFile(gitDiffContent) : void 0;
|
|
8113
8761
|
const scopeAnalysisContent = storyContent && filesModified ? ScopeGuardrail.buildAnalysis(storyContent, filesModified, fileDiffs) : "";
|
|
8114
|
-
if (scopeAnalysisContent) logger$
|
|
8762
|
+
if (scopeAnalysisContent) logger$17.debug({ storyKey }, "Scope analysis detected out-of-scope files");
|
|
8115
8763
|
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" : "";
|
|
8116
8764
|
const sections = [
|
|
8117
8765
|
{
|
|
@@ -8156,11 +8804,11 @@ async function runCodeReview(deps, params) {
|
|
|
8156
8804
|
}
|
|
8157
8805
|
];
|
|
8158
8806
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
8159
|
-
if (assembleResult.truncated) logger$
|
|
8807
|
+
if (assembleResult.truncated) logger$17.warn({
|
|
8160
8808
|
storyKey,
|
|
8161
8809
|
tokenCount: assembleResult.tokenCount
|
|
8162
8810
|
}, "Code-review prompt truncated to fit token ceiling");
|
|
8163
|
-
logger$
|
|
8811
|
+
logger$17.debug({
|
|
8164
8812
|
storyKey,
|
|
8165
8813
|
tokenCount: assembleResult.tokenCount,
|
|
8166
8814
|
truncated: assembleResult.truncated
|
|
@@ -8181,7 +8829,7 @@ async function runCodeReview(deps, params) {
|
|
|
8181
8829
|
dispatchResult = await handle.result;
|
|
8182
8830
|
} catch (err) {
|
|
8183
8831
|
const error = err instanceof Error ? err.message : String(err);
|
|
8184
|
-
logger$
|
|
8832
|
+
logger$17.error({
|
|
8185
8833
|
storyKey,
|
|
8186
8834
|
error
|
|
8187
8835
|
}, "Code-review dispatch threw unexpected error");
|
|
@@ -8197,7 +8845,7 @@ async function runCodeReview(deps, params) {
|
|
|
8197
8845
|
const rawOutput = dispatchResult.output ?? void 0;
|
|
8198
8846
|
if (dispatchResult.status === "failed") {
|
|
8199
8847
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""} ${dispatchResult.output ? `Stderr: ${dispatchResult.output}` : ""}`.trim();
|
|
8200
|
-
logger$
|
|
8848
|
+
logger$17.warn({
|
|
8201
8849
|
storyKey,
|
|
8202
8850
|
exitCode: dispatchResult.exitCode
|
|
8203
8851
|
}, "Code-review dispatch failed");
|
|
@@ -8207,7 +8855,7 @@ async function runCodeReview(deps, params) {
|
|
|
8207
8855
|
};
|
|
8208
8856
|
}
|
|
8209
8857
|
if (dispatchResult.status === "timeout") {
|
|
8210
|
-
logger$
|
|
8858
|
+
logger$17.warn({ storyKey }, "Code-review dispatch timed out");
|
|
8211
8859
|
return {
|
|
8212
8860
|
...defaultFailResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage),
|
|
8213
8861
|
rawOutput
|
|
@@ -8215,7 +8863,7 @@ async function runCodeReview(deps, params) {
|
|
|
8215
8863
|
}
|
|
8216
8864
|
if (dispatchResult.parsed === null) {
|
|
8217
8865
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
8218
|
-
logger$
|
|
8866
|
+
logger$17.warn({
|
|
8219
8867
|
storyKey,
|
|
8220
8868
|
details
|
|
8221
8869
|
}, "Code-review output schema validation failed");
|
|
@@ -8233,7 +8881,7 @@ async function runCodeReview(deps, params) {
|
|
|
8233
8881
|
const parseResult = CodeReviewResultSchema.safeParse(dispatchResult.parsed);
|
|
8234
8882
|
if (!parseResult.success) {
|
|
8235
8883
|
const details = parseResult.error.message;
|
|
8236
|
-
logger$
|
|
8884
|
+
logger$17.warn({
|
|
8237
8885
|
storyKey,
|
|
8238
8886
|
details
|
|
8239
8887
|
}, "Code-review output failed schema validation");
|
|
@@ -8249,13 +8897,13 @@ async function runCodeReview(deps, params) {
|
|
|
8249
8897
|
};
|
|
8250
8898
|
}
|
|
8251
8899
|
const parsed = parseResult.data;
|
|
8252
|
-
if (parsed.agentVerdict !== parsed.verdict) logger$
|
|
8900
|
+
if (parsed.agentVerdict !== parsed.verdict) logger$17.info({
|
|
8253
8901
|
storyKey,
|
|
8254
8902
|
agentVerdict: parsed.agentVerdict,
|
|
8255
8903
|
pipelineVerdict: parsed.verdict,
|
|
8256
8904
|
issues: parsed.issues
|
|
8257
8905
|
}, "Pipeline overrode agent verdict based on issue severities");
|
|
8258
|
-
logger$
|
|
8906
|
+
logger$17.info({
|
|
8259
8907
|
storyKey,
|
|
8260
8908
|
verdict: parsed.verdict,
|
|
8261
8909
|
issues: parsed.issues
|
|
@@ -8280,11 +8928,236 @@ async function getArchConstraints$2(deps) {
|
|
|
8280
8928
|
if (constraints.length === 0) return "";
|
|
8281
8929
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
8282
8930
|
} catch (err) {
|
|
8283
|
-
logger$
|
|
8931
|
+
logger$17.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
8284
8932
|
return "";
|
|
8285
8933
|
}
|
|
8286
8934
|
}
|
|
8287
8935
|
|
|
8936
|
+
//#endregion
|
|
8937
|
+
//#region src/modules/compiled-workflows/merge-to-main.ts
|
|
8938
|
+
const logger$16 = createLogger("compiled-workflows:merge-to-main");
|
|
8939
|
+
/**
|
|
8940
|
+
* Execute the merge-to-main phase: merge the story branch into the base branch.
|
|
8941
|
+
*
|
|
8942
|
+
* Attempts fast-forward first, falls back to 3-way merge. On conflict:
|
|
8943
|
+
* emits `pipeline:merge-conflict-detected` event, aborts the merge, preserves
|
|
8944
|
+
* the worktree and branch for operator inspection, and returns a failure result.
|
|
8945
|
+
*
|
|
8946
|
+
* Merge commands run against `projectRoot` (the main working tree).
|
|
8947
|
+
* The main working tree must already be on `startBranch` (checked out at
|
|
8948
|
+
* orchestrator startup — no branch switching is performed here).
|
|
8949
|
+
*
|
|
8950
|
+
* @param params - Merge phase parameters (storyKey, branchName, startBranch,
|
|
8951
|
+
* worktreeManager, eventBus, projectRoot)
|
|
8952
|
+
* @returns MergeToMainResult — success=true on merged; success=false with
|
|
8953
|
+
* reason='merge-conflict-detected' and conflictingFiles on conflict.
|
|
8954
|
+
*/
|
|
8955
|
+
async function runMergeToMain(params) {
|
|
8956
|
+
const { storyKey, branchName, startBranch, worktreeManager, eventBus, projectRoot } = params;
|
|
8957
|
+
logger$16.info({
|
|
8958
|
+
storyKey,
|
|
8959
|
+
branchName,
|
|
8960
|
+
startBranch
|
|
8961
|
+
}, "Starting merge-to-main phase");
|
|
8962
|
+
const ffSuccess = tryFfMerge(branchName, projectRoot);
|
|
8963
|
+
if (ffSuccess) {
|
|
8964
|
+
logger$16.info({
|
|
8965
|
+
storyKey,
|
|
8966
|
+
branchName
|
|
8967
|
+
}, "Fast-forward merge succeeded");
|
|
8968
|
+
await cleanupAfterSuccessfulMerge(storyKey, branchName, worktreeManager, projectRoot);
|
|
8969
|
+
return { success: true };
|
|
8970
|
+
}
|
|
8971
|
+
logger$16.info({
|
|
8972
|
+
storyKey,
|
|
8973
|
+
branchName
|
|
8974
|
+
}, "Fast-forward merge failed — attempting 3-way merge");
|
|
8975
|
+
const threeWayResult = tryThreeWayMerge(branchName, projectRoot);
|
|
8976
|
+
if (threeWayResult.success) {
|
|
8977
|
+
logger$16.info({
|
|
8978
|
+
storyKey,
|
|
8979
|
+
branchName
|
|
8980
|
+
}, "3-way merge succeeded");
|
|
8981
|
+
await cleanupAfterSuccessfulMerge(storyKey, branchName, worktreeManager, projectRoot);
|
|
8982
|
+
return { success: true };
|
|
8983
|
+
}
|
|
8984
|
+
const { conflictingFiles } = threeWayResult;
|
|
8985
|
+
logger$16.warn({
|
|
8986
|
+
storyKey,
|
|
8987
|
+
branchName,
|
|
8988
|
+
conflictingFiles
|
|
8989
|
+
}, "Merge conflict detected — preserving worktree for operator inspection");
|
|
8990
|
+
eventBus.emit("pipeline:merge-conflict-detected", {
|
|
8991
|
+
storyKey,
|
|
8992
|
+
branchName,
|
|
8993
|
+
conflictingFiles
|
|
8994
|
+
});
|
|
8995
|
+
return {
|
|
8996
|
+
success: false,
|
|
8997
|
+
reason: "merge-conflict-detected",
|
|
8998
|
+
conflictingFiles
|
|
8999
|
+
};
|
|
9000
|
+
}
|
|
9001
|
+
/**
|
|
9002
|
+
* Attempt a fast-forward merge of `branchName` into the current branch.
|
|
9003
|
+
*
|
|
9004
|
+
* @param branchName - Branch to merge
|
|
9005
|
+
* @param projectRoot - Working directory (main worktree, already on startBranch)
|
|
9006
|
+
* @returns - true if FF succeeded, false if it failed (branch diverged)
|
|
9007
|
+
*/
|
|
9008
|
+
function tryFfMerge(branchName, projectRoot) {
|
|
9009
|
+
try {
|
|
9010
|
+
execFileSync("git", [
|
|
9011
|
+
"merge",
|
|
9012
|
+
"--ff-only",
|
|
9013
|
+
branchName
|
|
9014
|
+
], {
|
|
9015
|
+
cwd: projectRoot,
|
|
9016
|
+
stdio: [
|
|
9017
|
+
"ignore",
|
|
9018
|
+
"pipe",
|
|
9019
|
+
"pipe"
|
|
9020
|
+
]
|
|
9021
|
+
});
|
|
9022
|
+
return true;
|
|
9023
|
+
} catch {
|
|
9024
|
+
return false;
|
|
9025
|
+
}
|
|
9026
|
+
}
|
|
9027
|
+
/**
|
|
9028
|
+
* Attempt a 3-way merge of `branchName` into the current branch.
|
|
9029
|
+
*
|
|
9030
|
+
* On conflict: parses conflicting files from `git diff --name-only --diff-filter=U`
|
|
9031
|
+
* and aborts the merge before returning.
|
|
9032
|
+
*
|
|
9033
|
+
* @param branchName - Branch to merge
|
|
9034
|
+
* @param projectRoot - Working directory (main worktree, already on startBranch)
|
|
9035
|
+
* @returns - { success: true } on clean merge;
|
|
9036
|
+
* { success: false, conflictingFiles: string[] } on conflict
|
|
9037
|
+
*/
|
|
9038
|
+
function tryThreeWayMerge(branchName, projectRoot) {
|
|
9039
|
+
try {
|
|
9040
|
+
execFileSync("git", [
|
|
9041
|
+
"merge",
|
|
9042
|
+
"--no-edit",
|
|
9043
|
+
branchName
|
|
9044
|
+
], {
|
|
9045
|
+
cwd: projectRoot,
|
|
9046
|
+
stdio: [
|
|
9047
|
+
"ignore",
|
|
9048
|
+
"pipe",
|
|
9049
|
+
"pipe"
|
|
9050
|
+
]
|
|
9051
|
+
});
|
|
9052
|
+
return {
|
|
9053
|
+
success: true,
|
|
9054
|
+
conflictingFiles: []
|
|
9055
|
+
};
|
|
9056
|
+
} catch {
|
|
9057
|
+
let conflictingFiles = [];
|
|
9058
|
+
try {
|
|
9059
|
+
const diffOutput = execFileSync("git", [
|
|
9060
|
+
"diff",
|
|
9061
|
+
"--name-only",
|
|
9062
|
+
"--diff-filter=U"
|
|
9063
|
+
], {
|
|
9064
|
+
cwd: projectRoot,
|
|
9065
|
+
encoding: "utf-8",
|
|
9066
|
+
stdio: [
|
|
9067
|
+
"ignore",
|
|
9068
|
+
"pipe",
|
|
9069
|
+
"pipe"
|
|
9070
|
+
]
|
|
9071
|
+
});
|
|
9072
|
+
conflictingFiles = diffOutput.trim().split("\n").filter((line) => line.length > 0);
|
|
9073
|
+
} catch (diffErr) {
|
|
9074
|
+
logger$16.warn({ err: diffErr }, "Failed to list conflicting files (best-effort)");
|
|
9075
|
+
}
|
|
9076
|
+
try {
|
|
9077
|
+
execFileSync("git", ["merge", "--abort"], {
|
|
9078
|
+
cwd: projectRoot,
|
|
9079
|
+
stdio: [
|
|
9080
|
+
"ignore",
|
|
9081
|
+
"pipe",
|
|
9082
|
+
"pipe"
|
|
9083
|
+
]
|
|
9084
|
+
});
|
|
9085
|
+
} catch (abortErr) {
|
|
9086
|
+
logger$16.warn({ err: abortErr }, "Failed to abort merge (best-effort)");
|
|
9087
|
+
}
|
|
9088
|
+
return {
|
|
9089
|
+
success: false,
|
|
9090
|
+
conflictingFiles
|
|
9091
|
+
};
|
|
9092
|
+
}
|
|
9093
|
+
}
|
|
9094
|
+
/**
|
|
9095
|
+
* Clean up the worktree and delete the merged branch after a successful merge.
|
|
9096
|
+
*
|
|
9097
|
+
* Cleanup is best-effort — a failure here does not revert the already-completed
|
|
9098
|
+
* git merge. Both operations are attempted independently.
|
|
9099
|
+
*
|
|
9100
|
+
* @param storyKey - Story key (used as worktree task ID)
|
|
9101
|
+
* @param branchName - Branch that was merged (to delete)
|
|
9102
|
+
* @param worktreeManager - Manager for removing the worktree directory
|
|
9103
|
+
* @param projectRoot - Working directory for git branch deletion
|
|
9104
|
+
*/
|
|
9105
|
+
async function cleanupAfterSuccessfulMerge(storyKey, branchName, worktreeManager, projectRoot) {
|
|
9106
|
+
try {
|
|
9107
|
+
await worktreeManager.cleanupWorktree(storyKey);
|
|
9108
|
+
logger$16.info({ storyKey }, "Worktree removed after successful merge");
|
|
9109
|
+
} catch (worktreeErr) {
|
|
9110
|
+
logger$16.warn({
|
|
9111
|
+
storyKey,
|
|
9112
|
+
err: worktreeErr
|
|
9113
|
+
}, "Failed to remove worktree (best-effort)");
|
|
9114
|
+
}
|
|
9115
|
+
try {
|
|
9116
|
+
execFileSync("git", [
|
|
9117
|
+
"branch",
|
|
9118
|
+
"-d",
|
|
9119
|
+
branchName
|
|
9120
|
+
], {
|
|
9121
|
+
cwd: projectRoot,
|
|
9122
|
+
stdio: [
|
|
9123
|
+
"ignore",
|
|
9124
|
+
"pipe",
|
|
9125
|
+
"pipe"
|
|
9126
|
+
]
|
|
9127
|
+
});
|
|
9128
|
+
logger$16.info({
|
|
9129
|
+
storyKey,
|
|
9130
|
+
branchName
|
|
9131
|
+
}, "Merged branch deleted");
|
|
9132
|
+
} catch (branchErr) {
|
|
9133
|
+
logger$16.warn({
|
|
9134
|
+
storyKey,
|
|
9135
|
+
branchName,
|
|
9136
|
+
err: branchErr
|
|
9137
|
+
}, "Failed to delete merged branch (best-effort)");
|
|
9138
|
+
}
|
|
9139
|
+
}
|
|
9140
|
+
/**
|
|
9141
|
+
* Create a serialized merge queue to prevent concurrent git merge operations.
|
|
9142
|
+
*
|
|
9143
|
+
* Returns an `enqueueMerge` function that wraps `runMergeToMain`. All calls
|
|
9144
|
+
* through the returned function are serialized: each invocation waits for the
|
|
9145
|
+
* previous to fully complete before starting. This prevents data-corruption
|
|
9146
|
+
* from concurrent `git merge` operations against the same base branch (AC7).
|
|
9147
|
+
*
|
|
9148
|
+
* Used by `orchestrator-impl.ts` to create a per-run merge queue. Exported
|
|
9149
|
+
* separately so the serialization logic can be unit-tested independently of
|
|
9150
|
+
* the orchestrator (see AC8d in Story 75-2).
|
|
9151
|
+
*
|
|
9152
|
+
* @returns A queue-serialized wrapper around `runMergeToMain`.
|
|
9153
|
+
*/
|
|
9154
|
+
function createMergeQueue() {
|
|
9155
|
+
let queue = Promise.resolve();
|
|
9156
|
+
return (params) => new Promise((resolve$6, reject) => {
|
|
9157
|
+
queue = queue.then(() => runMergeToMain(params)).then(resolve$6, reject).then(() => void 0, () => void 0);
|
|
9158
|
+
});
|
|
9159
|
+
}
|
|
9160
|
+
|
|
8288
9161
|
//#endregion
|
|
8289
9162
|
//#region src/modules/compiled-workflows/test-plan.ts
|
|
8290
9163
|
const logger$15 = createLogger("compiled-workflows:test-plan");
|
|
@@ -12071,6 +12944,17 @@ function topologicalSortByDependencies(keys, projectRoot) {
|
|
|
12071
12944
|
function toSdlcEventBus(bus) {
|
|
12072
12945
|
return bus;
|
|
12073
12946
|
}
|
|
12947
|
+
/**
|
|
12948
|
+
* Project the monolith event bus to `TypedEventBus<CoreEvents>` for GitWorktreeManager.
|
|
12949
|
+
*
|
|
12950
|
+
* Story 75-1 (Path E spike 2026-05-10): OrchestratorEvents mirrors the CoreEvents worktree
|
|
12951
|
+
* events ('worktree:created', 'worktree:removed') so the cast is safe at runtime.
|
|
12952
|
+
* TypeScript cannot perform the direct cast due to generic method signatures; the
|
|
12953
|
+
* `as unknown` intermediate is isolated here to keep call sites clean.
|
|
12954
|
+
*/
|
|
12955
|
+
function toCoreEventBus(bus) {
|
|
12956
|
+
return bus;
|
|
12957
|
+
}
|
|
12074
12958
|
function estimateDispatchCost(input, output) {
|
|
12075
12959
|
return (input * 3 + output * 15) / 1e6;
|
|
12076
12960
|
}
|
|
@@ -12386,8 +13270,13 @@ function checkProfileStaleness(projectRoot) {
|
|
|
12386
13270
|
* @returns A fully-configured ImplementationOrchestrator ready to call run()
|
|
12387
13271
|
*/
|
|
12388
13272
|
function createImplementationOrchestrator(deps) {
|
|
12389
|
-
const { db, pack, contextCompiler, dispatcher, eventBus, config, projectRoot, tokenCeilings, stateStore, telemetryPersistence, ingestionServer, repoMapInjector, maxRepoMapTokens, agentId, runManifest = null } = deps;
|
|
12390
|
-
const
|
|
13273
|
+
const { db, pack, contextCompiler, dispatcher, eventBus, config, projectRoot, tokenCeilings, stateStore, telemetryPersistence, ingestionServer, repoMapInjector, maxRepoMapTokens, agentId, runManifest = null, worktreeManager } = deps;
|
|
13274
|
+
const noWorktree = config.noWorktree ?? false;
|
|
13275
|
+
const _worktreeManager = worktreeManager ?? (projectRoot !== void 0 && !noWorktree ? createGitWorktreeManager({
|
|
13276
|
+
eventBus: toCoreEventBus(eventBus),
|
|
13277
|
+
projectRoot
|
|
13278
|
+
}) : void 0);
|
|
13279
|
+
const logger$27 = createLogger("implementation-orchestrator");
|
|
12391
13280
|
const telemetryAdvisor = db !== void 0 ? createTelemetryAdvisor({ db }) : void 0;
|
|
12392
13281
|
const wgRepo = new WorkGraphRepository(db);
|
|
12393
13282
|
const _wgInProgressWritten = new Set();
|
|
@@ -12413,6 +13302,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12413
13302
|
let _completedDispatches = 0;
|
|
12414
13303
|
let _maxConcurrentActual = 0;
|
|
12415
13304
|
let _packageSnapshot;
|
|
13305
|
+
let _orchestratorStartBranch;
|
|
12416
13306
|
let _contractMismatches;
|
|
12417
13307
|
const _costChecker = new CostGovernanceChecker();
|
|
12418
13308
|
let _costWarningEmitted = false;
|
|
@@ -12429,6 +13319,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12429
13319
|
const verificationPipeline = createDefaultVerificationPipeline(toSdlcEventBus(eventBus), void 0);
|
|
12430
13320
|
const _stateStoreCache = new Map();
|
|
12431
13321
|
const _checkpoints = new Map();
|
|
13322
|
+
const enqueueMerge = createMergeQueue();
|
|
12432
13323
|
const MEMORY_PRESSURE_BACKOFF_MS = [
|
|
12433
13324
|
3e4,
|
|
12434
13325
|
6e4,
|
|
@@ -12471,7 +13362,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12471
13362
|
const existingCount = storyState?.retry_count ?? 0;
|
|
12472
13363
|
_storyRetryCount.set(storyKey, existingCount);
|
|
12473
13364
|
} catch (err) {
|
|
12474
|
-
logger$
|
|
13365
|
+
logger$27.warn({
|
|
12475
13366
|
err,
|
|
12476
13367
|
storyKey
|
|
12477
13368
|
}, "initRetryCount: failed to read manifest — starting at 0");
|
|
@@ -12485,7 +13376,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12485
13376
|
const current = _storyRetryCount.get(storyKey) ?? 0;
|
|
12486
13377
|
const next = current + 1;
|
|
12487
13378
|
_storyRetryCount.set(storyKey, next);
|
|
12488
|
-
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$
|
|
13379
|
+
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$27.warn({
|
|
12489
13380
|
err,
|
|
12490
13381
|
storyKey
|
|
12491
13382
|
}, "patchStoryState(retry_count) failed — pipeline continues"));
|
|
@@ -12498,7 +13389,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12498
13389
|
const nowMs = Date.now();
|
|
12499
13390
|
for (const [phase, startMs] of starts) {
|
|
12500
13391
|
const endMs = ends?.get(phase);
|
|
12501
|
-
if (endMs === void 0) logger$
|
|
13392
|
+
if (endMs === void 0) logger$27.warn({
|
|
12502
13393
|
storyKey,
|
|
12503
13394
|
phase
|
|
12504
13395
|
}, "Phase has no end time — story may have errored mid-phase. Duration capped to now() and may be inflated.");
|
|
@@ -12515,7 +13406,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12515
13406
|
const wallClockSeconds = startedAt ? Math.round((new Date(completedAt).getTime() - new Date(startedAt).getTime()) / 1e3) : 0;
|
|
12516
13407
|
const wallClockMs = startedAt ? new Date(completedAt).getTime() - new Date(startedAt).getTime() : 0;
|
|
12517
13408
|
const tokenAgg = await aggregateTokenUsageForStory(db, config.pipelineRunId, storyKey);
|
|
12518
|
-
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$
|
|
13409
|
+
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$27.warn({
|
|
12519
13410
|
err,
|
|
12520
13411
|
storyKey
|
|
12521
13412
|
}, "patchStoryState(cost_usd) failed — pipeline continues"));
|
|
@@ -12551,7 +13442,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12551
13442
|
recordedAt: completedAt,
|
|
12552
13443
|
timestamp: completedAt
|
|
12553
13444
|
}).catch((storeErr) => {
|
|
12554
|
-
logger$
|
|
13445
|
+
logger$27.warn({
|
|
12555
13446
|
err: storeErr,
|
|
12556
13447
|
storyKey
|
|
12557
13448
|
}, "Failed to record metric to StateStore (best-effort)");
|
|
@@ -12573,7 +13464,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12573
13464
|
rationale: `Story ${storyKey} completed with result=${result} in ${wallClockSeconds}s. Tokens: ${tokenAgg.input}+${tokenAgg.output}. Review cycles: ${reviewCycles}.`
|
|
12574
13465
|
});
|
|
12575
13466
|
} catch (decisionErr) {
|
|
12576
|
-
logger$
|
|
13467
|
+
logger$27.warn({
|
|
12577
13468
|
err: decisionErr,
|
|
12578
13469
|
storyKey
|
|
12579
13470
|
}, "Failed to write story-metrics decision (best-effort)");
|
|
@@ -12652,7 +13543,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12652
13543
|
const LOW_OUTPUT_TOKEN_THRESHOLD = 100;
|
|
12653
13544
|
const unverified = tokenAgg.output < LOW_OUTPUT_TOKEN_THRESHOLD;
|
|
12654
13545
|
if (unverified) {
|
|
12655
|
-
logger$
|
|
13546
|
+
logger$27.warn({
|
|
12656
13547
|
storyKey,
|
|
12657
13548
|
outputTokens: tokenAgg.output,
|
|
12658
13549
|
threshold: LOW_OUTPUT_TOKEN_THRESHOLD
|
|
@@ -12676,13 +13567,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
12676
13567
|
...unverified ? { unverified: true } : {}
|
|
12677
13568
|
});
|
|
12678
13569
|
} catch (emitErr) {
|
|
12679
|
-
logger$
|
|
13570
|
+
logger$27.warn({
|
|
12680
13571
|
err: emitErr,
|
|
12681
13572
|
storyKey
|
|
12682
13573
|
}, "Failed to emit story:metrics event (best-effort)");
|
|
12683
13574
|
}
|
|
12684
13575
|
} catch (err) {
|
|
12685
|
-
logger$
|
|
13576
|
+
logger$27.warn({
|
|
12686
13577
|
err,
|
|
12687
13578
|
storyKey
|
|
12688
13579
|
}, "Failed to write story metrics (best-effort)");
|
|
@@ -12711,7 +13602,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12711
13602
|
rationale: `Story ${storyKey} ${outcome} after ${reviewCycles} review cycle(s).`
|
|
12712
13603
|
});
|
|
12713
13604
|
} catch (err) {
|
|
12714
|
-
logger$
|
|
13605
|
+
logger$27.warn({
|
|
12715
13606
|
err,
|
|
12716
13607
|
storyKey
|
|
12717
13608
|
}, "Failed to write story-outcome decision (best-effort)");
|
|
@@ -12749,7 +13640,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12749
13640
|
rationale: `Escalation diagnosis for ${payload.storyKey}: ${diagnosis.recommendedAction} — ${diagnosis.rationale}`
|
|
12750
13641
|
});
|
|
12751
13642
|
} catch (err) {
|
|
12752
|
-
logger$
|
|
13643
|
+
logger$27.warn({
|
|
12753
13644
|
err,
|
|
12754
13645
|
storyKey: payload.storyKey
|
|
12755
13646
|
}, "Failed to persist escalation diagnosis (best-effort)");
|
|
@@ -12799,7 +13690,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12799
13690
|
const existing = _stories.get(storyKey);
|
|
12800
13691
|
if (existing !== void 0) {
|
|
12801
13692
|
Object.assign(existing, updates);
|
|
12802
|
-
persistStoryState(storyKey, existing).catch((err) => logger$
|
|
13693
|
+
persistStoryState(storyKey, existing).catch((err) => logger$27.warn({
|
|
12803
13694
|
err,
|
|
12804
13695
|
storyKey
|
|
12805
13696
|
}, "StateStore write failed after updateStory"));
|
|
@@ -12808,12 +13699,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
12808
13699
|
storyKey,
|
|
12809
13700
|
conflict: err
|
|
12810
13701
|
});
|
|
12811
|
-
else logger$
|
|
13702
|
+
else logger$27.warn({
|
|
12812
13703
|
err,
|
|
12813
13704
|
storyKey
|
|
12814
13705
|
}, "mergeStory failed");
|
|
12815
13706
|
});
|
|
12816
|
-
else if (updates.phase === "ESCALATED" || updates.phase === "VERIFICATION_FAILED") stateStore?.rollbackStory(storyKey).catch((err) => logger$
|
|
13707
|
+
else if (updates.phase === "ESCALATED" || updates.phase === "VERIFICATION_FAILED") stateStore?.rollbackStory(storyKey).catch((err) => logger$27.warn({
|
|
12817
13708
|
err,
|
|
12818
13709
|
storyKey
|
|
12819
13710
|
}, "rollbackStory failed — branch may persist"));
|
|
@@ -12825,7 +13716,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12825
13716
|
...updates
|
|
12826
13717
|
};
|
|
12827
13718
|
const opts = targetStatus === "complete" || targetStatus === "escalated" ? { completedAt: fullUpdated.completedAt } : void 0;
|
|
12828
|
-
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$
|
|
13719
|
+
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$27.warn({
|
|
12829
13720
|
err,
|
|
12830
13721
|
storyKey
|
|
12831
13722
|
}, "wg_stories status update failed (best-effort)"));
|
|
@@ -12841,7 +13732,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12841
13732
|
status: "dispatched",
|
|
12842
13733
|
phase: String(updates.phase),
|
|
12843
13734
|
started_at: fullUpdated.startedAt ?? new Date().toISOString()
|
|
12844
|
-
}).catch((err) => logger$
|
|
13735
|
+
}).catch((err) => logger$27.warn({
|
|
12845
13736
|
err,
|
|
12846
13737
|
storyKey
|
|
12847
13738
|
}, "patchStoryState(dispatched) failed — pipeline continues"));
|
|
@@ -12853,13 +13744,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
12853
13744
|
completed_at: fullUpdated.completedAt ?? new Date().toISOString(),
|
|
12854
13745
|
review_cycles: fullUpdated.reviewCycles ?? 0,
|
|
12855
13746
|
dispatches: _storyDispatches.get(storyKey) ?? 0
|
|
12856
|
-
}).catch((err) => logger$
|
|
13747
|
+
}).catch((err) => logger$27.warn({
|
|
12857
13748
|
err,
|
|
12858
13749
|
storyKey
|
|
12859
13750
|
}, `patchStoryState(${manifestStatus}) failed — pipeline continues`));
|
|
12860
13751
|
} else {
|
|
12861
13752
|
const intermediatePhase = updates.phase;
|
|
12862
|
-
runManifest.patchStoryState(storyKey, { phase: String(intermediatePhase) }).catch((err) => logger$
|
|
13753
|
+
runManifest.patchStoryState(storyKey, { phase: String(intermediatePhase) }).catch((err) => logger$27.warn({
|
|
12863
13754
|
err,
|
|
12864
13755
|
storyKey,
|
|
12865
13756
|
phase: intermediatePhase
|
|
@@ -12890,7 +13781,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12890
13781
|
};
|
|
12891
13782
|
await stateStore.setStoryState(storyKey, record);
|
|
12892
13783
|
} catch (err) {
|
|
12893
|
-
logger$
|
|
13784
|
+
logger$27.warn({
|
|
12894
13785
|
err,
|
|
12895
13786
|
storyKey
|
|
12896
13787
|
}, "StateStore.setStoryState failed (best-effort)");
|
|
@@ -12906,7 +13797,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12906
13797
|
token_usage_json: serialized
|
|
12907
13798
|
});
|
|
12908
13799
|
} catch (err) {
|
|
12909
|
-
logger$
|
|
13800
|
+
logger$27.warn({ err }, "Failed to persist orchestrator state");
|
|
12910
13801
|
}
|
|
12911
13802
|
}
|
|
12912
13803
|
function recordProgress() {
|
|
@@ -12954,7 +13845,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12954
13845
|
...Object.keys(perStoryState).length > 0 ? { perStoryState } : {}
|
|
12955
13846
|
});
|
|
12956
13847
|
if (config.pipelineRunId !== void 0) updatePipelineRun(db, config.pipelineRunId, { current_phase: "implementation" }).catch((err) => {
|
|
12957
|
-
logger$
|
|
13848
|
+
logger$27.debug({ err }, "Heartbeat: failed to touch updated_at (non-fatal)");
|
|
12958
13849
|
});
|
|
12959
13850
|
const elapsed = Date.now() - _lastProgressTs;
|
|
12960
13851
|
let childPids = [];
|
|
@@ -12976,7 +13867,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12976
13867
|
}
|
|
12977
13868
|
if (childActive) {
|
|
12978
13869
|
_lastProgressTs = Date.now();
|
|
12979
|
-
logger$
|
|
13870
|
+
logger$27.debug({
|
|
12980
13871
|
storyKey: key,
|
|
12981
13872
|
phase: s$1.phase,
|
|
12982
13873
|
childPids
|
|
@@ -12985,7 +13876,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
12985
13876
|
}
|
|
12986
13877
|
_stalledStories.add(key);
|
|
12987
13878
|
_storiesWithStall.add(key);
|
|
12988
|
-
logger$
|
|
13879
|
+
logger$27.warn({
|
|
12989
13880
|
storyKey: key,
|
|
12990
13881
|
phase: s$1.phase,
|
|
12991
13882
|
elapsedMs: elapsed,
|
|
@@ -13030,7 +13921,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13030
13921
|
for (let attempt = 0; attempt < MEMORY_PRESSURE_BACKOFF_MS.length; attempt++) {
|
|
13031
13922
|
const memState = dispatcher.getMemoryState();
|
|
13032
13923
|
if (!memState.isPressured) return true;
|
|
13033
|
-
logger$
|
|
13924
|
+
logger$27.warn({
|
|
13034
13925
|
storyKey,
|
|
13035
13926
|
freeMB: memState.freeMB,
|
|
13036
13927
|
thresholdMB: memState.thresholdMB,
|
|
@@ -13050,12 +13941,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
13050
13941
|
* exhausted retries the story is ESCALATED.
|
|
13051
13942
|
*/
|
|
13052
13943
|
async function processStory(storyKey, storyOptions) {
|
|
13053
|
-
logger$
|
|
13944
|
+
logger$27.info({ storyKey }, "Processing story");
|
|
13054
13945
|
await initRetryCount(storyKey);
|
|
13055
13946
|
{
|
|
13056
13947
|
const memoryOk = await checkMemoryPressure(storyKey);
|
|
13057
13948
|
if (!memoryOk) {
|
|
13058
|
-
logger$
|
|
13949
|
+
logger$27.warn({ storyKey }, "Memory pressure exhausted — escalating story without dispatch");
|
|
13059
13950
|
const memPressureState = {
|
|
13060
13951
|
phase: "ESCALATED",
|
|
13061
13952
|
reviewCycles: 0,
|
|
@@ -13064,7 +13955,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13064
13955
|
completedAt: new Date().toISOString()
|
|
13065
13956
|
};
|
|
13066
13957
|
_stories.set(storyKey, memPressureState);
|
|
13067
|
-
persistStoryState(storyKey, memPressureState).catch((err) => logger$
|
|
13958
|
+
persistStoryState(storyKey, memPressureState).catch((err) => logger$27.warn({
|
|
13068
13959
|
err,
|
|
13069
13960
|
storyKey
|
|
13070
13961
|
}, "StateStore write failed after memory-pressure escalation"));
|
|
@@ -13079,9 +13970,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
13079
13970
|
return;
|
|
13080
13971
|
}
|
|
13081
13972
|
}
|
|
13973
|
+
let effectiveProjectRoot = projectRoot;
|
|
13974
|
+
if (!noWorktree && _worktreeManager !== void 0 && projectRoot !== void 0) {
|
|
13975
|
+
const wt = await _worktreeManager.createWorktree(storyKey);
|
|
13976
|
+
effectiveProjectRoot = wt.worktreePath;
|
|
13977
|
+
}
|
|
13082
13978
|
await waitIfPaused();
|
|
13083
13979
|
if (_state !== "RUNNING") return;
|
|
13084
|
-
stateStore?.branchForStory(storyKey).catch((err) => logger$
|
|
13980
|
+
stateStore?.branchForStory(storyKey).catch((err) => logger$27.warn({
|
|
13085
13981
|
err,
|
|
13086
13982
|
storyKey
|
|
13087
13983
|
}, "branchForStory failed — continuing without branch isolation"));
|
|
@@ -13092,7 +13988,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13092
13988
|
});
|
|
13093
13989
|
let storyFilePath;
|
|
13094
13990
|
let sourceAcHash;
|
|
13095
|
-
const artifactsDir =
|
|
13991
|
+
const artifactsDir = effectiveProjectRoot ? join$1(effectiveProjectRoot, "_bmad-output", "implementation-artifacts") : void 0;
|
|
13096
13992
|
if (artifactsDir && existsSync(artifactsDir)) try {
|
|
13097
13993
|
const files = readdirSync(artifactsDir);
|
|
13098
13994
|
const STALE_SUFFIX = /\.stale-\d+\.md$/;
|
|
@@ -13100,7 +13996,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13100
13996
|
if (match$2) {
|
|
13101
13997
|
const candidatePath = join$1(artifactsDir, match$2);
|
|
13102
13998
|
const validation = await isValidStoryFile(candidatePath);
|
|
13103
|
-
if (!validation.valid) logger$
|
|
13999
|
+
if (!validation.valid) logger$27.warn({
|
|
13104
14000
|
storyKey,
|
|
13105
14001
|
storyFilePath: candidatePath,
|
|
13106
14002
|
reason: validation.reason
|
|
@@ -13108,7 +14004,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13108
14004
|
else {
|
|
13109
14005
|
let isDrift = false;
|
|
13110
14006
|
try {
|
|
13111
|
-
const epicsPath =
|
|
14007
|
+
const epicsPath = effectiveProjectRoot ? findEpicsFile(effectiveProjectRoot) : void 0;
|
|
13112
14008
|
if (epicsPath !== void 0) {
|
|
13113
14009
|
const epicContent = readFileSync(epicsPath, "utf-8");
|
|
13114
14010
|
const sourceSection = extractStorySection(epicContent, storyKey);
|
|
@@ -13125,7 +14021,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13125
14021
|
storedHash,
|
|
13126
14022
|
currentHash
|
|
13127
14023
|
});
|
|
13128
|
-
logger$
|
|
14024
|
+
logger$27.info({
|
|
13129
14025
|
storyKey,
|
|
13130
14026
|
storedHash,
|
|
13131
14027
|
currentHash
|
|
@@ -13136,7 +14032,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13136
14032
|
} catch {}
|
|
13137
14033
|
if (!isDrift) {
|
|
13138
14034
|
storyFilePath = candidatePath;
|
|
13139
|
-
logger$
|
|
14035
|
+
logger$27.info({
|
|
13140
14036
|
storyKey,
|
|
13141
14037
|
storyFilePath
|
|
13142
14038
|
}, "Found existing story file — skipping create-story");
|
|
@@ -13156,12 +14052,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
13156
14052
|
const staleName = match$2.replace(/\.md$/, `.stale-${ts}.md`);
|
|
13157
14053
|
const stalePath = join$1(artifactsDir, staleName);
|
|
13158
14054
|
renameSync(candidatePath, stalePath);
|
|
13159
|
-
logger$
|
|
14055
|
+
logger$27.info({
|
|
13160
14056
|
storyKey,
|
|
13161
14057
|
staleName
|
|
13162
14058
|
}, `[orchestrator] story ${storyKey}: renamed drifted artifact to ${staleName} before re-dispatch`);
|
|
13163
14059
|
} catch (renameErr) {
|
|
13164
|
-
logger$
|
|
14060
|
+
logger$27.warn({
|
|
13165
14061
|
storyKey,
|
|
13166
14062
|
err: renameErr
|
|
13167
14063
|
}, "Failed to rename stale artifact before create-story re-dispatch; relying on 58-9d fraud-guard");
|
|
@@ -13169,8 +14065,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
13169
14065
|
}
|
|
13170
14066
|
}
|
|
13171
14067
|
} catch {}
|
|
13172
|
-
if (storyFilePath === void 0 &&
|
|
13173
|
-
logger$
|
|
14068
|
+
if (storyFilePath === void 0 && effectiveProjectRoot && isImplicitlyCovered(storyKey, effectiveProjectRoot)) {
|
|
14069
|
+
logger$27.info({ storyKey }, `Story ${storyKey} appears implicitly covered — all expected new files already exist. Skipping create-story.`);
|
|
13174
14070
|
endPhase(storyKey, "create-story");
|
|
13175
14071
|
eventBus.emit("orchestrator:story-phase-complete", {
|
|
13176
14072
|
storyKey,
|
|
@@ -13199,7 +14095,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13199
14095
|
pack,
|
|
13200
14096
|
contextCompiler,
|
|
13201
14097
|
dispatcher,
|
|
13202
|
-
projectRoot,
|
|
14098
|
+
projectRoot: effectiveProjectRoot,
|
|
13203
14099
|
tokenCeilings,
|
|
13204
14100
|
otlpEndpoint: _otlpEndpoint,
|
|
13205
14101
|
agentId
|
|
@@ -13223,7 +14119,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13223
14119
|
output_tokens: createResult.tokenUsage.output,
|
|
13224
14120
|
cost_usd: estimateDispatchCost(createResult.tokenUsage.input, createResult.tokenUsage.output),
|
|
13225
14121
|
metadata: JSON.stringify({ storyKey })
|
|
13226
|
-
})).catch((tokenErr) => logger$
|
|
14122
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
13227
14123
|
storyKey,
|
|
13228
14124
|
err: tokenErr
|
|
13229
14125
|
}, "Failed to record create-story token usage"));
|
|
@@ -13231,7 +14127,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13231
14127
|
if (createResult.result === "failed") {
|
|
13232
14128
|
const errMsg = createResult.error ?? "create-story failed";
|
|
13233
14129
|
const stderrSnippet = errMsg.includes("--- stderr ---") ? errMsg.slice(errMsg.indexOf("--- stderr ---") + 15, errMsg.indexOf("--- stderr ---") + 515) : errMsg.slice(0, 500);
|
|
13234
|
-
logger$
|
|
14130
|
+
logger$27.error({
|
|
13235
14131
|
storyKey,
|
|
13236
14132
|
stderrSnippet
|
|
13237
14133
|
}, `Create-story failed: ${stderrSnippet.split("\n")[0]}`);
|
|
@@ -13267,13 +14163,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
13267
14163
|
await persistState();
|
|
13268
14164
|
return;
|
|
13269
14165
|
}
|
|
13270
|
-
if (
|
|
13271
|
-
const expectedArtifactsDir = join$1(
|
|
14166
|
+
if (effectiveProjectRoot !== void 0) {
|
|
14167
|
+
const expectedArtifactsDir = join$1(effectiveProjectRoot, "_bmad-output", "implementation-artifacts");
|
|
13272
14168
|
const escapedExpectedDir = expectedArtifactsDir.replace("/_bmad-output/", "/\\_bmad-output/");
|
|
13273
14169
|
let claimedPath = createResult.story_file;
|
|
13274
14170
|
if (claimedPath.startsWith(escapedExpectedDir)) {
|
|
13275
14171
|
claimedPath = claimedPath.replace("/\\_bmad-output/", "/_bmad-output/");
|
|
13276
|
-
logger$
|
|
14172
|
+
logger$27.warn({
|
|
13277
14173
|
storyKey,
|
|
13278
14174
|
originalClaim: createResult.story_file,
|
|
13279
14175
|
normalizedClaim: claimedPath
|
|
@@ -13291,7 +14187,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13291
14187
|
if (escapedVariant !== claimedPath && existsSync(escapedVariant)) try {
|
|
13292
14188
|
renameSync(escapedVariant, claimedPath);
|
|
13293
14189
|
actualPath = claimedPath;
|
|
13294
|
-
logger$
|
|
14190
|
+
logger$27.warn({
|
|
13295
14191
|
storyKey,
|
|
13296
14192
|
escapedVariant,
|
|
13297
14193
|
canonicalPath: claimedPath
|
|
@@ -13302,7 +14198,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13302
14198
|
});
|
|
13303
14199
|
} catch (renameErr) {
|
|
13304
14200
|
actualPath = escapedVariant;
|
|
13305
|
-
logger$
|
|
14201
|
+
logger$27.warn({
|
|
13306
14202
|
storyKey,
|
|
13307
14203
|
escapedVariant,
|
|
13308
14204
|
canonicalPath: claimedPath,
|
|
@@ -13317,7 +14213,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13317
14213
|
if (actualPath === null) {
|
|
13318
14214
|
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
13319
14215
|
const errMsg = `create-story claimed success (story_file: ${createResult.story_file}) but the file does not exist on disk (output tokens: ${outputTokens})`;
|
|
13320
|
-
logger$
|
|
14216
|
+
logger$27.error({
|
|
13321
14217
|
storyKey,
|
|
13322
14218
|
claimedPath: createResult.story_file,
|
|
13323
14219
|
outputTokens
|
|
@@ -13344,7 +14240,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13344
14240
|
const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
|
|
13345
14241
|
const dispatchStartISO = new Date(dispatchStartMs).toISOString();
|
|
13346
14242
|
const errMsg = `create-story claimed success but did not rewrite ${actualPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
|
|
13347
|
-
logger$
|
|
14243
|
+
logger$27.error({
|
|
13348
14244
|
storyKey,
|
|
13349
14245
|
claimedPath: actualPath,
|
|
13350
14246
|
mtimeISO,
|
|
@@ -13367,7 +14263,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13367
14263
|
return;
|
|
13368
14264
|
}
|
|
13369
14265
|
} catch (verifyErr) {
|
|
13370
|
-
logger$
|
|
14266
|
+
logger$27.warn({
|
|
13371
14267
|
storyKey,
|
|
13372
14268
|
err: verifyErr
|
|
13373
14269
|
}, "create-story post-dispatch file verification threw; proceeding with claimed path");
|
|
@@ -13390,7 +14286,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13390
14286
|
const overlap = computeTitleOverlap(expectedTitle, createResult.story_title);
|
|
13391
14287
|
if (overlap < TITLE_OVERLAP_WARNING_THRESHOLD) {
|
|
13392
14288
|
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.`;
|
|
13393
|
-
logger$
|
|
14289
|
+
logger$27.warn({
|
|
13394
14290
|
storyKey,
|
|
13395
14291
|
expectedTitle,
|
|
13396
14292
|
generatedTitle: createResult.story_title,
|
|
@@ -13400,7 +14296,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13400
14296
|
storyKey,
|
|
13401
14297
|
msg
|
|
13402
14298
|
});
|
|
13403
|
-
} else logger$
|
|
14299
|
+
} else logger$27.debug({
|
|
13404
14300
|
storyKey,
|
|
13405
14301
|
expectedTitle,
|
|
13406
14302
|
generatedTitle: createResult.story_title,
|
|
@@ -13409,7 +14305,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13409
14305
|
}
|
|
13410
14306
|
}
|
|
13411
14307
|
} catch (titleValidationErr) {
|
|
13412
|
-
logger$
|
|
14308
|
+
logger$27.debug({
|
|
13413
14309
|
storyKey,
|
|
13414
14310
|
err: titleValidationErr
|
|
13415
14311
|
}, "Story title validation skipped due to error");
|
|
@@ -13432,7 +14328,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13432
14328
|
await persistState();
|
|
13433
14329
|
return;
|
|
13434
14330
|
}
|
|
13435
|
-
if (storyFilePath !== void 0 &&
|
|
14331
|
+
if (storyFilePath !== void 0 && effectiveProjectRoot !== void 0) try {
|
|
13436
14332
|
const epicId = storyKey.split("-")[0] ?? storyKey;
|
|
13437
14333
|
const fidelityImplDecisions = await getDecisionsByPhase(db, "implementation");
|
|
13438
14334
|
let fidelitySourceContent;
|
|
@@ -13450,7 +14346,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13450
14346
|
const pathDrift = pathFidelity?.drift ?? 0;
|
|
13451
14347
|
const clauseDrift = clauseFidelity.drift;
|
|
13452
14348
|
const overallDrift = Math.max(pathDrift, clauseDrift);
|
|
13453
|
-
logger$
|
|
14349
|
+
logger$27.debug({
|
|
13454
14350
|
storyKey,
|
|
13455
14351
|
pathDrift,
|
|
13456
14352
|
clauseDrift,
|
|
@@ -13472,7 +14368,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13472
14368
|
if (pathMissing.length > 0) reasons.push(`${pathMissing.length} named path(s) missing`);
|
|
13473
14369
|
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})`);
|
|
13474
14370
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall (rendered ${clauseFidelity.renderedClauseCount}/${clauseFidelity.sourceClauseCount} = ${Math.round(clauseFidelity.clauseRatio * 100)}%)`);
|
|
13475
|
-
logger$
|
|
14371
|
+
logger$27.warn({
|
|
13476
14372
|
storyKey,
|
|
13477
14373
|
pathDrift,
|
|
13478
14374
|
clauseDrift,
|
|
@@ -13515,7 +14411,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13515
14411
|
storyFilePath = void 0;
|
|
13516
14412
|
continue;
|
|
13517
14413
|
} catch (renameErr) {
|
|
13518
|
-
logger$
|
|
14414
|
+
logger$27.warn({
|
|
13519
14415
|
storyKey,
|
|
13520
14416
|
err: renameErr,
|
|
13521
14417
|
stalePath
|
|
@@ -13529,7 +14425,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13529
14425
|
if (numericMismatches.length > 0) reasons.push(`numeric mismatches: ${numericMismatches.map((m) => `${m.noun} (source=${m.sourceCount}, rendered=${m.renderedCount})`).join("; ")}`);
|
|
13530
14426
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall: source=${clauseFidelity.sourceClauseCount}, rendered=${clauseFidelity.renderedClauseCount}`);
|
|
13531
14427
|
const errMsg = `create-story output drifted from source AC after ${MAX_FIDELITY_RETRIES} retries; ` + reasons.join("; ");
|
|
13532
|
-
logger$
|
|
14428
|
+
logger$27.error({
|
|
13533
14429
|
storyKey,
|
|
13534
14430
|
pathDrift,
|
|
13535
14431
|
clauseDrift,
|
|
@@ -13556,7 +14452,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13556
14452
|
}
|
|
13557
14453
|
}
|
|
13558
14454
|
} catch (fidelityErr) {
|
|
13559
|
-
logger$
|
|
14455
|
+
logger$27.warn({
|
|
13560
14456
|
storyKey,
|
|
13561
14457
|
err: fidelityErr
|
|
13562
14458
|
}, "fidelity gate threw; proceeding without retry");
|
|
@@ -13587,21 +14483,21 @@ function createImplementationOrchestrator(deps) {
|
|
|
13587
14483
|
...contract.transport !== void 0 ? { transport: contract.transport } : {}
|
|
13588
14484
|
})
|
|
13589
14485
|
});
|
|
13590
|
-
logger$
|
|
14486
|
+
logger$27.info({
|
|
13591
14487
|
storyKey,
|
|
13592
14488
|
contractCount: contracts.length,
|
|
13593
14489
|
contracts
|
|
13594
14490
|
}, "Stored interface contract declarations");
|
|
13595
14491
|
}
|
|
13596
14492
|
} catch (err) {
|
|
13597
|
-
logger$
|
|
14493
|
+
logger$27.warn({
|
|
13598
14494
|
storyKey,
|
|
13599
14495
|
error: err instanceof Error ? err.message : String(err)
|
|
13600
14496
|
}, "Failed to parse interface contracts — continuing without contract declarations");
|
|
13601
14497
|
}
|
|
13602
14498
|
if (storyFilePath && _probeAuthorEffectiveMode === "enabled") try {
|
|
13603
14499
|
let probeAuthorEpicContent = "";
|
|
13604
|
-
const probeAuthorEpicsPath = findEpicFileForStory(
|
|
14500
|
+
const probeAuthorEpicsPath = findEpicFileForStory(effectiveProjectRoot ?? process.cwd(), storyKey);
|
|
13605
14501
|
if (probeAuthorEpicsPath) try {
|
|
13606
14502
|
const epicFull = readFileSync(probeAuthorEpicsPath, "utf-8");
|
|
13607
14503
|
const section = extractStorySection(epicFull, storyKey);
|
|
@@ -13612,7 +14508,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13612
14508
|
const isStateIntegrating = stateIntegratingEnabled && detectsStateIntegratingAC(probeAuthorEpicContent);
|
|
13613
14509
|
if (isEventDriven || isStateIntegrating) {
|
|
13614
14510
|
const triggerClass = isEventDriven && isStateIntegrating ? "both" : isStateIntegrating ? "state-integrating" : "event-driven";
|
|
13615
|
-
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { probe_author_triggered_by: triggerClass }).catch((err) => logger$
|
|
14511
|
+
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { probe_author_triggered_by: triggerClass }).catch((err) => logger$27.warn({
|
|
13616
14512
|
err,
|
|
13617
14513
|
storyKey
|
|
13618
14514
|
}, "patchStoryState(probe_author_triggered_by) failed — pipeline continues"));
|
|
@@ -13627,7 +14523,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13627
14523
|
pack,
|
|
13628
14524
|
contextCompiler,
|
|
13629
14525
|
dispatcher,
|
|
13630
|
-
projectRoot,
|
|
14526
|
+
projectRoot: effectiveProjectRoot,
|
|
13631
14527
|
tokenCeilings,
|
|
13632
14528
|
otlpEndpoint: _otlpEndpoint,
|
|
13633
14529
|
agentId
|
|
@@ -13646,7 +14542,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13646
14542
|
});
|
|
13647
14543
|
}
|
|
13648
14544
|
});
|
|
13649
|
-
logger$
|
|
14545
|
+
logger$27.info({
|
|
13650
14546
|
storyKey,
|
|
13651
14547
|
result: probeAuthorResult.result,
|
|
13652
14548
|
probesAuthoredCount: probeAuthorResult.probesAuthoredCount
|
|
@@ -13658,14 +14554,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
13658
14554
|
output_tokens: probeAuthorResult.tokenUsage.output,
|
|
13659
14555
|
cost_usd: estimateDispatchCost(probeAuthorResult.tokenUsage.input, probeAuthorResult.tokenUsage.output),
|
|
13660
14556
|
metadata: JSON.stringify({ storyKey })
|
|
13661
|
-
})).catch((tokenErr) => logger$
|
|
14557
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
13662
14558
|
storyKey,
|
|
13663
14559
|
err: tokenErr
|
|
13664
14560
|
}, "Failed to record probe-author token usage"));
|
|
13665
|
-
} else logger$
|
|
13666
|
-
} else logger$
|
|
14561
|
+
} else logger$27.debug({ storyKey }, "probe-author: story artifact already has ## Runtime Probes — skipping gate");
|
|
14562
|
+
} else logger$27.debug({ storyKey }, "probe-author: source AC not event-driven — skipping gate");
|
|
13667
14563
|
} catch (probeAuthorErr) {
|
|
13668
|
-
logger$
|
|
14564
|
+
logger$27.warn({
|
|
13669
14565
|
storyKey,
|
|
13670
14566
|
err: probeAuthorErr
|
|
13671
14567
|
}, "probe-author gate threw unexpectedly; proceeding to test-plan without authored probes");
|
|
@@ -13683,7 +14579,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13683
14579
|
pack,
|
|
13684
14580
|
contextCompiler,
|
|
13685
14581
|
dispatcher,
|
|
13686
|
-
projectRoot,
|
|
14582
|
+
projectRoot: effectiveProjectRoot,
|
|
13687
14583
|
tokenCeilings,
|
|
13688
14584
|
otlpEndpoint: _otlpEndpoint,
|
|
13689
14585
|
agentId
|
|
@@ -13694,10 +14590,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
13694
14590
|
});
|
|
13695
14591
|
testPlanPhaseResult = testPlanResult.result;
|
|
13696
14592
|
testPlanTokenUsage = testPlanResult.tokenUsage;
|
|
13697
|
-
if (testPlanResult.result === "success") logger$
|
|
13698
|
-
else logger$
|
|
14593
|
+
if (testPlanResult.result === "success") logger$27.info({ storyKey }, "Test plan generated successfully");
|
|
14594
|
+
else logger$27.warn({ storyKey }, "Test planning returned failed result — proceeding to dev-story without test plan");
|
|
13699
14595
|
} catch (err) {
|
|
13700
|
-
logger$
|
|
14596
|
+
logger$27.warn({
|
|
13701
14597
|
storyKey,
|
|
13702
14598
|
err
|
|
13703
14599
|
}, "Test planning failed — proceeding to dev-story without test plan");
|
|
@@ -13710,7 +14606,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13710
14606
|
output_tokens: testPlanTokenUsage.output,
|
|
13711
14607
|
cost_usd: estimateDispatchCost(testPlanTokenUsage.input, testPlanTokenUsage.output),
|
|
13712
14608
|
metadata: JSON.stringify({ storyKey })
|
|
13713
|
-
})).catch((tokenErr) => logger$
|
|
14609
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
13714
14610
|
storyKey,
|
|
13715
14611
|
err: tokenErr
|
|
13716
14612
|
}, "Failed to record test-plan token usage"));
|
|
@@ -13762,7 +14658,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13762
14658
|
let baselineHeadSha;
|
|
13763
14659
|
try {
|
|
13764
14660
|
baselineHeadSha = execSync("git rev-parse HEAD", {
|
|
13765
|
-
cwd:
|
|
14661
|
+
cwd: effectiveProjectRoot ?? process.cwd(),
|
|
13766
14662
|
encoding: "utf-8",
|
|
13767
14663
|
timeout: 3e3,
|
|
13768
14664
|
stdio: [
|
|
@@ -13778,7 +14674,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13778
14674
|
storyContentForAnalysis = await readFile$1(storyFilePath ?? "", "utf-8");
|
|
13779
14675
|
storyContentForVerification = storyContentForAnalysis;
|
|
13780
14676
|
} catch (err) {
|
|
13781
|
-
logger$
|
|
14677
|
+
logger$27.error({
|
|
13782
14678
|
storyKey,
|
|
13783
14679
|
storyFilePath,
|
|
13784
14680
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -13786,7 +14682,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13786
14682
|
}
|
|
13787
14683
|
const analysis = analyzeStoryComplexity(storyContentForAnalysis);
|
|
13788
14684
|
const batches = planTaskBatches(analysis);
|
|
13789
|
-
logger$
|
|
14685
|
+
logger$27.info({
|
|
13790
14686
|
storyKey,
|
|
13791
14687
|
estimatedScope: analysis.estimatedScope,
|
|
13792
14688
|
batchCount: batches.length,
|
|
@@ -13804,7 +14700,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13804
14700
|
if (_state !== "RUNNING") break;
|
|
13805
14701
|
const taskScope = batch.taskIds.map((id, i) => `T${id}: ${batch.taskTitles[i] ?? ""}`).join("\n");
|
|
13806
14702
|
const priorFiles = allFilesModified.size > 0 ? Array.from(allFilesModified) : void 0;
|
|
13807
|
-
logger$
|
|
14703
|
+
logger$27.info({
|
|
13808
14704
|
storyKey,
|
|
13809
14705
|
batchIndex: batch.batchIndex,
|
|
13810
14706
|
taskCount: batch.taskIds.length
|
|
@@ -13818,7 +14714,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13818
14714
|
pack,
|
|
13819
14715
|
contextCompiler,
|
|
13820
14716
|
dispatcher,
|
|
13821
|
-
projectRoot,
|
|
14717
|
+
projectRoot: effectiveProjectRoot,
|
|
13822
14718
|
tokenCeilings,
|
|
13823
14719
|
otlpEndpoint: _otlpEndpoint,
|
|
13824
14720
|
repoMapInjector,
|
|
@@ -13835,7 +14731,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13835
14731
|
});
|
|
13836
14732
|
} catch (batchErr) {
|
|
13837
14733
|
const errMsg = batchErr instanceof Error ? batchErr.message : String(batchErr);
|
|
13838
|
-
logger$
|
|
14734
|
+
logger$27.warn({
|
|
13839
14735
|
storyKey,
|
|
13840
14736
|
batchIndex: batch.batchIndex,
|
|
13841
14737
|
error: errMsg
|
|
@@ -13856,7 +14752,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13856
14752
|
filesModified: batchFilesModified,
|
|
13857
14753
|
result: batchResult.result === "success" ? "success" : "failed"
|
|
13858
14754
|
};
|
|
13859
|
-
logger$
|
|
14755
|
+
logger$27.info(batchMetrics, "Batch dev-story metrics");
|
|
13860
14756
|
for (const f$1 of batchFilesModified) allFilesModified.add(f$1);
|
|
13861
14757
|
if (batchFilesModified.length > 0) batchFileGroups.push({
|
|
13862
14758
|
batchIndex: batch.batchIndex,
|
|
@@ -13875,13 +14771,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
13875
14771
|
durationMs: batchDurationMs,
|
|
13876
14772
|
result: batchMetrics.result
|
|
13877
14773
|
})
|
|
13878
|
-
})).catch((tokenErr) => logger$
|
|
14774
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
13879
14775
|
storyKey,
|
|
13880
14776
|
batchIndex: batch.batchIndex,
|
|
13881
14777
|
err: tokenErr
|
|
13882
14778
|
}, "Failed to record batch token usage"));
|
|
13883
14779
|
if (batchResult.tokenUsage?.output !== void 0) devOutputTokenCount = (devOutputTokenCount ?? 0) + batchResult.tokenUsage.output;
|
|
13884
|
-
if (batchResult.result === "failed") logger$
|
|
14780
|
+
if (batchResult.result === "failed") logger$27.warn({
|
|
13885
14781
|
storyKey,
|
|
13886
14782
|
batchIndex: batch.batchIndex,
|
|
13887
14783
|
error: batchResult.error
|
|
@@ -13902,7 +14798,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13902
14798
|
pack,
|
|
13903
14799
|
contextCompiler,
|
|
13904
14800
|
dispatcher,
|
|
13905
|
-
projectRoot,
|
|
14801
|
+
projectRoot: effectiveProjectRoot,
|
|
13906
14802
|
tokenCeilings,
|
|
13907
14803
|
otlpEndpoint: _otlpEndpoint,
|
|
13908
14804
|
repoMapInjector,
|
|
@@ -13924,7 +14820,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13924
14820
|
output_tokens: devResult.tokenUsage.output,
|
|
13925
14821
|
cost_usd: estimateDispatchCost(devResult.tokenUsage.input, devResult.tokenUsage.output),
|
|
13926
14822
|
metadata: JSON.stringify({ storyKey })
|
|
13927
|
-
})).catch((tokenErr) => logger$
|
|
14823
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
13928
14824
|
storyKey,
|
|
13929
14825
|
err: tokenErr
|
|
13930
14826
|
}, "Failed to record dev-story token usage"));
|
|
@@ -13937,9 +14833,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
13937
14833
|
let checkpointHandled = false;
|
|
13938
14834
|
if (devResult.result === "failed" && devResult.error?.startsWith("dispatch_timeout")) {
|
|
13939
14835
|
endPhase(storyKey, "dev-story");
|
|
13940
|
-
const timeoutFiles = checkGitDiffFiles(
|
|
14836
|
+
const timeoutFiles = checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
13941
14837
|
if (timeoutFiles.length === 0) {
|
|
13942
|
-
logger$
|
|
14838
|
+
logger$27.warn({ storyKey }, "Dev-story timeout with zero modified files — escalating immediately (no checkpoint)");
|
|
13943
14839
|
updateStory(storyKey, {
|
|
13944
14840
|
phase: "ESCALATED",
|
|
13945
14841
|
error: "timeout-no-files",
|
|
@@ -13955,14 +14851,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
13955
14851
|
await persistState();
|
|
13956
14852
|
return;
|
|
13957
14853
|
}
|
|
13958
|
-
logger$
|
|
14854
|
+
logger$27.info({
|
|
13959
14855
|
storyKey,
|
|
13960
14856
|
filesCount: timeoutFiles.length
|
|
13961
14857
|
}, "Dev-story timeout with partial files — capturing checkpoint");
|
|
13962
14858
|
let gitDiff = "";
|
|
13963
14859
|
try {
|
|
13964
14860
|
gitDiff = execSync(`git diff HEAD -- ${timeoutFiles.map((f$1) => `"${f$1}"`).join(" ")}`, {
|
|
13965
|
-
cwd:
|
|
14861
|
+
cwd: effectiveProjectRoot ?? process.cwd(),
|
|
13966
14862
|
encoding: "utf-8",
|
|
13967
14863
|
timeout: 1e4,
|
|
13968
14864
|
stdio: [
|
|
@@ -13972,7 +14868,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13972
14868
|
]
|
|
13973
14869
|
}).trim();
|
|
13974
14870
|
} catch (diffErr) {
|
|
13975
|
-
logger$
|
|
14871
|
+
logger$27.warn({
|
|
13976
14872
|
storyKey,
|
|
13977
14873
|
error: diffErr instanceof Error ? diffErr.message : String(diffErr)
|
|
13978
14874
|
}, "Failed to capture git diff for checkpoint — proceeding with empty diff");
|
|
@@ -13999,7 +14895,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13999
14895
|
recordedAt: new Date().toISOString(),
|
|
14000
14896
|
sprint: config.sprint
|
|
14001
14897
|
}).catch((storeErr) => {
|
|
14002
|
-
logger$
|
|
14898
|
+
logger$27.warn({
|
|
14003
14899
|
err: storeErr,
|
|
14004
14900
|
storyKey
|
|
14005
14901
|
}, "Failed to record timeout metric to StateStore (best-effort)");
|
|
@@ -14058,9 +14954,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
14058
14954
|
checkpointRetryPrompt = assembled.prompt;
|
|
14059
14955
|
} catch {
|
|
14060
14956
|
checkpointRetryPrompt = `Continue story ${storyKey} from checkpoint. Your prior attempt timed out. Do not redo completed work.`;
|
|
14061
|
-
logger$
|
|
14957
|
+
logger$27.warn({ storyKey }, "Failed to assemble checkpoint retry prompt — using fallback");
|
|
14062
14958
|
}
|
|
14063
|
-
logger$
|
|
14959
|
+
logger$27.info({
|
|
14064
14960
|
storyKey,
|
|
14065
14961
|
filesCount: checkpointData.filesModified.length
|
|
14066
14962
|
}, "Dispatching checkpoint retry for timed-out story");
|
|
@@ -14073,7 +14969,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14073
14969
|
taskType: "dev-story",
|
|
14074
14970
|
outputSchema: DevStoryResultSchema,
|
|
14075
14971
|
...checkpointRetryMaxTurns !== void 0 ? { maxTurns: checkpointRetryMaxTurns } : {},
|
|
14076
|
-
...
|
|
14972
|
+
...effectiveProjectRoot !== void 0 ? { workingDirectory: effectiveProjectRoot } : {},
|
|
14077
14973
|
..._otlpEndpoint !== void 0 ? { otlpEndpoint: _otlpEndpoint } : {},
|
|
14078
14974
|
...config.perStoryContextCeilings?.[storyKey] !== void 0 ? { maxContextTokens: config.perStoryContextCeilings[storyKey] } : {},
|
|
14079
14975
|
storyKey
|
|
@@ -14089,7 +14985,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14089
14985
|
} : void 0 }
|
|
14090
14986
|
});
|
|
14091
14987
|
if (checkpointRetryResult.status === "timeout") {
|
|
14092
|
-
logger$
|
|
14988
|
+
logger$27.warn({ storyKey }, "Checkpoint retry dispatch timed out — escalating story");
|
|
14093
14989
|
updateStory(storyKey, {
|
|
14094
14990
|
phase: "ESCALATED",
|
|
14095
14991
|
error: "checkpoint-retry-timeout",
|
|
@@ -14107,9 +15003,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
14107
15003
|
}
|
|
14108
15004
|
const retryParsed = checkpointRetryResult.parsed;
|
|
14109
15005
|
replaceDevStorySignals(retryParsed);
|
|
14110
|
-
devFilesModified = retryParsed?.files_modified ?? checkGitDiffFiles(
|
|
15006
|
+
devFilesModified = retryParsed?.files_modified ?? checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
14111
15007
|
if (checkpointRetryResult.status === "completed" && retryParsed?.result === "success") devStoryWasSuccess = true;
|
|
14112
|
-
else logger$
|
|
15008
|
+
else logger$27.warn({
|
|
14113
15009
|
storyKey,
|
|
14114
15010
|
status: checkpointRetryResult.status
|
|
14115
15011
|
}, "Checkpoint retry completed with failure — proceeding to code review");
|
|
@@ -14119,13 +15015,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14119
15015
|
replaceDevStorySignals(devResult);
|
|
14120
15016
|
if (devResult.result === "success") devStoryWasSuccess = true;
|
|
14121
15017
|
else {
|
|
14122
|
-
logger$
|
|
15018
|
+
logger$27.warn({
|
|
14123
15019
|
storyKey,
|
|
14124
15020
|
error: devResult.error,
|
|
14125
15021
|
filesModified: devFilesModified.length
|
|
14126
15022
|
}, "Dev-story reported failure, proceeding to code review");
|
|
14127
15023
|
if (!devResult.error?.startsWith("dispatch_timeout")) {
|
|
14128
|
-
logger$
|
|
15024
|
+
logger$27.warn({
|
|
14129
15025
|
storyKey,
|
|
14130
15026
|
error: devResult.error
|
|
14131
15027
|
}, "Agent process failure (non-timeout) — story will proceed to code review with partial work");
|
|
@@ -14157,12 +15053,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14157
15053
|
}
|
|
14158
15054
|
let gitDiffFiles;
|
|
14159
15055
|
if (devStoryWasSuccess) {
|
|
14160
|
-
gitDiffFiles = checkGitDiffFiles(
|
|
15056
|
+
gitDiffFiles = checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
14161
15057
|
if (gitDiffFiles.length === 0) {
|
|
14162
15058
|
let hasNewCommits = false;
|
|
14163
15059
|
if (baselineHeadSha) try {
|
|
14164
15060
|
const currentHead = execSync("git rev-parse HEAD", {
|
|
14165
|
-
cwd:
|
|
15061
|
+
cwd: effectiveProjectRoot ?? process.cwd(),
|
|
14166
15062
|
encoding: "utf-8",
|
|
14167
15063
|
timeout: 3e3,
|
|
14168
15064
|
stdio: [
|
|
@@ -14176,7 +15072,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14176
15072
|
if (hasNewCommits && baselineHeadSha) {
|
|
14177
15073
|
try {
|
|
14178
15074
|
const committedFiles = execSync(`git diff --name-only ${baselineHeadSha}..HEAD`, {
|
|
14179
|
-
cwd:
|
|
15075
|
+
cwd: effectiveProjectRoot ?? process.cwd(),
|
|
14180
15076
|
encoding: "utf-8",
|
|
14181
15077
|
timeout: 5e3,
|
|
14182
15078
|
stdio: [
|
|
@@ -14187,13 +15083,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14187
15083
|
}).trim();
|
|
14188
15084
|
if (committedFiles.length > 0) gitDiffFiles = committedFiles.split("\n").filter(Boolean);
|
|
14189
15085
|
} catch {}
|
|
14190
|
-
logger$
|
|
15086
|
+
logger$27.info({
|
|
14191
15087
|
storyKey,
|
|
14192
15088
|
baselineHeadSha,
|
|
14193
15089
|
committedFileCount: gitDiffFiles?.length ?? 0
|
|
14194
15090
|
}, "Working tree clean but new commits detected since dispatch — skipping zero-diff escalation");
|
|
14195
15091
|
} else {
|
|
14196
|
-
logger$
|
|
15092
|
+
logger$27.warn({ storyKey }, "Zero-diff detected after COMPLETE dev-story — no file changes and no new commits");
|
|
14197
15093
|
eventBus.emit("orchestrator:zero-diff-escalation", {
|
|
14198
15094
|
storyKey,
|
|
14199
15095
|
reason: "zero-diff-on-complete"
|
|
@@ -14222,11 +15118,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
14222
15118
|
let buildVerifyResult = config.skipBuildVerify === true ? { status: "skipped" } : runBuildVerification({
|
|
14223
15119
|
verifyCommand: pack.manifest.verifyCommand,
|
|
14224
15120
|
verifyTimeoutMs: pack.manifest.verifyTimeoutMs,
|
|
14225
|
-
projectRoot:
|
|
15121
|
+
projectRoot: effectiveProjectRoot ?? process.cwd(),
|
|
14226
15122
|
changedFiles: gitDiffFiles
|
|
14227
15123
|
});
|
|
14228
15124
|
if (buildVerifyResult.status === "passed") {
|
|
14229
|
-
const resolvedRootForTsc =
|
|
15125
|
+
const resolvedRootForTsc = effectiveProjectRoot ?? process.cwd();
|
|
14230
15126
|
const tscBin = join$1(resolvedRootForTsc, "node_modules", ".bin", "tsc");
|
|
14231
15127
|
const typecheckConfig = join$1(resolvedRootForTsc, "tsconfig.typecheck.json");
|
|
14232
15128
|
const defaultConfig = join$1(resolvedRootForTsc, "tsconfig.json");
|
|
@@ -14243,10 +15139,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
14243
15139
|
"pipe"
|
|
14244
15140
|
]
|
|
14245
15141
|
});
|
|
14246
|
-
logger$
|
|
15142
|
+
logger$27.info({ storyKey }, "Secondary typecheck (tsc --noEmit) passed");
|
|
14247
15143
|
} catch (tscErr) {
|
|
14248
15144
|
const tscOutput = tscErr instanceof Error && "stdout" in tscErr ? String(tscErr.stdout ?? "").slice(0, 2e3) : "";
|
|
14249
|
-
logger$
|
|
15145
|
+
logger$27.warn({
|
|
14250
15146
|
storyKey,
|
|
14251
15147
|
tscOutput
|
|
14252
15148
|
}, "Secondary typecheck (tsc --noEmit) failed — treating as build failure");
|
|
@@ -14261,16 +15157,16 @@ function createImplementationOrchestrator(deps) {
|
|
|
14261
15157
|
if (buildVerifyResult.status === "passed") {
|
|
14262
15158
|
_buildPassed = true;
|
|
14263
15159
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
14264
|
-
logger$
|
|
15160
|
+
logger$27.info({ storyKey }, "Build verification passed");
|
|
14265
15161
|
} else if (buildVerifyResult.status === "failed" || buildVerifyResult.status === "timeout") {
|
|
14266
15162
|
const truncatedOutput = (buildVerifyResult.output ?? "").slice(0, 2e3);
|
|
14267
15163
|
const reason = buildVerifyResult.reason ?? "build-verification-failed";
|
|
14268
15164
|
let retryPassed = false;
|
|
14269
15165
|
if (_packageSnapshot !== void 0 && buildVerifyResult.status !== "timeout") {
|
|
14270
|
-
const resolvedRoot =
|
|
15166
|
+
const resolvedRoot = effectiveProjectRoot ?? process.cwd();
|
|
14271
15167
|
const hasChanges = detectPackageChanges(_packageSnapshot, resolvedRoot);
|
|
14272
15168
|
if (hasChanges) {
|
|
14273
|
-
logger$
|
|
15169
|
+
logger$27.warn({ storyKey }, "Package files changed since snapshot — restoring to prevent cascade");
|
|
14274
15170
|
const restoreResult = restorePackageSnapshot(_packageSnapshot, { projectRoot: resolvedRoot });
|
|
14275
15171
|
if (restoreResult.restored) {
|
|
14276
15172
|
const retryAfterRestore = runBuildVerification({
|
|
@@ -14283,11 +15179,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
14283
15179
|
retryPassed = true;
|
|
14284
15180
|
_buildPassed = true;
|
|
14285
15181
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
14286
|
-
logger$
|
|
15182
|
+
logger$27.warn({
|
|
14287
15183
|
storyKey,
|
|
14288
15184
|
filesRestored: restoreResult.filesRestored
|
|
14289
15185
|
}, "Build passed after package snapshot restore — cross-story pollution detected and cleaned");
|
|
14290
|
-
} else logger$
|
|
15186
|
+
} else logger$27.warn({
|
|
14291
15187
|
storyKey,
|
|
14292
15188
|
filesRestored: restoreResult.filesRestored
|
|
14293
15189
|
}, "Build still fails after snapshot restore — story has its own build errors");
|
|
@@ -14298,8 +15194,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
14298
15194
|
const missingPkgMatch = fullOutput.match(/Cannot find (?:module|package) ['"]([^'"]+)['"]/) ?? fullOutput.match(/ERR_MODULE_NOT_FOUND[^]*?['"]([^'"]+)['"]/);
|
|
14299
15195
|
if (missingPkgMatch && buildVerifyResult.status !== "timeout") {
|
|
14300
15196
|
const missingPkg = missingPkgMatch[1].replace(/^(@[^/]+\/[^/]+)\/.*$/, "$1").replace(/^([^@][^/]*)\/.*$/, "$1");
|
|
14301
|
-
const resolvedRoot =
|
|
14302
|
-
logger$
|
|
15197
|
+
const resolvedRoot = effectiveProjectRoot ?? process.cwd();
|
|
15198
|
+
logger$27.warn({
|
|
14303
15199
|
storyKey,
|
|
14304
15200
|
missingPkg
|
|
14305
15201
|
}, "Build-fix retry: detected missing npm package — attempting npm install");
|
|
@@ -14310,7 +15206,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14310
15206
|
encoding: "utf-8",
|
|
14311
15207
|
stdio: "pipe"
|
|
14312
15208
|
});
|
|
14313
|
-
logger$
|
|
15209
|
+
logger$27.warn({
|
|
14314
15210
|
storyKey,
|
|
14315
15211
|
missingPkg
|
|
14316
15212
|
}, "Build-fix retry: npm install succeeded — retrying build verification");
|
|
@@ -14324,18 +15220,18 @@ function createImplementationOrchestrator(deps) {
|
|
|
14324
15220
|
retryPassed = true;
|
|
14325
15221
|
_buildPassed = true;
|
|
14326
15222
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
14327
|
-
logger$
|
|
15223
|
+
logger$27.warn({
|
|
14328
15224
|
storyKey,
|
|
14329
15225
|
missingPkg
|
|
14330
15226
|
}, "Build-fix retry: build verification passed after installing missing package");
|
|
14331
|
-
} else logger$
|
|
15227
|
+
} else logger$27.warn({
|
|
14332
15228
|
storyKey,
|
|
14333
15229
|
missingPkg,
|
|
14334
15230
|
retryStatus: retryResult.status
|
|
14335
15231
|
}, "Build-fix retry: build still fails after installing missing package — escalating");
|
|
14336
15232
|
} catch (installErr) {
|
|
14337
15233
|
const installMsg = installErr instanceof Error ? installErr.message : String(installErr);
|
|
14338
|
-
logger$
|
|
15234
|
+
logger$27.warn({
|
|
14339
15235
|
storyKey,
|
|
14340
15236
|
missingPkg,
|
|
14341
15237
|
error: installMsg
|
|
@@ -14345,7 +15241,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14345
15241
|
if (!retryPassed) {
|
|
14346
15242
|
let buildFixPassed = false;
|
|
14347
15243
|
if (buildVerifyResult.status === "failed" && storyFilePath !== void 0) try {
|
|
14348
|
-
logger$
|
|
15244
|
+
logger$27.info({ storyKey }, "Dispatching build-fix agent");
|
|
14349
15245
|
startPhase(storyKey, "build-fix");
|
|
14350
15246
|
const storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
14351
15247
|
let buildFixTemplate;
|
|
@@ -14366,7 +15262,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14366
15262
|
agent: deps.agentId ?? "claude-code",
|
|
14367
15263
|
taskType: "build-fix",
|
|
14368
15264
|
maxTurns: 15,
|
|
14369
|
-
workingDirectory:
|
|
15265
|
+
workingDirectory: effectiveProjectRoot ?? process.cwd(),
|
|
14370
15266
|
...config.perStoryContextCeilings?.[storyKey] !== void 0 ? { maxContextTokens: config.perStoryContextCeilings[storyKey] } : {},
|
|
14371
15267
|
..._otlpEndpoint !== void 0 ? { otlpEndpoint: _otlpEndpoint } : {}
|
|
14372
15268
|
});
|
|
@@ -14375,18 +15271,18 @@ function createImplementationOrchestrator(deps) {
|
|
|
14375
15271
|
const retryAfterFix = runBuildVerification({
|
|
14376
15272
|
verifyCommand: pack.manifest.verifyCommand,
|
|
14377
15273
|
verifyTimeoutMs: pack.manifest.verifyTimeoutMs,
|
|
14378
|
-
projectRoot:
|
|
15274
|
+
projectRoot: effectiveProjectRoot ?? process.cwd(),
|
|
14379
15275
|
changedFiles: gitDiffFiles
|
|
14380
15276
|
});
|
|
14381
15277
|
if (retryAfterFix.status === "passed") {
|
|
14382
15278
|
buildFixPassed = true;
|
|
14383
15279
|
_buildPassed = true;
|
|
14384
15280
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
14385
|
-
logger$
|
|
14386
|
-
} else logger$
|
|
15281
|
+
logger$27.info({ storyKey }, "Build passed after build-fix dispatch");
|
|
15282
|
+
} else logger$27.warn({ storyKey }, "Build still fails after build-fix dispatch — escalating");
|
|
14387
15283
|
} catch (fixErr) {
|
|
14388
15284
|
const fixMsg = fixErr instanceof Error ? fixErr.message : String(fixErr);
|
|
14389
|
-
logger$
|
|
15285
|
+
logger$27.warn({
|
|
14390
15286
|
storyKey,
|
|
14391
15287
|
error: fixMsg
|
|
14392
15288
|
}, "Build-fix dispatch failed — escalating");
|
|
@@ -14423,7 +15319,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14423
15319
|
eventBus.emit("decision:halt-skipped-non-interactive", payload);
|
|
14424
15320
|
}
|
|
14425
15321
|
}).catch((err) => {
|
|
14426
|
-
logger$
|
|
15322
|
+
logger$27.warn({
|
|
14427
15323
|
err,
|
|
14428
15324
|
storyKey
|
|
14429
15325
|
}, "interactive prompt failed — continuing with default action");
|
|
@@ -14440,7 +15336,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14440
15336
|
exitCode: buildVerifyResult.exitCode ?? 1,
|
|
14441
15337
|
output: truncatedOutput
|
|
14442
15338
|
});
|
|
14443
|
-
logger$
|
|
15339
|
+
logger$27.warn({
|
|
14444
15340
|
storyKey,
|
|
14445
15341
|
reason,
|
|
14446
15342
|
exitCode: buildVerifyResult.exitCode,
|
|
@@ -14470,11 +15366,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
14470
15366
|
if (filesModified.length > 0) {
|
|
14471
15367
|
const icResult = detectInterfaceChanges({
|
|
14472
15368
|
filesModified,
|
|
14473
|
-
projectRoot:
|
|
15369
|
+
projectRoot: effectiveProjectRoot ?? process.cwd(),
|
|
14474
15370
|
storyKey
|
|
14475
15371
|
});
|
|
14476
15372
|
if (icResult.potentiallyAffectedTests.length > 0) {
|
|
14477
|
-
logger$
|
|
15373
|
+
logger$27.warn({
|
|
14478
15374
|
storyKey,
|
|
14479
15375
|
modifiedInterfaces: icResult.modifiedInterfaces,
|
|
14480
15376
|
potentiallyAffectedTests: icResult.potentiallyAffectedTests
|
|
@@ -14514,7 +15410,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14514
15410
|
rawOutput: reviewResult.rawOutput
|
|
14515
15411
|
} : void 0;
|
|
14516
15412
|
let sourceEpicContent;
|
|
14517
|
-
const epicsPath = findEpicFileForStory(
|
|
15413
|
+
const epicsPath = findEpicFileForStory(effectiveProjectRoot ?? process.cwd(), storyKey);
|
|
14518
15414
|
if (epicsPath) try {
|
|
14519
15415
|
const epicFull = readFileSync(epicsPath, "utf-8");
|
|
14520
15416
|
const section = extractStorySection(epicFull, storyKey);
|
|
@@ -14523,7 +15419,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14523
15419
|
await persistDevStorySignals(storyKey, devStorySignals, runManifest);
|
|
14524
15420
|
const verifContext = assembleVerificationContext({
|
|
14525
15421
|
storyKey,
|
|
14526
|
-
workingDir:
|
|
15422
|
+
workingDir: effectiveProjectRoot ?? process.cwd(),
|
|
14527
15423
|
reviewResult: latestReviewSignals,
|
|
14528
15424
|
storyContent: storyContentForVerification,
|
|
14529
15425
|
devStoryResult: devStorySignals,
|
|
@@ -14557,20 +15453,20 @@ function createImplementationOrchestrator(deps) {
|
|
|
14557
15453
|
adapter: db,
|
|
14558
15454
|
engine: "linear"
|
|
14559
15455
|
}).catch((recoveryErr) => {
|
|
14560
|
-
logger$
|
|
15456
|
+
logger$27.warn({
|
|
14561
15457
|
storyKey,
|
|
14562
15458
|
err: recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr)
|
|
14563
15459
|
}, "Recovery Engine invocation failed — falling through to VERIFICATION_FAILED (best-effort)");
|
|
14564
15460
|
return null;
|
|
14565
15461
|
});
|
|
14566
15462
|
if (recoveryResult?.action === "halt-entire-run") {
|
|
14567
|
-
logger$
|
|
15463
|
+
logger$27.error({
|
|
14568
15464
|
storyKey,
|
|
14569
15465
|
pendingProposalsCount: recoveryResult.pendingProposalsCount
|
|
14570
15466
|
}, "Recovery Engine safety valve: halting entire run due to >= 5 pending proposals");
|
|
14571
15467
|
_budgetExhausted = true;
|
|
14572
15468
|
} else if (recoveryResult?.action === "retry") {
|
|
14573
|
-
logger$
|
|
15469
|
+
logger$27.info({
|
|
14574
15470
|
storyKey,
|
|
14575
15471
|
attempt: recoveryResult.attempt,
|
|
14576
15472
|
retryBudgetRemaining: recoveryResult.retryBudgetRemaining
|
|
@@ -14582,7 +15478,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14582
15478
|
pack,
|
|
14583
15479
|
contextCompiler,
|
|
14584
15480
|
dispatcher,
|
|
14585
|
-
projectRoot,
|
|
15481
|
+
projectRoot: effectiveProjectRoot,
|
|
14586
15482
|
tokenCeilings,
|
|
14587
15483
|
otlpEndpoint: _otlpEndpoint,
|
|
14588
15484
|
repoMapInjector,
|
|
@@ -14598,7 +15494,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14598
15494
|
await persistDevStorySignals(storyKey, devStorySignals, runManifest);
|
|
14599
15495
|
const retryVerifContext = assembleVerificationContext({
|
|
14600
15496
|
storyKey,
|
|
14601
|
-
workingDir:
|
|
15497
|
+
workingDir: effectiveProjectRoot ?? process.cwd(),
|
|
14602
15498
|
reviewResult: latestReviewSignals,
|
|
14603
15499
|
storyContent: storyContentForVerification,
|
|
14604
15500
|
devStoryResult: devStorySignals,
|
|
@@ -14610,23 +15506,23 @@ function createImplementationOrchestrator(deps) {
|
|
|
14610
15506
|
verificationStore.set(storyKey, retryVerifSummary);
|
|
14611
15507
|
await persistVerificationResult(storyKey, retryVerifSummary, runManifest);
|
|
14612
15508
|
if (retryVerifSummary.status !== "fail") {
|
|
14613
|
-
logger$
|
|
15509
|
+
logger$27.info({ storyKey }, "Recovery Engine Tier A retry succeeded — story proceeding to COMPLETE");
|
|
14614
15510
|
shouldFallThroughToComplete = true;
|
|
14615
|
-
} else logger$
|
|
15511
|
+
} else logger$27.warn({ storyKey }, "Recovery Engine Tier A retry still failed — falling through to VERIFICATION_FAILED");
|
|
14616
15512
|
} catch (retryErr) {
|
|
14617
|
-
logger$
|
|
15513
|
+
logger$27.warn({
|
|
14618
15514
|
storyKey,
|
|
14619
15515
|
err: retryErr instanceof Error ? retryErr.message : String(retryErr)
|
|
14620
15516
|
}, "Recovery Engine Tier A re-dispatch threw — falling through to VERIFICATION_FAILED");
|
|
14621
15517
|
}
|
|
14622
15518
|
} else if (recoveryResult?.action === "propose") {
|
|
14623
|
-
logger$
|
|
15519
|
+
logger$27.info({ storyKey }, "Recovery Engine Tier B: proposal appended — marking story ESCALATED for operator re-scope");
|
|
14624
15520
|
updateStory(storyKey, {
|
|
14625
15521
|
phase: "ESCALATED",
|
|
14626
15522
|
completedAt: new Date().toISOString(),
|
|
14627
15523
|
error: "recovery-engine-propose"
|
|
14628
15524
|
});
|
|
14629
|
-
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$
|
|
15525
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$27.warn({
|
|
14630
15526
|
err,
|
|
14631
15527
|
storyKey
|
|
14632
15528
|
}, "StateStore write failed after recovery-propose"));
|
|
@@ -14640,7 +15536,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14640
15536
|
await persistState();
|
|
14641
15537
|
return "verification-failed";
|
|
14642
15538
|
} else if (recoveryResult?.action === "halt") {
|
|
14643
|
-
logger$
|
|
15539
|
+
logger$27.warn({ storyKey }, "Recovery Engine Tier C: halt — invoking interactive prompt for operator decision");
|
|
14644
15540
|
const haltRunId = config.pipelineRunId ?? storyKey;
|
|
14645
15541
|
await runInteractivePrompt({
|
|
14646
15542
|
runId: haltRunId,
|
|
@@ -14657,7 +15553,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14657
15553
|
eventBus.emit("decision:halt-skipped-non-interactive", haltPayload);
|
|
14658
15554
|
}
|
|
14659
15555
|
}).catch((err) => {
|
|
14660
|
-
logger$
|
|
15556
|
+
logger$27.warn({
|
|
14661
15557
|
err,
|
|
14662
15558
|
storyKey
|
|
14663
15559
|
}, "Recovery Engine Tier C: interactive prompt failed — escalating anyway");
|
|
@@ -14667,7 +15563,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14667
15563
|
completedAt: new Date().toISOString(),
|
|
14668
15564
|
error: "recovery-engine-halt"
|
|
14669
15565
|
});
|
|
14670
|
-
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$
|
|
15566
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$27.warn({
|
|
14671
15567
|
err,
|
|
14672
15568
|
storyKey
|
|
14673
15569
|
}, "StateStore write failed after recovery-halt"));
|
|
@@ -14687,7 +15583,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14687
15583
|
phase: "VERIFICATION_FAILED",
|
|
14688
15584
|
completedAt: new Date().toISOString()
|
|
14689
15585
|
});
|
|
14690
|
-
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$
|
|
15586
|
+
persistStoryState(storyKey, _stories.get(storyKey)).catch((err) => logger$27.warn({
|
|
14691
15587
|
err,
|
|
14692
15588
|
storyKey
|
|
14693
15589
|
}, "StateStore write failed after verification-failed"));
|
|
@@ -14713,7 +15609,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14713
15609
|
if (autoApprove?.downgradeLastVerdict !== void 0) completeUpdate.lastVerdict = autoApprove.downgradeLastVerdict;
|
|
14714
15610
|
updateStory(storyKey, completeUpdate);
|
|
14715
15611
|
if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
|
|
14716
|
-
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$
|
|
15612
|
+
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$27.warn({
|
|
14717
15613
|
storyKey,
|
|
14718
15614
|
category: "verification-result-missing"
|
|
14719
15615
|
}, "post-COMPLETE invariant: verification_result absent in manifest");
|
|
@@ -14782,7 +15678,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14782
15678
|
"NEEDS_MAJOR_REWORK": 2
|
|
14783
15679
|
};
|
|
14784
15680
|
for (const group of batchFileGroups) {
|
|
14785
|
-
logger$
|
|
15681
|
+
logger$27.info({
|
|
14786
15682
|
storyKey,
|
|
14787
15683
|
batchIndex: group.batchIndex,
|
|
14788
15684
|
fileCount: group.files.length
|
|
@@ -14793,7 +15689,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14793
15689
|
pack,
|
|
14794
15690
|
contextCompiler,
|
|
14795
15691
|
dispatcher,
|
|
14796
|
-
projectRoot,
|
|
15692
|
+
projectRoot: effectiveProjectRoot,
|
|
14797
15693
|
tokenCeilings,
|
|
14798
15694
|
otlpEndpoint: _otlpEndpoint,
|
|
14799
15695
|
repoMapInjector,
|
|
@@ -14803,7 +15699,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14803
15699
|
}, {
|
|
14804
15700
|
storyKey,
|
|
14805
15701
|
storyFilePath: storyFilePath ?? "",
|
|
14806
|
-
workingDirectory:
|
|
15702
|
+
workingDirectory: effectiveProjectRoot,
|
|
14807
15703
|
pipelineRunId: config.pipelineRunId,
|
|
14808
15704
|
filesModified: group.files,
|
|
14809
15705
|
buildPassed: _buildPassed,
|
|
@@ -14827,7 +15723,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14827
15723
|
rawOutput: lastRawOutput,
|
|
14828
15724
|
tokenUsage: aggregateTokens
|
|
14829
15725
|
};
|
|
14830
|
-
logger$
|
|
15726
|
+
logger$27.info({
|
|
14831
15727
|
storyKey,
|
|
14832
15728
|
batchCount: batchFileGroups.length,
|
|
14833
15729
|
verdict: worstVerdict,
|
|
@@ -14840,7 +15736,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14840
15736
|
pack,
|
|
14841
15737
|
contextCompiler,
|
|
14842
15738
|
dispatcher,
|
|
14843
|
-
projectRoot,
|
|
15739
|
+
projectRoot: effectiveProjectRoot,
|
|
14844
15740
|
tokenCeilings,
|
|
14845
15741
|
otlpEndpoint: _otlpEndpoint,
|
|
14846
15742
|
repoMapInjector,
|
|
@@ -14850,7 +15746,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14850
15746
|
}, {
|
|
14851
15747
|
storyKey,
|
|
14852
15748
|
storyFilePath: storyFilePath ?? "",
|
|
14853
|
-
workingDirectory:
|
|
15749
|
+
workingDirectory: effectiveProjectRoot,
|
|
14854
15750
|
pipelineRunId: config.pipelineRunId,
|
|
14855
15751
|
filesModified: devFilesModified,
|
|
14856
15752
|
buildPassed: _buildPassed,
|
|
@@ -14870,7 +15766,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14870
15766
|
storyKey,
|
|
14871
15767
|
reviewCycle: reviewCycles
|
|
14872
15768
|
})
|
|
14873
|
-
})).catch((tokenErr) => logger$
|
|
15769
|
+
})).catch((tokenErr) => logger$27.warn({
|
|
14874
15770
|
storyKey,
|
|
14875
15771
|
err: tokenErr
|
|
14876
15772
|
}, "Failed to record code-review token usage"));
|
|
@@ -14888,7 +15784,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14888
15784
|
...reviewResult.details !== void 0 ? { details: reviewResult.details } : {}
|
|
14889
15785
|
});
|
|
14890
15786
|
if (schemaValidationRetries <= MAX_SCHEMA_VALIDATION_RETRIES) {
|
|
14891
|
-
logger$
|
|
15787
|
+
logger$27.warn({
|
|
14892
15788
|
storyKey,
|
|
14893
15789
|
reviewCycles,
|
|
14894
15790
|
attempt: schemaValidationRetries,
|
|
@@ -14897,7 +15793,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14897
15793
|
previousIterationWasMalformed = true;
|
|
14898
15794
|
continue;
|
|
14899
15795
|
}
|
|
14900
|
-
logger$
|
|
15796
|
+
logger$27.warn({
|
|
14901
15797
|
storyKey,
|
|
14902
15798
|
reviewCycles,
|
|
14903
15799
|
schemaValidationRetries
|
|
@@ -14920,7 +15816,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14920
15816
|
}
|
|
14921
15817
|
if (isPhantomReview && !timeoutRetried) {
|
|
14922
15818
|
timeoutRetried = true;
|
|
14923
|
-
logger$
|
|
15819
|
+
logger$27.warn({
|
|
14924
15820
|
storyKey,
|
|
14925
15821
|
reviewCycles,
|
|
14926
15822
|
error: reviewResult.error
|
|
@@ -14928,7 +15824,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14928
15824
|
continue;
|
|
14929
15825
|
}
|
|
14930
15826
|
if (isPhantomReview && timeoutRetried) {
|
|
14931
|
-
logger$
|
|
15827
|
+
logger$27.warn({
|
|
14932
15828
|
storyKey,
|
|
14933
15829
|
reviewCycles,
|
|
14934
15830
|
error: reviewResult.error
|
|
@@ -14952,7 +15848,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14952
15848
|
verdict = reviewResult.verdict;
|
|
14953
15849
|
issueList = reviewResult.issue_list ?? [];
|
|
14954
15850
|
if (verdict === "NEEDS_MAJOR_REWORK" && reviewCycles > 0 && previousIssueList.length > 0 && issueList.length < previousIssueList.length) {
|
|
14955
|
-
logger$
|
|
15851
|
+
logger$27.info({
|
|
14956
15852
|
storyKey,
|
|
14957
15853
|
originalVerdict: verdict,
|
|
14958
15854
|
issuesBefore: previousIssueList.length,
|
|
@@ -14988,7 +15884,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14988
15884
|
if (_decomposition !== void 0) parts.push(`decomposed: ${_decomposition.batchCount} batches`);
|
|
14989
15885
|
parts.push(`${fileCount} files`);
|
|
14990
15886
|
parts.push(`${totalTokensK} tokens`);
|
|
14991
|
-
logger$
|
|
15887
|
+
logger$27.info({
|
|
14992
15888
|
storyKey,
|
|
14993
15889
|
verdict,
|
|
14994
15890
|
agentVerdict: reviewResult.agentVerdict
|
|
@@ -15032,9 +15928,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
15032
15928
|
}),
|
|
15033
15929
|
rationale: `Advisory notes from LGTM_WITH_NOTES review of ${storyKey}`
|
|
15034
15930
|
});
|
|
15035
|
-
logger$
|
|
15931
|
+
logger$27.info({ storyKey }, "Advisory notes persisted to decision store");
|
|
15036
15932
|
} catch (advisoryErr) {
|
|
15037
|
-
logger$
|
|
15933
|
+
logger$27.warn({
|
|
15038
15934
|
storyKey,
|
|
15039
15935
|
error: advisoryErr instanceof Error ? advisoryErr.message : String(advisoryErr)
|
|
15040
15936
|
}, "Failed to persist advisory notes (best-effort)");
|
|
@@ -15042,27 +15938,27 @@ function createImplementationOrchestrator(deps) {
|
|
|
15042
15938
|
if (telemetryPersistence !== void 0) try {
|
|
15043
15939
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
15044
15940
|
if (turns.length > 0) {
|
|
15045
|
-
const scorer = new EfficiencyScorer(logger$
|
|
15941
|
+
const scorer = new EfficiencyScorer(logger$27);
|
|
15046
15942
|
const effScore = scorer.score(storyKey, turns);
|
|
15047
15943
|
await telemetryPersistence.storeEfficiencyScore(effScore);
|
|
15048
|
-
logger$
|
|
15944
|
+
logger$27.info({
|
|
15049
15945
|
storyKey,
|
|
15050
15946
|
compositeScore: effScore.compositeScore,
|
|
15051
15947
|
modelCount: effScore.perModelBreakdown.length
|
|
15052
15948
|
}, "Efficiency score computed and persisted");
|
|
15053
|
-
} else logger$
|
|
15949
|
+
} else logger$27.debug({ storyKey }, "No turn analysis data available — skipping efficiency scoring");
|
|
15054
15950
|
} catch (effErr) {
|
|
15055
|
-
logger$
|
|
15951
|
+
logger$27.warn({
|
|
15056
15952
|
storyKey,
|
|
15057
15953
|
error: effErr instanceof Error ? effErr.message : String(effErr)
|
|
15058
15954
|
}, "Efficiency scoring failed — story verdict unchanged");
|
|
15059
15955
|
}
|
|
15060
15956
|
if (telemetryPersistence !== void 0) try {
|
|
15061
15957
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
15062
|
-
if (turns.length === 0) logger$
|
|
15958
|
+
if (turns.length === 0) logger$27.debug({ storyKey }, "No turn analysis data for telemetry categorization — skipping");
|
|
15063
15959
|
else {
|
|
15064
|
-
const categorizer = new Categorizer(logger$
|
|
15065
|
-
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$
|
|
15960
|
+
const categorizer = new Categorizer(logger$27);
|
|
15961
|
+
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$27);
|
|
15066
15962
|
const categoryStats = categorizer.computeCategoryStatsFromTurns(turns);
|
|
15067
15963
|
const consumerStats = consumerAnalyzer.analyzeFromTurns(turns);
|
|
15068
15964
|
await telemetryPersistence.storeCategoryStats(storyKey, categoryStats);
|
|
@@ -15070,7 +15966,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15070
15966
|
const growingCount = categoryStats.filter((c) => c.trend === "growing").length;
|
|
15071
15967
|
const topCategory = categoryStats[0]?.category ?? "none";
|
|
15072
15968
|
const topConsumer = consumerStats[0]?.consumerKey ?? "none";
|
|
15073
|
-
logger$
|
|
15969
|
+
logger$27.info({
|
|
15074
15970
|
storyKey,
|
|
15075
15971
|
topCategory,
|
|
15076
15972
|
topConsumer,
|
|
@@ -15078,7 +15974,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15078
15974
|
}, "Semantic categorization and consumer analysis complete");
|
|
15079
15975
|
}
|
|
15080
15976
|
} catch (catErr) {
|
|
15081
|
-
logger$
|
|
15977
|
+
logger$27.warn({
|
|
15082
15978
|
storyKey,
|
|
15083
15979
|
error: catErr instanceof Error ? catErr.message : String(catErr)
|
|
15084
15980
|
}, "Semantic categorization failed — story verdict unchanged");
|
|
@@ -15089,7 +15985,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15089
15985
|
pack,
|
|
15090
15986
|
contextCompiler,
|
|
15091
15987
|
dispatcher,
|
|
15092
|
-
projectRoot,
|
|
15988
|
+
projectRoot: effectiveProjectRoot,
|
|
15093
15989
|
tokenCeilings,
|
|
15094
15990
|
otlpEndpoint: _otlpEndpoint,
|
|
15095
15991
|
agentId
|
|
@@ -15098,9 +15994,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
15098
15994
|
storyFilePath: storyFilePath ?? "",
|
|
15099
15995
|
pipelineRunId: config.pipelineRunId,
|
|
15100
15996
|
filesModified: devFilesModified,
|
|
15101
|
-
workingDirectory:
|
|
15997
|
+
workingDirectory: effectiveProjectRoot
|
|
15102
15998
|
});
|
|
15103
|
-
logger$
|
|
15999
|
+
logger$27.debug({
|
|
15104
16000
|
storyKey,
|
|
15105
16001
|
expansion_priority: expansionResult.expansion_priority,
|
|
15106
16002
|
coverage_gaps: expansionResult.coverage_gaps.length
|
|
@@ -15113,11 +16009,73 @@ function createImplementationOrchestrator(deps) {
|
|
|
15113
16009
|
value: JSON.stringify(expansionResult)
|
|
15114
16010
|
});
|
|
15115
16011
|
} catch (expansionErr) {
|
|
15116
|
-
logger$
|
|
16012
|
+
logger$27.warn({
|
|
15117
16013
|
storyKey,
|
|
15118
16014
|
error: expansionErr instanceof Error ? expansionErr.message : String(expansionErr)
|
|
15119
16015
|
}, "Test expansion failed — story verdict unchanged");
|
|
15120
16016
|
}
|
|
16017
|
+
if (!noWorktree && _worktreeManager !== void 0 && _orchestratorStartBranch !== void 0 && projectRoot !== void 0) {
|
|
16018
|
+
const branchName = `substrate/story-${storyKey}`;
|
|
16019
|
+
logger$27.info({
|
|
16020
|
+
storyKey,
|
|
16021
|
+
branchName,
|
|
16022
|
+
startBranch: _orchestratorStartBranch
|
|
16023
|
+
}, "Invoking merge-to-main phase");
|
|
16024
|
+
let mergeResult;
|
|
16025
|
+
try {
|
|
16026
|
+
mergeResult = await enqueueMerge({
|
|
16027
|
+
storyKey,
|
|
16028
|
+
branchName,
|
|
16029
|
+
startBranch: _orchestratorStartBranch,
|
|
16030
|
+
worktreeManager: _worktreeManager,
|
|
16031
|
+
eventBus,
|
|
16032
|
+
projectRoot
|
|
16033
|
+
});
|
|
16034
|
+
} catch (mergeErr) {
|
|
16035
|
+
const errMsg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
16036
|
+
logger$27.error({
|
|
16037
|
+
storyKey,
|
|
16038
|
+
err: mergeErr
|
|
16039
|
+
}, "merge-to-main phase threw unexpectedly — escalating story");
|
|
16040
|
+
updateStory(storyKey, {
|
|
16041
|
+
phase: "ESCALATED",
|
|
16042
|
+
error: `merge-to-main-error: ${errMsg}`,
|
|
16043
|
+
completedAt: new Date().toISOString()
|
|
16044
|
+
});
|
|
16045
|
+
await emitEscalation({
|
|
16046
|
+
storyKey,
|
|
16047
|
+
lastVerdict: "merge-to-main-error",
|
|
16048
|
+
reviewCycles: completedReviewCycles,
|
|
16049
|
+
issues: [`merge-to-main phase threw: ${errMsg}`]
|
|
16050
|
+
});
|
|
16051
|
+
await persistState();
|
|
16052
|
+
return;
|
|
16053
|
+
}
|
|
16054
|
+
if (!mergeResult.success) {
|
|
16055
|
+
logger$27.warn({
|
|
16056
|
+
storyKey,
|
|
16057
|
+
branchName,
|
|
16058
|
+
conflictingFiles: mergeResult.conflictingFiles
|
|
16059
|
+
}, "merge-to-main conflict — escalating story with merge-conflict-detected");
|
|
16060
|
+
updateStory(storyKey, {
|
|
16061
|
+
phase: "ESCALATED",
|
|
16062
|
+
error: "merge-conflict-detected",
|
|
16063
|
+
completedAt: new Date().toISOString()
|
|
16064
|
+
});
|
|
16065
|
+
await emitEscalation({
|
|
16066
|
+
storyKey,
|
|
16067
|
+
lastVerdict: "merge-conflict-detected",
|
|
16068
|
+
reviewCycles: completedReviewCycles,
|
|
16069
|
+
issues: [`merge conflict in ${mergeResult.conflictingFiles?.length ?? 0} file(s): ${(mergeResult.conflictingFiles ?? []).join(", ")}`]
|
|
16070
|
+
});
|
|
16071
|
+
await persistState();
|
|
16072
|
+
return;
|
|
16073
|
+
}
|
|
16074
|
+
logger$27.info({
|
|
16075
|
+
storyKey,
|
|
16076
|
+
branchName
|
|
16077
|
+
}, "merge-to-main phase completed successfully");
|
|
16078
|
+
}
|
|
15121
16079
|
keepReviewing = false;
|
|
15122
16080
|
return;
|
|
15123
16081
|
}
|
|
@@ -15140,7 +16098,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15140
16098
|
await persistState();
|
|
15141
16099
|
return;
|
|
15142
16100
|
}
|
|
15143
|
-
logger$
|
|
16101
|
+
logger$27.info({
|
|
15144
16102
|
storyKey,
|
|
15145
16103
|
reviewCycles: finalReviewCycles,
|
|
15146
16104
|
issueCount: issueList.length
|
|
@@ -15206,13 +16164,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
15206
16164
|
fixPrompt = assembled.prompt;
|
|
15207
16165
|
} catch {
|
|
15208
16166
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, minor fixes needed`;
|
|
15209
|
-
logger$
|
|
16167
|
+
logger$27.warn({ storyKey }, "Failed to assemble auto-approve fix prompt, using fallback");
|
|
15210
16168
|
}
|
|
15211
16169
|
const handle = dispatcher.dispatch({
|
|
15212
16170
|
prompt: fixPrompt,
|
|
15213
16171
|
agent: deps.agentId ?? "claude-code",
|
|
15214
16172
|
taskType: "minor-fixes",
|
|
15215
|
-
workingDirectory:
|
|
16173
|
+
workingDirectory: effectiveProjectRoot,
|
|
15216
16174
|
...autoApproveMaxTurns !== void 0 ? { maxTurns: autoApproveMaxTurns } : {},
|
|
15217
16175
|
...config.perStoryContextCeilings?.[storyKey] !== void 0 ? { maxContextTokens: config.perStoryContextCeilings[storyKey] } : {},
|
|
15218
16176
|
..._otlpEndpoint !== void 0 ? { otlpEndpoint: _otlpEndpoint } : {},
|
|
@@ -15227,9 +16185,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
15227
16185
|
output: fixResult.tokenEstimate.output
|
|
15228
16186
|
} : void 0 }
|
|
15229
16187
|
});
|
|
15230
|
-
if (fixResult.status === "timeout") logger$
|
|
16188
|
+
if (fixResult.status === "timeout") logger$27.warn({ storyKey }, "Auto-approve fix timed out — approving anyway (issues were minor)");
|
|
15231
16189
|
} catch (err) {
|
|
15232
|
-
logger$
|
|
16190
|
+
logger$27.warn({
|
|
15233
16191
|
storyKey,
|
|
15234
16192
|
err
|
|
15235
16193
|
}, "Auto-approve fix dispatch failed — approving anyway (issues were minor)");
|
|
@@ -15257,7 +16215,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15257
16215
|
outcome: "retried",
|
|
15258
16216
|
cost_usd: 0,
|
|
15259
16217
|
timestamp: new Date().toISOString()
|
|
15260
|
-
}).catch((err) => logger$
|
|
16218
|
+
}).catch((err) => logger$27.warn({
|
|
15261
16219
|
err,
|
|
15262
16220
|
storyKey
|
|
15263
16221
|
}, "appendRecoveryEntry failed — pipeline continues"));
|
|
@@ -15309,9 +16267,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
15309
16267
|
} catch {}
|
|
15310
16268
|
let gitDiffContent = "";
|
|
15311
16269
|
try {
|
|
15312
|
-
const diffFiles = checkGitDiffFiles(
|
|
16270
|
+
const diffFiles = checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
15313
16271
|
if (diffFiles.length > 0) gitDiffContent = execSync(`git diff HEAD -- ${diffFiles.map((f$1) => `"${f$1}"`).join(" ")}`, {
|
|
15314
|
-
cwd:
|
|
16272
|
+
cwd: effectiveProjectRoot ?? process.cwd(),
|
|
15315
16273
|
encoding: "utf-8",
|
|
15316
16274
|
timeout: 1e4,
|
|
15317
16275
|
stdio: [
|
|
@@ -15397,7 +16355,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15397
16355
|
fixPrompt = assembled.prompt;
|
|
15398
16356
|
} catch {
|
|
15399
16357
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, taskType=${taskType}`;
|
|
15400
|
-
logger$
|
|
16358
|
+
logger$27.warn({
|
|
15401
16359
|
storyKey,
|
|
15402
16360
|
taskType
|
|
15403
16361
|
}, "Failed to assemble fix prompt, using fallback");
|
|
@@ -15411,7 +16369,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15411
16369
|
outputSchema: DevStoryResultSchema,
|
|
15412
16370
|
...fixMaxTurns !== void 0 ? { maxTurns: fixMaxTurns } : {},
|
|
15413
16371
|
...config.perStoryContextCeilings?.[storyKey] !== void 0 ? { maxContextTokens: config.perStoryContextCeilings[storyKey] } : {},
|
|
15414
|
-
...
|
|
16372
|
+
...effectiveProjectRoot !== void 0 ? { workingDirectory: effectiveProjectRoot } : {},
|
|
15415
16373
|
..._otlpEndpoint !== void 0 ? { otlpEndpoint: _otlpEndpoint } : {}
|
|
15416
16374
|
}) : dispatcher.dispatch({
|
|
15417
16375
|
prompt: fixPrompt,
|
|
@@ -15420,7 +16378,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15420
16378
|
...fixModel !== void 0 ? { model: fixModel } : {},
|
|
15421
16379
|
...fixMaxTurns !== void 0 ? { maxTurns: fixMaxTurns } : {},
|
|
15422
16380
|
...config.perStoryContextCeilings?.[storyKey] !== void 0 ? { maxContextTokens: config.perStoryContextCeilings[storyKey] } : {},
|
|
15423
|
-
...
|
|
16381
|
+
...effectiveProjectRoot !== void 0 ? { workingDirectory: effectiveProjectRoot } : {},
|
|
15424
16382
|
..._otlpEndpoint !== void 0 ? { otlpEndpoint: _otlpEndpoint } : {}
|
|
15425
16383
|
});
|
|
15426
16384
|
const fixResult = await handle.result;
|
|
@@ -15437,7 +16395,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15437
16395
|
if (taskType === "minor-fixes") {
|
|
15438
16396
|
const finalReviewCycles = reviewCycles + 1;
|
|
15439
16397
|
const downgradedVerdict = "LGTM_WITH_NOTES";
|
|
15440
|
-
logger$
|
|
16398
|
+
logger$27.warn({
|
|
15441
16399
|
storyKey,
|
|
15442
16400
|
reviewCycles: finalReviewCycles,
|
|
15443
16401
|
issueCount: issueList.length
|
|
@@ -15456,7 +16414,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15456
16414
|
keepReviewing = false;
|
|
15457
16415
|
return;
|
|
15458
16416
|
}
|
|
15459
|
-
logger$
|
|
16417
|
+
logger$27.warn({
|
|
15460
16418
|
storyKey,
|
|
15461
16419
|
taskType
|
|
15462
16420
|
}, "Fix dispatch timed out — escalating story");
|
|
@@ -15478,7 +16436,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15478
16436
|
}
|
|
15479
16437
|
if (fixResult.status === "failed") {
|
|
15480
16438
|
if (isMajorRework) {
|
|
15481
|
-
logger$
|
|
16439
|
+
logger$27.warn({
|
|
15482
16440
|
storyKey,
|
|
15483
16441
|
exitCode: fixResult.exitCode
|
|
15484
16442
|
}, "Major rework dispatch failed — escalating story");
|
|
@@ -15498,7 +16456,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15498
16456
|
await persistState();
|
|
15499
16457
|
return;
|
|
15500
16458
|
}
|
|
15501
|
-
logger$
|
|
16459
|
+
logger$27.warn({
|
|
15502
16460
|
storyKey,
|
|
15503
16461
|
taskType,
|
|
15504
16462
|
exitCode: fixResult.exitCode
|
|
@@ -15506,7 +16464,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15506
16464
|
}
|
|
15507
16465
|
if (isMajorRework) replaceDevStorySignals(fixResult.parsed);
|
|
15508
16466
|
} catch (err) {
|
|
15509
|
-
logger$
|
|
16467
|
+
logger$27.warn({
|
|
15510
16468
|
storyKey,
|
|
15511
16469
|
taskType,
|
|
15512
16470
|
err
|
|
@@ -15564,7 +16522,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15564
16522
|
eventBus.emit("decision:halt-skipped-non-interactive", payload);
|
|
15565
16523
|
}
|
|
15566
16524
|
}).catch((err) => {
|
|
15567
|
-
logger$
|
|
16525
|
+
logger$27.warn({ err }, "interactive prompt failed during cost-ceiling halt — continuing with default action");
|
|
15568
16526
|
});
|
|
15569
16527
|
} else eventBus.emit("decision:autonomous", {
|
|
15570
16528
|
runId,
|
|
@@ -15592,7 +16550,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15592
16550
|
severity: routeResult.severity
|
|
15593
16551
|
});
|
|
15594
16552
|
_budgetExhausted = true;
|
|
15595
|
-
logger$
|
|
16553
|
+
logger$27.warn({
|
|
15596
16554
|
skipped: allSkipped.length,
|
|
15597
16555
|
cumulative: result.cumulative,
|
|
15598
16556
|
ceiling: result.ceiling,
|
|
@@ -15611,7 +16569,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15611
16569
|
const completedStoryKeys = [];
|
|
15612
16570
|
for (const storyKey of group) {
|
|
15613
16571
|
if (_shutdownRequested) {
|
|
15614
|
-
logger$
|
|
16572
|
+
logger$27.info({ storyKey }, "shutdown requested — skipping dispatch");
|
|
15615
16573
|
return;
|
|
15616
16574
|
}
|
|
15617
16575
|
if (runManifest !== null && runManifest !== void 0) try {
|
|
@@ -15634,7 +16592,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15634
16592
|
}
|
|
15635
16593
|
}
|
|
15636
16594
|
} catch (err) {
|
|
15637
|
-
logger$
|
|
16595
|
+
logger$27.debug({ err }, "Cost ceiling check failed — proceeding without enforcement");
|
|
15638
16596
|
}
|
|
15639
16597
|
let optimizationDirectives;
|
|
15640
16598
|
if (telemetryAdvisor !== void 0 && completedStoryKeys.length > 0) try {
|
|
@@ -15642,13 +16600,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
15642
16600
|
const directives = telemetryAdvisor.formatOptimizationDirectives(recs);
|
|
15643
16601
|
if (directives.length > 0) {
|
|
15644
16602
|
optimizationDirectives = directives;
|
|
15645
|
-
logger$
|
|
16603
|
+
logger$27.debug({
|
|
15646
16604
|
storyKey,
|
|
15647
16605
|
directiveCount: recs.filter((r) => r.severity !== "info").length
|
|
15648
16606
|
}, "Optimization directives ready for dispatch");
|
|
15649
16607
|
}
|
|
15650
16608
|
} catch (err) {
|
|
15651
|
-
logger$
|
|
16609
|
+
logger$27.debug({
|
|
15652
16610
|
err,
|
|
15653
16611
|
storyKey
|
|
15654
16612
|
}, "Failed to fetch optimization directives — proceeding without");
|
|
@@ -15772,7 +16730,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15772
16730
|
recommendedAction: "serialize"
|
|
15773
16731
|
});
|
|
15774
16732
|
} catch {}
|
|
15775
|
-
logger$
|
|
16733
|
+
logger$27.info({
|
|
15776
16734
|
storyKeys: evt.storyKeys,
|
|
15777
16735
|
collisionPaths: evt.collisionPaths
|
|
15778
16736
|
}, "Cross-story file collision detected — serializing affected groups to prevent race conditions");
|
|
@@ -15785,7 +16743,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15785
16743
|
mergedGroupMap.set(root2, [...existing, ...group]);
|
|
15786
16744
|
}
|
|
15787
16745
|
const result = [...mergedGroupMap.values()];
|
|
15788
|
-
logger$
|
|
16746
|
+
logger$27.info({
|
|
15789
16747
|
originalGroupCount: batchGroups.length,
|
|
15790
16748
|
mergedGroupCount: result.length,
|
|
15791
16749
|
collisionCount
|
|
@@ -15829,7 +16787,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15829
16787
|
async function shutdownGracefully(reason, signal) {
|
|
15830
16788
|
if (_shutdownRequested) return;
|
|
15831
16789
|
_shutdownRequested = true;
|
|
15832
|
-
logger$
|
|
16790
|
+
logger$27.info({
|
|
15833
16791
|
reason,
|
|
15834
16792
|
signal
|
|
15835
16793
|
}, "Graceful shutdown initiated — stopping new dispatches");
|
|
@@ -15839,8 +16797,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
15839
16797
|
run_status: "stopped",
|
|
15840
16798
|
stopped_reason: reason,
|
|
15841
16799
|
stopped_at: new Date().toISOString()
|
|
15842
|
-
}).catch((err) => logger$
|
|
15843
|
-
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$
|
|
16800
|
+
}).catch((err) => logger$27.warn({ err }, "patchRunStatus failed during shutdown (best-effort)"));
|
|
16801
|
+
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$27.warn({ err }, "updatePipelineRun(stopped) failed during shutdown (best-effort)"));
|
|
15844
16802
|
const activePhases = [
|
|
15845
16803
|
"PENDING",
|
|
15846
16804
|
"IN_STORY_CREATION",
|
|
@@ -15851,7 +16809,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15851
16809
|
"CHECKPOINT"
|
|
15852
16810
|
];
|
|
15853
16811
|
const cancellations = [];
|
|
15854
|
-
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$
|
|
16812
|
+
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$27.warn({
|
|
15855
16813
|
err,
|
|
15856
16814
|
storyKey
|
|
15857
16815
|
}, "wg_stories → cancelled failed during shutdown (best-effort)")));
|
|
@@ -15860,15 +16818,29 @@ function createImplementationOrchestrator(deps) {
|
|
|
15860
16818
|
}
|
|
15861
16819
|
async function run(storyKeys) {
|
|
15862
16820
|
if (_state === "RUNNING" || _state === "PAUSED") {
|
|
15863
|
-
logger$
|
|
16821
|
+
logger$27.warn({ state: _state }, "run() called while orchestrator is already running or paused — ignoring");
|
|
15864
16822
|
return getStatus();
|
|
15865
16823
|
}
|
|
15866
16824
|
if (_state === "COMPLETE") {
|
|
15867
|
-
logger$
|
|
16825
|
+
logger$27.warn({ state: _state }, "run() called on a COMPLETE orchestrator — ignoring");
|
|
15868
16826
|
return getStatus();
|
|
15869
16827
|
}
|
|
15870
16828
|
_state = "RUNNING";
|
|
15871
16829
|
_startedAt = new Date().toISOString();
|
|
16830
|
+
if (projectRoot !== void 0) try {
|
|
16831
|
+
_orchestratorStartBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
16832
|
+
cwd: projectRoot,
|
|
16833
|
+
encoding: "utf-8",
|
|
16834
|
+
stdio: [
|
|
16835
|
+
"ignore",
|
|
16836
|
+
"pipe",
|
|
16837
|
+
"pipe"
|
|
16838
|
+
]
|
|
16839
|
+
}).trim();
|
|
16840
|
+
logger$27.info({ orchestratorStartBranch: _orchestratorStartBranch }, "Captured orchestrator start branch for merge-to-main");
|
|
16841
|
+
} catch (branchErr) {
|
|
16842
|
+
logger$27.warn({ err: branchErr }, "Failed to capture orchestrator start branch — merge-to-main will skip worktree integration");
|
|
16843
|
+
}
|
|
15872
16844
|
for (const key of storyKeys) {
|
|
15873
16845
|
const pendingState = {
|
|
15874
16846
|
phase: "PENDING",
|
|
@@ -15910,12 +16882,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
15910
16882
|
await persistState();
|
|
15911
16883
|
recordProgress();
|
|
15912
16884
|
if (config.enableHeartbeat) startHeartbeat();
|
|
16885
|
+
if (_orchestratorStartBranch !== void 0 && runManifest !== null) runManifest.patchRunStatus({ orchestrator_start_branch: _orchestratorStartBranch }).catch((err) => logger$27.warn({ err }, "Failed to persist orchestrator_start_branch to manifest (best-effort)"));
|
|
15913
16886
|
const _startupTimings = {};
|
|
15914
16887
|
if (projectRoot !== void 0) {
|
|
15915
16888
|
const seedStart = Date.now();
|
|
15916
16889
|
const seedResult = await seedMethodologyContext(db, projectRoot);
|
|
15917
16890
|
_startupTimings.seedMethodologyMs = Date.now() - seedStart;
|
|
15918
|
-
if (seedResult.decisionsCreated > 0) logger$
|
|
16891
|
+
if (seedResult.decisionsCreated > 0) logger$27.info({
|
|
15919
16892
|
decisionsCreated: seedResult.decisionsCreated,
|
|
15920
16893
|
skippedCategories: seedResult.skippedCategories,
|
|
15921
16894
|
durationMs: _startupTimings.seedMethodologyMs
|
|
@@ -15925,12 +16898,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
15925
16898
|
const ingestStart = Date.now();
|
|
15926
16899
|
try {
|
|
15927
16900
|
const ingestResult = await autoIngestEpicsDependencies(db, projectRoot);
|
|
15928
|
-
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$
|
|
16901
|
+
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$27.info({
|
|
15929
16902
|
...ingestResult,
|
|
15930
16903
|
durationMs: Date.now() - ingestStart
|
|
15931
16904
|
}, "Auto-ingested stories and dependencies from epics document");
|
|
15932
16905
|
} catch (err) {
|
|
15933
|
-
logger$
|
|
16906
|
+
logger$27.debug({ err }, "Auto-ingest from epics document skipped — work graph may be unavailable");
|
|
15934
16907
|
}
|
|
15935
16908
|
}
|
|
15936
16909
|
const sigtermHandler = () => {
|
|
@@ -15948,7 +16921,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15948
16921
|
_startupTimings.stateStoreInitMs = Date.now() - stateStoreInitStart;
|
|
15949
16922
|
for (const key of storyKeys) {
|
|
15950
16923
|
const pendingState = _stories.get(key);
|
|
15951
|
-
if (pendingState !== void 0) persistStoryState(key, pendingState).catch((err) => logger$
|
|
16924
|
+
if (pendingState !== void 0) persistStoryState(key, pendingState).catch((err) => logger$27.warn({
|
|
15952
16925
|
err,
|
|
15953
16926
|
storyKey: key
|
|
15954
16927
|
}, "StateStore write failed during PENDING init"));
|
|
@@ -15959,12 +16932,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
15959
16932
|
_startupTimings.queryStoriesMs = Date.now() - queryStoriesStart;
|
|
15960
16933
|
for (const record of existingRecords) _stateStoreCache.set(record.storyKey, record);
|
|
15961
16934
|
} catch (err) {
|
|
15962
|
-
logger$
|
|
16935
|
+
logger$27.warn({ err }, "StateStore.queryStories() failed during init — status merge will be empty (best-effort)");
|
|
15963
16936
|
}
|
|
15964
16937
|
}
|
|
15965
16938
|
if (ingestionServer !== void 0) {
|
|
15966
16939
|
if (telemetryPersistence !== void 0) try {
|
|
15967
|
-
const pipelineLogger = logger$
|
|
16940
|
+
const pipelineLogger = logger$27;
|
|
15968
16941
|
const telemetryPipeline = new TelemetryPipeline({
|
|
15969
16942
|
normalizer: new TelemetryNormalizer(pipelineLogger),
|
|
15970
16943
|
turnAnalyzer: new TurnAnalyzer(pipelineLogger),
|
|
@@ -15976,14 +16949,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
15976
16949
|
persistence: telemetryPersistence
|
|
15977
16950
|
});
|
|
15978
16951
|
ingestionServer.setPipeline(telemetryPipeline);
|
|
15979
|
-
logger$
|
|
16952
|
+
logger$27.info("TelemetryPipeline wired to IngestionServer");
|
|
15980
16953
|
} catch (pipelineErr) {
|
|
15981
|
-
logger$
|
|
16954
|
+
logger$27.warn({ err: pipelineErr }, "Failed to create TelemetryPipeline — continuing without analysis pipeline");
|
|
15982
16955
|
}
|
|
15983
|
-
await ingestionServer.start().catch((err) => logger$
|
|
16956
|
+
await ingestionServer.start().catch((err) => logger$27.warn({ err }, "IngestionServer.start() failed — continuing without telemetry (best-effort)"));
|
|
15984
16957
|
try {
|
|
15985
16958
|
_otlpEndpoint = ingestionServer.getOtlpEnvVars().OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
15986
|
-
logger$
|
|
16959
|
+
logger$27.info({ otlpEndpoint: _otlpEndpoint }, "OTLP telemetry ingestion active");
|
|
15987
16960
|
} catch {}
|
|
15988
16961
|
}
|
|
15989
16962
|
let contractDeclarations = [];
|
|
@@ -16023,12 +16996,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
16023
16996
|
const conflictDetectStart = Date.now();
|
|
16024
16997
|
const { batches, edges: contractEdges } = detectConflictGroupsWithContracts(storyKeys, { moduleMap: pack.manifest.conflictGroups }, contractDeclarations);
|
|
16025
16998
|
_startupTimings.conflictDetectMs = Date.now() - conflictDetectStart;
|
|
16026
|
-
if (contractEdges.length > 0) logger$
|
|
16999
|
+
if (contractEdges.length > 0) logger$27.info({
|
|
16027
17000
|
contractEdges,
|
|
16028
17001
|
edgeCount: contractEdges.length
|
|
16029
17002
|
}, "Contract dependency edges detected — applying contract-aware dispatch ordering");
|
|
16030
|
-
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$
|
|
16031
|
-
logger$
|
|
17003
|
+
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$27.warn({ err }, "contract dep persistence failed (best-effort)"));
|
|
17004
|
+
logger$27.info({
|
|
16032
17005
|
storyCount: storyKeys.length,
|
|
16033
17006
|
groupCount: batches.reduce((sum, b) => sum + b.length, 0),
|
|
16034
17007
|
batchCount: batches.length,
|
|
@@ -16038,7 +17011,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16038
17011
|
groups: batch.map((g) => g.join(","))
|
|
16039
17012
|
}))
|
|
16040
17013
|
}, "Orchestrator starting");
|
|
16041
|
-
logger$
|
|
17014
|
+
logger$27.info({
|
|
16042
17015
|
storyCount: storyKeys.length,
|
|
16043
17016
|
conflictGroups: batches.length,
|
|
16044
17017
|
maxConcurrency: config.maxConcurrency
|
|
@@ -16059,7 +17032,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16059
17032
|
exitCode,
|
|
16060
17033
|
output: truncatedOutput
|
|
16061
17034
|
});
|
|
16062
|
-
logger$
|
|
17035
|
+
logger$27.error({
|
|
16063
17036
|
exitCode,
|
|
16064
17037
|
reason: preFlightResult.reason
|
|
16065
17038
|
}, "Pre-flight build check failed — aborting pipeline before any story dispatch");
|
|
@@ -16068,19 +17041,19 @@ function createImplementationOrchestrator(deps) {
|
|
|
16068
17041
|
await persistState();
|
|
16069
17042
|
return getStatus();
|
|
16070
17043
|
}
|
|
16071
|
-
if (preFlightResult.status !== "skipped") logger$
|
|
17044
|
+
if (preFlightResult.status !== "skipped") logger$27.info("Pre-flight build check passed");
|
|
16072
17045
|
}
|
|
16073
|
-
logger$
|
|
17046
|
+
logger$27.info(_startupTimings, "Orchestrator startup timings (ms)");
|
|
16074
17047
|
const totalGroups = batches.reduce((sum, b) => sum + b.length, 0);
|
|
16075
17048
|
const actualConcurrency = Math.min(config.maxConcurrency, totalGroups);
|
|
16076
17049
|
if (actualConcurrency > 1 && projectRoot !== void 0) try {
|
|
16077
17050
|
_packageSnapshot = capturePackageSnapshot({ projectRoot });
|
|
16078
|
-
logger$
|
|
17051
|
+
logger$27.info({
|
|
16079
17052
|
fileCount: _packageSnapshot.files.size,
|
|
16080
17053
|
installCommand: _packageSnapshot.installCommand
|
|
16081
17054
|
}, "Package snapshot captured for concurrent story protection");
|
|
16082
17055
|
} catch (snapErr) {
|
|
16083
|
-
logger$
|
|
17056
|
+
logger$27.warn({ err: snapErr }, "Failed to capture package snapshot — continuing without protection");
|
|
16084
17057
|
}
|
|
16085
17058
|
try {
|
|
16086
17059
|
for (const rawBatchGroups of batches) {
|
|
@@ -16105,14 +17078,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
16105
17078
|
manifest: runManifest,
|
|
16106
17079
|
adapter: db
|
|
16107
17080
|
});
|
|
16108
|
-
if (!recoveryResult.noStale) logger$
|
|
17081
|
+
if (!recoveryResult.noStale) logger$27.info({
|
|
16109
17082
|
recovered: recoveryResult.recovered,
|
|
16110
17083
|
stillFailed: recoveryResult.stillFailed,
|
|
16111
17084
|
recoveredCount: recoveryResult.recovered.length,
|
|
16112
17085
|
stillFailedCount: recoveryResult.stillFailed.length
|
|
16113
17086
|
}, "Cross-story race recovery complete");
|
|
16114
17087
|
} catch (recoveryErr) {
|
|
16115
|
-
logger$
|
|
17088
|
+
logger$27.warn({ err: recoveryErr }, "Cross-story race recovery failed (non-fatal) — pipeline continues");
|
|
16116
17089
|
}
|
|
16117
17090
|
}
|
|
16118
17091
|
}
|
|
@@ -16121,7 +17094,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16121
17094
|
_state = "FAILED";
|
|
16122
17095
|
_completedAt = new Date().toISOString();
|
|
16123
17096
|
await persistState();
|
|
16124
|
-
logger$
|
|
17097
|
+
logger$27.error({ err }, "Orchestrator failed with unhandled error");
|
|
16125
17098
|
return getStatus();
|
|
16126
17099
|
}
|
|
16127
17100
|
stopHeartbeat();
|
|
@@ -16131,7 +17104,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16131
17104
|
const totalDeclarations = contractDeclarations.length;
|
|
16132
17105
|
const currentSprintDeclarations = contractDeclarations.filter((d) => storyKeys.includes(d.storyKey));
|
|
16133
17106
|
const stalePruned = totalDeclarations - currentSprintDeclarations.length;
|
|
16134
|
-
if (stalePruned > 0) logger$
|
|
17107
|
+
if (stalePruned > 0) logger$27.info({
|
|
16135
17108
|
stalePruned,
|
|
16136
17109
|
remaining: currentSprintDeclarations.length
|
|
16137
17110
|
}, "Pruned stale contract declarations from previous epics");
|
|
@@ -16145,11 +17118,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
16145
17118
|
contractName: mismatch.contractName,
|
|
16146
17119
|
mismatchDescription: mismatch.mismatchDescription
|
|
16147
17120
|
});
|
|
16148
|
-
logger$
|
|
17121
|
+
logger$27.warn({
|
|
16149
17122
|
mismatchCount: mismatches.length,
|
|
16150
17123
|
mismatches
|
|
16151
17124
|
}, "Post-sprint contract verification found mismatches — manual review required");
|
|
16152
|
-
} else if (currentSprintDeclarations.length > 0) logger$
|
|
17125
|
+
} else if (currentSprintDeclarations.length > 0) logger$27.info("Post-sprint contract verification passed — all declared contracts satisfied");
|
|
16153
17126
|
eventBus.emit("pipeline:contract-verification-summary", {
|
|
16154
17127
|
verified: currentSprintDeclarations.length,
|
|
16155
17128
|
stalePruned,
|
|
@@ -16184,12 +17157,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
16184
17157
|
});
|
|
16185
17158
|
await stateStore.setContractVerification(sk, records);
|
|
16186
17159
|
}
|
|
16187
|
-
logger$
|
|
17160
|
+
logger$27.info({ storyCount: contractsByStory.size }, "Contract verification results persisted to StateStore");
|
|
16188
17161
|
} catch (persistErr) {
|
|
16189
|
-
logger$
|
|
17162
|
+
logger$27.warn({ err: persistErr }, "Failed to persist contract verification results to StateStore");
|
|
16190
17163
|
}
|
|
16191
17164
|
} catch (err) {
|
|
16192
|
-
logger$
|
|
17165
|
+
logger$27.error({ err }, "Post-sprint contract verification threw an error — skipping");
|
|
16193
17166
|
}
|
|
16194
17167
|
if (projectRoot !== void 0) try {
|
|
16195
17168
|
const indicators = checkProfileStaleness(projectRoot);
|
|
@@ -16199,10 +17172,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
16199
17172
|
message,
|
|
16200
17173
|
indicators
|
|
16201
17174
|
});
|
|
16202
|
-
logger$
|
|
17175
|
+
logger$27.warn({ indicators }, message);
|
|
16203
17176
|
}
|
|
16204
17177
|
} catch (err) {
|
|
16205
|
-
logger$
|
|
17178
|
+
logger$27.debug({ err }, "Profile staleness check failed (best-effort)");
|
|
16206
17179
|
}
|
|
16207
17180
|
let completed = 0;
|
|
16208
17181
|
let escalated = 0;
|
|
@@ -16221,8 +17194,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
16221
17194
|
} finally {
|
|
16222
17195
|
process.off("SIGTERM", sigtermHandler);
|
|
16223
17196
|
process.off("SIGINT", sigintHandler);
|
|
16224
|
-
if (stateStore !== void 0) await stateStore.close().catch((err) => logger$
|
|
16225
|
-
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$
|
|
17197
|
+
if (stateStore !== void 0) await stateStore.close().catch((err) => logger$27.warn({ err }, "StateStore.close() failed (best-effort)"));
|
|
17198
|
+
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$27.warn({ err }, "IngestionServer.stop() failed (best-effort)"));
|
|
16226
17199
|
}
|
|
16227
17200
|
}
|
|
16228
17201
|
function pause() {
|
|
@@ -16231,7 +17204,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16231
17204
|
_pauseGate = createPauseGate();
|
|
16232
17205
|
_state = "PAUSED";
|
|
16233
17206
|
eventBus.emit("orchestrator:paused", {});
|
|
16234
|
-
logger$
|
|
17207
|
+
logger$27.info("Orchestrator paused");
|
|
16235
17208
|
}
|
|
16236
17209
|
function resume() {
|
|
16237
17210
|
if (_state !== "PAUSED") return;
|
|
@@ -16242,7 +17215,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16242
17215
|
}
|
|
16243
17216
|
_state = "RUNNING";
|
|
16244
17217
|
eventBus.emit("orchestrator:resumed", {});
|
|
16245
|
-
logger$
|
|
17218
|
+
logger$27.info("Orchestrator resumed");
|
|
16246
17219
|
}
|
|
16247
17220
|
return {
|
|
16248
17221
|
run,
|
|
@@ -17658,8 +18631,8 @@ async function resolveContext(ref, deps, runId, params, stepOutputs) {
|
|
|
17658
18631
|
return params[key] ?? "";
|
|
17659
18632
|
}
|
|
17660
18633
|
if (source.startsWith("decision:")) {
|
|
17661
|
-
const path$
|
|
17662
|
-
const [phase, category] = path$
|
|
18634
|
+
const path$6 = source.slice(9);
|
|
18635
|
+
const [phase, category] = path$6.split(".");
|
|
17663
18636
|
if (!phase || !category) return "";
|
|
17664
18637
|
const decisions = await getDecisionsByPhaseForRun(deps.db, runId, phase);
|
|
17665
18638
|
const filtered = decisions.filter((d) => d.category === category);
|
|
@@ -17730,8 +18703,8 @@ async function runSteps(steps, deps, runId, phase, params) {
|
|
|
17730
18703
|
for (const ref of step.context) {
|
|
17731
18704
|
let value;
|
|
17732
18705
|
if (ref.source.startsWith("decision:")) {
|
|
17733
|
-
const path$
|
|
17734
|
-
const [decPhase, decCategory] = path$
|
|
18706
|
+
const path$6 = ref.source.slice(9);
|
|
18707
|
+
const [decPhase, decCategory] = path$6.split(".");
|
|
17735
18708
|
if (decPhase && decCategory) {
|
|
17736
18709
|
const decisions = await getDecisionsByPhaseForRun(deps.db, runId, decPhase);
|
|
17737
18710
|
const filtered = decisions.filter((d) => d.category === decCategory);
|
|
@@ -28778,8 +29751,8 @@ var require_uri_all = __commonJS({ "node_modules/uri-js/dist/es5/uri.all.js"(exp
|
|
|
28778
29751
|
wsComponents.secure = void 0;
|
|
28779
29752
|
}
|
|
28780
29753
|
if (wsComponents.resourceName) {
|
|
28781
|
-
var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path$
|
|
28782
|
-
wsComponents.path = path$
|
|
29754
|
+
var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path$6 = _wsComponents$resourc2[0], query = _wsComponents$resourc2[1];
|
|
29755
|
+
wsComponents.path = path$6 && path$6 !== "/" ? path$6 : void 0;
|
|
28783
29756
|
wsComponents.query = query;
|
|
28784
29757
|
wsComponents.resourceName = void 0;
|
|
28785
29758
|
}
|
|
@@ -29120,12 +30093,12 @@ var require_util = __commonJS({ "node_modules/ajv/lib/compile/util.js"(exports,
|
|
|
29120
30093
|
return "'" + escapeQuotes(str) + "'";
|
|
29121
30094
|
}
|
|
29122
30095
|
function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
|
|
29123
|
-
var path$
|
|
29124
|
-
return joinPaths(currentPath, path$
|
|
30096
|
+
var path$6 = jsonPointers ? "'/' + " + expr + (isNumber ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'";
|
|
30097
|
+
return joinPaths(currentPath, path$6);
|
|
29125
30098
|
}
|
|
29126
30099
|
function getPath(currentPath, prop, jsonPointers) {
|
|
29127
|
-
var path$
|
|
29128
|
-
return joinPaths(currentPath, path$
|
|
30100
|
+
var path$6 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop));
|
|
30101
|
+
return joinPaths(currentPath, path$6);
|
|
29129
30102
|
}
|
|
29130
30103
|
var JSON_POINTER$1 = /^\/(?:[^~]|~0|~1)*$/;
|
|
29131
30104
|
var RELATIVE_JSON_POINTER$1 = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
|
@@ -33293,16 +34266,16 @@ var require_ajv = __commonJS({ "node_modules/ajv/lib/ajv.js"(exports, module) {
|
|
|
33293
34266
|
return metaOpts;
|
|
33294
34267
|
}
|
|
33295
34268
|
function setLogger(self) {
|
|
33296
|
-
var logger$
|
|
33297
|
-
if (logger$
|
|
34269
|
+
var logger$27 = self._opts.logger;
|
|
34270
|
+
if (logger$27 === false) self.logger = {
|
|
33298
34271
|
log: noop,
|
|
33299
34272
|
warn: noop,
|
|
33300
34273
|
error: noop
|
|
33301
34274
|
};
|
|
33302
34275
|
else {
|
|
33303
|
-
if (logger$
|
|
33304
|
-
if (!(typeof logger$
|
|
33305
|
-
self.logger = logger$
|
|
34276
|
+
if (logger$27 === void 0) logger$27 = console;
|
|
34277
|
+
if (!(typeof logger$27 == "object" && logger$27.log && logger$27.warn && logger$27.error)) throw new Error("logger must implement log, warn and error methods");
|
|
34278
|
+
self.logger = logger$27;
|
|
33306
34279
|
}
|
|
33307
34280
|
}
|
|
33308
34281
|
function noop() {}
|
|
@@ -33334,8 +34307,8 @@ var ToolRegistry = class {
|
|
|
33334
34307
|
if (!valid) {
|
|
33335
34308
|
const errors = validate$1.errors ?? [];
|
|
33336
34309
|
const messages = errors.map((e) => {
|
|
33337
|
-
const path$
|
|
33338
|
-
return `${path$
|
|
34310
|
+
const path$6 = e.instancePath ?? e.dataPath ?? "";
|
|
34311
|
+
return `${path$6} ${e.message ?? ""}`.trim();
|
|
33339
34312
|
}).join(", ");
|
|
33340
34313
|
return {
|
|
33341
34314
|
content: `Validation failed for tool '${name}': ${messages}`,
|
|
@@ -40041,10 +41014,10 @@ var PathBase = class {
|
|
|
40041
41014
|
/**
|
|
40042
41015
|
* Get the Path object referenced by the string path, resolved from this Path
|
|
40043
41016
|
*/
|
|
40044
|
-
resolve(path$
|
|
40045
|
-
if (!path$
|
|
40046
|
-
const rootPath = this.getRootString(path$
|
|
40047
|
-
const dir = path$
|
|
41017
|
+
resolve(path$6) {
|
|
41018
|
+
if (!path$6) return this;
|
|
41019
|
+
const rootPath = this.getRootString(path$6);
|
|
41020
|
+
const dir = path$6.substring(rootPath.length);
|
|
40048
41021
|
const dirParts = dir.split(this.splitSep);
|
|
40049
41022
|
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
|
|
40050
41023
|
return result;
|
|
@@ -40699,8 +41672,8 @@ var PathWin32 = class PathWin32 extends PathBase {
|
|
|
40699
41672
|
/**
|
|
40700
41673
|
* @internal
|
|
40701
41674
|
*/
|
|
40702
|
-
getRootString(path$
|
|
40703
|
-
return win32.parse(path$
|
|
41675
|
+
getRootString(path$6) {
|
|
41676
|
+
return win32.parse(path$6).root;
|
|
40704
41677
|
}
|
|
40705
41678
|
/**
|
|
40706
41679
|
* @internal
|
|
@@ -40745,8 +41718,8 @@ var PathPosix = class PathPosix extends PathBase {
|
|
|
40745
41718
|
/**
|
|
40746
41719
|
* @internal
|
|
40747
41720
|
*/
|
|
40748
|
-
getRootString(path$
|
|
40749
|
-
return path$
|
|
41721
|
+
getRootString(path$6) {
|
|
41722
|
+
return path$6.startsWith("/") ? "/" : "";
|
|
40750
41723
|
}
|
|
40751
41724
|
/**
|
|
40752
41725
|
* @internal
|
|
@@ -40839,9 +41812,9 @@ var PathScurryBase = class {
|
|
|
40839
41812
|
/**
|
|
40840
41813
|
* Get the depth of a provided path, string, or the cwd
|
|
40841
41814
|
*/
|
|
40842
|
-
depth(path$
|
|
40843
|
-
if (typeof path$
|
|
40844
|
-
return path$
|
|
41815
|
+
depth(path$6 = this.cwd) {
|
|
41816
|
+
if (typeof path$6 === "string") path$6 = this.cwd.resolve(path$6);
|
|
41817
|
+
return path$6.depth();
|
|
40845
41818
|
}
|
|
40846
41819
|
/**
|
|
40847
41820
|
* Return the cache of child entries. Exposed so subclasses can create
|
|
@@ -41222,9 +42195,9 @@ var PathScurryBase = class {
|
|
|
41222
42195
|
process$1();
|
|
41223
42196
|
return results;
|
|
41224
42197
|
}
|
|
41225
|
-
chdir(path$
|
|
42198
|
+
chdir(path$6 = this.cwd) {
|
|
41226
42199
|
const oldCwd = this.cwd;
|
|
41227
|
-
this.cwd = typeof path$
|
|
42200
|
+
this.cwd = typeof path$6 === "string" ? this.cwd.resolve(path$6) : path$6;
|
|
41228
42201
|
this.cwd[setAsCwd](oldCwd);
|
|
41229
42202
|
}
|
|
41230
42203
|
};
|
|
@@ -41608,8 +42581,8 @@ var MatchRecord = class {
|
|
|
41608
42581
|
this.store.set(target, current === void 0 ? n$1 : n$1 & current);
|
|
41609
42582
|
}
|
|
41610
42583
|
entries() {
|
|
41611
|
-
return [...this.store.entries()].map(([path$
|
|
41612
|
-
path$
|
|
42584
|
+
return [...this.store.entries()].map(([path$6, n$1]) => [
|
|
42585
|
+
path$6,
|
|
41613
42586
|
!!(n$1 & 2),
|
|
41614
42587
|
!!(n$1 & 1)
|
|
41615
42588
|
]);
|
|
@@ -41785,9 +42758,9 @@ var GlobUtil = class {
|
|
|
41785
42758
|
signal;
|
|
41786
42759
|
maxDepth;
|
|
41787
42760
|
includeChildMatches;
|
|
41788
|
-
constructor(patterns, path$
|
|
42761
|
+
constructor(patterns, path$6, opts) {
|
|
41789
42762
|
this.patterns = patterns;
|
|
41790
|
-
this.path = path$
|
|
42763
|
+
this.path = path$6;
|
|
41791
42764
|
this.opts = opts;
|
|
41792
42765
|
this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
|
|
41793
42766
|
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
@@ -41808,11 +42781,11 @@ var GlobUtil = class {
|
|
|
41808
42781
|
});
|
|
41809
42782
|
}
|
|
41810
42783
|
}
|
|
41811
|
-
#ignored(path$
|
|
41812
|
-
return this.seen.has(path$
|
|
42784
|
+
#ignored(path$6) {
|
|
42785
|
+
return this.seen.has(path$6) || !!this.#ignore?.ignored?.(path$6);
|
|
41813
42786
|
}
|
|
41814
|
-
#childrenIgnored(path$
|
|
41815
|
-
return !!this.#ignore?.childrenIgnored?.(path$
|
|
42787
|
+
#childrenIgnored(path$6) {
|
|
42788
|
+
return !!this.#ignore?.childrenIgnored?.(path$6);
|
|
41816
42789
|
}
|
|
41817
42790
|
pause() {
|
|
41818
42791
|
this.paused = true;
|
|
@@ -41994,8 +42967,8 @@ var GlobUtil = class {
|
|
|
41994
42967
|
};
|
|
41995
42968
|
var GlobWalker = class extends GlobUtil {
|
|
41996
42969
|
matches = new Set();
|
|
41997
|
-
constructor(patterns, path$
|
|
41998
|
-
super(patterns, path$
|
|
42970
|
+
constructor(patterns, path$6, opts) {
|
|
42971
|
+
super(patterns, path$6, opts);
|
|
41999
42972
|
}
|
|
42000
42973
|
matchEmit(e) {
|
|
42001
42974
|
this.matches.add(e);
|
|
@@ -42022,8 +42995,8 @@ var GlobWalker = class extends GlobUtil {
|
|
|
42022
42995
|
};
|
|
42023
42996
|
var GlobStream = class extends GlobUtil {
|
|
42024
42997
|
results;
|
|
42025
|
-
constructor(patterns, path$
|
|
42026
|
-
super(patterns, path$
|
|
42998
|
+
constructor(patterns, path$6, opts) {
|
|
42999
|
+
super(patterns, path$6, opts);
|
|
42027
43000
|
this.results = new Minipass({
|
|
42028
43001
|
signal: this.signal,
|
|
42029
43002
|
objectMode: true
|
|
@@ -44583,7 +45556,7 @@ function resolveProbeAuthorStateIntegrating(cliFlag) {
|
|
|
44583
45556
|
* substrate run --non-interactive --halt-on none --events --output-format json
|
|
44584
45557
|
*/
|
|
44585
45558
|
async function runRunAction(options) {
|
|
44586
|
-
const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, epic: epicNumber, dryRun, maxReviewCycles = 2, engine, agent: agentId, registry: injectedRegistry, haltOn: haltOnOpt, costCeiling, probeAuthor, probeAuthorStateIntegrating: probeAuthorStateIntegratingFlag, nonInteractive, verifyAc } = options;
|
|
45559
|
+
const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, epic: epicNumber, dryRun, maxReviewCycles = 2, engine, agent: agentId, registry: injectedRegistry, haltOn: haltOnOpt, costCeiling, probeAuthor, probeAuthorStateIntegrating: probeAuthorStateIntegratingFlag, nonInteractive, verifyAc, noWorktree } = options;
|
|
44587
45560
|
const haltOn = haltOnOpt;
|
|
44588
45561
|
const VALID_PROBE_AUTHOR_MODES = [
|
|
44589
45562
|
"enabled",
|
|
@@ -44803,7 +45776,8 @@ async function runRunAction(options) {
|
|
|
44803
45776
|
engineType: resolvedEngine,
|
|
44804
45777
|
maxReviewCycles: effectiveMaxReviewCycles,
|
|
44805
45778
|
retryBudget: configRetryBudget ?? 2,
|
|
44806
|
-
agentId
|
|
45779
|
+
agentId,
|
|
45780
|
+
...noWorktree === true ? { noWorktree: true } : {}
|
|
44807
45781
|
});
|
|
44808
45782
|
let storyKeys = [...parsedStoryKeys];
|
|
44809
45783
|
if (!existsSync$1(dbDir)) mkdirSync$1(dbDir, { recursive: true });
|
|
@@ -44902,7 +45876,8 @@ async function runRunAction(options) {
|
|
|
44902
45876
|
...agentId !== void 0 ? { agent: agentId } : {},
|
|
44903
45877
|
...skipVerification === true ? { skip_verification: true } : {},
|
|
44904
45878
|
...eventsFlag === true ? { events: true } : {},
|
|
44905
|
-
...nonInteractive === true ? { non_interactive: true } : {}
|
|
45879
|
+
...nonInteractive === true ? { non_interactive: true } : {},
|
|
45880
|
+
...noWorktree === true ? { no_worktree: true } : {}
|
|
44906
45881
|
};
|
|
44907
45882
|
const manifest = RunManifest.open(pipelineRun.id, runsDir);
|
|
44908
45883
|
await manifest.patchCLIFlags(cliFlags);
|
|
@@ -45354,7 +46329,8 @@ async function runRunAction(options) {
|
|
|
45354
46329
|
skipPreflight: skipPreflight === true,
|
|
45355
46330
|
...skipVerification === true ? { skipVerification: true } : {},
|
|
45356
46331
|
...probeAuthor !== void 0 ? { probeAuthorMode: probeAuthor } : {},
|
|
45357
|
-
probeAuthorStateIntegrating: resolvedProbeAuthorStateIntegrating
|
|
46332
|
+
probeAuthorStateIntegrating: resolvedProbeAuthorStateIntegrating,
|
|
46333
|
+
...noWorktree === true ? { noWorktree: true } : {}
|
|
45358
46334
|
},
|
|
45359
46335
|
projectRoot,
|
|
45360
46336
|
tokenCeilings,
|
|
@@ -45572,7 +46548,7 @@ async function runRunAction(options) {
|
|
|
45572
46548
|
}
|
|
45573
46549
|
}
|
|
45574
46550
|
async function runFullPipeline(options) {
|
|
45575
|
-
const { packName, packPath, dbDir, dbPath, startPhase, stopAfter, concept, concurrency, outputFormat, projectRoot, events: eventsFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, maxReviewCycles = 2, retryBudget, registry: injectedRegistry, tokenCeilings, stories: explicitStories, telemetryEnabled: fullTelemetryEnabled, telemetryPort: fullTelemetryPort, agentId, meshUrl: fpMeshUrl, meshProjectId: fpMeshProjectId, engineType: fpEngineType, probeAuthor, probeAuthorStateIntegrating: fpProbeAuthorStateIntegrating } = options;
|
|
46551
|
+
const { packName, packPath, dbDir, dbPath, startPhase, stopAfter, concept, concurrency, outputFormat, projectRoot, events: eventsFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, skipVerification, maxReviewCycles = 2, retryBudget, registry: injectedRegistry, tokenCeilings, stories: explicitStories, telemetryEnabled: fullTelemetryEnabled, telemetryPort: fullTelemetryPort, agentId, meshUrl: fpMeshUrl, meshProjectId: fpMeshProjectId, engineType: fpEngineType, probeAuthor, probeAuthorStateIntegrating: fpProbeAuthorStateIntegrating, noWorktree } = options;
|
|
45576
46552
|
if (!existsSync$1(dbDir)) mkdirSync$1(dbDir, { recursive: true });
|
|
45577
46553
|
let doltServerFull = null;
|
|
45578
46554
|
try {
|
|
@@ -45881,7 +46857,8 @@ async function runFullPipeline(options) {
|
|
|
45881
46857
|
skipPreflight: skipPreflight === true,
|
|
45882
46858
|
...skipVerification === true ? { skipVerification: true } : {},
|
|
45883
46859
|
...probeAuthor !== void 0 ? { probeAuthorMode: probeAuthor } : {},
|
|
45884
|
-
...fpProbeAuthorStateIntegrating !== void 0 ? { probeAuthorStateIntegrating: fpProbeAuthorStateIntegrating } : {}
|
|
46860
|
+
...fpProbeAuthorStateIntegrating !== void 0 ? { probeAuthorStateIntegrating: fpProbeAuthorStateIntegrating } : {},
|
|
46861
|
+
...noWorktree === true ? { noWorktree: true } : {}
|
|
45885
46862
|
},
|
|
45886
46863
|
projectRoot,
|
|
45887
46864
|
tokenCeilings,
|
|
@@ -46091,7 +47068,7 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
46091
47068
|
"",
|
|
46092
47069
|
"--halt-on defaults to critical. Skipped halt decisions are recorded as",
|
|
46093
47070
|
"decision:halt-skipped-non-interactive events in --non-interactive mode."
|
|
46094
|
-
].join("\n ")).option("--verify-ac", "Run AC-to-test traceability heuristic after the pipeline completes (Story 74-1)").action(async (opts) => {
|
|
47071
|
+
].join("\n ")).option("--verify-ac", "Run AC-to-test traceability heuristic after the pipeline completes (Story 74-1)").option("--no-worktree", "Bypass per-story git worktrees (safety valve for submodules, bare repos, or large checkouts where parallel worktrees blow disk — not the recommended path)").action(async (opts) => {
|
|
46095
47072
|
if (opts.helpAgent) {
|
|
46096
47073
|
process.exitCode = await runHelpAgent();
|
|
46097
47074
|
return;
|
|
@@ -46138,7 +47115,8 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
46138
47115
|
probeAuthor: opts.probeAuthor,
|
|
46139
47116
|
probeAuthorStateIntegrating: opts.probeAuthorStateIntegrating,
|
|
46140
47117
|
nonInteractive: opts.nonInteractive,
|
|
46141
|
-
verifyAc: opts.verifyAc
|
|
47118
|
+
verifyAc: opts.verifyAc,
|
|
47119
|
+
noWorktree: opts.worktree === false || process.env["SUBSTRATE_NO_WORKTREE"] === "1"
|
|
46142
47120
|
});
|
|
46143
47121
|
if (opts.nonInteractive === true) process.exit(exitCode);
|
|
46144
47122
|
process.exitCode = exitCode;
|
|
@@ -46146,5 +47124,5 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
46146
47124
|
}
|
|
46147
47125
|
|
|
46148
47126
|
//#endregion
|
|
46149
|
-
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
46150
|
-
//# sourceMappingURL=run-
|
|
47127
|
+
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
47128
|
+
//# sourceMappingURL=run-CElciHC1.js.map
|