@lumenflow/cli 2.18.3 → 2.20.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.
Files changed (128) hide show
  1. package/README.md +44 -42
  2. package/dist/agent-session.js +1 -1
  3. package/dist/agent-session.js.map +1 -1
  4. package/dist/commands/integrate.js +1 -0
  5. package/dist/commands/integrate.js.map +1 -1
  6. package/dist/commands.js +1 -0
  7. package/dist/commands.js.map +1 -1
  8. package/dist/delegation-list.js +140 -0
  9. package/dist/delegation-list.js.map +1 -0
  10. package/dist/docs-sync.js +1 -0
  11. package/dist/docs-sync.js.map +1 -1
  12. package/dist/doctor.js +36 -99
  13. package/dist/doctor.js.map +1 -1
  14. package/dist/gates-plan-resolvers.js +150 -0
  15. package/dist/gates-plan-resolvers.js.map +1 -0
  16. package/dist/gates-runners.js +533 -0
  17. package/dist/gates-runners.js.map +1 -0
  18. package/dist/gates-types.js +3 -0
  19. package/dist/gates-types.js.map +1 -1
  20. package/dist/gates-utils.js +316 -0
  21. package/dist/gates-utils.js.map +1 -0
  22. package/dist/gates.js +44 -1016
  23. package/dist/gates.js.map +1 -1
  24. package/dist/hooks/enforcement-generator.js +16 -880
  25. package/dist/hooks/enforcement-generator.js.map +1 -1
  26. package/dist/hooks/enforcement-sync.js +6 -5
  27. package/dist/hooks/enforcement-sync.js.map +1 -1
  28. package/dist/hooks/generators/auto-checkpoint.js +123 -0
  29. package/dist/hooks/generators/auto-checkpoint.js.map +1 -0
  30. package/dist/hooks/generators/enforce-worktree.js +188 -0
  31. package/dist/hooks/generators/enforce-worktree.js.map +1 -0
  32. package/dist/hooks/generators/index.js +16 -0
  33. package/dist/hooks/generators/index.js.map +1 -0
  34. package/dist/hooks/generators/pre-compact-checkpoint.js +134 -0
  35. package/dist/hooks/generators/pre-compact-checkpoint.js.map +1 -0
  36. package/dist/hooks/generators/require-wu.js +115 -0
  37. package/dist/hooks/generators/require-wu.js.map +1 -0
  38. package/dist/hooks/generators/session-start-recovery.js +101 -0
  39. package/dist/hooks/generators/session-start-recovery.js.map +1 -0
  40. package/dist/hooks/generators/signal-utils.js +52 -0
  41. package/dist/hooks/generators/signal-utils.js.map +1 -0
  42. package/dist/hooks/generators/warn-incomplete.js +65 -0
  43. package/dist/hooks/generators/warn-incomplete.js.map +1 -0
  44. package/dist/init-detection.js +228 -0
  45. package/dist/init-detection.js.map +1 -0
  46. package/dist/init-scaffolding.js +146 -0
  47. package/dist/init-scaffolding.js.map +1 -0
  48. package/dist/init-templates.js +1928 -0
  49. package/dist/init-templates.js.map +1 -0
  50. package/dist/init.js +137 -2425
  51. package/dist/init.js.map +1 -1
  52. package/dist/initiative-edit.js +42 -11
  53. package/dist/initiative-edit.js.map +1 -1
  54. package/dist/initiative-remove-wu.js +0 -0
  55. package/dist/initiative-status.js +29 -2
  56. package/dist/initiative-status.js.map +1 -1
  57. package/dist/mem-context.js +22 -9
  58. package/dist/mem-context.js.map +1 -1
  59. package/dist/orchestrate-init-status.js +32 -1
  60. package/dist/orchestrate-init-status.js.map +1 -1
  61. package/dist/orchestrate-initiative.js +2 -2
  62. package/dist/orchestrate-initiative.js.map +1 -1
  63. package/dist/orchestrate-monitor.js +38 -38
  64. package/dist/orchestrate-monitor.js.map +1 -1
  65. package/dist/plan-link.js +7 -14
  66. package/dist/plan-link.js.map +1 -1
  67. package/dist/public-manifest.js +19 -5
  68. package/dist/public-manifest.js.map +1 -1
  69. package/dist/shared-validators.js +1 -0
  70. package/dist/shared-validators.js.map +1 -1
  71. package/dist/spawn-list.js +0 -0
  72. package/dist/sync-templates.js +2 -1
  73. package/dist/sync-templates.js.map +1 -1
  74. package/dist/wu-claim-branch.js +121 -0
  75. package/dist/wu-claim-branch.js.map +1 -0
  76. package/dist/wu-claim-output.js +83 -0
  77. package/dist/wu-claim-output.js.map +1 -0
  78. package/dist/wu-claim-resume-handler.js +85 -0
  79. package/dist/wu-claim-resume-handler.js.map +1 -0
  80. package/dist/wu-claim-state.js +572 -0
  81. package/dist/wu-claim-state.js.map +1 -0
  82. package/dist/wu-claim-validation.js +439 -0
  83. package/dist/wu-claim-validation.js.map +1 -0
  84. package/dist/wu-claim-worktree.js +221 -0
  85. package/dist/wu-claim-worktree.js.map +1 -0
  86. package/dist/wu-claim.js +96 -1394
  87. package/dist/wu-claim.js.map +1 -1
  88. package/dist/wu-code-path-coverage.js +81 -0
  89. package/dist/wu-code-path-coverage.js.map +1 -0
  90. package/dist/wu-create-content.js +256 -0
  91. package/dist/wu-create-content.js.map +1 -0
  92. package/dist/wu-create-readiness.js +57 -0
  93. package/dist/wu-create-readiness.js.map +1 -0
  94. package/dist/wu-create-validation.js +124 -0
  95. package/dist/wu-create-validation.js.map +1 -0
  96. package/dist/wu-create.js +45 -442
  97. package/dist/wu-create.js.map +1 -1
  98. package/dist/wu-done.js +151 -249
  99. package/dist/wu-done.js.map +1 -1
  100. package/dist/wu-edit-operations.js +401 -0
  101. package/dist/wu-edit-operations.js.map +1 -0
  102. package/dist/wu-edit-validators.js +280 -0
  103. package/dist/wu-edit-validators.js.map +1 -0
  104. package/dist/wu-edit.js +43 -759
  105. package/dist/wu-edit.js.map +1 -1
  106. package/dist/wu-prep.js +43 -127
  107. package/dist/wu-prep.js.map +1 -1
  108. package/dist/wu-repair.js +1 -1
  109. package/dist/wu-repair.js.map +1 -1
  110. package/dist/wu-sandbox.js +253 -0
  111. package/dist/wu-sandbox.js.map +1 -0
  112. package/dist/wu-spawn-prompt-builders.js +1124 -0
  113. package/dist/wu-spawn-prompt-builders.js.map +1 -0
  114. package/dist/wu-spawn-strategy-resolver.js +319 -0
  115. package/dist/wu-spawn-strategy-resolver.js.map +1 -0
  116. package/dist/wu-spawn.js +9 -1398
  117. package/dist/wu-spawn.js.map +1 -1
  118. package/dist/wu-status.js +4 -0
  119. package/dist/wu-status.js.map +1 -1
  120. package/dist/wu-validate.js +1 -1
  121. package/dist/wu-validate.js.map +1 -1
  122. package/package.json +15 -11
  123. package/templates/core/LUMENFLOW.md.template +29 -99
  124. package/templates/core/UPGRADING.md.template +2 -2
  125. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +1 -1
  126. package/templates/core/ai/onboarding/quick-ref-commands.md.template +29 -4
  127. package/templates/core/ai/onboarding/release-process.md.template +1 -1
  128. package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +8 -8
