@lumenflow/cli 3.12.5 → 3.12.6

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.
Files changed (123) hide show
  1. package/dist/chunk-2D2VOCA4.js +37 -0
  2. package/dist/chunk-2D5KFYGX.js +284 -0
  3. package/dist/chunk-2GXVIN57.js +14072 -0
  4. package/dist/chunk-2MQ7HZWZ.js +26 -0
  5. package/dist/chunk-2UFQ3A3C.js +643 -0
  6. package/dist/chunk-3RG5ZIWI.js +10 -0
  7. package/dist/chunk-4N74J3UT.js +15 -0
  8. package/dist/chunk-5GTOXFYR.js +392 -0
  9. package/dist/chunk-5VY6MQMC.js +240 -0
  10. package/dist/chunk-67XVPMRY.js +1297 -0
  11. package/dist/chunk-6HO4GWJE.js +164 -0
  12. package/dist/chunk-6W5XHWYV.js +1890 -0
  13. package/dist/chunk-6X4EMYJQ.js +64 -0
  14. package/dist/chunk-6XYXI2NQ.js +772 -0
  15. package/dist/chunk-7ANSOV6Q.js +285 -0
  16. package/dist/chunk-A624LFLB.js +1380 -0
  17. package/dist/chunk-ADN5NHG4.js +126 -0
  18. package/dist/chunk-B7YJYJKG.js +33 -0
  19. package/dist/chunk-CCLHCPKG.js +210 -0
  20. package/dist/chunk-CK36VROC.js +1584 -0
  21. package/dist/chunk-D3UOFRSB.js +81 -0
  22. package/dist/chunk-DFR4DJBM.js +230 -0
  23. package/dist/chunk-DSYBDHYH.js +79 -0
  24. package/dist/chunk-DWMLTXKQ.js +1176 -0
  25. package/dist/chunk-E3REJTAJ.js +28 -0
  26. package/dist/chunk-EA3IVO64.js +633 -0
  27. package/dist/chunk-EK2AKZKD.js +55 -0
  28. package/dist/chunk-ELD7JTTT.js +343 -0
  29. package/dist/chunk-EX6TT2XI.js +195 -0
  30. package/dist/chunk-EXINSFZE.js +82 -0
  31. package/dist/chunk-EZ6ZBYBM.js +510 -0
  32. package/dist/chunk-FBKAPTJ2.js +16 -0
  33. package/dist/chunk-FVLV5RYH.js +1118 -0
  34. package/dist/chunk-GDNSBQVK.js +2485 -0
  35. package/dist/chunk-GPQHMBNN.js +278 -0
  36. package/dist/chunk-GTFJB67L.js +68 -0
  37. package/dist/chunk-HANJXVKW.js +1127 -0
  38. package/dist/chunk-HEVS5YLD.js +269 -0
  39. package/dist/chunk-HMEVZKPQ.js +9 -0
  40. package/dist/chunk-HRGSYNLM.js +3511 -0
  41. package/dist/chunk-ISZR5N4K.js +60 -0
  42. package/dist/chunk-J6SUPR2C.js +226 -0
  43. package/dist/chunk-JERYVEIZ.js +244 -0
  44. package/dist/chunk-JHHWGL2N.js +87 -0
  45. package/dist/chunk-JONWQUB5.js +775 -0
  46. package/dist/chunk-K2DIWWDM.js +1766 -0
  47. package/dist/chunk-KY4PGL5V.js +969 -0
  48. package/dist/chunk-L737LQ4C.js +1285 -0
  49. package/dist/chunk-LFTWYIB2.js +497 -0
  50. package/dist/chunk-LV47RFNJ.js +41 -0
  51. package/dist/chunk-MKSAITI7.js +15 -0
  52. package/dist/chunk-MZ7RKIX4.js +212 -0
  53. package/dist/chunk-NAP6CFSO.js +84 -0
  54. package/dist/chunk-ND6MY37M.js +16 -0
  55. package/dist/chunk-NMG736UR.js +683 -0
  56. package/dist/chunk-NRAXROED.js +32 -0
  57. package/dist/chunk-NRIZR3A7.js +690 -0
  58. package/dist/chunk-NX43BG3M.js +233 -0
  59. package/dist/chunk-O645XLSI.js +297 -0
  60. package/dist/chunk-OMJD6A3S.js +235 -0
  61. package/dist/chunk-QB6SJD4T.js +430 -0
  62. package/dist/chunk-QFSTL4J3.js +276 -0
  63. package/dist/chunk-QLGDFMFX.js +212 -0
  64. package/dist/chunk-RIAAGL2E.js +13 -0
  65. package/dist/chunk-RWO5XMZ6.js +86 -0
  66. package/dist/chunk-RXRKBBSM.js +149 -0
  67. package/dist/chunk-RZOZMML6.js +363 -0
  68. package/dist/chunk-U7I7FS7T.js +113 -0
  69. package/dist/chunk-UI42RODY.js +717 -0
  70. package/dist/chunk-UTVMVSCO.js +519 -0
  71. package/dist/chunk-V6OJGLBA.js +1746 -0
  72. package/dist/chunk-W2JHVH7D.js +152 -0
  73. package/dist/chunk-WD3Y7VQN.js +280 -0
  74. package/dist/chunk-WOCTQ5MS.js +303 -0
  75. package/dist/chunk-WZR3ZUNN.js +696 -0
  76. package/dist/chunk-XGI665H7.js +150 -0
  77. package/dist/chunk-XKY65P2T.js +304 -0
  78. package/dist/chunk-Y4CQZY65.js +57 -0
  79. package/dist/chunk-YFEXKLVE.js +194 -0
  80. package/dist/chunk-YHO3HS5X.js +287 -0
  81. package/dist/chunk-YLS7AZSX.js +738 -0
  82. package/dist/chunk-ZE473AO6.js +49 -0
  83. package/dist/chunk-ZF747T3O.js +644 -0
  84. package/dist/chunk-ZHCZHZH3.js +43 -0
  85. package/dist/chunk-ZZNZX2XY.js +87 -0
  86. package/dist/constants-7QAP3VQ4.js +23 -0
  87. package/dist/dist-IY3UUMWK.js +33 -0
  88. package/dist/init-templates.js +9 -9
  89. package/dist/invariants-runner-W5RGHCSU.js +27 -0
  90. package/dist/lane-lock-6J36HD5O.js +35 -0
  91. package/dist/mem-checkpoint-core-EANG2GVN.js +14 -0
  92. package/dist/mem-signal-core-2LZ2WYHW.js +19 -0
  93. package/dist/memory-store-OLB5FO7K.js +18 -0
  94. package/dist/service-6BYCOCO5.js +13 -0
  95. package/dist/spawn-policy-resolver-NTSZYQ6R.js +17 -0
  96. package/dist/spawn-task-builder-R4E2BHSW.js +22 -0
  97. package/dist/wu-claim.js +2 -2
  98. package/dist/wu-claim.js.map +1 -1
  99. package/dist/wu-done-gates.js +25 -4
  100. package/dist/wu-done-gates.js.map +1 -1
  101. package/dist/wu-done-ownership.js +6 -1
  102. package/dist/wu-done-ownership.js.map +1 -1
  103. package/dist/wu-done-pr-WLFFFEPJ.js +25 -0
  104. package/dist/wu-done-validation-3J5E36FE.js +30 -0
  105. package/dist/wu-done.js +6 -6
  106. package/dist/wu-done.js.map +1 -1
  107. package/dist/wu-duplicate-id-detector-5S7JHELK.js +232 -0
  108. package/dist/wu-edit-operations.js +58 -17
  109. package/dist/wu-edit-operations.js.map +1 -1
  110. package/dist/wu-edit-validators.js +104 -28
  111. package/dist/wu-edit-validators.js.map +1 -1
  112. package/dist/wu-edit.js +1 -1
  113. package/dist/wu-edit.js.map +1 -1
  114. package/dist/wu-spawn-prompt-builders.js +8 -7
  115. package/dist/wu-spawn-prompt-builders.js.map +1 -1
  116. package/package.json +8 -8
  117. package/packs/sidekick/.turbo/turbo-build.log +1 -1
  118. package/packs/sidekick/package.json +1 -1
  119. package/packs/software-delivery/.turbo/turbo-build.log +1 -1
  120. package/packs/software-delivery/package.json +1 -1
  121. package/templates/core/LUMENFLOW.md.template +1 -1
  122. package/templates/core/ai/onboarding/quick-ref-commands.md.template +3 -3
  123. package/templates/core/ai/onboarding/starting-prompt.md.template +11 -11
@@ -0,0 +1,1766 @@
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
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
+ };