@lumenflow/cli 3.1.3 → 3.2.1

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