@@ -0,0 +1,1124 @@
1
+ /**
2
+ * WU Spawn Prompt Builders
3
+ *
4
+ * Extracted from wu-spawn.ts (WU-1652).
5
+ * Contains all prompt section generators, formatters, and template helpers
6
+ * used to build spawn/handoff prompts for sub-agents.
7
+ *
8
+ * @module wu-spawn-prompt-builders
9
+ */
10
+ import { existsSync } from 'node:fs';
11
+ import path from 'node:path';
12
+ import { minimatch } from 'minimatch';
13
+ // WU-2252: Import invariants loader for spawn output injection
14
+ import { loadInvariants, INVARIANT_TYPES } from '@lumenflow/core/invariants-runner';
15
+ import { validateSpawnArgs, generateExecutionModeSection, generateThinkToolGuidance, } from '@lumenflow/core/wu-spawn-helpers';
16
+ import { getConfig } from '@lumenflow/core/config';
17
+ import { generateClientSkillsGuidance, generateSkillsSelectionSection, } from '@lumenflow/core/wu-spawn-skills';
18
+ // WU-1253: Template loader for extracted prompt templates
19
+ import { loadTemplatesWithOverrides, replaceTokens } from '@lumenflow/core/template-loader';
20
+ // WU-1192: Import prompt generation from Core (single source of truth)
21
+ // WU-1203: Import generateAgentCoordinationSection from core for config-driven progress signals
22
+ // WU-1288: Import policy-based test guidance and mandatory standards generators
23
+ import { TRUNCATION_WARNING_BANNER, SPAWN_END_SENTINEL, generateTestGuidance, generateAgentCoordinationSection, generatePolicyBasedTestGuidance, generateMandatoryStandards, generateEnforcementSummary, } from '@lumenflow/core/wu-spawn';
24
+ // WU-1288: Import resolvePolicy for methodology policy resolution
25
+ import { resolvePolicy } from '@lumenflow/core/resolve-policy';
26
+ // WU-1240: Import memory context integration for spawn prompts
27
+ import { generateMemoryContextSection, checkMemoryLayerInitialized, getMemoryContextMaxSize, } from '@lumenflow/core/wu-spawn-context';
28
+ // Re-export core constants for backwards compatibility
29
+ export { TRUNCATION_WARNING_BANNER, SPAWN_END_SENTINEL, generateTestGuidance, generateAgentCoordinationSection, };
30
+ // Re-export helper functions used by orchestration layer
31
+ export { validateSpawnArgs, generateExecutionModeSection, generateThinkToolGuidance, generateMemoryContextSection, checkMemoryLayerInitialized, getMemoryContextMaxSize, };
32
+ // Re-export skills functions used by orchestration layer
33
+ export { generateClientSkillsGuidance, generateSkillsSelectionSection };
34
+ // Re-export config
35
+ export { getConfig };
36
+ // Re-export policy resolver
37
+ export { resolvePolicy };
38
+ // ─── Mandatory Agent Detection ───
39
+ /**
40
+ * Mandatory agent trigger patterns.
41
+ * Mirrors MANDATORY_TRIGGERS from orchestration.constants.ts.
42
+ *
43
+ * Note: For LumenFlow framework development, this is empty since we don't have
44
+ * application-specific concerns like PHI, auth, or RLS. Projects using LumenFlow
45
+ * should configure their own triggers based on their domain requirements.
46
+ */
47
+ const MANDATORY_TRIGGERS = {
48
+ // No mandatory triggers for LumenFlow framework development.
49
+ };
50
+ /**
51
+ * Detect mandatory agents based on code paths.
52
+ *
53
+ * @param {string[]} codePaths - Array of file paths
54
+ * @returns {string[]} Array of mandatory agent names
55
+ */
56
+ export function detectMandatoryAgents(codePaths) {
57
+ if (!codePaths || codePaths.length === 0) {
58
+ return [];
59
+ }
60
+ const triggeredAgents = new Set();
61
+ for (const [agentName, patterns] of Object.entries(MANDATORY_TRIGGERS)) {
62
+ const isTriggered = codePaths.some((filePath) => patterns.some((pattern) => minimatch(filePath, pattern)));
63
+ if (isTriggered) {
64
+ triggeredAgents.add(agentName);
65
+ }
66
+ }
67
+ return Array.from(triggeredAgents);
68
+ }
69
+ // ─── Formatters ───
70
+ /**
71
+ * Format acceptance criteria as markdown list
72
+ *
73
+ * @param {string[]|undefined} acceptance - Acceptance criteria array
74
+ * @returns {string} Formatted acceptance criteria
75
+ */
76
+ export function formatAcceptance(acceptance) {
77
+ if (!acceptance || acceptance.length === 0) {
78
+ return '- No acceptance criteria defined';
79
+ }
80
+ return acceptance.map((item) => `- [ ] ${item}`).join('\n');
81
+ }
82
+ /**
83
+ * Format spec_refs as markdown links
84
+ *
85
+ * @param {string[]|undefined} specRefs - Spec references array
86
+ * @returns {string} Formatted references or empty string if none
87
+ */
88
+ function formatSpecRefs(specRefs) {
89
+ if (!specRefs || specRefs.length === 0) {
90
+ return '';
91
+ }
92
+ return specRefs.map((ref) => `- ${ref}`).join('\n');
93
+ }
94
+ /**
95
+ * Format risks as markdown list
96
+ *
97
+ * @param {string[]|undefined} risks - Risks array
98
+ * @returns {string} Formatted risks or empty string if none
99
+ */
100
+ function formatRisks(risks) {
101
+ if (!risks || risks.length === 0) {
102
+ return '';
103
+ }
104
+ return risks.map((risk) => `- ${risk}`).join('\n');
105
+ }
106
+ /**
107
+ * Format manual tests as markdown checklist
108
+ *
109
+ * @param {string[]|undefined} manualTests - Manual test steps
110
+ * @returns {string} Formatted tests or empty string if none
111
+ */
112
+ function formatManualTests(manualTests) {
113
+ if (!manualTests || manualTests.length === 0) {
114
+ return '';
115
+ }
116
+ return manualTests.map((test) => `- [ ] ${test}`).join('\n');
117
+ }
118
+ // ─── Implementation Context ───
119
+ /**
120
+ * Generate implementation context section (WU-1833)
121
+ *
122
+ * Includes spec_refs, notes, risks, and tests.manual if present.
123
+ * Sections with no content are omitted to keep prompts lean.
124
+ *
125
+ * @param {object} doc - WU YAML document
126
+ * @returns {string} Implementation context section or empty string
127
+ */
128
+ export function generateImplementationContext(doc) {
129
+ const sections = [];
130
+ // References (spec_refs)
131
+ const refs = formatSpecRefs(doc.spec_refs);
132
+ if (refs) {
133
+ sections.push(`## References\n\n${refs}`);
134
+ }
135
+ // Implementation Notes
136
+ if (doc.notes && doc.notes.trim()) {
137
+ sections.push(`## Implementation Notes\n\n${doc.notes.trim()}`);
138
+ }
139
+ // Risks
140
+ const risks = formatRisks(doc.risks);
141
+ if (risks) {
142
+ sections.push(`## Risks\n\n${risks}`);
143
+ }
144
+ // Manual Verification (tests.manual)
145
+ const manualTests = formatManualTests(doc.tests?.manual);
146
+ if (manualTests) {
147
+ sections.push(`## Manual Verification\n\n${manualTests}`);
148
+ }
149
+ if (sections.length === 0) {
150
+ return '';
151
+ }
152
+ return sections.join('\n\n---\n\n');
153
+ }
154
+ // ─── Invariants ───
155
+ /**
156
+ * Check if a code path matches an invariant based on type
157
+ *
158
+ * @param {object} invariant - Invariant definition
159
+ * @param {string[]} codePaths - Array of code paths
160
+ * @returns {boolean} True if code paths match the invariant
161
+ */
162
+ function codePathMatchesInvariant(invariant, codePaths) {
163
+ switch (invariant.type) {
164
+ case INVARIANT_TYPES.FORBIDDEN_FILE:
165
+ case INVARIANT_TYPES.REQUIRED_FILE:
166
+ return codePaths.some((p) => p === invariant.path || minimatch(p, invariant.path) || minimatch(invariant.path, p));
167
+ case INVARIANT_TYPES.MUTUAL_EXCLUSIVITY:
168
+ return codePaths.some((p) => invariant.paths.some((invPath) => p === invPath || minimatch(p, invPath)));
169
+ case INVARIANT_TYPES.FORBIDDEN_PATTERN:
170
+ case INVARIANT_TYPES.REQUIRED_PATTERN:
171
+ return (invariant.scope?.some((scopePattern) => codePaths.some((p) => minimatch(p, scopePattern))) ?? false);
172
+ // WU-2254: forbidden-import uses 'from' glob instead of 'scope'
173
+ case INVARIANT_TYPES.FORBIDDEN_IMPORT:
174
+ return invariant.from ? codePaths.some((p) => minimatch(p, invariant.from)) : false;
175
+ default:
176
+ return false;
177
+ }
178
+ }
179
+ /**
180
+ * Format a single invariant for output
181
+ *
182
+ * @param {object} inv - Invariant definition
183
+ * @returns {string[]} Lines of formatted output
184
+ */
185
+ function formatInvariantForOutput(inv) {
186
+ const lines = [`### ${inv.id} (${inv.type})`, '', inv.description, ''];
187
+ if (inv.message) {
188
+ lines.push(`**Action:** ${inv.message}`, '');
189
+ }
190
+ if (inv.path) {
191
+ lines.push(`**Path:** \`${inv.path}\``);
192
+ }
193
+ if (inv.paths) {
194
+ const formattedPaths = inv.paths.map((p) => `\`${p}\``).join(', ');
195
+ lines.push(`**Paths:** ${formattedPaths}`);
196
+ }
197
+ // WU-2254: forbidden-import specific fields
198
+ if (inv.from) {
199
+ lines.push(`**From:** \`${inv.from}\``);
200
+ }
201
+ if (inv.cannot_import && Array.isArray(inv.cannot_import)) {
202
+ const formattedImports = inv.cannot_import.map((m) => `\`${m}\``).join(', ');
203
+ lines.push(`**Cannot Import:** ${formattedImports}`);
204
+ }
205
+ // WU-2254: required-pattern specific fields
206
+ if (inv.pattern &&
207
+ (inv.type === INVARIANT_TYPES.REQUIRED_PATTERN ||
208
+ inv.type === INVARIANT_TYPES.FORBIDDEN_PATTERN)) {
209
+ lines.push(`**Pattern:** \`${inv.pattern}\``);
210
+ }
211
+ if (inv.scope && Array.isArray(inv.scope)) {
212
+ const formattedScope = inv.scope.map((s) => `\`${s}\``).join(', ');
213
+ lines.push(`**Scope:** ${formattedScope}`);
214
+ }
215
+ lines.push('');
216
+ return lines;
217
+ }
218
+ /**
219
+ * WU-2252: Generate invariants/prior-art section for code_paths
220
+ *
221
+ * Loads relevant invariants from invariants.yml and generates a section
222
+ * that surfaces constraints and prior-art for the WU's code_paths.
223
+ *
224
+ * @param {string[]} codePaths - Array of code paths from the WU
225
+ * @returns {string} Invariants/prior-art section or empty string if none relevant
226
+ */
227
+ export function generateInvariantsPriorArtSection(codePaths) {
228
+ if (!codePaths || codePaths.length === 0) {
229
+ return '';
230
+ }
231
+ // Try to load tools/invariants.yml
232
+ const invariantsPath = path.resolve('tools/invariants.yml');
233
+ if (!existsSync(invariantsPath)) {
234
+ return '';
235
+ }
236
+ let invariants;
237
+ try {
238
+ invariants = loadInvariants(invariantsPath);
239
+ }
240
+ catch {
241
+ return '';
242
+ }
243
+ if (!invariants || invariants.length === 0) {
244
+ return '';
245
+ }
246
+ // Find relevant invariants based on code_paths
247
+ const relevantInvariants = invariants.filter((inv) => codePathMatchesInvariant(inv, codePaths));
248
+ if (relevantInvariants.length === 0) {
249
+ return '';
250
+ }
251
+ // Format the section
252
+ const lines = [
253
+ '## Invariants/Prior-Art (WU-2252)',
254
+ '',
255
+ 'The following repo invariants are relevant to your code_paths:',
256
+ '',
257
+ ...relevantInvariants.flatMap(formatInvariantForOutput),
258
+ '**IMPORTANT:** Do not create specs or acceptance criteria that conflict with these invariants.',
259
+ ];
260
+ return lines.join('\n');
261
+ }
262
+ // ─── Preamble and Constraints ───
263
+ /**
264
+ * Generate the context loading preamble using the strategy
265
+ *
266
+ * @param {string} id - WU ID
267
+ * @param {SpawnStrategy} strategy - Client strategy
268
+ * @returns {string} Context loading preamble
269
+ */
270
+ export function generatePreamble(id, strategy) {
271
+ return strategy.getPreamble(id);
272
+ }
273
+ /**
274
+ * Generate the constraints block (appended at end per Lost in the Middle research)
275
+ *
276
+ * WU-2247: Aligned with LumenFlow section 7.2 (stop-and-ask) and section 7.3 (anti-loop guard).
277
+ * Includes item 6: MEMORY LAYER COORDINATION (WU-1589).
278
+ *
279
+ * @param {string} id - WU ID
280
+ * @returns {string} Constraints block
281
+ */
282
+ export function generateConstraints(id) {
283
+ return `---
284
+
285
+ <constraints>
286
+ CRITICAL RULES - ENFORCE BEFORE EVERY ACTION:
287
+
288
+ 1. TDD CHECKPOINT (VERIFY BEFORE IMPLEMENTATION)
289
+ - Did you write tests BEFORE implementation?
290
+ - Is there at least one failing test for each acceptance criterion?
291
+ - Never skip the RED phase — failing tests prove the test works
292
+
293
+ 2. ANTI-LOOP GUARD (LumenFlow §7.3)
294
+ - Max 3 attempts per unique error before escalating
295
+ - If same error repeats 3x, STOP and report with full context
296
+ - Retry with different approach, not same command
297
+
298
+ 3. STOP-AND-ASK TRIGGERS (LumenFlow §7.2 - narrow scope)
299
+ - Policy changes, auth/permissions modifications
300
+ - PII/PHI/safety issues, cloud spend, secrets, backups
301
+ - Same error repeats 3x
302
+ - For ordinary errors: fix and retry autonomously (up to 3 attempts)
303
+
304
+ 4. VERIFY COMPLETION before reporting success
305
+ - Run: node packages/@lumenflow/agent/dist/agent-verification.js ${id} (from shared checkout)
306
+ - Exit 0 = passed, Exit 1 = INCOMPLETE
307
+ - Never report "done" if verification fails
308
+
309
+ 5. NEVER FABRICATE COMPLETION
310
+ - If blockers remain, report INCOMPLETE
311
+ - If verification fails, summarize failures
312
+ - Honesty over false completion
313
+
314
+ 6. GIT WORKFLOW (CRITICAL - GitHub rules reject merge commits)
315
+ - GitHub REJECTS merge commits on main
316
+ - ALWAYS use \`git rebase origin/main\` before push
317
+ - Push to main via \`git push origin lane/...:main\` (fast-forward only)
318
+ - NEVER use \`git merge\` on main branch
319
+ - Let \`pnpm wu:done\` handle the merge workflow
320
+
321
+ 7. MEMORY LAYER COORDINATION (INIT-007)
322
+ - Use \`pnpm mem:checkpoint --wu ${id}\` to save progress before risky operations
323
+ - Check \`pnpm mem:inbox --wu ${id}\` periodically for parallel signals from other agents
324
+ - Checkpoint triggers (WU-1943): checkpoint after each acceptance criterion completed, checkpoint before gates, checkpoint every 30 tool calls
325
+
326
+ 8. SKIP-GATES AUTONOMY (WU-1142)
327
+ - If gates fail, first check if failure is pre-existing on main: \`git checkout main && pnpm gates\`
328
+ - 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\`
329
+ - Do NOT ask for approval - autonomous skip-gates for pre-existing failures is correct
330
+ - This prevents getting stuck on infrastructure debt
331
+ </constraints>`;
332
+ }
333
+ export function generateCodexConstraints(id) {
334
+ return `## Constraints (Critical)
335
+
336
+ 1. **TDD checkpoint**: tests BEFORE implementation; never skip RED
337
+ 2. **Stop on errors**: if any command fails, report BLOCKED (never DONE) with the error
338
+ 3. **Verify before success**: run \`pnpm gates\` in the worktree, then run \`node packages/@lumenflow/agent/dist/agent-verification.js ${id}\` (from the shared checkout)
339
+ 4. **No fabrication**: if blockers remain or verification fails, report INCOMPLETE
340
+ 5. **Git workflow**: avoid merge commits; let \`pnpm wu:done\` handle completion
341
+ 6. **Scope discipline**: stay within \`code_paths\`; capture out-of-scope issues via \`pnpm mem:create\`
342
+ 7. **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\``;
343
+ }
344
+ // ─── Section Generators ───
345
+ /**
346
+ * Generate mandatory agent advisory section
347
+ *
348
+ * @param {string[]} mandatoryAgents - Array of mandatory agent names
349
+ * @param {string} _id - WU ID (reserved for future use)
350
+ * @returns {string} Mandatory agent section or empty string
351
+ */
352
+ export function generateMandatoryAgentSection(mandatoryAgents, _id) {
353
+ if (mandatoryAgents.length === 0) {
354
+ return '';
355
+ }
356
+ const agentList = mandatoryAgents.map((agent) => ` - ${agent}`).join('\n');
357
+ return `
358
+ ## Mandatory Agents (MUST invoke before wu:done)
359
+
360
+ Based on code_paths, the following agents MUST be invoked:
361
+
362
+ ${agentList}
363
+
364
+ Run: pnpm orchestrate:monitor to check agent status
365
+ `;
366
+ }
367
+ /**
368
+ * Generate effort scaling rules section (WU-1986)
369
+ *
370
+ * Based on Anthropic multi-agent research: helps agents decide when to
371
+ * spawn sub-agents vs handle inline.
372
+ *
373
+ * @returns {string} Effort scaling section
374
+ */
375
+ export function generateEffortScalingRules() {
376
+ return `## Effort Scaling (When to Spawn Sub-Agents)
377
+
378
+ Use this heuristic to decide complexity:
379
+
380
+ | Complexity | Approach | Tool Calls |
381
+ |------------|----------|------------|
382
+ | **Simple** (single file, <50 lines) | Handle inline | 3-10 |
383
+ | **Moderate** (2-3 files, clear scope) | Handle inline | 10-20 |
384
+ | **Complex** (4+ files, exploration needed) | Spawn Explore agent first | 20+ |
385
+ | **Multi-domain** (cross-cutting concerns) | Spawn specialized sub-agents | Varies |
386
+
387
+ **Rule**: If you need >30 tool calls for a subtask, consider spawning a sub-agent with a focused scope.`;
388
+ }
389
+ /**
390
+ * Generate parallel tool call guidance (WU-1986)
391
+ *
392
+ * Based on Anthropic research: 3+ parallel tool calls significantly improve performance.
393
+ *
394
+ * @returns {string} Parallel tool call guidance
395
+ */
396
+ export function generateParallelToolCallGuidance() {
397
+ return `## Parallel Tool Calls (Performance)
398
+
399
+ **IMPORTANT**: Make 3+ tool calls in parallel when operations are independent.
400
+
401
+ Good examples:
402
+ - Reading multiple files simultaneously
403
+ - Running independent grep searches
404
+ - Spawning multiple Explore agents for different areas
405
+
406
+ Bad examples:
407
+ - Reading a file then editing it (sequential dependency)
408
+ - Running tests then checking results (sequential)
409
+
410
+ Parallelism reduces latency by 50-90% for complex tasks.`;
411
+ }
412
+ /**
413
+ * Generate iterative search heuristics (WU-1986)
414
+ *
415
+ * Based on Anthropic research: start broad, narrow focus.
416
+ *
417
+ * @returns {string} Search heuristics section
418
+ */
419
+ export function generateIterativeSearchHeuristics() {
420
+ return `## Search Strategy (Broad to Narrow)
421
+
422
+ When exploring the codebase:
423
+
424
+ 1. **Start broad**: Use Explore agent or glob patterns to understand structure
425
+ 2. **Evaluate findings**: What patterns exist? What's relevant?
426
+ 3. **Narrow focus**: Target specific files/functions based on findings
427
+ 4. **Iterate**: Refine if initial approach misses the target
428
+
429
+ Avoid: Jumping directly to specific file edits without understanding context.`;
430
+ }
431
+ /**
432
+ * Generate token budget awareness section (WU-1986)
433
+ *
434
+ * @param {string} id - WU ID
435
+ * @returns {string} Token budget section
436
+ */
437
+ export function generateTokenBudgetAwareness(id) {
438
+ return `## Token Budget Awareness
439
+
440
+ Context limit is ~200K tokens. Monitor your usage:
441
+
442
+ - **At 50+ tool calls**: Create a checkpoint (\`pnpm mem:checkpoint --wu ${id}\`)
443
+ - **At 100+ tool calls**: Consider spawning fresh sub-agent with focused scope
444
+ - **Before risky operations**: Always checkpoint first
445
+
446
+ If approaching limits, summarize progress and spawn continuation agent.`;
447
+ }
448
+ /**
449
+ * Generate structured completion format (WU-1986)
450
+ *
451
+ * @param {string} id - WU ID
452
+ * @returns {string} Completion format section
453
+ */
454
+ export function generateCompletionFormat(_id) {
455
+ return `## Completion Report Format
456
+
457
+ When finishing, provide structured output:
458
+
459
+ \`\`\`
460
+ ## Summary
461
+ <1-3 sentences describing what was accomplished>
462
+
463
+ ## Artifacts
464
+ - Files modified: <list>
465
+ - Tests added: <list>
466
+ - Documentation updated: <list>
467
+
468
+ ## Verification
469
+ - Gates: <pass/fail>
470
+ - Tests: <X passing, Y failing>
471
+
472
+ ## Blockers (if any)
473
+ - <blocker description>
474
+
475
+ ## Follow-up (if needed)
476
+ - <suggested next WU or action>
477
+ \`\`\`
478
+
479
+ This format enables orchestrator to track progress across waves.`;
480
+ }
481
+ /**
482
+ * Generate quick fix commands section (WU-1987)
483
+ *
484
+ * Provides format/lint/typecheck commands for quick fixes before gates.
485
+ *
486
+ * @returns {string} Quick fix commands section
487
+ */
488
+ export function generateQuickFixCommands() {
489
+ return `## Quick Fix Commands
490
+
491
+ If gates fail, try these before investigating:
492
+
493
+ \`\`\`bash
494
+ pnpm format # Auto-fix formatting issues
495
+ pnpm lint # Check linting (use --fix for auto-fix)
496
+ pnpm typecheck # Check TypeScript types
497
+ \`\`\`
498
+
499
+ **Use before gates** to catch simple issues early. These are faster than full \`pnpm gates\`.`;
500
+ }
501
+ /**
502
+ * Generate Worktree Block Recovery section (WU-1134)
503
+ *
504
+ * Provides guidance for agents when they're blocked by the worktree hook.
505
+ * This happens when agents try to commit from main instead of the worktree.
506
+ *
507
+ * @param {string} worktreePath - Worktree path from WU YAML
508
+ * @returns {string} Worktree block recovery section
509
+ */
510
+ export function generateWorktreeBlockRecoverySection(worktreePath) {
511
+ return `## When Blocked by Worktree Hook
512
+
513
+ If you encounter a "worktree required" or "commit blocked" error:
514
+
515
+ 1. **Check existing worktrees**: \`git worktree list\`
516
+ 2. **Navigate to the worktree**: \`cd ${worktreePath || 'worktrees/<lane>-wu-xxx'}\`
517
+ 3. **Retry your operation** from within the worktree
518
+ 4. **Use relative paths only** (never absolute paths starting with /)
519
+
520
+ ### Common Causes
521
+
522
+ - Running \`git commit\` from main checkout instead of worktree
523
+ - Using absolute paths that bypass worktree isolation
524
+ - Forgetting to \`cd\` to worktree after \`wu:claim\`
525
+
526
+ ### Quick Fix
527
+
528
+ \`\`\`bash
529
+ # Check where you are
530
+ pwd
531
+ git worktree list
532
+
533
+ # Navigate to your worktree
534
+ cd ${worktreePath || 'worktrees/<lane>-wu-xxx'}
535
+
536
+ # Retry your commit
537
+ git add . && git commit -m "your message"
538
+ \`\`\``;
539
+ }
540
+ /**
541
+ * Generate Lane Selection section (WU-2107)
542
+ *
543
+ * Provides guidance on lane selection when creating new WUs.
544
+ * Points agents to wu:infer-lane for automated lane suggestions.
545
+ *
546
+ * @returns {string} Lane Selection section
547
+ */
548
+ export function generateLaneSelectionSection() {
549
+ return `## Lane Selection
550
+
551
+ When creating new WUs, use the correct lane to enable parallelization:
552
+
553
+ \`\`\`bash
554
+ # Get lane suggestion based on code paths and description
555
+ pnpm wu:infer-lane --id WU-XXX
556
+
557
+ # Or infer from manual inputs
558
+ pnpm wu:infer-lane --paths "tools/**" --desc "CLI improvements"
559
+ \`\`\`
560
+
561
+ **Lane taxonomy**: See \`.lumenflow.lane-inference.yaml\` for valid lanes and patterns.
562
+
563
+ **Why lanes matter**: WIP=1 per lane means correct lane selection enables parallel work across lanes.`;
564
+ }
565
+ /**
566
+ * Generate Worktree Path Guidance section (WU-2362)
567
+ *
568
+ * Provides guidance for sub-agents on working within worktrees, including
569
+ * how to determine the worktree root and where to create stamps.
570
+ *
571
+ * Problem: CLAUDE_PROJECT_DIR is hook-only; sub-agents inherit parent cwd (main).
572
+ * Solution: Use git rev-parse --show-toplevel to determine actual worktree root.
573
+ *
574
+ * @param {string|undefined} worktreePath - Worktree path from WU YAML
575
+ * @returns {string} Worktree path guidance section
576
+ */
577
+ export function generateWorktreePathGuidance(worktreePath) {
578
+ if (!worktreePath) {
579
+ return '';
580
+ }
581
+ return `## Worktree Path Guidance (WU-2362)
582
+
583
+ **Your worktree:** \`${worktreePath}\`
584
+
585
+ ### Finding the Worktree Root
586
+
587
+ Sub-agents may inherit the parent's cwd (main checkout). To find the actual worktree root:
588
+
589
+ \`\`\`bash
590
+ # Get the worktree root (not main checkout)
591
+ git rev-parse --show-toplevel
592
+ \`\`\`
593
+
594
+ ### Stamp Creation
595
+
596
+ When creating \`.lumenflow/\` stamps or other artifacts:
597
+
598
+ 1. **ALWAYS** create stamps in the **worktree**, not main
599
+ 2. Use \`git rev-parse --show-toplevel\` to get the correct base path
600
+ 3. Stamps created on main will be lost when the worktree merges
601
+
602
+ \`\`\`bash
603
+ # CORRECT: Create stamp in worktree
604
+ WORKTREE_ROOT=$(git rev-parse --show-toplevel)
605
+ mkdir -p "$WORKTREE_ROOT/.lumenflow/agent-runs"
606
+ touch "$WORKTREE_ROOT/.lumenflow/agent-runs/code-reviewer.stamp"
607
+
608
+ # WRONG: Hardcoded path to main
609
+ # touch /path/to/main/.lumenflow/agent-runs/code-reviewer.stamp
610
+ \`\`\`
611
+
612
+ ### Why This Matters
613
+
614
+ - Stamps on main get overwritten by worktree merge
615
+ - \`wu:done\` validates stamps exist in the worktree branch
616
+ - Parallel WUs in other lanes won't see your stamps if on main`;
617
+ }
618
+ /**
619
+ * Generate the Bug Discovery section (WU-1592, WU-2284)
620
+ *
621
+ * Instructs sub-agents to capture bugs found mid-WU via mem:create.
622
+ * This enables scope-creep tracking and ensures discovered bugs
623
+ * are not lost when agents encounter issues outside their WU scope.
624
+ *
625
+ * WU-2284: Added explicit prohibition against using wu:create directly
626
+ * for discovered issues. Agents must use mem:create for capture, then
627
+ * human triage decides whether to promote to a WU.
628
+ *
629
+ * @param {string} id - WU ID
630
+ * @returns {string} Bug Discovery section
631
+ */
632
+ export function generateBugDiscoverySection(id) {
633
+ return `## Bug Discovery (Mid-WU Issue Capture)
634
+
635
+ If you discover a bug or issue **outside the scope of this WU**:
636
+
637
+ 1. **Capture it immediately** using:
638
+ \`\`\`bash
639
+ pnpm mem:create 'Bug: <description>' --type discovery --tags bug,scope-creep --wu ${id}
640
+ \`\`\`
641
+
642
+ 2. **Continue with your WU** — do not fix bugs outside your scope
643
+ 3. **Reference in notes** — mention the mem node ID in your completion notes
644
+
645
+ ### NEVER use wu:create for discovered issues
646
+
647
+ **Do NOT use \`wu:create\` directly for bugs discovered mid-WU.**
648
+
649
+ - \`mem:create\` = **capture** (immediate, no human approval needed)
650
+ - \`wu:create\` = **planned work** (requires human triage and approval)
651
+
652
+ Discovered issues MUST go through human triage before becoming WUs.
653
+ Using \`wu:create\` directly bypasses the triage workflow and creates
654
+ unreviewed work items.
655
+
656
+ ### When to Capture
657
+
658
+ - Found a bug in code NOT in your \`code_paths\`
659
+ - Discovered an issue that would require >10 lines to fix
660
+ - Encountered broken behaviour unrelated to your acceptance criteria
661
+
662
+ ### Triage Workflow
663
+
664
+ After WU completion, bugs can be promoted to Bug WUs by humans:
665
+ \`\`\`bash
666
+ pnpm mem:triage --wu ${id} # List discoveries for this WU
667
+ pnpm mem:triage --promote <node-id> --lane "<lane>" # Create Bug WU (human action)
668
+ \`\`\`
669
+
670
+ See: https://lumenflow.dev/reference/agent-invocation-guide/ §Bug Discovery`;
671
+ }
672
+ /**
673
+ * Generate lane-specific guidance
674
+ *
675
+ * @param {string} lane - Lane name
676
+ * @returns {string} Lane-specific guidance or empty string
677
+ */
678
+ export function generateLaneGuidance(lane) {
679
+ if (!lane)
680
+ return '';
681
+ const laneParent = lane.split(':')[0].trim();
682
+ const guidance = {
683
+ Operations: `## Lane-Specific: Tooling
684
+
685
+ - Update tool documentation in tools/README.md or relevant docs if adding new CLI commands`,
686
+ Intelligence: `## Lane-Specific: Intelligence
687
+
688
+ - All prompt changes require golden dataset evaluation (pnpm prompts:eval)
689
+ - Follow prompt versioning guidelines in ai/prompts/README.md`,
690
+ Experience: `## Lane-Specific: Experience
691
+
692
+ - Follow design system tokens defined in the project
693
+ - Ensure accessibility compliance (WCAG 2.1 AA)`,
694
+ Core: `## Lane-Specific: Core
695
+
696
+ - Maintain hexagonal architecture boundaries
697
+ - Update domain model documentation if changing entities`,
698
+ };
699
+ return guidance[laneParent] || '';
700
+ }
701
+ /**
702
+ * Generate the Action section based on WU claim status (WU-1745).
703
+ *
704
+ * If WU is already claimed (has claimed_at and worktree_path), tells agent
705
+ * to continue in the existing worktree.
706
+ *
707
+ * If WU is unclaimed (status: ready), tells agent to run wu:claim first.
708
+ *
709
+ * @param {object} doc - WU YAML document
710
+ * @param {string} id - WU ID
711
+ * @returns {string} Action section content
712
+ */
713
+ export function generateActionSection(doc, id) {
714
+ const isAlreadyClaimed = doc.claimed_at && doc.worktree_path;
715
+ if (isAlreadyClaimed) {
716
+ return `This WU is already claimed. Continue implementation in worktree following all standards above.
717
+
718
+ cd ${doc.worktree_path}`;
719
+ }
720
+ // WU is unclaimed - agent needs to claim first
721
+ const laneSlug = (doc.lane || 'unknown')
722
+ .toLowerCase()
723
+ .replace(/[:\s]+/g, '-')
724
+ .replace(/-+/g, '-');
725
+ return `**FIRST: Claim this WU before starting work:**
726
+
727
+ \`\`\`bash
728
+ pnpm wu:claim --id ${id} --lane "${doc.lane}"
729
+ cd worktrees/${laneSlug}-${id.toLowerCase()}
730
+ \`\`\`
731
+
732
+ Then implement following all standards above.
733
+
734
+ **CRITICAL:** Never use \`git worktree add\` directly. Always use \`pnpm wu:claim\` to ensure:
735
+ - Event tracking in .lumenflow/state/wu-events.jsonl
736
+ - Lane lock acquisition (WIP=1 enforcement)
737
+ - Session tracking for context recovery`;
738
+ }
739
+ /**
740
+ * Generate the Completion Workflow section for sub-agents (WU-2682).
741
+ *
742
+ * Explicitly instructs sub-agents to run wu:done autonomously after gates pass.
743
+ * This prevents agents from asking permission instead of completing.
744
+ *
745
+ * @param {string} id - WU ID
746
+ * @returns {string} Completion Workflow section
747
+ */
748
+ export function generateCompletionWorkflowSection(id) {
749
+ return `## Completion Workflow
750
+
751
+ **CRITICAL: Complete autonomously. Do NOT ask for permission.**
752
+
753
+ After all acceptance criteria are satisfied:
754
+
755
+ 1. Run gates in the worktree: \`pnpm gates\`
756
+ 2. If gates pass, cd back to main checkout
757
+ 3. Run: \`pnpm wu:done --id ${id}\`
758
+
759
+ \`\`\`bash
760
+ # From worktree, after gates pass:
761
+ cd /path/to/main # NOT the worktree
762
+ pnpm wu:done --id ${id}
763
+ \`\`\`
764
+
765
+ **wu:done** handles: merge to main, stamp creation, worktree cleanup.
766
+
767
+ **Do not ask** "should I run wu:done?" — just run it when gates pass.`;
768
+ }
769
+ export function generateClientBlocksSection(clientContext) {
770
+ if (!clientContext?.config?.blocks?.length)
771
+ return '';
772
+ const blocks = clientContext.config.blocks
773
+ .map((block) => `### ${block.title}\n\n${block.content}`)
774
+ .join('\n\n');
775
+ return `## Client Guidance (${clientContext.name})\n\n${blocks}`;
776
+ }
777
+ // ─── Template Helpers ───
778
+ /**
779
+ * WU-1253: Try to load templates for spawn prompt sections.
780
+ *
781
+ * Implements shadow mode: tries templates first, returns empty map
782
+ * if templates aren't available (caller uses hardcoded fallback).
783
+ *
784
+ * @param clientName - Client name for overrides (e.g., 'claude-code', 'cursor')
785
+ * @param context - Token values for replacement
786
+ * @returns Map of template id to processed content, empty if templates unavailable
787
+ */
788
+ export function tryLoadTemplates(clientName, context) {
789
+ const result = new Map();
790
+ try {
791
+ const baseDir = process.cwd();
792
+ const templates = loadTemplatesWithOverrides(baseDir, clientName);
793
+ // Process each template: replace tokens
794
+ for (const [id, template] of templates) {
795
+ const processed = replaceTokens(template.content, context);
796
+ result.set(id, processed);
797
+ }
798
+ }
799
+ catch {
800
+ // Template loading failed - return empty map for hardcoded fallback
801
+ }
802
+ return result;
803
+ }
804
+ /**
805
+ * WU-1253: Build template context from WU document.
806
+ *
807
+ * @param doc - WU YAML document
808
+ * @param id - WU ID
809
+ * @returns Context for template token replacement
810
+ */
811
+ export function buildSpawnTemplateContext(doc, id) {
812
+ const lane = doc.lane || '';
813
+ const laneParent = lane.split(':')[0]?.trim() || '';
814
+ const type = (doc.type || 'feature').toLowerCase();
815
+ return {
816
+ WU_ID: id,
817
+ LANE: lane,
818
+ TYPE: type,
819
+ TITLE: doc.title || '',
820
+ DESCRIPTION: doc.description || '',
821
+ WORKTREE_PATH: doc.worktree_path || '',
822
+ laneParent,
823
+ // Lowercase aliases for condition evaluation
824
+ type,
825
+ lane,
826
+ worktreePath: doc.worktree_path || '',
827
+ };
828
+ }
829
+ // ─── Full Prompt Generators ───
830
+ /**
831
+ * Generate the complete Task tool invocation
832
+ *
833
+ * @param {object} doc - WU YAML document
834
+ * @param {string} id - WU ID
835
+ * @param {SpawnStrategy} strategy - Client strategy
836
+ * @param {object} [options={}] - Thinking mode options
837
+ * @param {boolean} [options.thinking] - Whether extended thinking is enabled
838
+ * @param {boolean} [options.noThinking] - Whether thinking is explicitly disabled
839
+ * @param {string} [options.budget] - Token budget for thinking
840
+ * @returns {string} Complete Task tool invocation
841
+ */
842
+ export function generateTaskInvocation(doc, id, strategy, options = {}) {
843
+ const codePaths = doc.code_paths || [];
844
+ const mandatoryAgents = detectMandatoryAgents(codePaths);
845
+ // WU-1253: Try loading templates (shadow mode - falls back to hardcoded if unavailable)
846
+ // WU-1681: Use resolved client from caller; fall back for template loading only
847
+ const clientName = options.client?.name || 'claude-code';
848
+ const templateContext = buildSpawnTemplateContext(doc, id);
849
+ const templates = tryLoadTemplates(clientName, templateContext);
850
+ const preamble = generatePreamble(id, strategy);
851
+ const clientContext = options.client;
852
+ const config = options.config || getConfig();
853
+ // WU-1288: Resolve methodology policy from config
854
+ const policy = resolvePolicy(config);
855
+ // WU-1142: Use type-aware test guidance instead of hardcoded TDD directive
856
+ // WU-1288: Use policy-based test guidance that respects methodology.testing config
857
+ // WU-1253: Try template first, fall back to policy-based guidance
858
+ const testGuidance = templates.get('tdd-directive') || generatePolicyBasedTestGuidance(doc.type, policy);
859
+ // WU-1288: Generate enforcement summary from resolved policy
860
+ const enforcementSummary = generateEnforcementSummary(policy);
861
+ // WU-1288: Generate mandatory standards based on resolved policy
862
+ const mandatoryStandards = generateMandatoryStandards(policy);
863
+ // WU-1142: Pass lane to get byLane skills
864
+ const clientSkillsGuidance = generateClientSkillsGuidance(clientContext, doc.lane);
865
+ // WU-1253: Try template for skills-selection, build skills section
866
+ const skillsTemplateContent = templates.get('skills-selection');
867
+ const skillsGuidanceSuffix = clientSkillsGuidance ? '\n' + clientSkillsGuidance : '';
868
+ const skillsBaseContent = skillsTemplateContent || generateSkillsSelectionSection(doc, config, clientContext?.name);
869
+ const skillsSection = skillsBaseContent + skillsGuidanceSuffix;
870
+ const clientBlocks = generateClientBlocksSection(clientContext);
871
+ const mandatorySection = generateMandatoryAgentSection(mandatoryAgents, id);
872
+ const laneGuidance = generateLaneGuidance(doc.lane);
873
+ // WU-1253: Try template for bug-discovery
874
+ const bugDiscoverySection = templates.get('bug-discovery') || generateBugDiscoverySection(id);
875
+ // WU-1253: Try template for constraints
876
+ const constraints = templates.get('constraints') || generateConstraints(id);
877
+ const implementationContext = generateImplementationContext(doc);
878
+ // WU-2252: Generate invariants/prior-art section for code_paths
879
+ const invariantsPriorArt = generateInvariantsPriorArtSection(codePaths);
880
+ // WU-1986: Anthropic multi-agent best practices sections
881
+ // WU-1253: Try templates for these sections
882
+ const effortScaling = templates.get('effort-scaling') || generateEffortScalingRules();
883
+ const parallelToolCalls = templates.get('parallel-tool-calls') || generateParallelToolCallGuidance();
884
+ const searchHeuristics = templates.get('search-heuristics') || generateIterativeSearchHeuristics();
885
+ const tokenBudget = templates.get('token-budget') || generateTokenBudgetAwareness(id);
886
+ const completionFormat = generateCompletionFormat(id);
887
+ // WU-1987: Agent coordination and quick fix sections
888
+ const agentCoordination = generateAgentCoordinationSection(id);
889
+ // WU-1253: Try template for quick-fix-commands
890
+ const quickFix = templates.get('quick-fix-commands') || generateQuickFixCommands();
891
+ // WU-2107: Lane selection guidance
892
+ // WU-1253: Try template for lane-selection
893
+ const laneSelection = templates.get('lane-selection') || generateLaneSelectionSection();
894
+ // WU-2362: Worktree path guidance for sub-agents
895
+ const worktreeGuidance = generateWorktreePathGuidance(doc.worktree_path);
896
+ // WU-1134: Worktree block recovery guidance
897
+ // WU-1253: Try template for worktree-recovery
898
+ const worktreeBlockRecovery = templates.get('worktree-recovery') || generateWorktreeBlockRecoverySection(doc.worktree_path);
899
+ // WU-1240: Memory context section
900
+ // Include if explicitly enabled and not disabled via noContext
901
+ const shouldIncludeMemoryContext = options.includeMemoryContext && !options.noContext;
902
+ const memoryContextSection = shouldIncludeMemoryContext ? options.memoryContextContent || '' : '';
903
+ // Generate thinking mode sections if applicable
904
+ const executionModeSection = generateExecutionModeSection(options);
905
+ const thinkToolGuidance = generateThinkToolGuidance(options);
906
+ // Build optional sections string
907
+ const thinkingSections = [executionModeSection, thinkToolGuidance]
908
+ .filter((section) => section.length > 0)
909
+ .join('\n\n---\n\n');
910
+ const thinkingBlock = thinkingSections ? `${thinkingSections}\n\n---\n\n` : '';
911
+ // Build the task prompt
912
+ // WU-1131: Warning banner at start, end sentinel after constraints
913
+ // WU-1142: Type-aware test guidance (TDD for code, format-only for docs, etc.)
914
+ const taskPrompt = `${TRUNCATION_WARNING_BANNER}<task>
915
+ ${preamble}
916
+ </task>
917
+
918
+ ---
919
+
920
+ ${testGuidance}
921
+
922
+ ---
923
+
924
+ # ${id}: ${doc.title || 'Untitled'}
925
+
926
+ ## WU Details
927
+
928
+ - **ID:** ${id}
929
+ - **Lane:** ${doc.lane || 'Unknown'}
930
+ - **Type:** ${doc.type || 'feature'}
931
+ - **Status:** ${doc.status || 'unknown'}
932
+ - **Worktree:** ${doc.worktree_path || `worktrees/<lane>-${id.toLowerCase()}`}
933
+
934
+ ## Description
935
+
936
+ ${doc.description || 'No description provided.'}
937
+
938
+ ## Acceptance Criteria
939
+
940
+ ${formatAcceptance(doc.acceptance)}
941
+
942
+ ## Code Paths
943
+
944
+ ${codePaths.length > 0 ? codePaths.map((p) => `- ${p}`).join('\n') : '- No code paths defined'}
945
+ ${mandatorySection}${invariantsPriorArt ? `---\n\n${invariantsPriorArt}\n\n` : ''}${implementationContext ? `---\n\n${implementationContext}\n\n` : ''}---
946
+
947
+ ${thinkingBlock}${skillsSection}
948
+ ${memoryContextSection ? `---\n\n${memoryContextSection}\n\n` : ''}---
949
+
950
+ ${mandatoryStandards}
951
+
952
+ ---
953
+
954
+ ${enforcementSummary}
955
+
956
+ ${clientBlocks ? `---\n\n${clientBlocks}\n\n` : ''}${worktreeGuidance ? `---\n\n${worktreeGuidance}\n\n` : ''}---
957
+
958
+ ${bugDiscoverySection}
959
+
960
+ ---
961
+
962
+ ${effortScaling}
963
+
964
+ ---
965
+
966
+ ${parallelToolCalls}
967
+
968
+ ---
969
+
970
+ ${searchHeuristics}
971
+
972
+ ---
973
+
974
+ ${tokenBudget}
975
+
976
+ ---
977
+
978
+ ${completionFormat}
979
+
980
+ ---
981
+
982
+ ${agentCoordination}
983
+
984
+ ---
985
+
986
+ ${quickFix}
987
+
988
+ ---
989
+
990
+ ${laneSelection}
991
+
992
+ ---
993
+
994
+ ${laneGuidance}${laneGuidance ? '\n\n---\n\n' : ''}## Action
995
+
996
+ ${generateActionSection(doc, id)}
997
+
998
+ ---
999
+
1000
+ ${worktreeBlockRecovery}
1001
+
1002
+ ${constraints}
1003
+
1004
+ ${SPAWN_END_SENTINEL}`;
1005
+ // Escape special characters for XML output
1006
+ const escapedPrompt = taskPrompt
1007
+ .replace(/&/g, '&amp;')
1008
+ .replace(/</g, '&lt;')
1009
+ .replace(/>/g, '&gt;');
1010
+ // Build the Task tool invocation block using antml format
1011
+ // Using array join to avoid XML parsing issues
1012
+ const openTag = '<' + 'antml:invoke name="Task">';
1013
+ const closeTag = '</' + 'antml:invoke>';
1014
+ const paramOpen = '<' + 'antml:parameter name="';
1015
+ const paramClose = '</' + 'antml:parameter>';
1016
+ const invocation = [
1017
+ '<' + 'antml:function_calls>',
1018
+ openTag,
1019
+ `${paramOpen}subagent_type">general-purpose${paramClose}`,
1020
+ `${paramOpen}description">Execute ${id}${paramClose}`,
1021
+ `${paramOpen}prompt">${escapedPrompt}${paramClose}`,
1022
+ closeTag,
1023
+ '</' + 'antml:function_calls>',
1024
+ ].join('\n');
1025
+ return invocation;
1026
+ }
1027
+ export function generateCodexPrompt(doc, id, strategy, options = {}) {
1028
+ const codePaths = doc.code_paths || [];
1029
+ const mandatoryAgents = detectMandatoryAgents(codePaths);
1030
+ const preamble = generatePreamble(id, strategy);
1031
+ // WU-1142: Use type-aware test guidance instead of hardcoded TDD directive
1032
+ const testGuidance = generateTestGuidance(doc.type);
1033
+ const mandatorySection = generateMandatoryAgentSection(mandatoryAgents, id);
1034
+ const laneGuidance = generateLaneGuidance(doc.lane);
1035
+ const bugDiscoverySection = generateBugDiscoverySection(id);
1036
+ const implementationContext = generateImplementationContext(doc);
1037
+ const action = generateActionSection(doc, id);
1038
+ const constraints = generateCodexConstraints(id);
1039
+ const clientContext = options.client;
1040
+ const config = options.config || getConfig();
1041
+ // WU-1142: Pass lane to get byLane skills
1042
+ const clientSkillsGuidance = generateClientSkillsGuidance(clientContext, doc.lane);
1043
+ const skillsSection = generateSkillsSelectionSection(doc, config, clientContext?.name) +
1044
+ (clientSkillsGuidance ? `\n${clientSkillsGuidance}` : '');
1045
+ const clientBlocks = generateClientBlocksSection(clientContext);
1046
+ const executionModeSection = generateExecutionModeSection(options);
1047
+ const thinkToolGuidance = generateThinkToolGuidance(options);
1048
+ const thinkingSections = [executionModeSection, thinkToolGuidance]
1049
+ .filter((section) => section.length > 0)
1050
+ .join('\n\n---\n\n');
1051
+ const thinkingBlock = thinkingSections ? `${thinkingSections}\n\n---\n\n` : '';
1052
+ // WU-1134: Worktree block recovery guidance
1053
+ const worktreeBlockRecovery = generateWorktreeBlockRecoverySection(doc.worktree_path);
1054
+ // WU-1240: Memory context section
1055
+ const shouldIncludeMemoryContext = options.includeMemoryContext && !options.noContext;
1056
+ const memoryContextSection = shouldIncludeMemoryContext ? options.memoryContextContent || '' : '';
1057
+ // WU-1131: Warning banner at start, end sentinel after constraints
1058
+ // WU-1142: Type-aware test guidance
1059
+ return `${TRUNCATION_WARNING_BANNER}# ${id}: ${doc.title || 'Untitled'}
1060
+
1061
+ ${testGuidance}
1062
+
1063
+ ---
1064
+
1065
+ ## Context
1066
+
1067
+ ${preamble}
1068
+
1069
+ ---
1070
+
1071
+ ## WU Details
1072
+
1073
+ - **ID:** ${id}
1074
+ - **Lane:** ${doc.lane || 'Unknown'}
1075
+ - **Type:** ${doc.type || 'feature'}
1076
+ - **Status:** ${doc.status || 'unknown'}
1077
+ - **Worktree:** ${doc.worktree_path || `worktrees/<lane>-${id.toLowerCase()}`}
1078
+
1079
+ ## Description
1080
+
1081
+ ${doc.description || 'No description provided.'}
1082
+
1083
+ ## Scope (code_paths)
1084
+
1085
+ Only change files within these paths:
1086
+
1087
+ ${codePaths.length > 0 ? codePaths.map((p) => `- ${p}`).join('\n') : '- No code paths defined'}
1088
+
1089
+ ## Acceptance Criteria
1090
+
1091
+ ${formatAcceptance(doc.acceptance)}
1092
+
1093
+ ---
1094
+
1095
+ ${skillsSection}
1096
+ ${memoryContextSection ? `---\n\n${memoryContextSection}\n\n` : ''}---
1097
+
1098
+ ## Action
1099
+
1100
+ ${action}
1101
+
1102
+ ---
1103
+
1104
+ ## Verification
1105
+
1106
+ - Run in worktree: \`pnpm gates\`
1107
+ - From shared checkout: \`node packages/@lumenflow/agent/dist/agent-verification.js ${id}\`
1108
+
1109
+ ---
1110
+
1111
+ ${mandatorySection}${implementationContext ? `${implementationContext}\n\n---\n\n` : ''}${clientBlocks ? `${clientBlocks}\n\n---\n\n` : ''}${thinkingBlock}${bugDiscoverySection}
1112
+
1113
+ ---
1114
+
1115
+ ${laneGuidance}${laneGuidance ? '\n\n---\n\n' : ''}${worktreeBlockRecovery}
1116
+
1117
+ ---
1118
+
1119
+ ${constraints}
1120
+
1121
+ ${SPAWN_END_SENTINEL}
1122
+ `;
1123
+ }
1124
+ //# sourceMappingURL=wu-spawn-prompt-builders.js.map