@lumenflow/cli 3.16.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/config-get.js +3 -3
- package/dist/config-get.js.map +1 -1
- package/dist/config-set.js +3 -3
- package/dist/config-set.js.map +1 -1
- package/dist/docs-sync.js +302 -57
- package/dist/docs-sync.js.map +1 -1
- package/dist/doctor.js +3 -3
- package/dist/doctor.js.map +1 -1
- package/dist/gate-defaults.js +3 -0
- package/dist/gate-defaults.js.map +1 -1
- package/dist/gates-plan-resolvers.js +3 -4
- package/dist/gates-plan-resolvers.js.map +1 -1
- package/dist/gates-runners.js +48 -0
- package/dist/gates-runners.js.map +1 -1
- package/dist/gates-utils.js +64 -3
- package/dist/gates-utils.js.map +1 -1
- package/dist/gates.js +2 -1
- package/dist/gates.js.map +1 -1
- package/dist/init-scaffolding.js +28 -1
- package/dist/init-scaffolding.js.map +1 -1
- package/dist/init-templates.js +6 -2
- package/dist/init-templates.js.map +1 -1
- package/dist/init.js +22 -25
- package/dist/init.js.map +1 -1
- package/dist/lane-create.js +2 -2
- package/dist/lane-create.js.map +1 -1
- package/dist/lane-edit.js +2 -2
- package/dist/lane-edit.js.map +1 -1
- package/dist/lane-lock.js +8 -6
- package/dist/lane-lock.js.map +1 -1
- package/dist/lane-setup.js +7 -5
- package/dist/lane-setup.js.map +1 -1
- package/dist/lane-status.js +7 -5
- package/dist/lane-status.js.map +1 -1
- package/dist/lane-validate.js +8 -6
- package/dist/lane-validate.js.map +1 -1
- package/dist/lumenflow-upgrade.js +22 -13
- package/dist/lumenflow-upgrade.js.map +1 -1
- package/dist/onboard.js +15 -16
- package/dist/onboard.js.map +1 -1
- package/dist/orchestrate-initiative.js +29 -8
- package/dist/orchestrate-initiative.js.map +1 -1
- package/dist/state-doctor.js +3 -4
- package/dist/state-doctor.js.map +1 -1
- package/dist/wu-done-policies.js +38 -0
- package/dist/wu-done-policies.js.map +1 -1
- package/dist/wu-edit-operations.js +27 -24
- package/dist/wu-edit-operations.js.map +1 -1
- package/dist/wu-edit-validators.js +68 -0
- package/dist/wu-edit-validators.js.map +1 -1
- package/dist/wu-edit.js +11 -3
- package/dist/wu-edit.js.map +1 -1
- package/package.json +8 -8
- package/packs/sidekick/.turbo/turbo-build.log +1 -1
- package/packs/sidekick/package.json +1 -1
- package/packs/software-delivery/.turbo/turbo-build.log +1 -1
- package/packs/software-delivery/package.json +1 -1
- package/templates/core/AGENTS.md.template +2 -1
- package/templates/core/LUMENFLOW.md.template +5 -1
- package/templates/core/UPGRADING.md.template +14 -10
- package/templates/core/ai/onboarding/initiative-orchestration.md.template +1 -1
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +11 -10
- package/templates/core/ai/onboarding/starting-prompt.md.template +3 -3
- package/templates/vendors/claude/.claude/CLAUDE.md.template +2 -1
- package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +2 -1
- package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +2 -1
- package/dist/chunk-2D2VOCA4.js +0 -37
- package/dist/chunk-2D5KFYGX.js +0 -284
- package/dist/chunk-2GXVIN57.js +0 -14072
- package/dist/chunk-2MQ7HZWZ.js +0 -26
- package/dist/chunk-2UFQ3A3C.js +0 -643
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-4N74J3UT.js +0 -15
- package/dist/chunk-5GTOXFYR.js +0 -392
- package/dist/chunk-5VY6MQMC.js +0 -240
- package/dist/chunk-67XVPMRY.js +0 -1297
- package/dist/chunk-6HO4GWJE.js +0 -164
- package/dist/chunk-6W5XHWYV.js +0 -1890
- package/dist/chunk-6X4EMYJQ.js +0 -64
- package/dist/chunk-6XYXI2NQ.js +0 -772
- package/dist/chunk-7ANSOV6Q.js +0 -285
- package/dist/chunk-A624LFLB.js +0 -1380
- package/dist/chunk-ADN5NHG4.js +0 -126
- package/dist/chunk-B7YJYJKG.js +0 -33
- package/dist/chunk-CCLHCPKG.js +0 -210
- package/dist/chunk-CK36VROC.js +0 -1584
- package/dist/chunk-D3UOFRSB.js +0 -81
- package/dist/chunk-DFR4DJBM.js +0 -230
- package/dist/chunk-DSYBDHYH.js +0 -79
- package/dist/chunk-DWMLTXKQ.js +0 -1176
- package/dist/chunk-E3REJTAJ.js +0 -28
- package/dist/chunk-EA3IVO64.js +0 -633
- package/dist/chunk-EK2AKZKD.js +0 -55
- package/dist/chunk-ELD7JTTT.js +0 -343
- package/dist/chunk-EX6TT2XI.js +0 -195
- package/dist/chunk-EXINSFZE.js +0 -82
- package/dist/chunk-EZ6ZBYBM.js +0 -510
- package/dist/chunk-FBKAPTJ2.js +0 -16
- package/dist/chunk-FVLV5RYH.js +0 -1118
- package/dist/chunk-GDNSBQVK.js +0 -2485
- package/dist/chunk-GPQHMBNN.js +0 -278
- package/dist/chunk-GTFJB67L.js +0 -68
- package/dist/chunk-HANJXVKW.js +0 -1127
- package/dist/chunk-HEVS5YLD.js +0 -269
- package/dist/chunk-HMEVZKPQ.js +0 -9
- package/dist/chunk-HRGSYNLM.js +0 -3511
- package/dist/chunk-ISZR5N4K.js +0 -60
- package/dist/chunk-J6SUPR2C.js +0 -226
- package/dist/chunk-JERYVEIZ.js +0 -244
- package/dist/chunk-JHHWGL2N.js +0 -87
- package/dist/chunk-JONWQUB5.js +0 -775
- package/dist/chunk-K2DIWWDM.js +0 -1766
- package/dist/chunk-KY4PGL5V.js +0 -969
- package/dist/chunk-L737LQ4C.js +0 -1285
- package/dist/chunk-LFTWYIB2.js +0 -497
- package/dist/chunk-LV47RFNJ.js +0 -41
- package/dist/chunk-MKSAITI7.js +0 -15
- package/dist/chunk-MZ7RKIX4.js +0 -212
- package/dist/chunk-NAP6CFSO.js +0 -84
- package/dist/chunk-ND6MY37M.js +0 -16
- package/dist/chunk-NMG736UR.js +0 -683
- package/dist/chunk-NRAXROED.js +0 -32
- package/dist/chunk-NRIZR3A7.js +0 -690
- package/dist/chunk-NX43BG3M.js +0 -233
- package/dist/chunk-O645XLSI.js +0 -297
- package/dist/chunk-OMJD6A3S.js +0 -235
- package/dist/chunk-QB6SJD4T.js +0 -430
- package/dist/chunk-QFSTL4J3.js +0 -276
- package/dist/chunk-QLGDFMFX.js +0 -212
- package/dist/chunk-RIAAGL2E.js +0 -13
- package/dist/chunk-RWO5XMZ6.js +0 -86
- package/dist/chunk-RXRKBBSM.js +0 -149
- package/dist/chunk-RZOZMML6.js +0 -363
- package/dist/chunk-U7I7FS7T.js +0 -113
- package/dist/chunk-UI42RODY.js +0 -717
- package/dist/chunk-UTVMVSCO.js +0 -519
- package/dist/chunk-V6OJGLBA.js +0 -1746
- package/dist/chunk-W2JHVH7D.js +0 -152
- package/dist/chunk-WD3Y7VQN.js +0 -280
- package/dist/chunk-WOCTQ5MS.js +0 -303
- package/dist/chunk-WZR3ZUNN.js +0 -696
- package/dist/chunk-XGI665H7.js +0 -150
- package/dist/chunk-XKY65P2T.js +0 -304
- package/dist/chunk-Y4CQZY65.js +0 -57
- package/dist/chunk-YFEXKLVE.js +0 -194
- package/dist/chunk-YHO3HS5X.js +0 -287
- package/dist/chunk-YLS7AZSX.js +0 -738
- package/dist/chunk-ZE473AO6.js +0 -49
- package/dist/chunk-ZF747T3O.js +0 -644
- package/dist/chunk-ZHCZHZH3.js +0 -43
- package/dist/chunk-ZZNZX2XY.js +0 -87
- package/dist/constants-7QAP3VQ4.js +0 -23
- package/dist/dist-IY3UUMWK.js +0 -33
- package/dist/invariants-runner-W5RGHCSU.js +0 -27
- package/dist/lane-lock-6J36HD5O.js +0 -35
- package/dist/mem-checkpoint-core-EANG2GVN.js +0 -14
- package/dist/mem-signal-core-2LZ2WYHW.js +0 -19
- package/dist/memory-store-OLB5FO7K.js +0 -18
- package/dist/service-6BYCOCO5.js +0 -13
- package/dist/spawn-policy-resolver-NTSZYQ6R.js +0 -17
- package/dist/spawn-task-builder-R4E2BHSW.js +0 -22
- package/dist/wu-done-pr-WLFFFEPJ.js +0 -25
- package/dist/wu-done-validation-3J5E36FE.js +0 -30
- package/dist/wu-duplicate-id-detector-5S7JHELK.js +0 -232
- package/packs/sidekick/.turbo/turbo-typecheck.log +0 -4
- package/packs/software-delivery/.turbo/turbo-typecheck.log +0 -4
package/dist/chunk-K2DIWWDM.js
DELETED
|
@@ -1,1766 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
checkSizingAdvisory
|
|
3
|
-
} from "./chunk-DSYBDHYH.js";
|
|
4
|
-
import {
|
|
5
|
-
resolveStateDir
|
|
6
|
-
} from "./chunk-NRAXROED.js";
|
|
7
|
-
import {
|
|
8
|
-
isInWorktree
|
|
9
|
-
} from "./chunk-E3REJTAJ.js";
|
|
10
|
-
import {
|
|
11
|
-
SpawnStrategyFactory,
|
|
12
|
-
WUStateStore,
|
|
13
|
-
WU_BRIEF_EVIDENCE_NOTE_PREFIX,
|
|
14
|
-
WU_OPTIONS,
|
|
15
|
-
createWUParser,
|
|
16
|
-
formatDependencyError,
|
|
17
|
-
validateSpawnDependencies
|
|
18
|
-
} from "./chunk-2GXVIN57.js";
|
|
19
|
-
import {
|
|
20
|
-
SPAWN_END_SENTINEL,
|
|
21
|
-
TRUNCATION_WARNING_BANNER,
|
|
22
|
-
evaluateCondition,
|
|
23
|
-
formatSpawnRecordedMessage,
|
|
24
|
-
generateAgentCoordinationSection,
|
|
25
|
-
generateClientSkillsGuidance,
|
|
26
|
-
generateExecutionModeSection,
|
|
27
|
-
generateSkillsSelectionSection,
|
|
28
|
-
generateThinkToolGuidance,
|
|
29
|
-
loadTemplatesWithOverrides,
|
|
30
|
-
recordSpawnToRegistry,
|
|
31
|
-
replaceTokens,
|
|
32
|
-
resolveClientConfig,
|
|
33
|
-
validateSpawnArgs
|
|
34
|
-
} from "./chunk-6W5XHWYV.js";
|
|
35
|
-
import {
|
|
36
|
-
checkLaneLock,
|
|
37
|
-
getLockPolicyForLane,
|
|
38
|
-
getWipLimitForLane
|
|
39
|
-
} from "./chunk-JONWQUB5.js";
|
|
40
|
-
import {
|
|
41
|
-
createGitForPath
|
|
42
|
-
} from "./chunk-2UFQ3A3C.js";
|
|
43
|
-
import {
|
|
44
|
-
TEST_METHODOLOGY_HINTS,
|
|
45
|
-
classifyWork,
|
|
46
|
-
generateCodeCraftGuidance,
|
|
47
|
-
generateDesignContextSection,
|
|
48
|
-
generateEnforcementSummary,
|
|
49
|
-
generateMandatoryStandards,
|
|
50
|
-
generatePolicyBasedTestGuidance,
|
|
51
|
-
generateReadBeforeWriteDiscipline,
|
|
52
|
-
generateSelfReviewDirective
|
|
53
|
-
} from "./chunk-NMG736UR.js";
|
|
54
|
-
import {
|
|
55
|
-
INVARIANT_TYPES,
|
|
56
|
-
loadInvariants
|
|
57
|
-
} from "./chunk-EZ6ZBYBM.js";
|
|
58
|
-
import {
|
|
59
|
-
parseYAML
|
|
60
|
-
} from "./chunk-NRIZR3A7.js";
|
|
61
|
-
import {
|
|
62
|
-
WU_PATHS
|
|
63
|
-
} from "./chunk-6HO4GWJE.js";
|
|
64
|
-
import {
|
|
65
|
-
BRANCHES,
|
|
66
|
-
CONFIG_FILES,
|
|
67
|
-
DIRECTORIES,
|
|
68
|
-
EMOJI,
|
|
69
|
-
FILE_SYSTEM,
|
|
70
|
-
LUMENFLOW_PATHS,
|
|
71
|
-
PATTERNS,
|
|
72
|
-
REMOTES
|
|
73
|
-
} from "./chunk-DWMLTXKQ.js";
|
|
74
|
-
import {
|
|
75
|
-
WU_STATUS,
|
|
76
|
-
findProjectRoot,
|
|
77
|
-
getConfig,
|
|
78
|
-
resolvePolicy
|
|
79
|
-
} from "./chunk-V6OJGLBA.js";
|
|
80
|
-
import {
|
|
81
|
-
ErrorCodes,
|
|
82
|
-
createError,
|
|
83
|
-
die
|
|
84
|
-
} from "./chunk-RXRKBBSM.js";
|
|
85
|
-
|
|
86
|
-
// src/wu-spawn-strategy-resolver.ts
|
|
87
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
88
|
-
|
|
89
|
-
// ../core/dist/wu-spawn-context.js
|
|
90
|
-
import { existsSync, statSync } from "fs";
|
|
91
|
-
import path from "path";
|
|
92
|
-
var DEFAULT_MAX_SIZE = 4096;
|
|
93
|
-
var MEMORY_PATHS = {
|
|
94
|
-
MEMORY_DIR: LUMENFLOW_PATHS.MEMORY_DIR,
|
|
95
|
-
MEMORY_FILE: "memory.jsonl"
|
|
96
|
-
};
|
|
97
|
-
var MEMORY_CONTEXT_ERRORS = {
|
|
98
|
-
DEPRECATED_SPAWN_CONTEXT_MAX_SIZE: "memory.spawn_context_max_size is no longer supported. Use memory.delegation_context_max_size instead."
|
|
99
|
-
};
|
|
100
|
-
var MEMORY_CONTEXT_SECTION_HEADER = "## Memory Context";
|
|
101
|
-
async function checkMemoryLayerInitialized(baseDir) {
|
|
102
|
-
const memoryFilePath = path.join(baseDir, MEMORY_PATHS.MEMORY_DIR, MEMORY_PATHS.MEMORY_FILE);
|
|
103
|
-
if (!existsSync(memoryFilePath)) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
try {
|
|
107
|
-
const stats = statSync(memoryFilePath);
|
|
108
|
-
return stats.size > 0;
|
|
109
|
-
} catch {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
function getMemoryContextMaxSize(config) {
|
|
114
|
-
const memoryConfig = config;
|
|
115
|
-
if (memoryConfig?.memory?.spawn_context_max_size !== void 0) {
|
|
116
|
-
throw createError(ErrorCodes.DEPRECATED_API, MEMORY_CONTEXT_ERRORS.DEPRECATED_SPAWN_CONTEXT_MAX_SIZE);
|
|
117
|
-
}
|
|
118
|
-
return memoryConfig?.memory?.delegation_context_max_size ?? DEFAULT_MAX_SIZE;
|
|
119
|
-
}
|
|
120
|
-
function hasGenerateContext(module) {
|
|
121
|
-
if (!module || typeof module !== "object") {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
const candidate = module;
|
|
125
|
-
return typeof candidate.generateContext === "function";
|
|
126
|
-
}
|
|
127
|
-
async function callMemContextCore(baseDir, options) {
|
|
128
|
-
try {
|
|
129
|
-
const memoryModuleName = "@lumenflow/memory";
|
|
130
|
-
const memModule = await import(memoryModuleName);
|
|
131
|
-
if (!hasGenerateContext(memModule)) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
return await memModule.generateContext(baseDir, options);
|
|
135
|
-
} catch {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function formatForSpawnPrompt(contextBlock, wuId) {
|
|
140
|
-
if (!contextBlock || contextBlock.trim() === "") {
|
|
141
|
-
return "";
|
|
142
|
-
}
|
|
143
|
-
let content = contextBlock.replace(/^<!--\s*mem:context[^>]*-->\s*\n*/m, "");
|
|
144
|
-
content = content.replace(/^## /gm, "### ");
|
|
145
|
-
const header = `${MEMORY_CONTEXT_SECTION_HEADER}
|
|
146
|
-
|
|
147
|
-
`;
|
|
148
|
-
const intro = `Prior context from memory layer for ${wuId}:
|
|
149
|
-
|
|
150
|
-
`;
|
|
151
|
-
return header + intro + content.trim() + "\n";
|
|
152
|
-
}
|
|
153
|
-
async function generateMemoryContextSection(baseDir, options) {
|
|
154
|
-
const { wuId, lane, maxSize = DEFAULT_MAX_SIZE, sortByDecay = false, trackAccess = false, maxRecentSummaries, maxProjectNodes } = options;
|
|
155
|
-
const isInitialized = await checkMemoryLayerInitialized(baseDir);
|
|
156
|
-
if (!isInitialized) {
|
|
157
|
-
return "";
|
|
158
|
-
}
|
|
159
|
-
const result = await callMemContextCore(baseDir, {
|
|
160
|
-
wuId,
|
|
161
|
-
maxSize,
|
|
162
|
-
sortByDecay,
|
|
163
|
-
trackAccess,
|
|
164
|
-
lane,
|
|
165
|
-
maxRecentSummaries,
|
|
166
|
-
maxProjectNodes
|
|
167
|
-
});
|
|
168
|
-
if (!result) {
|
|
169
|
-
return "";
|
|
170
|
-
}
|
|
171
|
-
if (!result.success || result.stats.totalNodes === 0) {
|
|
172
|
-
return "";
|
|
173
|
-
}
|
|
174
|
-
return formatForSpawnPrompt(result.contextBlock, wuId);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/wu-spawn-prompt-builders.ts
|
|
178
|
-
import { existsSync as existsSync2 } from "fs";
|
|
179
|
-
import path2 from "path";
|
|
180
|
-
import { fileURLToPath } from "url";
|
|
181
|
-
import { minimatch } from "minimatch";
|
|
182
|
-
|
|
183
|
-
// src/wu-spawn-completion.ts
|
|
184
|
-
var COMPLETION_COMMANDS = {
|
|
185
|
-
GATES: "pnpm gates",
|
|
186
|
-
STATUS_PREFIX: "pnpm wu:status --id",
|
|
187
|
-
DONE_PREFIX: "pnpm wu:done --id",
|
|
188
|
-
RECOVER_PREFIX: "pnpm wu:recover --id"
|
|
189
|
-
};
|
|
190
|
-
var WU_STATUS_VALUES = {
|
|
191
|
-
DONE: "done",
|
|
192
|
-
IN_PROGRESS: "in_progress"
|
|
193
|
-
};
|
|
194
|
-
function formatWuCommand(commandPrefix, id) {
|
|
195
|
-
return `${commandPrefix} ${id}`;
|
|
196
|
-
}
|
|
197
|
-
function generateCompletionWorkflowSection(id) {
|
|
198
|
-
const statusCommand = formatWuCommand(COMPLETION_COMMANDS.STATUS_PREFIX, id);
|
|
199
|
-
const doneCommand = formatWuCommand(COMPLETION_COMMANDS.DONE_PREFIX, id);
|
|
200
|
-
const recoverCommand = formatWuCommand(COMPLETION_COMMANDS.RECOVER_PREFIX, id);
|
|
201
|
-
return `## Completion Workflow
|
|
202
|
-
|
|
203
|
-
**CRITICAL: Complete autonomously. Do NOT ask for permission.**
|
|
204
|
-
|
|
205
|
-
After all acceptance criteria are satisfied:
|
|
206
|
-
|
|
207
|
-
1. Run gates in the worktree: \`${COMPLETION_COMMANDS.GATES}\`
|
|
208
|
-
2. If gates pass, cd back to main checkout
|
|
209
|
-
3. Verify status from main: \`${statusCommand}\`
|
|
210
|
-
4. If status is \`${WU_STATUS_VALUES.DONE}\`, stop and report already completed.
|
|
211
|
-
do NOT run \`${doneCommand}\`.
|
|
212
|
-
do NOT run \`${recoverCommand}\`.
|
|
213
|
-
5. If status is \`${WU_STATUS_VALUES.IN_PROGRESS}\`, continue autonomously with \`${doneCommand}\`.
|
|
214
|
-
|
|
215
|
-
\`\`\`bash
|
|
216
|
-
# From worktree, after gates pass:
|
|
217
|
-
cd /path/to/main # NOT the worktree
|
|
218
|
-
${statusCommand}
|
|
219
|
-
|
|
220
|
-
# Status decision:
|
|
221
|
-
# - done: report already completed, stop.
|
|
222
|
-
# - in_progress: complete now.
|
|
223
|
-
${doneCommand}
|
|
224
|
-
\`\`\`
|
|
225
|
-
|
|
226
|
-
**wu:done** handles: merge to main, stamp creation, worktree cleanup.
|
|
227
|
-
|
|
228
|
-
**Do not ask** "should I run wu:done?" \u2014 just run it when gates pass.`;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// src/wu-spawn-prompt-builders.ts
|
|
232
|
-
var SPAWN_PROMPT_BUILDERS_DIR = path2.dirname(fileURLToPath(import.meta.url));
|
|
233
|
-
var DEFAULT_TEMPLATE_BASE_DIR = findProjectRoot(SPAWN_PROMPT_BUILDERS_DIR);
|
|
234
|
-
var DEFAULT_WORKTREES_DIR_SEGMENT = DIRECTORIES.WORKTREES.replace(/\/+$/g, "");
|
|
235
|
-
var PRIMARY_MAIN_REF = `${REMOTES.ORIGIN}/${BRANCHES.MAIN}`;
|
|
236
|
-
var LANE_GUIDANCE_TEMPLATE_ID_PREFIX = "lane-guidance-";
|
|
237
|
-
var DESIGN_CONTEXT_TEMPLATE_ID_PREFIX = "design-context-";
|
|
238
|
-
var VERIFICATION_TEMPLATE_ID_PREFIX = "verification-";
|
|
239
|
-
var REQUIRED_VERIFICATION_TEMPLATE_ID = "verification-requirements";
|
|
240
|
-
var VERIFICATION_TEMPLATE_IDS = /* @__PURE__ */ new Set([
|
|
241
|
-
"documentation-directive",
|
|
242
|
-
"visual-directive",
|
|
243
|
-
"refactor-directive",
|
|
244
|
-
"structured-content-directive"
|
|
245
|
-
]);
|
|
246
|
-
function normalizeDirectorySegment(value, fallback) {
|
|
247
|
-
const normalized = value.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
248
|
-
return normalized.length > 0 ? normalized : fallback;
|
|
249
|
-
}
|
|
250
|
-
function resolveWorktreesDirSegment(config) {
|
|
251
|
-
const configuredWorktreesDir = config?.directories.worktrees;
|
|
252
|
-
if (configuredWorktreesDir) {
|
|
253
|
-
return normalizeDirectorySegment(configuredWorktreesDir, DEFAULT_WORKTREES_DIR_SEGMENT);
|
|
254
|
-
}
|
|
255
|
-
return DEFAULT_WORKTREES_DIR_SEGMENT;
|
|
256
|
-
}
|
|
257
|
-
function resolveWorktreePathHint(doc, id, config) {
|
|
258
|
-
if (doc.worktree_path) {
|
|
259
|
-
return doc.worktree_path;
|
|
260
|
-
}
|
|
261
|
-
return `${resolveWorktreesDirSegment(config)}/<lane>-${id.toLowerCase()}`;
|
|
262
|
-
}
|
|
263
|
-
function resolveClaimWorktreePathHint(lane, id, config) {
|
|
264
|
-
const laneSlug = (lane || "unknown").toLowerCase().replace(/[:\s]+/g, "-").replace(/-+/g, "-");
|
|
265
|
-
return `${resolveWorktreesDirSegment(config)}/${laneSlug}-${id.toLowerCase()}`;
|
|
266
|
-
}
|
|
267
|
-
function usesNonTddHint(testMethodologyHint) {
|
|
268
|
-
return testMethodologyHint === TEST_METHODOLOGY_HINTS.SMOKE_TEST || testMethodologyHint === TEST_METHODOLOGY_HINTS.STRUCTURED_CONTENT;
|
|
269
|
-
}
|
|
270
|
-
function resolveLaneGuidanceSection(templates, lane) {
|
|
271
|
-
const templateSections = collectTemplateSections(
|
|
272
|
-
templates,
|
|
273
|
-
(id) => id.startsWith(LANE_GUIDANCE_TEMPLATE_ID_PREFIX)
|
|
274
|
-
);
|
|
275
|
-
if (templateSections.length > 0) {
|
|
276
|
-
return templateSections.join("\n\n---\n\n");
|
|
277
|
-
}
|
|
278
|
-
return generateLaneGuidance(lane);
|
|
279
|
-
}
|
|
280
|
-
function collectTemplateSections(templates, matcher) {
|
|
281
|
-
return Array.from(templates.entries()).filter(([id]) => matcher(id)).map(([, content]) => content.trim()).filter((content) => content.length > 0);
|
|
282
|
-
}
|
|
283
|
-
function resolveVerificationGuidanceSection(templates, fallback) {
|
|
284
|
-
const requiredVerificationSections = collectTemplateSections(
|
|
285
|
-
templates,
|
|
286
|
-
(id) => id === REQUIRED_VERIFICATION_TEMPLATE_ID
|
|
287
|
-
);
|
|
288
|
-
const strategySections = collectTemplateSections(
|
|
289
|
-
templates,
|
|
290
|
-
(id) => id !== REQUIRED_VERIFICATION_TEMPLATE_ID && (id.startsWith("methodology-") || id.startsWith(VERIFICATION_TEMPLATE_ID_PREFIX) || VERIFICATION_TEMPLATE_IDS.has(id))
|
|
291
|
-
);
|
|
292
|
-
const templateSections = [...requiredVerificationSections, ...strategySections];
|
|
293
|
-
if (templateSections.length > 0) {
|
|
294
|
-
return templateSections.join("\n\n---\n\n");
|
|
295
|
-
}
|
|
296
|
-
return fallback;
|
|
297
|
-
}
|
|
298
|
-
function resolveDesignContextSection(templates, classification) {
|
|
299
|
-
const templateSections = collectTemplateSections(
|
|
300
|
-
templates,
|
|
301
|
-
(id) => id.startsWith(DESIGN_CONTEXT_TEMPLATE_ID_PREFIX)
|
|
302
|
-
);
|
|
303
|
-
if (templateSections.length > 0) {
|
|
304
|
-
return templateSections.join("\n\n---\n\n");
|
|
305
|
-
}
|
|
306
|
-
return generateDesignContextSection(classification);
|
|
307
|
-
}
|
|
308
|
-
var MANDATORY_TRIGGERS = {
|
|
309
|
-
// No mandatory triggers for LumenFlow framework development.
|
|
310
|
-
};
|
|
311
|
-
function detectMandatoryAgents(codePaths) {
|
|
312
|
-
if (!codePaths || codePaths.length === 0) {
|
|
313
|
-
return [];
|
|
314
|
-
}
|
|
315
|
-
const triggeredAgents = /* @__PURE__ */ new Set();
|
|
316
|
-
for (const [agentName, patterns] of Object.entries(MANDATORY_TRIGGERS)) {
|
|
317
|
-
const isTriggered = codePaths.some(
|
|
318
|
-
(filePath) => patterns.some((pattern) => minimatch(filePath, pattern))
|
|
319
|
-
);
|
|
320
|
-
if (isTriggered) {
|
|
321
|
-
triggeredAgents.add(agentName);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return Array.from(triggeredAgents);
|
|
325
|
-
}
|
|
326
|
-
function formatAcceptance(acceptance) {
|
|
327
|
-
if (!acceptance || acceptance.length === 0) {
|
|
328
|
-
return "- No acceptance criteria defined";
|
|
329
|
-
}
|
|
330
|
-
return acceptance.map((item) => `- [ ] ${item}`).join("\n");
|
|
331
|
-
}
|
|
332
|
-
function formatSpecRefs(specRefs) {
|
|
333
|
-
if (!specRefs || specRefs.length === 0) {
|
|
334
|
-
return "";
|
|
335
|
-
}
|
|
336
|
-
return specRefs.map((ref) => `- ${ref}`).join("\n");
|
|
337
|
-
}
|
|
338
|
-
function formatRisks(risks) {
|
|
339
|
-
if (!risks || risks.length === 0) {
|
|
340
|
-
return "";
|
|
341
|
-
}
|
|
342
|
-
return risks.map((risk) => `- ${risk}`).join("\n");
|
|
343
|
-
}
|
|
344
|
-
function formatManualTests(manualTests) {
|
|
345
|
-
if (!manualTests || manualTests.length === 0) {
|
|
346
|
-
return "";
|
|
347
|
-
}
|
|
348
|
-
return manualTests.map((test) => `- [ ] ${test}`).join("\n");
|
|
349
|
-
}
|
|
350
|
-
function formatTestPaths(testPaths) {
|
|
351
|
-
if (!testPaths || testPaths.length === 0) {
|
|
352
|
-
return "";
|
|
353
|
-
}
|
|
354
|
-
return testPaths.map((testPath) => `- \`${testPath}\``).join("\n");
|
|
355
|
-
}
|
|
356
|
-
function formatRequiredVerification(doc) {
|
|
357
|
-
const sections = [];
|
|
358
|
-
const unitTests = formatTestPaths(doc.tests?.unit);
|
|
359
|
-
if (unitTests) {
|
|
360
|
-
sections.push(`### Unit Test Paths
|
|
361
|
-
|
|
362
|
-
${unitTests}`);
|
|
363
|
-
}
|
|
364
|
-
const e2eTests = formatTestPaths(doc.tests?.e2e);
|
|
365
|
-
if (e2eTests) {
|
|
366
|
-
sections.push(`### E2E Test Paths
|
|
367
|
-
|
|
368
|
-
${e2eTests}`);
|
|
369
|
-
}
|
|
370
|
-
const manualTests = formatManualTests(doc.tests?.manual);
|
|
371
|
-
if (manualTests) {
|
|
372
|
-
sections.push(`### Manual Verification
|
|
373
|
-
|
|
374
|
-
${manualTests}`);
|
|
375
|
-
}
|
|
376
|
-
return sections.join("\n\n");
|
|
377
|
-
}
|
|
378
|
-
function generateRequiredVerificationSection(doc) {
|
|
379
|
-
const requiredVerification = formatRequiredVerification(doc);
|
|
380
|
-
if (!requiredVerification) {
|
|
381
|
-
return "";
|
|
382
|
-
}
|
|
383
|
-
return `## Required Verification From WU Spec
|
|
384
|
-
|
|
385
|
-
${requiredVerification}`;
|
|
386
|
-
}
|
|
387
|
-
function generateImplementationContext(doc) {
|
|
388
|
-
const sections = [];
|
|
389
|
-
const refs = formatSpecRefs(doc.spec_refs);
|
|
390
|
-
if (refs) {
|
|
391
|
-
sections.push(`## References
|
|
392
|
-
|
|
393
|
-
${refs}`);
|
|
394
|
-
}
|
|
395
|
-
if (doc.notes && doc.notes.trim()) {
|
|
396
|
-
sections.push(`## Implementation Notes
|
|
397
|
-
|
|
398
|
-
${doc.notes.trim()}`);
|
|
399
|
-
}
|
|
400
|
-
const risks = formatRisks(doc.risks);
|
|
401
|
-
if (risks) {
|
|
402
|
-
sections.push(`## Risks
|
|
403
|
-
|
|
404
|
-
${risks}`);
|
|
405
|
-
}
|
|
406
|
-
if (sections.length === 0) {
|
|
407
|
-
return "";
|
|
408
|
-
}
|
|
409
|
-
return sections.join("\n\n---\n\n");
|
|
410
|
-
}
|
|
411
|
-
function codePathMatchesInvariant(invariant, codePaths) {
|
|
412
|
-
switch (invariant.type) {
|
|
413
|
-
case INVARIANT_TYPES.FORBIDDEN_FILE:
|
|
414
|
-
case INVARIANT_TYPES.REQUIRED_FILE: {
|
|
415
|
-
const invariantPath = invariant.path;
|
|
416
|
-
if (!invariantPath) {
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
return codePaths.some(
|
|
420
|
-
(p) => p === invariantPath || minimatch(p, invariantPath) || minimatch(invariantPath, p)
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
case INVARIANT_TYPES.MUTUAL_EXCLUSIVITY: {
|
|
424
|
-
const invariantPaths = invariant.paths;
|
|
425
|
-
if (!invariantPaths || invariantPaths.length === 0) {
|
|
426
|
-
return false;
|
|
427
|
-
}
|
|
428
|
-
return codePaths.some(
|
|
429
|
-
(p) => invariantPaths.some((invPath) => p === invPath || minimatch(p, invPath))
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
case INVARIANT_TYPES.FORBIDDEN_PATTERN:
|
|
433
|
-
case INVARIANT_TYPES.REQUIRED_PATTERN:
|
|
434
|
-
return invariant.scope?.some(
|
|
435
|
-
(scopePattern) => codePaths.some((p) => minimatch(p, scopePattern))
|
|
436
|
-
) ?? false;
|
|
437
|
-
// WU-2254: forbidden-import uses 'from' glob instead of 'scope'
|
|
438
|
-
case INVARIANT_TYPES.FORBIDDEN_IMPORT:
|
|
439
|
-
return invariant.from ? codePaths.some((p) => minimatch(p, invariant.from)) : false;
|
|
440
|
-
default:
|
|
441
|
-
return false;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
function formatInvariantForOutput(inv) {
|
|
445
|
-
const lines = [`### ${inv.id} (${inv.type})`, "", inv.description, ""];
|
|
446
|
-
if (inv.message) {
|
|
447
|
-
lines.push(`**Action:** ${inv.message}`, "");
|
|
448
|
-
}
|
|
449
|
-
if (inv.path) {
|
|
450
|
-
lines.push(`**Path:** \`${inv.path}\``);
|
|
451
|
-
}
|
|
452
|
-
if (inv.paths) {
|
|
453
|
-
const formattedPaths = inv.paths.map((p) => `\`${p}\``).join(", ");
|
|
454
|
-
lines.push(`**Paths:** ${formattedPaths}`);
|
|
455
|
-
}
|
|
456
|
-
if (inv.from) {
|
|
457
|
-
lines.push(`**From:** \`${inv.from}\``);
|
|
458
|
-
}
|
|
459
|
-
if (inv.cannot_import && Array.isArray(inv.cannot_import)) {
|
|
460
|
-
const formattedImports = inv.cannot_import.map((m) => `\`${m}\``).join(", ");
|
|
461
|
-
lines.push(`**Cannot Import:** ${formattedImports}`);
|
|
462
|
-
}
|
|
463
|
-
if (inv.pattern && (inv.type === INVARIANT_TYPES.REQUIRED_PATTERN || inv.type === INVARIANT_TYPES.FORBIDDEN_PATTERN)) {
|
|
464
|
-
lines.push(`**Pattern:** \`${inv.pattern}\``);
|
|
465
|
-
}
|
|
466
|
-
if (inv.scope && Array.isArray(inv.scope)) {
|
|
467
|
-
const formattedScope = inv.scope.map((s) => `\`${s}\``).join(", ");
|
|
468
|
-
lines.push(`**Scope:** ${formattedScope}`);
|
|
469
|
-
}
|
|
470
|
-
lines.push("");
|
|
471
|
-
return lines;
|
|
472
|
-
}
|
|
473
|
-
function generateInvariantsPriorArtSection(codePaths) {
|
|
474
|
-
if (!codePaths || codePaths.length === 0) {
|
|
475
|
-
return "";
|
|
476
|
-
}
|
|
477
|
-
const invariantsPath = path2.resolve("tools/invariants.yml");
|
|
478
|
-
if (!existsSync2(invariantsPath)) {
|
|
479
|
-
return "";
|
|
480
|
-
}
|
|
481
|
-
let invariants;
|
|
482
|
-
try {
|
|
483
|
-
invariants = loadInvariants(invariantsPath);
|
|
484
|
-
} catch {
|
|
485
|
-
return "";
|
|
486
|
-
}
|
|
487
|
-
if (!invariants || invariants.length === 0) {
|
|
488
|
-
return "";
|
|
489
|
-
}
|
|
490
|
-
const relevantInvariants = invariants.filter((inv) => codePathMatchesInvariant(inv, codePaths));
|
|
491
|
-
if (relevantInvariants.length === 0) {
|
|
492
|
-
return "";
|
|
493
|
-
}
|
|
494
|
-
const lines = [
|
|
495
|
-
"## Invariants/Prior-Art (WU-2252)",
|
|
496
|
-
"",
|
|
497
|
-
"The following repo invariants are relevant to your code_paths:",
|
|
498
|
-
"",
|
|
499
|
-
...relevantInvariants.flatMap(formatInvariantForOutput),
|
|
500
|
-
"**IMPORTANT:** Do not create specs or acceptance criteria that conflict with these invariants."
|
|
501
|
-
];
|
|
502
|
-
return lines.join("\n");
|
|
503
|
-
}
|
|
504
|
-
function generatePreamble(id, strategy) {
|
|
505
|
-
return strategy.getPreamble(id);
|
|
506
|
-
}
|
|
507
|
-
function generateConstraints(id, options) {
|
|
508
|
-
const includeTdd = options?.includeTddCheckpoint !== false;
|
|
509
|
-
const tddCheckpointBlock = includeTdd ? `
|
|
510
|
-
1. TDD CHECKPOINT (VERIFY BEFORE IMPLEMENTATION)
|
|
511
|
-
- Did you write tests BEFORE implementation?
|
|
512
|
-
- Is there at least one failing test for each acceptance criterion?
|
|
513
|
-
- Never skip the RED phase \u2014 failing tests prove the test works
|
|
514
|
-
|
|
515
|
-
` : "";
|
|
516
|
-
const antiLoopNum = includeTdd ? 2 : 1;
|
|
517
|
-
const stopAskNum = includeTdd ? 3 : 2;
|
|
518
|
-
const verifyNum = includeTdd ? 4 : 3;
|
|
519
|
-
const neverFabNum = includeTdd ? 5 : 4;
|
|
520
|
-
const gitNum = includeTdd ? 6 : 5;
|
|
521
|
-
const memNum = includeTdd ? 7 : 6;
|
|
522
|
-
const skipGatesNum = includeTdd ? 8 : 7;
|
|
523
|
-
return `---
|
|
524
|
-
|
|
525
|
-
<constraints>
|
|
526
|
-
CRITICAL RULES - ENFORCE BEFORE EVERY ACTION:
|
|
527
|
-
${tddCheckpointBlock}${antiLoopNum}. ANTI-LOOP GUARD (LumenFlow \xA77.3)
|
|
528
|
-
- Max 3 attempts per unique error before escalating
|
|
529
|
-
- If same error repeats 3x, STOP and report with full context
|
|
530
|
-
- Retry with different approach, not same command
|
|
531
|
-
|
|
532
|
-
${stopAskNum}. STOP-AND-ASK TRIGGERS (LumenFlow \xA77.2 - narrow scope)
|
|
533
|
-
- Policy changes, auth/permissions modifications
|
|
534
|
-
- PII/safety issues, cloud spend, secrets, backups
|
|
535
|
-
- Same error repeats 3x
|
|
536
|
-
- For ordinary errors: fix and retry autonomously (up to 3 attempts)
|
|
537
|
-
|
|
538
|
-
${verifyNum}. VERIFY COMPLETION before reporting success
|
|
539
|
-
- Run: node packages/@lumenflow/agent/dist/agent-verification.js ${id} (from shared checkout)
|
|
540
|
-
- Exit 0 = passed, Exit 1 = INCOMPLETE
|
|
541
|
-
- Never report "done" if verification fails
|
|
542
|
-
|
|
543
|
-
${neverFabNum}. NEVER FABRICATE COMPLETION
|
|
544
|
-
- If blockers remain, report INCOMPLETE
|
|
545
|
-
- If verification fails, summarize failures
|
|
546
|
-
- Honesty over false completion
|
|
547
|
-
|
|
548
|
-
${gitNum}. GIT WORKFLOW (CRITICAL - GitHub rules reject merge commits)
|
|
549
|
-
- GitHub REJECTS merge commits on main
|
|
550
|
-
- ALWAYS use \`git rebase ${PRIMARY_MAIN_REF}\` before push
|
|
551
|
-
- Push to main via \`git push origin lane/...:main\` (fast-forward only)
|
|
552
|
-
- NEVER use \`git merge\` on main branch
|
|
553
|
-
- Let \`pnpm wu:done\` handle the merge workflow
|
|
554
|
-
|
|
555
|
-
${memNum}. MEMORY LAYER COORDINATION (INIT-007)
|
|
556
|
-
- Use \`pnpm mem:checkpoint --wu ${id}\` to save progress before risky operations
|
|
557
|
-
- Check \`pnpm mem:inbox --wu ${id}\` periodically for parallel signals from other agents
|
|
558
|
-
- Checkpoint triggers (WU-1943): checkpoint after each acceptance criterion completed, checkpoint before gates, checkpoint every 30 tool calls
|
|
559
|
-
|
|
560
|
-
${skipGatesNum}. SKIP-GATES AUTONOMY (WU-1142)
|
|
561
|
-
- If gates fail, first check if failure is pre-existing on main: \`git checkout main && pnpm gates\`
|
|
562
|
-
- If failure exists on main (not your change), use: \`pnpm wu:done --id ${id} --skip-gates --reason "pre-existing on main" --fix-wu WU-XXXX\`
|
|
563
|
-
- Do NOT ask for approval - autonomous skip-gates for pre-existing failures is correct
|
|
564
|
-
- This prevents getting stuck on infrastructure debt
|
|
565
|
-
</constraints>`;
|
|
566
|
-
}
|
|
567
|
-
function generateCodexConstraints(id, options) {
|
|
568
|
-
const includeTdd = options?.includeTddCheckpoint !== false;
|
|
569
|
-
const tddLine = includeTdd ? "1. **TDD checkpoint**: tests BEFORE implementation; never skip RED" : "";
|
|
570
|
-
const stopNum = includeTdd ? 2 : 1;
|
|
571
|
-
const verifyNum = includeTdd ? 3 : 2;
|
|
572
|
-
const fabricateNum = includeTdd ? 4 : 3;
|
|
573
|
-
const gitNum = includeTdd ? 5 : 4;
|
|
574
|
-
const scopeNum = includeTdd ? 6 : 5;
|
|
575
|
-
const skipGatesNum = includeTdd ? 7 : 6;
|
|
576
|
-
return `## Constraints (Critical)
|
|
577
|
-
|
|
578
|
-
${tddLine}${tddLine ? "\n" : ""}${stopNum}. **Stop on errors**: if UnsafeAny command fails, report BLOCKED (never DONE) with the error
|
|
579
|
-
${verifyNum}. **Verify before success**: run \`pnpm gates\` in the worktree, then run \`node packages/@lumenflow/agent/dist/agent-verification.js ${id}\` (from the shared checkout)
|
|
580
|
-
${fabricateNum}. **No fabrication**: if blockers remain or verification fails, report INCOMPLETE
|
|
581
|
-
${gitNum}. **Git workflow**: avoid merge commits; let \`pnpm wu:done\` handle completion
|
|
582
|
-
${scopeNum}. **Scope discipline**: stay within \`code_paths\`; capture out-of-scope issues via \`pnpm mem:create\`
|
|
583
|
-
${skipGatesNum}. **Skip-gates for pre-existing**: if gates fail due to pre-existing issue on main, use \`--skip-gates --reason "pre-existing" --fix-wu WU-XXX\``;
|
|
584
|
-
}
|
|
585
|
-
function generateMandatoryAgentSection(mandatoryAgents, _id) {
|
|
586
|
-
if (mandatoryAgents.length === 0) {
|
|
587
|
-
return "";
|
|
588
|
-
}
|
|
589
|
-
const agentList = mandatoryAgents.map((agent) => ` - ${agent}`).join("\n");
|
|
590
|
-
return `
|
|
591
|
-
## Mandatory Agents (MUST invoke before wu:done)
|
|
592
|
-
|
|
593
|
-
Based on code_paths, the following agents MUST be invoked:
|
|
594
|
-
|
|
595
|
-
${agentList}
|
|
596
|
-
|
|
597
|
-
Run: pnpm orchestrate:monitor to check agent status
|
|
598
|
-
`;
|
|
599
|
-
}
|
|
600
|
-
function generateEffortScalingRules() {
|
|
601
|
-
return `## Effort Scaling (When to Spawn Sub-Agents)
|
|
602
|
-
|
|
603
|
-
Use this heuristic to decide complexity:
|
|
604
|
-
|
|
605
|
-
| Complexity | Approach | Tool Calls |
|
|
606
|
-
|------------|----------|------------|
|
|
607
|
-
| **Simple** (single file, <50 lines) | Handle inline | 3-10 |
|
|
608
|
-
| **Moderate** (2-3 files, clear scope) | Handle inline | 10-20 |
|
|
609
|
-
| **Complex** (4+ files, exploration needed) | Spawn Explore agent first | 20+ |
|
|
610
|
-
| **Multi-domain** (cross-cutting concerns) | Spawn specialized sub-agents | Varies |
|
|
611
|
-
|
|
612
|
-
**Rule**: If you need >30 tool calls for a subtask, consider spawning a sub-agent with a focused scope.`;
|
|
613
|
-
}
|
|
614
|
-
function generateParallelToolCallGuidance() {
|
|
615
|
-
return `## Parallel Tool Calls (Performance)
|
|
616
|
-
|
|
617
|
-
**IMPORTANT**: Make 3+ tool calls in parallel when operations are independent.
|
|
618
|
-
|
|
619
|
-
Good examples:
|
|
620
|
-
- Reading multiple files simultaneously
|
|
621
|
-
- Running independent grep searches
|
|
622
|
-
- Spawning multiple Explore agents for different areas
|
|
623
|
-
|
|
624
|
-
Bad examples:
|
|
625
|
-
- Reading a file then editing it (sequential dependency)
|
|
626
|
-
- Running tests then checking results (sequential)
|
|
627
|
-
|
|
628
|
-
Parallelism reduces latency by 50-90% for complex tasks.`;
|
|
629
|
-
}
|
|
630
|
-
function generateIterativeSearchHeuristics() {
|
|
631
|
-
return `## Search Strategy (Broad to Narrow)
|
|
632
|
-
|
|
633
|
-
When exploring the codebase:
|
|
634
|
-
|
|
635
|
-
1. **Start broad**: Use Explore agent or glob patterns to understand structure
|
|
636
|
-
2. **Evaluate findings**: What patterns exist? What's relevant?
|
|
637
|
-
3. **Narrow focus**: Target specific files/functions based on findings
|
|
638
|
-
4. **Iterate**: Refine if initial approach misses the target
|
|
639
|
-
|
|
640
|
-
Avoid: Jumping directly to specific file edits without understanding context.`;
|
|
641
|
-
}
|
|
642
|
-
function generateTokenBudgetAwareness(id) {
|
|
643
|
-
return `## Token Budget Awareness
|
|
644
|
-
|
|
645
|
-
Context limit is ~200K tokens. Monitor your usage:
|
|
646
|
-
|
|
647
|
-
- **At 50+ tool calls**: Create a checkpoint (\`pnpm mem:checkpoint --wu ${id}\`)
|
|
648
|
-
- **At 100+ tool calls**: Consider spawning fresh sub-agent with focused scope
|
|
649
|
-
- **Before risky operations**: Always checkpoint first
|
|
650
|
-
|
|
651
|
-
If approaching limits, summarize progress and spawn continuation agent.`;
|
|
652
|
-
}
|
|
653
|
-
function generateCompletionFormat(_id) {
|
|
654
|
-
return `## Completion Report Format
|
|
655
|
-
|
|
656
|
-
When finishing, provide structured output:
|
|
657
|
-
|
|
658
|
-
\`\`\`
|
|
659
|
-
## Summary
|
|
660
|
-
<1-3 sentences describing what was accomplished>
|
|
661
|
-
|
|
662
|
-
## Artifacts
|
|
663
|
-
- Files modified: <list>
|
|
664
|
-
- Tests added: <list>
|
|
665
|
-
- Documentation updated: <list>
|
|
666
|
-
|
|
667
|
-
## Verification
|
|
668
|
-
- Gates: <pass/fail>
|
|
669
|
-
- Tests: <X passing, Y failing>
|
|
670
|
-
|
|
671
|
-
## Blockers (if UnsafeAny)
|
|
672
|
-
- <blocker description>
|
|
673
|
-
|
|
674
|
-
## Follow-up (if needed)
|
|
675
|
-
- <suggested next WU or action>
|
|
676
|
-
\`\`\`
|
|
677
|
-
|
|
678
|
-
This format enables orchestrator to track progress across waves.`;
|
|
679
|
-
}
|
|
680
|
-
function generateQuickFixCommands() {
|
|
681
|
-
return `## Quick Fix Commands
|
|
682
|
-
|
|
683
|
-
If gates fail, try these before investigating:
|
|
684
|
-
|
|
685
|
-
\`\`\`bash
|
|
686
|
-
pnpm format # Auto-fix formatting issues
|
|
687
|
-
pnpm lint # Check linting (use --fix for auto-fix)
|
|
688
|
-
pnpm typecheck # Check TypeScript types
|
|
689
|
-
\`\`\`
|
|
690
|
-
|
|
691
|
-
**Use before gates** to catch simple issues early. These are faster than full \`pnpm gates\`.`;
|
|
692
|
-
}
|
|
693
|
-
function generateWorktreeBlockRecoverySection(worktreePath, config) {
|
|
694
|
-
const worktreePathHint = worktreePath || `${resolveWorktreesDirSegment(config)}/<lane>-wu-xxx`;
|
|
695
|
-
return `## When Blocked by Worktree Hook
|
|
696
|
-
|
|
697
|
-
If you encounter a "worktree required" or "commit blocked" error:
|
|
698
|
-
|
|
699
|
-
1. **Check existing worktrees**: \`git worktree list\`
|
|
700
|
-
2. **Navigate to the worktree**: \`cd ${worktreePathHint}\`
|
|
701
|
-
3. **Retry your operation** from within the worktree
|
|
702
|
-
4. **Use relative paths only** (never absolute paths starting with /)
|
|
703
|
-
|
|
704
|
-
### Common Causes
|
|
705
|
-
|
|
706
|
-
- Running \`git commit\` from main checkout instead of worktree
|
|
707
|
-
- Using absolute paths that bypass worktree isolation
|
|
708
|
-
- Forgetting to \`cd\` to worktree after \`wu:claim\`
|
|
709
|
-
|
|
710
|
-
### Quick Fix
|
|
711
|
-
|
|
712
|
-
\`\`\`bash
|
|
713
|
-
# Check where you are
|
|
714
|
-
pwd
|
|
715
|
-
git worktree list
|
|
716
|
-
|
|
717
|
-
# Navigate to your worktree
|
|
718
|
-
cd ${worktreePathHint}
|
|
719
|
-
|
|
720
|
-
# Retry your commit
|
|
721
|
-
git add . && git commit -m "your message"
|
|
722
|
-
\`\`\``;
|
|
723
|
-
}
|
|
724
|
-
function generateLaneSelectionSection(laneInferencePath = CONFIG_FILES.LANE_INFERENCE) {
|
|
725
|
-
return `## Lane Selection
|
|
726
|
-
|
|
727
|
-
When creating new WUs, use the correct lane to enable parallelization:
|
|
728
|
-
|
|
729
|
-
\`\`\`bash
|
|
730
|
-
# Get lane suggestion based on code paths and description
|
|
731
|
-
pnpm wu:infer-lane --id WU-XXX
|
|
732
|
-
|
|
733
|
-
# Or infer from manual inputs
|
|
734
|
-
pnpm wu:infer-lane --paths "tools/**" --desc "CLI improvements"
|
|
735
|
-
\`\`\`
|
|
736
|
-
|
|
737
|
-
**Lane taxonomy**: See \`${laneInferencePath}\` for valid lanes and patterns.
|
|
738
|
-
|
|
739
|
-
**Why lanes matter**: WIP=1 per lane means correct lane selection enables parallel work across lanes.`;
|
|
740
|
-
}
|
|
741
|
-
function generateWorktreePathGuidance(worktreePath) {
|
|
742
|
-
if (!worktreePath) {
|
|
743
|
-
return "";
|
|
744
|
-
}
|
|
745
|
-
return `## Worktree Path Guidance (WU-2362)
|
|
746
|
-
|
|
747
|
-
**Your worktree:** \`${worktreePath}\`
|
|
748
|
-
|
|
749
|
-
### Finding the Worktree Root
|
|
750
|
-
|
|
751
|
-
Sub-agents may inherit the parent's cwd (main checkout). To find the actual worktree root:
|
|
752
|
-
|
|
753
|
-
\`\`\`bash
|
|
754
|
-
# Get the worktree root (not main checkout)
|
|
755
|
-
git rev-parse --show-toplevel
|
|
756
|
-
\`\`\`
|
|
757
|
-
|
|
758
|
-
### Stamp Creation
|
|
759
|
-
|
|
760
|
-
When creating \`.lumenflow/\` stamps or other artifacts:
|
|
761
|
-
|
|
762
|
-
1. **ALWAYS** create stamps in the **worktree**, not main
|
|
763
|
-
2. Use \`git rev-parse --show-toplevel\` to get the correct base path
|
|
764
|
-
3. Stamps created on main will be lost when the worktree merges
|
|
765
|
-
|
|
766
|
-
\`\`\`bash
|
|
767
|
-
# CORRECT: Create stamp in worktree
|
|
768
|
-
WORKTREE_ROOT=$(git rev-parse --show-toplevel)
|
|
769
|
-
mkdir -p "$WORKTREE_ROOT/.lumenflow/agent-runs"
|
|
770
|
-
touch "$WORKTREE_ROOT/.lumenflow/agent-runs/code-reviewer.stamp"
|
|
771
|
-
|
|
772
|
-
# WRONG: Hardcoded path to main
|
|
773
|
-
# touch /path/to/main/.lumenflow/agent-runs/code-reviewer.stamp
|
|
774
|
-
\`\`\`
|
|
775
|
-
|
|
776
|
-
### Why This Matters
|
|
777
|
-
|
|
778
|
-
- Stamps on main get overwritten by worktree merge
|
|
779
|
-
- \`wu:done\` validates stamps exist in the worktree branch
|
|
780
|
-
- Parallel WUs in other lanes won't see your stamps if on main`;
|
|
781
|
-
}
|
|
782
|
-
function generateBugDiscoverySection(id) {
|
|
783
|
-
return `## Bug Discovery (Mid-WU Issue Capture)
|
|
784
|
-
|
|
785
|
-
If you discover a bug or issue **outside the scope of this WU**:
|
|
786
|
-
|
|
787
|
-
1. **Capture it immediately** using:
|
|
788
|
-
\`\`\`bash
|
|
789
|
-
pnpm mem:create 'Bug: <description>' --type discovery --tags bug,scope-creep --wu ${id}
|
|
790
|
-
\`\`\`
|
|
791
|
-
|
|
792
|
-
2. **Continue with your WU** \u2014 do not fix bugs outside your scope
|
|
793
|
-
3. **Reference in notes** \u2014 mention the mem node ID in your completion notes
|
|
794
|
-
|
|
795
|
-
### NEVER use wu:create for discovered issues
|
|
796
|
-
|
|
797
|
-
**Do NOT use \`wu:create\` directly for bugs discovered mid-WU.**
|
|
798
|
-
|
|
799
|
-
- \`mem:create\` = **capture** (immediate, no human approval needed)
|
|
800
|
-
- \`wu:create\` = **planned work** (requires human triage and approval)
|
|
801
|
-
|
|
802
|
-
Discovered issues MUST go through human triage before becoming WUs.
|
|
803
|
-
Using \`wu:create\` directly bypasses the triage workflow and creates
|
|
804
|
-
unreviewed work items.
|
|
805
|
-
|
|
806
|
-
### When to Capture
|
|
807
|
-
|
|
808
|
-
- Found a bug in code NOT in your \`code_paths\`
|
|
809
|
-
- Discovered an issue that would require >10 lines to fix
|
|
810
|
-
- Encountered broken behaviour unrelated to your acceptance criteria
|
|
811
|
-
|
|
812
|
-
### Triage Workflow
|
|
813
|
-
|
|
814
|
-
After WU completion, bugs can be promoted to Bug WUs by humans:
|
|
815
|
-
\`\`\`bash
|
|
816
|
-
pnpm mem:triage --wu ${id} # List discoveries for this WU
|
|
817
|
-
pnpm mem:triage --promote <node-id> --lane "<lane>" # Create Bug WU (human action)
|
|
818
|
-
\`\`\`
|
|
819
|
-
|
|
820
|
-
See: https://lumenflow.dev/reference/agent-invocation-guide/ \xA7Bug Discovery`;
|
|
821
|
-
}
|
|
822
|
-
function generateLaneGuidance(lane) {
|
|
823
|
-
if (!lane) return "";
|
|
824
|
-
const laneParent = lane.split(":")[0].trim();
|
|
825
|
-
const guidance = {
|
|
826
|
-
Operations: `## Lane-Specific: Tooling
|
|
827
|
-
|
|
828
|
-
- Update tool documentation in tools/README.md or relevant docs if adding new CLI commands`,
|
|
829
|
-
Intelligence: `## Lane-Specific: Intelligence
|
|
830
|
-
|
|
831
|
-
- For prompt/classification work, run the project-specific evaluation command defined by your local templates/config
|
|
832
|
-
- Follow prompt versioning guidelines documented for this project`,
|
|
833
|
-
Experience: `## Lane-Specific: Experience
|
|
834
|
-
|
|
835
|
-
- Follow design system tokens defined in the project
|
|
836
|
-
- Ensure accessibility compliance (WCAG 2.1 AA)`,
|
|
837
|
-
Core: `## Lane-Specific: Core
|
|
838
|
-
|
|
839
|
-
- Maintain hexagonal architecture boundaries
|
|
840
|
-
- Update domain model documentation if changing entities`
|
|
841
|
-
};
|
|
842
|
-
return guidance[laneParent] || "";
|
|
843
|
-
}
|
|
844
|
-
function generateActionSection(doc, id, config) {
|
|
845
|
-
const isAlreadyClaimed = doc.claimed_at && doc.worktree_path;
|
|
846
|
-
if (isAlreadyClaimed) {
|
|
847
|
-
return `This WU is already claimed. Continue implementation in worktree following all standards above.
|
|
848
|
-
|
|
849
|
-
cd ${doc.worktree_path}`;
|
|
850
|
-
}
|
|
851
|
-
const claimWorktreePathHint = resolveClaimWorktreePathHint(doc.lane, id, config);
|
|
852
|
-
return `**FIRST: Claim this WU before starting work:**
|
|
853
|
-
|
|
854
|
-
\`\`\`bash
|
|
855
|
-
pnpm wu:claim --id ${id} --lane "${doc.lane}"
|
|
856
|
-
cd ${claimWorktreePathHint}
|
|
857
|
-
\`\`\`
|
|
858
|
-
|
|
859
|
-
Then implement following all standards above.
|
|
860
|
-
|
|
861
|
-
**CRITICAL:** Never use \`git worktree add\` directly. Always use \`pnpm wu:claim\` to ensure:
|
|
862
|
-
- Event tracking in ${LUMENFLOW_PATHS.WU_EVENTS}
|
|
863
|
-
- Lane lock acquisition (WIP=1 enforcement)
|
|
864
|
-
- Session tracking for context recovery`;
|
|
865
|
-
}
|
|
866
|
-
function generateCompletionWorkflowSection2(id) {
|
|
867
|
-
return generateCompletionWorkflowSection(id);
|
|
868
|
-
}
|
|
869
|
-
function generateClientBlocksSection(clientContext) {
|
|
870
|
-
if (!clientContext?.config?.blocks?.length) return "";
|
|
871
|
-
const blocks = clientContext.config.blocks.map((block) => `### ${block.title}
|
|
872
|
-
|
|
873
|
-
${block.content}`).join("\n\n");
|
|
874
|
-
return `## Client Guidance (${clientContext.name})
|
|
875
|
-
|
|
876
|
-
${blocks}`;
|
|
877
|
-
}
|
|
878
|
-
function tryLoadTemplates(clientName, context, baseDir = DEFAULT_TEMPLATE_BASE_DIR) {
|
|
879
|
-
const result = /* @__PURE__ */ new Map();
|
|
880
|
-
try {
|
|
881
|
-
const templates = loadTemplatesWithOverrides(baseDir, clientName);
|
|
882
|
-
for (const [id, template] of templates) {
|
|
883
|
-
const condition = template.frontmatter.condition;
|
|
884
|
-
if (!evaluateCondition(condition, context)) {
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
const processed = replaceTokens(template.content, context);
|
|
888
|
-
result.set(id, processed);
|
|
889
|
-
}
|
|
890
|
-
} catch {
|
|
891
|
-
}
|
|
892
|
-
return result;
|
|
893
|
-
}
|
|
894
|
-
function buildSpawnTemplateContext(doc, id, policy, classification) {
|
|
895
|
-
const lane = doc.lane || "";
|
|
896
|
-
const laneParent = lane.split(":")[0]?.trim() || "";
|
|
897
|
-
const type = (doc.type || "feature").toLowerCase();
|
|
898
|
-
const requiredVerification = formatRequiredVerification(doc);
|
|
899
|
-
const workDomain = classification?.domain || "";
|
|
900
|
-
const workTestMethodologyHint = classification?.testMethodologyHint || "";
|
|
901
|
-
const context = {
|
|
902
|
-
WU_ID: id,
|
|
903
|
-
LANE: lane,
|
|
904
|
-
TYPE: type,
|
|
905
|
-
TITLE: doc.title || "",
|
|
906
|
-
DESCRIPTION: doc.description || "",
|
|
907
|
-
WORKTREE_PATH: doc.worktree_path || "",
|
|
908
|
-
laneParent,
|
|
909
|
-
WORK_DOMAIN: workDomain,
|
|
910
|
-
WORK_TEST_METHODOLOGY_HINT: workTestMethodologyHint,
|
|
911
|
-
REQUIRED_VERIFICATION: requiredVerification,
|
|
912
|
-
// Lowercase aliases for condition evaluation
|
|
913
|
-
type,
|
|
914
|
-
lane,
|
|
915
|
-
worktreePath: doc.worktree_path || "",
|
|
916
|
-
"work.domain": workDomain,
|
|
917
|
-
"work.testMethodologyHint": workTestMethodologyHint,
|
|
918
|
-
hasRequiredVerification: requiredVerification ? "true" : void 0,
|
|
919
|
-
"tests.hasUnit": doc.tests?.unit?.length ? "true" : void 0,
|
|
920
|
-
"tests.hasE2E": doc.tests?.e2e?.length ? "true" : void 0,
|
|
921
|
-
"tests.hasManual": doc.tests?.manual?.length ? "true" : void 0
|
|
922
|
-
};
|
|
923
|
-
if (policy) {
|
|
924
|
-
context["policy.testing"] = policy.testing;
|
|
925
|
-
context["policy.architecture"] = policy.architecture;
|
|
926
|
-
}
|
|
927
|
-
return context;
|
|
928
|
-
}
|
|
929
|
-
function generateTaskInvocation(doc, id, strategy, options = {}) {
|
|
930
|
-
const codePaths = doc.code_paths || [];
|
|
931
|
-
const mandatoryAgents = detectMandatoryAgents(codePaths);
|
|
932
|
-
const preamble = generatePreamble(id, strategy);
|
|
933
|
-
const clientContext = options.client;
|
|
934
|
-
const config = options.config || getConfig();
|
|
935
|
-
const policy = resolvePolicy(config);
|
|
936
|
-
const classificationConfig = config?.methodology?.work_classification;
|
|
937
|
-
const classification = classifyWork(
|
|
938
|
-
{
|
|
939
|
-
code_paths: doc.code_paths,
|
|
940
|
-
lane: doc.lane,
|
|
941
|
-
type: doc.type,
|
|
942
|
-
description: doc.description
|
|
943
|
-
},
|
|
944
|
-
classificationConfig
|
|
945
|
-
);
|
|
946
|
-
const clientName = options.client?.name || "claude-code";
|
|
947
|
-
const templateContext = buildSpawnTemplateContext(doc, id, policy, classification);
|
|
948
|
-
const templateBaseDir = options.baseDir || DEFAULT_TEMPLATE_BASE_DIR;
|
|
949
|
-
const templates = tryLoadTemplates(clientName, templateContext, templateBaseDir);
|
|
950
|
-
const testGuidanceFallback = [
|
|
951
|
-
generateRequiredVerificationSection(doc),
|
|
952
|
-
generatePolicyBasedTestGuidance(doc.type || "feature", policy, {
|
|
953
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
954
|
-
})
|
|
955
|
-
].filter((section) => section.length > 0).join("\n\n---\n\n");
|
|
956
|
-
const testGuidance = resolveVerificationGuidanceSection(templates, testGuidanceFallback);
|
|
957
|
-
const enforcementSummary = generateEnforcementSummary(policy, {
|
|
958
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
959
|
-
});
|
|
960
|
-
const mandatoryStandards = generateMandatoryStandards(policy, {
|
|
961
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
962
|
-
});
|
|
963
|
-
const codeCraftGuidance = templates.get("code-craft") || generateCodeCraftGuidance();
|
|
964
|
-
const readBeforeWrite = templates.get("read-before-write") || generateReadBeforeWriteDiscipline();
|
|
965
|
-
const selfReviewDirective = templates.get("self-review") || generateSelfReviewDirective(id);
|
|
966
|
-
const clientSkillsGuidance = generateClientSkillsGuidance(clientContext, doc.lane);
|
|
967
|
-
const skillsTemplateContent = templates.get("skills-selection");
|
|
968
|
-
const skillsGuidanceSuffix = clientSkillsGuidance ? "\n" + clientSkillsGuidance : "";
|
|
969
|
-
const skillsBaseContent = skillsTemplateContent || generateSkillsSelectionSection(doc, config, clientContext?.name);
|
|
970
|
-
const skillsSection = skillsBaseContent + skillsGuidanceSuffix;
|
|
971
|
-
const clientBlocks = generateClientBlocksSection(clientContext);
|
|
972
|
-
const mandatorySection = generateMandatoryAgentSection(mandatoryAgents, id);
|
|
973
|
-
const bugDiscoverySection = templates.get("bug-discovery") || generateBugDiscoverySection(id);
|
|
974
|
-
const shouldIncludeTddCheckpoint = !usesNonTddHint(classification.testMethodologyHint) && policy.testing !== "none";
|
|
975
|
-
const constraints = templates.get("constraints") || generateConstraints(id, {
|
|
976
|
-
includeTddCheckpoint: shouldIncludeTddCheckpoint
|
|
977
|
-
});
|
|
978
|
-
const implementationContext = generateImplementationContext(doc);
|
|
979
|
-
const designContextSection = resolveDesignContextSection(templates, classification);
|
|
980
|
-
const invariantsPriorArt = generateInvariantsPriorArtSection(codePaths);
|
|
981
|
-
const effortScaling = templates.get("effort-scaling") || generateEffortScalingRules();
|
|
982
|
-
const parallelToolCalls = templates.get("parallel-tool-calls") || generateParallelToolCallGuidance();
|
|
983
|
-
const searchHeuristics = templates.get("search-heuristics") || generateIterativeSearchHeuristics();
|
|
984
|
-
const tokenBudget = templates.get("token-budget") || generateTokenBudgetAwareness(id);
|
|
985
|
-
const completionFormat = generateCompletionFormat(id);
|
|
986
|
-
const completionWorkflow = templates.get("completion-workflow") || generateCompletionWorkflowSection2(id);
|
|
987
|
-
const agentCoordination = generateAgentCoordinationSection(id);
|
|
988
|
-
const quickFix = templates.get("quick-fix-commands") || generateQuickFixCommands();
|
|
989
|
-
const laneSelection = templates.get("lane-selection") || generateLaneSelectionSection(CONFIG_FILES.LANE_INFERENCE);
|
|
990
|
-
const worktreePathHint = resolveWorktreePathHint(doc, id, config);
|
|
991
|
-
const worktreeGuidance = generateWorktreePathGuidance(doc.worktree_path);
|
|
992
|
-
const worktreeBlockRecovery = templates.get("worktree-recovery") || generateWorktreeBlockRecoverySection(worktreePathHint, config);
|
|
993
|
-
const laneGuidance = resolveLaneGuidanceSection(templates, doc.lane);
|
|
994
|
-
const shouldIncludeMemoryContext = options.includeMemoryContext && !options.noContext;
|
|
995
|
-
const memoryContextSection = shouldIncludeMemoryContext ? options.memoryContextContent || "" : "";
|
|
996
|
-
const executionModeSection = generateExecutionModeSection(options);
|
|
997
|
-
const thinkToolGuidance = generateThinkToolGuidance(options);
|
|
998
|
-
const thinkingSections = [executionModeSection, thinkToolGuidance].filter((section) => section.length > 0).join("\n\n---\n\n");
|
|
999
|
-
const thinkingBlock = thinkingSections ? `${thinkingSections}
|
|
1000
|
-
|
|
1001
|
-
---
|
|
1002
|
-
|
|
1003
|
-
` : "";
|
|
1004
|
-
const taskPrompt = `${TRUNCATION_WARNING_BANNER}<task>
|
|
1005
|
-
${preamble}
|
|
1006
|
-
</task>
|
|
1007
|
-
|
|
1008
|
-
---
|
|
1009
|
-
|
|
1010
|
-
${testGuidance}
|
|
1011
|
-
|
|
1012
|
-
---
|
|
1013
|
-
|
|
1014
|
-
# ${id}: ${doc.title || "Untitled"}
|
|
1015
|
-
|
|
1016
|
-
## WU Details
|
|
1017
|
-
|
|
1018
|
-
- **ID:** ${id}
|
|
1019
|
-
- **Lane:** ${doc.lane || "Unknown"}
|
|
1020
|
-
- **Type:** ${doc.type || "feature"}
|
|
1021
|
-
- **Status:** ${doc.status || "unknown"}
|
|
1022
|
-
- **Worktree:** ${worktreePathHint}
|
|
1023
|
-
|
|
1024
|
-
## Description
|
|
1025
|
-
|
|
1026
|
-
${doc.description || "No description provided."}
|
|
1027
|
-
|
|
1028
|
-
## Acceptance Criteria
|
|
1029
|
-
|
|
1030
|
-
${formatAcceptance(doc.acceptance)}
|
|
1031
|
-
|
|
1032
|
-
## Code Paths
|
|
1033
|
-
|
|
1034
|
-
${codePaths.length > 0 ? codePaths.map((p) => `- ${p}`).join("\n") : "- No code paths defined"}
|
|
1035
|
-
${mandatorySection}${invariantsPriorArt ? `---
|
|
1036
|
-
|
|
1037
|
-
${invariantsPriorArt}
|
|
1038
|
-
|
|
1039
|
-
` : ""}${implementationContext ? `---
|
|
1040
|
-
|
|
1041
|
-
${implementationContext}
|
|
1042
|
-
|
|
1043
|
-
` : ""}---
|
|
1044
|
-
|
|
1045
|
-
${thinkingBlock}${skillsSection}
|
|
1046
|
-
${memoryContextSection ? `---
|
|
1047
|
-
|
|
1048
|
-
${memoryContextSection}
|
|
1049
|
-
|
|
1050
|
-
` : ""}---
|
|
1051
|
-
|
|
1052
|
-
${mandatoryStandards}
|
|
1053
|
-
|
|
1054
|
-
---
|
|
1055
|
-
|
|
1056
|
-
${enforcementSummary}
|
|
1057
|
-
|
|
1058
|
-
---
|
|
1059
|
-
|
|
1060
|
-
${codeCraftGuidance}
|
|
1061
|
-
|
|
1062
|
-
---
|
|
1063
|
-
|
|
1064
|
-
${readBeforeWrite}
|
|
1065
|
-
|
|
1066
|
-
${designContextSection ? `---
|
|
1067
|
-
|
|
1068
|
-
${designContextSection}
|
|
1069
|
-
|
|
1070
|
-
` : ""}${clientBlocks ? `---
|
|
1071
|
-
|
|
1072
|
-
${clientBlocks}
|
|
1073
|
-
|
|
1074
|
-
` : ""}${worktreeGuidance ? `---
|
|
1075
|
-
|
|
1076
|
-
${worktreeGuidance}
|
|
1077
|
-
|
|
1078
|
-
` : ""}---
|
|
1079
|
-
|
|
1080
|
-
${bugDiscoverySection}
|
|
1081
|
-
|
|
1082
|
-
---
|
|
1083
|
-
|
|
1084
|
-
${effortScaling}
|
|
1085
|
-
|
|
1086
|
-
---
|
|
1087
|
-
|
|
1088
|
-
${parallelToolCalls}
|
|
1089
|
-
|
|
1090
|
-
---
|
|
1091
|
-
|
|
1092
|
-
${searchHeuristics}
|
|
1093
|
-
|
|
1094
|
-
---
|
|
1095
|
-
|
|
1096
|
-
${tokenBudget}
|
|
1097
|
-
|
|
1098
|
-
---
|
|
1099
|
-
|
|
1100
|
-
${completionFormat}
|
|
1101
|
-
|
|
1102
|
-
---
|
|
1103
|
-
|
|
1104
|
-
${completionWorkflow}
|
|
1105
|
-
|
|
1106
|
-
---
|
|
1107
|
-
|
|
1108
|
-
${agentCoordination}
|
|
1109
|
-
|
|
1110
|
-
---
|
|
1111
|
-
|
|
1112
|
-
${quickFix}
|
|
1113
|
-
|
|
1114
|
-
---
|
|
1115
|
-
|
|
1116
|
-
${laneSelection}
|
|
1117
|
-
|
|
1118
|
-
---
|
|
1119
|
-
|
|
1120
|
-
${laneGuidance}${laneGuidance ? "\n\n---\n\n" : ""}## Action
|
|
1121
|
-
|
|
1122
|
-
${generateActionSection(doc, id, config)}
|
|
1123
|
-
|
|
1124
|
-
---
|
|
1125
|
-
|
|
1126
|
-
${selfReviewDirective}
|
|
1127
|
-
|
|
1128
|
-
---
|
|
1129
|
-
|
|
1130
|
-
${worktreeBlockRecovery}
|
|
1131
|
-
|
|
1132
|
-
${constraints}
|
|
1133
|
-
|
|
1134
|
-
${SPAWN_END_SENTINEL}`;
|
|
1135
|
-
const escapedPrompt = taskPrompt.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1136
|
-
const openTag = '<antml:invoke name="Task">';
|
|
1137
|
-
const closeTag = "</antml:invoke>";
|
|
1138
|
-
const paramOpen = '<antml:parameter name="';
|
|
1139
|
-
const paramClose = "</antml:parameter>";
|
|
1140
|
-
const invocation = [
|
|
1141
|
-
"<antml:function_calls>",
|
|
1142
|
-
openTag,
|
|
1143
|
-
`${paramOpen}subagent_type">general-purpose${paramClose}`,
|
|
1144
|
-
`${paramOpen}description">Execute ${id}${paramClose}`,
|
|
1145
|
-
`${paramOpen}prompt">${escapedPrompt}${paramClose}`,
|
|
1146
|
-
closeTag,
|
|
1147
|
-
"</antml:function_calls>"
|
|
1148
|
-
].join("\n");
|
|
1149
|
-
return invocation;
|
|
1150
|
-
}
|
|
1151
|
-
function generateCodexPrompt(doc, id, strategy, options = {}) {
|
|
1152
|
-
const codePaths = doc.code_paths || [];
|
|
1153
|
-
const mandatoryAgents = detectMandatoryAgents(codePaths);
|
|
1154
|
-
const config = options.config || getConfig();
|
|
1155
|
-
const clientContext = options.client;
|
|
1156
|
-
const policy = resolvePolicy(config);
|
|
1157
|
-
const classificationConfig = config?.methodology?.work_classification;
|
|
1158
|
-
const classification = classifyWork(
|
|
1159
|
-
{
|
|
1160
|
-
code_paths: doc.code_paths,
|
|
1161
|
-
lane: doc.lane,
|
|
1162
|
-
type: doc.type,
|
|
1163
|
-
description: doc.description
|
|
1164
|
-
},
|
|
1165
|
-
classificationConfig
|
|
1166
|
-
);
|
|
1167
|
-
const preamble = generatePreamble(id, strategy);
|
|
1168
|
-
const mandatoryStandards = generateMandatoryStandards(policy, {
|
|
1169
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
1170
|
-
});
|
|
1171
|
-
const enforcementSummary = generateEnforcementSummary(policy, {
|
|
1172
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
1173
|
-
});
|
|
1174
|
-
const mandatorySection = generateMandatoryAgentSection(mandatoryAgents, id);
|
|
1175
|
-
const implementationContext = generateImplementationContext(doc);
|
|
1176
|
-
const action = generateActionSection(doc, id, config);
|
|
1177
|
-
const shouldIncludeTddCheckpoint = !usesNonTddHint(classification.testMethodologyHint) && policy.testing !== "none";
|
|
1178
|
-
const constraints = generateCodexConstraints(id, {
|
|
1179
|
-
includeTddCheckpoint: shouldIncludeTddCheckpoint
|
|
1180
|
-
});
|
|
1181
|
-
const worktreePathHint = resolveWorktreePathHint(doc, id, config);
|
|
1182
|
-
const clientName = options.client?.name || "claude-code";
|
|
1183
|
-
const templateContext = buildSpawnTemplateContext(doc, id, policy, classification);
|
|
1184
|
-
const templateBaseDir = options.baseDir || DEFAULT_TEMPLATE_BASE_DIR;
|
|
1185
|
-
const templates = tryLoadTemplates(clientName, templateContext, templateBaseDir);
|
|
1186
|
-
const testGuidanceFallback = [
|
|
1187
|
-
generateRequiredVerificationSection(doc),
|
|
1188
|
-
generatePolicyBasedTestGuidance(doc.type || "feature", policy, {
|
|
1189
|
-
testMethodologyHint: classification.testMethodologyHint
|
|
1190
|
-
})
|
|
1191
|
-
].filter((section) => section.length > 0).join("\n\n---\n\n");
|
|
1192
|
-
const testGuidance = resolveVerificationGuidanceSection(templates, testGuidanceFallback);
|
|
1193
|
-
const codeCraftGuidance = templates.get("code-craft") || generateCodeCraftGuidance();
|
|
1194
|
-
const readBeforeWrite = templates.get("read-before-write") || generateReadBeforeWriteDiscipline();
|
|
1195
|
-
const selfReviewDirective = templates.get("self-review") || generateSelfReviewDirective(id);
|
|
1196
|
-
const bugDiscoverySection = templates.get("bug-discovery") || generateBugDiscoverySection(id);
|
|
1197
|
-
const completionWorkflow = templates.get("completion-workflow") || generateCompletionWorkflowSection2(id);
|
|
1198
|
-
const clientSkillsGuidance = generateClientSkillsGuidance(clientContext, doc.lane);
|
|
1199
|
-
const skillsTemplateContent = templates.get("skills-selection");
|
|
1200
|
-
const skillsBaseContent = skillsTemplateContent || generateSkillsSelectionSection(doc, config, clientContext?.name);
|
|
1201
|
-
const skillsSection = skillsBaseContent + (clientSkillsGuidance ? `
|
|
1202
|
-
${clientSkillsGuidance}` : "");
|
|
1203
|
-
const clientBlocks = generateClientBlocksSection(clientContext);
|
|
1204
|
-
const laneGuidance = resolveLaneGuidanceSection(templates, doc.lane);
|
|
1205
|
-
const designContextSection = resolveDesignContextSection(templates, classification);
|
|
1206
|
-
const executionModeSection = generateExecutionModeSection(options);
|
|
1207
|
-
const thinkToolGuidance = generateThinkToolGuidance(options);
|
|
1208
|
-
const thinkingSections = [executionModeSection, thinkToolGuidance].filter((section) => section.length > 0).join("\n\n---\n\n");
|
|
1209
|
-
const thinkingBlock = thinkingSections ? `${thinkingSections}
|
|
1210
|
-
|
|
1211
|
-
---
|
|
1212
|
-
|
|
1213
|
-
` : "";
|
|
1214
|
-
const worktreeBlockRecovery = generateWorktreeBlockRecoverySection(worktreePathHint, config);
|
|
1215
|
-
const shouldIncludeMemoryContext = options.includeMemoryContext && !options.noContext;
|
|
1216
|
-
const memoryContextSection = shouldIncludeMemoryContext ? options.memoryContextContent || "" : "";
|
|
1217
|
-
return `${TRUNCATION_WARNING_BANNER}# ${id}: ${doc.title || "Untitled"}
|
|
1218
|
-
|
|
1219
|
-
${testGuidance}
|
|
1220
|
-
|
|
1221
|
-
---
|
|
1222
|
-
|
|
1223
|
-
## Context
|
|
1224
|
-
|
|
1225
|
-
${preamble}
|
|
1226
|
-
|
|
1227
|
-
---
|
|
1228
|
-
|
|
1229
|
-
## WU Details
|
|
1230
|
-
|
|
1231
|
-
- **ID:** ${id}
|
|
1232
|
-
- **Lane:** ${doc.lane || "Unknown"}
|
|
1233
|
-
- **Type:** ${doc.type || "feature"}
|
|
1234
|
-
- **Status:** ${doc.status || "unknown"}
|
|
1235
|
-
- **Worktree:** ${worktreePathHint}
|
|
1236
|
-
|
|
1237
|
-
## Description
|
|
1238
|
-
|
|
1239
|
-
${doc.description || "No description provided."}
|
|
1240
|
-
|
|
1241
|
-
## Scope (code_paths)
|
|
1242
|
-
|
|
1243
|
-
Only change files within these paths:
|
|
1244
|
-
|
|
1245
|
-
${codePaths.length > 0 ? codePaths.map((p) => `- ${p}`).join("\n") : "- No code paths defined"}
|
|
1246
|
-
|
|
1247
|
-
## Acceptance Criteria
|
|
1248
|
-
|
|
1249
|
-
${formatAcceptance(doc.acceptance)}
|
|
1250
|
-
|
|
1251
|
-
---
|
|
1252
|
-
|
|
1253
|
-
${mandatoryStandards}
|
|
1254
|
-
|
|
1255
|
-
---
|
|
1256
|
-
|
|
1257
|
-
${enforcementSummary}
|
|
1258
|
-
|
|
1259
|
-
---
|
|
1260
|
-
|
|
1261
|
-
${codeCraftGuidance}
|
|
1262
|
-
|
|
1263
|
-
---
|
|
1264
|
-
|
|
1265
|
-
${readBeforeWrite}
|
|
1266
|
-
|
|
1267
|
-
${designContextSection ? `---
|
|
1268
|
-
|
|
1269
|
-
${designContextSection}
|
|
1270
|
-
|
|
1271
|
-
` : ""}${skillsSection}
|
|
1272
|
-
${memoryContextSection ? `---
|
|
1273
|
-
|
|
1274
|
-
${memoryContextSection}
|
|
1275
|
-
|
|
1276
|
-
` : ""}---
|
|
1277
|
-
|
|
1278
|
-
## Action
|
|
1279
|
-
|
|
1280
|
-
${action}
|
|
1281
|
-
|
|
1282
|
-
---
|
|
1283
|
-
|
|
1284
|
-
${completionWorkflow}
|
|
1285
|
-
|
|
1286
|
-
---
|
|
1287
|
-
|
|
1288
|
-
## Verification
|
|
1289
|
-
|
|
1290
|
-
- Run in worktree: \`pnpm gates\`
|
|
1291
|
-
- From shared checkout: \`node packages/@lumenflow/agent/dist/agent-verification.js ${id}\`
|
|
1292
|
-
|
|
1293
|
-
---
|
|
1294
|
-
|
|
1295
|
-
${mandatorySection}${implementationContext ? `${implementationContext}
|
|
1296
|
-
|
|
1297
|
-
---
|
|
1298
|
-
|
|
1299
|
-
` : ""}${clientBlocks ? `${clientBlocks}
|
|
1300
|
-
|
|
1301
|
-
---
|
|
1302
|
-
|
|
1303
|
-
` : ""}${thinkingBlock}${bugDiscoverySection}
|
|
1304
|
-
|
|
1305
|
-
---
|
|
1306
|
-
|
|
1307
|
-
${laneGuidance}${laneGuidance ? "\n\n---\n\n" : ""}${selfReviewDirective}
|
|
1308
|
-
|
|
1309
|
-
---
|
|
1310
|
-
|
|
1311
|
-
${worktreeBlockRecovery}
|
|
1312
|
-
|
|
1313
|
-
---
|
|
1314
|
-
|
|
1315
|
-
${constraints}
|
|
1316
|
-
|
|
1317
|
-
${SPAWN_END_SENTINEL}
|
|
1318
|
-
`;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// src/wu-brief-sizing.ts
|
|
1322
|
-
function checkBriefSizing(input) {
|
|
1323
|
-
const { wuId, logPrefix, strictSizing, sizingEstimate } = input;
|
|
1324
|
-
const warnings = [];
|
|
1325
|
-
const errors = [];
|
|
1326
|
-
if (!sizingEstimate) {
|
|
1327
|
-
if (strictSizing) {
|
|
1328
|
-
errors.push(
|
|
1329
|
-
`${wuId}: --strict-sizing requires sizing_estimate metadata in WU YAML. Add sizing_estimate with estimated_files, estimated_tool_calls, and strategy.`
|
|
1330
|
-
);
|
|
1331
|
-
return { pass: false, warnings, errors };
|
|
1332
|
-
}
|
|
1333
|
-
return { pass: true, warnings, errors };
|
|
1334
|
-
}
|
|
1335
|
-
const advisory = checkSizingAdvisory(sizingEstimate);
|
|
1336
|
-
if (advisory.oversize) {
|
|
1337
|
-
if (strictSizing) {
|
|
1338
|
-
errors.push(...advisory.warnings.map((w) => `${wuId}: ${w}`));
|
|
1339
|
-
return { pass: false, warnings, errors };
|
|
1340
|
-
}
|
|
1341
|
-
for (const w of advisory.warnings) {
|
|
1342
|
-
const message = `${logPrefix} WARNING (${wuId}): ${w}`;
|
|
1343
|
-
warnings.push(message);
|
|
1344
|
-
console.warn(message);
|
|
1345
|
-
}
|
|
1346
|
-
return { pass: true, warnings, errors };
|
|
1347
|
-
}
|
|
1348
|
-
return { pass: true, warnings, errors };
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
// src/wu-spawn-strategy-resolver.ts
|
|
1352
|
-
import crypto from "crypto";
|
|
1353
|
-
var BRIEF_LOG_PREFIX = "[wu:brief]";
|
|
1354
|
-
var DELEGATE_LOG_PREFIX = "[wu:delegate]";
|
|
1355
|
-
var BRIEF_EVIDENCE_PROGRESS = "wu:brief executed";
|
|
1356
|
-
function buildBriefAttestation(output, clientName, generatedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1357
|
-
return {
|
|
1358
|
-
algorithm: "sha256",
|
|
1359
|
-
promptHash: crypto.createHash("sha256").update(output, "utf8").digest("hex"),
|
|
1360
|
-
promptLength: output.length,
|
|
1361
|
-
generatedAt,
|
|
1362
|
-
clientName
|
|
1363
|
-
};
|
|
1364
|
-
}
|
|
1365
|
-
function checkLaneOccupation(lane) {
|
|
1366
|
-
const lockPolicy = getLockPolicyForLane(lane);
|
|
1367
|
-
if (lockPolicy === "none") {
|
|
1368
|
-
return null;
|
|
1369
|
-
}
|
|
1370
|
-
const lockStatus = checkLaneLock(lane);
|
|
1371
|
-
if (lockStatus.locked && lockStatus.metadata) {
|
|
1372
|
-
return lockStatus.metadata;
|
|
1373
|
-
}
|
|
1374
|
-
return null;
|
|
1375
|
-
}
|
|
1376
|
-
function generateLaneOccupationWarning(lockMetadata, targetWuId, options = {}) {
|
|
1377
|
-
const { isStale = false } = options;
|
|
1378
|
-
let warning = `\u26A0\uFE0F Lane "${lockMetadata.lane}" is occupied by ${lockMetadata.wuId}
|
|
1379
|
-
`;
|
|
1380
|
-
const lockPolicy = options.lockPolicy ?? getLockPolicyForLane(lockMetadata.lane);
|
|
1381
|
-
const wipLimit = options.wipLimit ?? getWipLimitForLane(lockMetadata.lane);
|
|
1382
|
-
warning += ` This violates WIP=${wipLimit} (lock_policy=${lockPolicy}).
|
|
1383
|
-
|
|
1384
|
-
`;
|
|
1385
|
-
if (isStale) {
|
|
1386
|
-
warning += ` \u23F0 This lock is STALE (>24 hours old) - the WU may be abandoned.
|
|
1387
|
-
`;
|
|
1388
|
-
warning += ` Consider using pnpm wu:block --id ${lockMetadata.wuId} if work is stalled.
|
|
1389
|
-
|
|
1390
|
-
`;
|
|
1391
|
-
}
|
|
1392
|
-
warning += ` Options:
|
|
1393
|
-
`;
|
|
1394
|
-
warning += ` 1. Wait for ${lockMetadata.wuId} to complete or block
|
|
1395
|
-
`;
|
|
1396
|
-
warning += ` 2. Choose a different lane for ${targetWuId}
|
|
1397
|
-
`;
|
|
1398
|
-
warning += ` 3. Block ${lockMetadata.wuId} if work is stalled: pnpm wu:block --id ${lockMetadata.wuId}`;
|
|
1399
|
-
return warning;
|
|
1400
|
-
}
|
|
1401
|
-
var BRIEF_PARSER_CONFIG = {
|
|
1402
|
-
name: "wu-brief",
|
|
1403
|
-
description: "Generate handoff prompt for sub-agent WU execution"
|
|
1404
|
-
};
|
|
1405
|
-
var DELEGATE_PARSER_CONFIG = {
|
|
1406
|
-
name: "wu-delegate",
|
|
1407
|
-
description: "Generate delegation prompt and record explicit lineage intent"
|
|
1408
|
-
};
|
|
1409
|
-
function parseAndValidateArgs(parserConfig = BRIEF_PARSER_CONFIG) {
|
|
1410
|
-
const args = createWUParser({
|
|
1411
|
-
name: parserConfig.name,
|
|
1412
|
-
description: parserConfig.description,
|
|
1413
|
-
options: [
|
|
1414
|
-
WU_OPTIONS.id,
|
|
1415
|
-
WU_OPTIONS.thinking,
|
|
1416
|
-
WU_OPTIONS.noThinking,
|
|
1417
|
-
WU_OPTIONS.budget,
|
|
1418
|
-
WU_OPTIONS.codex,
|
|
1419
|
-
WU_OPTIONS.parentWu,
|
|
1420
|
-
// WU-1945: Parent WU for spawn registry tracking
|
|
1421
|
-
WU_OPTIONS.client,
|
|
1422
|
-
WU_OPTIONS.vendor,
|
|
1423
|
-
WU_OPTIONS.noContext,
|
|
1424
|
-
// WU-1240: Skip memory context injection
|
|
1425
|
-
WU_OPTIONS.evidenceOnly,
|
|
1426
|
-
// WU-2222: Evidence recording without prompt generation
|
|
1427
|
-
WU_OPTIONS.strictSizing
|
|
1428
|
-
// WU-2141: Strict sizing enforcement
|
|
1429
|
-
],
|
|
1430
|
-
required: ["id"],
|
|
1431
|
-
allowPositionalId: true
|
|
1432
|
-
});
|
|
1433
|
-
try {
|
|
1434
|
-
validateSpawnArgs(args);
|
|
1435
|
-
} catch (e) {
|
|
1436
|
-
die(e.message);
|
|
1437
|
-
}
|
|
1438
|
-
return args;
|
|
1439
|
-
}
|
|
1440
|
-
function loadWUDocument(id, wuPath) {
|
|
1441
|
-
if (!existsSync3(wuPath)) {
|
|
1442
|
-
die(
|
|
1443
|
-
`WU file not found: ${wuPath}
|
|
1444
|
-
|
|
1445
|
-
Cannot spawn a sub-agent for a WU that doesn't exist.
|
|
1446
|
-
|
|
1447
|
-
Options:
|
|
1448
|
-
1. Create the WU first: pnpm wu:create --id ${id} --lane <lane> --title "..."
|
|
1449
|
-
2. Check if the WU ID is correct`
|
|
1450
|
-
);
|
|
1451
|
-
}
|
|
1452
|
-
let text;
|
|
1453
|
-
try {
|
|
1454
|
-
text = readFileSync(wuPath, { encoding: FILE_SYSTEM.UTF8 });
|
|
1455
|
-
} catch (e) {
|
|
1456
|
-
die(
|
|
1457
|
-
`Failed to read WU file: ${wuPath}
|
|
1458
|
-
|
|
1459
|
-
Error: ${e.message}
|
|
1460
|
-
|
|
1461
|
-
Options:
|
|
1462
|
-
1. Check file permissions: ls -la ${wuPath}
|
|
1463
|
-
2. Ensure the file exists and is readable`
|
|
1464
|
-
);
|
|
1465
|
-
}
|
|
1466
|
-
try {
|
|
1467
|
-
return parseYAML(text);
|
|
1468
|
-
} catch (e) {
|
|
1469
|
-
die(
|
|
1470
|
-
`Failed to parse WU YAML ${wuPath}
|
|
1471
|
-
|
|
1472
|
-
Error: ${e.message}
|
|
1473
|
-
|
|
1474
|
-
Options:
|
|
1475
|
-
1. Validate YAML syntax: pnpm wu:validate --id ${id}
|
|
1476
|
-
2. Fix YAML errors manually and retry`
|
|
1477
|
-
);
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
function resolveClientName(args, config, logPrefix = BRIEF_LOG_PREFIX) {
|
|
1481
|
-
let clientName = args.client;
|
|
1482
|
-
if (!clientName && args.vendor) {
|
|
1483
|
-
console.warn(`${logPrefix} ${EMOJI.WARNING} Warning: --vendor is deprecated. Use --client.`);
|
|
1484
|
-
clientName = args.vendor;
|
|
1485
|
-
}
|
|
1486
|
-
if (args.codex && !clientName) {
|
|
1487
|
-
console.warn(
|
|
1488
|
-
`${logPrefix} ${EMOJI.WARNING} Warning: --codex is deprecated. Use --client codex-cli.`
|
|
1489
|
-
);
|
|
1490
|
-
clientName = "codex-cli";
|
|
1491
|
-
}
|
|
1492
|
-
const resolved = clientName || config.agents.defaultClient || "claude-code";
|
|
1493
|
-
if (!clientName && !config.agents.defaultClient) {
|
|
1494
|
-
console.warn(
|
|
1495
|
-
`${logPrefix} Warning: No --client specified. Falling back to 'claude-code'. Available clients: claude-code, codex-cli, cursor, gemini-cli, windsurf`
|
|
1496
|
-
);
|
|
1497
|
-
}
|
|
1498
|
-
return resolved;
|
|
1499
|
-
}
|
|
1500
|
-
async function checkAndWarnLaneOccupation(lane, id, logPrefix = BRIEF_LOG_PREFIX) {
|
|
1501
|
-
if (!lane) return;
|
|
1502
|
-
const existingLock = checkLaneOccupation(lane);
|
|
1503
|
-
if (existingLock && existingLock.wuId !== id) {
|
|
1504
|
-
const { isLockStale } = await import("./lane-lock-6J36HD5O.js");
|
|
1505
|
-
const isStale = isLockStale(existingLock);
|
|
1506
|
-
const warning = generateLaneOccupationWarning(existingLock, id, { isStale });
|
|
1507
|
-
console.warn(`${logPrefix} ${EMOJI.WARNING}
|
|
1508
|
-
${warning}
|
|
1509
|
-
`);
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
async function recordWuBriefEvidence(options, dependencies = {}) {
|
|
1513
|
-
const { wuId, workspaceRoot, clientName, promptHash, forceRecord, claimedMode, claimedBranch } = options;
|
|
1514
|
-
const checkWorktree = dependencies.isInWorktree ?? isInWorktree;
|
|
1515
|
-
const isInWorktree2 = checkWorktree({ cwd: workspaceRoot });
|
|
1516
|
-
let shouldRecordEvidence = forceRecord === true || isInWorktree2;
|
|
1517
|
-
if (!shouldRecordEvidence) {
|
|
1518
|
-
const normalizedClaimedMode = typeof claimedMode === "string" ? claimedMode.trim() : "";
|
|
1519
|
-
const isBranchClaim = normalizedClaimedMode === "branch-pr" || normalizedClaimedMode === "branch-only";
|
|
1520
|
-
if (isBranchClaim) {
|
|
1521
|
-
const getCurrentBranch = dependencies.getCurrentBranch ?? (async (cwd) => {
|
|
1522
|
-
return createGitForPath(cwd).getCurrentBranch();
|
|
1523
|
-
});
|
|
1524
|
-
const activeBranch = await getCurrentBranch(workspaceRoot).then((branch) => branch.trim()).catch(() => "");
|
|
1525
|
-
const normalizedClaimedBranch = typeof claimedBranch === "string" ? claimedBranch.trim() : "";
|
|
1526
|
-
if (normalizedClaimedBranch.length > 0) {
|
|
1527
|
-
shouldRecordEvidence = activeBranch === normalizedClaimedBranch;
|
|
1528
|
-
} else {
|
|
1529
|
-
shouldRecordEvidence = activeBranch.length > 0 && activeBranch !== BRANCHES.MAIN && activeBranch !== BRANCHES.MASTER;
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
if (!shouldRecordEvidence) {
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
const stateDir = resolveStateDir(workspaceRoot);
|
|
1537
|
-
const createStore = dependencies.createStore ?? ((dir) => new WUStateStore(dir));
|
|
1538
|
-
const store = createStore(stateDir);
|
|
1539
|
-
const note = `${WU_BRIEF_EVIDENCE_NOTE_PREFIX} generated via ${clientName}`;
|
|
1540
|
-
const nextSteps = promptHash ? `client=${clientName};hash=${promptHash}` : `client=${clientName}`;
|
|
1541
|
-
await store.checkpoint(wuId, note, {
|
|
1542
|
-
progress: BRIEF_EVIDENCE_PROGRESS,
|
|
1543
|
-
nextSteps
|
|
1544
|
-
});
|
|
1545
|
-
}
|
|
1546
|
-
async function emitSpawnOutputWithRegistry(options, dependencies = {}) {
|
|
1547
|
-
const {
|
|
1548
|
-
id,
|
|
1549
|
-
output,
|
|
1550
|
-
isCodexClient,
|
|
1551
|
-
parentWu,
|
|
1552
|
-
lane,
|
|
1553
|
-
briefAttestation,
|
|
1554
|
-
recordDelegationIntent = false,
|
|
1555
|
-
logPrefix: prefix = BRIEF_LOG_PREFIX
|
|
1556
|
-
} = options;
|
|
1557
|
-
const log = dependencies.log ?? console.log;
|
|
1558
|
-
const recordSpawn = dependencies.recordSpawn ?? recordSpawnToRegistry;
|
|
1559
|
-
const formatSpawnMessage = dependencies.formatSpawnMessage ?? formatSpawnRecordedMessage;
|
|
1560
|
-
if (isCodexClient) {
|
|
1561
|
-
log(`${prefix} Generated Codex/GPT prompt for ${id}`);
|
|
1562
|
-
log(`${prefix} Copy the Markdown below:
|
|
1563
|
-
`);
|
|
1564
|
-
log(output.trimEnd());
|
|
1565
|
-
} else {
|
|
1566
|
-
log(`${prefix} Generated Task tool invocation for ${id}`);
|
|
1567
|
-
log(`${prefix} Copy the block below to spawn a sub-agent:
|
|
1568
|
-
`);
|
|
1569
|
-
log(output);
|
|
1570
|
-
}
|
|
1571
|
-
if (!recordDelegationIntent || !parentWu) {
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
const config = getConfig({ projectRoot: process.cwd() });
|
|
1575
|
-
const registryResult = await recordSpawn({
|
|
1576
|
-
parentWuId: parentWu,
|
|
1577
|
-
targetWuId: id,
|
|
1578
|
-
lane: lane || "Unknown",
|
|
1579
|
-
baseDir: config.state.stateDir,
|
|
1580
|
-
briefAttestation
|
|
1581
|
-
});
|
|
1582
|
-
const registryMessage = formatSpawnMessage(registryResult.spawnId, registryResult.error);
|
|
1583
|
-
log(`
|
|
1584
|
-
${registryMessage}`);
|
|
1585
|
-
}
|
|
1586
|
-
async function runBriefLogic(options = {}) {
|
|
1587
|
-
const {
|
|
1588
|
-
mode = "brief",
|
|
1589
|
-
parserConfig = mode === "delegate" ? DELEGATE_PARSER_CONFIG : BRIEF_PARSER_CONFIG,
|
|
1590
|
-
logPrefix = BRIEF_LOG_PREFIX
|
|
1591
|
-
} = options;
|
|
1592
|
-
const args = parseAndValidateArgs(parserConfig);
|
|
1593
|
-
const explicitDelegation = mode === "delegate";
|
|
1594
|
-
const effectiveLogPrefix = explicitDelegation ? DELEGATE_LOG_PREFIX : logPrefix;
|
|
1595
|
-
const commandLabel = explicitDelegation ? "wu:delegate" : "wu:brief";
|
|
1596
|
-
const depResult = await validateSpawnDependencies();
|
|
1597
|
-
if (!depResult.valid) {
|
|
1598
|
-
die(formatDependencyError(commandLabel, depResult.missing));
|
|
1599
|
-
}
|
|
1600
|
-
if (explicitDelegation && !args.parentWu) {
|
|
1601
|
-
die(
|
|
1602
|
-
"wu:delegate requires --parent-wu to record delegation lineage intent.\n\nExample:\n pnpm wu:delegate --id WU-123 --parent-wu WU-100 --client <client>"
|
|
1603
|
-
);
|
|
1604
|
-
}
|
|
1605
|
-
if (explicitDelegation && args.evidenceOnly) {
|
|
1606
|
-
die(
|
|
1607
|
-
"wu:delegate does not support --evidence-only.\n\nUse:\n - pnpm wu:delegate --id WU-123 --parent-wu WU-100 --client <client> # delegation prompt + lineage\n - pnpm wu:brief --id WU-123 --evidence-only # self-implementation evidence only"
|
|
1608
|
-
);
|
|
1609
|
-
}
|
|
1610
|
-
if (!explicitDelegation && args.parentWu) {
|
|
1611
|
-
console.warn(
|
|
1612
|
-
`${effectiveLogPrefix} ${EMOJI.WARNING} --parent-wu does not record lineage in generation-only mode.`
|
|
1613
|
-
);
|
|
1614
|
-
console.warn(
|
|
1615
|
-
`${effectiveLogPrefix} ${EMOJI.WARNING} Use wu:delegate for explicit, side-effectful delegation intent tracking.`
|
|
1616
|
-
);
|
|
1617
|
-
console.warn("");
|
|
1618
|
-
}
|
|
1619
|
-
const id = args.id.toUpperCase();
|
|
1620
|
-
if (!PATTERNS.WU_ID.test(id)) {
|
|
1621
|
-
die(`Invalid WU id '${args.id}'. Expected format WU-123`);
|
|
1622
|
-
}
|
|
1623
|
-
const wuPath = WU_PATHS.WU(id);
|
|
1624
|
-
const doc = loadWUDocument(id, wuPath);
|
|
1625
|
-
const validStatuses = [WU_STATUS.READY, WU_STATUS.IN_PROGRESS];
|
|
1626
|
-
const status = doc.status || "unknown";
|
|
1627
|
-
if (!validStatuses.includes(status)) {
|
|
1628
|
-
console.warn(`${effectiveLogPrefix} ${EMOJI.WARNING} Warning: ${id} has status '${status}'.`);
|
|
1629
|
-
console.warn(
|
|
1630
|
-
`${effectiveLogPrefix} ${EMOJI.WARNING} Sub-agents typically work on ready or in_progress WUs.`
|
|
1631
|
-
);
|
|
1632
|
-
console.warn("");
|
|
1633
|
-
}
|
|
1634
|
-
await checkAndWarnLaneOccupation(doc.lane, id, effectiveLogPrefix);
|
|
1635
|
-
const sizingEstimate = doc.sizing_estimate;
|
|
1636
|
-
const sizingResult = checkBriefSizing({
|
|
1637
|
-
wuId: id,
|
|
1638
|
-
logPrefix: effectiveLogPrefix,
|
|
1639
|
-
strictSizing: Boolean(args.strictSizing),
|
|
1640
|
-
sizingEstimate
|
|
1641
|
-
});
|
|
1642
|
-
if (!sizingResult.pass) {
|
|
1643
|
-
const errorList = sizingResult.errors.map((e) => ` - ${e}`).join("\n");
|
|
1644
|
-
die(
|
|
1645
|
-
`${effectiveLogPrefix} Sizing check failed (--strict-sizing):
|
|
1646
|
-
|
|
1647
|
-
${errorList}
|
|
1648
|
-
|
|
1649
|
-
Options:
|
|
1650
|
-
1. Add sizing_estimate metadata to WU YAML
|
|
1651
|
-
2. Add exception_type and exception_reason if thresholds are intentionally exceeded
|
|
1652
|
-
3. Remove --strict-sizing to use advisory mode`
|
|
1653
|
-
);
|
|
1654
|
-
}
|
|
1655
|
-
const thinkingOptions = {
|
|
1656
|
-
thinking: args.thinking,
|
|
1657
|
-
noThinking: args.noThinking,
|
|
1658
|
-
budget: args.budget
|
|
1659
|
-
};
|
|
1660
|
-
const config = getConfig();
|
|
1661
|
-
const clientName = resolveClientName(args, config, effectiveLogPrefix);
|
|
1662
|
-
const baseDir = process.cwd();
|
|
1663
|
-
const recordEvidenceOrFail = async (options2 = {}) => {
|
|
1664
|
-
try {
|
|
1665
|
-
await recordWuBriefEvidence({
|
|
1666
|
-
wuId: id,
|
|
1667
|
-
workspaceRoot: baseDir,
|
|
1668
|
-
clientName,
|
|
1669
|
-
promptHash: options2.promptHash,
|
|
1670
|
-
forceRecord: options2.forceRecord,
|
|
1671
|
-
claimedMode: typeof doc.claimed_mode === "string" ? doc.claimed_mode : void 0,
|
|
1672
|
-
claimedBranch: typeof doc.claimed_branch === "string" ? doc.claimed_branch : void 0
|
|
1673
|
-
});
|
|
1674
|
-
} catch (error) {
|
|
1675
|
-
die(
|
|
1676
|
-
`${effectiveLogPrefix} Failed to record wu:brief evidence for ${id}: ${error.message}
|
|
1677
|
-
|
|
1678
|
-
Fix options:
|
|
1679
|
-
1. Ensure state directory is writable
|
|
1680
|
-
2. Retry: pnpm wu:brief --id ${id}`
|
|
1681
|
-
);
|
|
1682
|
-
}
|
|
1683
|
-
};
|
|
1684
|
-
if (args.evidenceOnly) {
|
|
1685
|
-
await recordEvidenceOrFail();
|
|
1686
|
-
console.log(
|
|
1687
|
-
`${effectiveLogPrefix} Recorded wu:brief evidence for ${id} (evidence-only mode; no handoff prompt generated).`
|
|
1688
|
-
);
|
|
1689
|
-
console.log(`${effectiveLogPrefix} Continue implementing ${id} in the current session.`);
|
|
1690
|
-
return;
|
|
1691
|
-
}
|
|
1692
|
-
let memoryContextContent = "";
|
|
1693
|
-
const shouldIncludeMemoryContext = !args.noContext;
|
|
1694
|
-
if (shouldIncludeMemoryContext) {
|
|
1695
|
-
const isMemoryInitialized = await checkMemoryLayerInitialized(baseDir);
|
|
1696
|
-
if (isMemoryInitialized) {
|
|
1697
|
-
const maxSize = getMemoryContextMaxSize(config);
|
|
1698
|
-
memoryContextContent = await generateMemoryContextSection(baseDir, {
|
|
1699
|
-
wuId: id,
|
|
1700
|
-
lane: doc.lane,
|
|
1701
|
-
maxSize
|
|
1702
|
-
});
|
|
1703
|
-
if (memoryContextContent) {
|
|
1704
|
-
console.log(
|
|
1705
|
-
`${effectiveLogPrefix} Memory context loaded (${memoryContextContent.length} bytes)`
|
|
1706
|
-
);
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
const strategy = SpawnStrategyFactory.create(clientName);
|
|
1711
|
-
const clientContext = { name: clientName, config: resolveClientConfig(config, clientName) };
|
|
1712
|
-
const isCodexClient = clientName === "codex-cli" || args.codex;
|
|
1713
|
-
if (isCodexClient) {
|
|
1714
|
-
const prompt = generateCodexPrompt(doc, id, strategy, {
|
|
1715
|
-
...thinkingOptions,
|
|
1716
|
-
client: clientContext,
|
|
1717
|
-
config
|
|
1718
|
-
});
|
|
1719
|
-
const briefAttestation2 = explicitDelegation ? buildBriefAttestation(prompt, clientName) : void 0;
|
|
1720
|
-
await emitSpawnOutputWithRegistry({
|
|
1721
|
-
id,
|
|
1722
|
-
output: prompt,
|
|
1723
|
-
isCodexClient: true,
|
|
1724
|
-
parentWu: args.parentWu,
|
|
1725
|
-
lane: doc.lane,
|
|
1726
|
-
briefAttestation: briefAttestation2,
|
|
1727
|
-
recordDelegationIntent: explicitDelegation,
|
|
1728
|
-
logPrefix: effectiveLogPrefix
|
|
1729
|
-
});
|
|
1730
|
-
await recordEvidenceOrFail({
|
|
1731
|
-
promptHash: briefAttestation2?.promptHash,
|
|
1732
|
-
forceRecord: explicitDelegation
|
|
1733
|
-
});
|
|
1734
|
-
return;
|
|
1735
|
-
}
|
|
1736
|
-
const invocation = generateTaskInvocation(doc, id, strategy, {
|
|
1737
|
-
...thinkingOptions,
|
|
1738
|
-
client: clientContext,
|
|
1739
|
-
config,
|
|
1740
|
-
// WU-1240: Include memory context in spawn prompt
|
|
1741
|
-
baseDir,
|
|
1742
|
-
includeMemoryContext: shouldIncludeMemoryContext && memoryContextContent.length > 0,
|
|
1743
|
-
memoryContextContent,
|
|
1744
|
-
noContext: args.noContext
|
|
1745
|
-
});
|
|
1746
|
-
const briefAttestation = explicitDelegation ? buildBriefAttestation(invocation, clientName) : void 0;
|
|
1747
|
-
await emitSpawnOutputWithRegistry({
|
|
1748
|
-
id,
|
|
1749
|
-
output: invocation,
|
|
1750
|
-
isCodexClient: false,
|
|
1751
|
-
parentWu: args.parentWu,
|
|
1752
|
-
lane: doc.lane,
|
|
1753
|
-
briefAttestation,
|
|
1754
|
-
recordDelegationIntent: explicitDelegation,
|
|
1755
|
-
logPrefix: effectiveLogPrefix
|
|
1756
|
-
});
|
|
1757
|
-
await recordEvidenceOrFail({
|
|
1758
|
-
promptHash: briefAttestation?.promptHash,
|
|
1759
|
-
forceRecord: explicitDelegation
|
|
1760
|
-
});
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
export {
|
|
1764
|
-
recordWuBriefEvidence,
|
|
1765
|
-
runBriefLogic
|
|
1766
|
-
};
|