@lumenflow/cli 2.18.3 → 2.19.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 (104) hide show
  1. package/README.md +42 -41
  2. package/dist/delegation-list.js +140 -0
  3. package/dist/delegation-list.js.map +1 -0
  4. package/dist/doctor.js +35 -99
  5. package/dist/doctor.js.map +1 -1
  6. package/dist/gates-plan-resolvers.js +150 -0
  7. package/dist/gates-plan-resolvers.js.map +1 -0
  8. package/dist/gates-runners.js +533 -0
  9. package/dist/gates-runners.js.map +1 -0
  10. package/dist/gates-types.js +3 -0
  11. package/dist/gates-types.js.map +1 -1
  12. package/dist/gates-utils.js +316 -0
  13. package/dist/gates-utils.js.map +1 -0
  14. package/dist/gates.js +44 -1016
  15. package/dist/gates.js.map +1 -1
  16. package/dist/hooks/enforcement-generator.js +16 -880
  17. package/dist/hooks/enforcement-generator.js.map +1 -1
  18. package/dist/hooks/enforcement-sync.js +1 -4
  19. package/dist/hooks/enforcement-sync.js.map +1 -1
  20. package/dist/hooks/generators/auto-checkpoint.js +123 -0
  21. package/dist/hooks/generators/auto-checkpoint.js.map +1 -0
  22. package/dist/hooks/generators/enforce-worktree.js +188 -0
  23. package/dist/hooks/generators/enforce-worktree.js.map +1 -0
  24. package/dist/hooks/generators/index.js +16 -0
  25. package/dist/hooks/generators/index.js.map +1 -0
  26. package/dist/hooks/generators/pre-compact-checkpoint.js +134 -0
  27. package/dist/hooks/generators/pre-compact-checkpoint.js.map +1 -0
  28. package/dist/hooks/generators/require-wu.js +115 -0
  29. package/dist/hooks/generators/require-wu.js.map +1 -0
  30. package/dist/hooks/generators/session-start-recovery.js +101 -0
  31. package/dist/hooks/generators/session-start-recovery.js.map +1 -0
  32. package/dist/hooks/generators/signal-utils.js +52 -0
  33. package/dist/hooks/generators/signal-utils.js.map +1 -0
  34. package/dist/hooks/generators/warn-incomplete.js +65 -0
  35. package/dist/hooks/generators/warn-incomplete.js.map +1 -0
  36. package/dist/init-detection.js +228 -0
  37. package/dist/init-detection.js.map +1 -0
  38. package/dist/init-scaffolding.js +146 -0
  39. package/dist/init-scaffolding.js.map +1 -0
  40. package/dist/init-templates.js +1928 -0
  41. package/dist/init-templates.js.map +1 -0
  42. package/dist/init.js +136 -2425
  43. package/dist/init.js.map +1 -1
  44. package/dist/initiative-edit.js +42 -11
  45. package/dist/initiative-edit.js.map +1 -1
  46. package/dist/initiative-remove-wu.js +0 -0
  47. package/dist/initiative-status.js +29 -2
  48. package/dist/initiative-status.js.map +1 -1
  49. package/dist/mem-context.js +22 -9
  50. package/dist/mem-context.js.map +1 -1
  51. package/dist/orchestrate-init-status.js +32 -1
  52. package/dist/orchestrate-init-status.js.map +1 -1
  53. package/dist/orchestrate-monitor.js +38 -38
  54. package/dist/orchestrate-monitor.js.map +1 -1
  55. package/dist/public-manifest.js +12 -5
  56. package/dist/public-manifest.js.map +1 -1
  57. package/dist/shared-validators.js +1 -0
  58. package/dist/shared-validators.js.map +1 -1
  59. package/dist/spawn-list.js +0 -0
  60. package/dist/wu-claim-branch.js +121 -0
  61. package/dist/wu-claim-branch.js.map +1 -0
  62. package/dist/wu-claim-output.js +83 -0
  63. package/dist/wu-claim-output.js.map +1 -0
  64. package/dist/wu-claim-resume-handler.js +85 -0
  65. package/dist/wu-claim-resume-handler.js.map +1 -0
  66. package/dist/wu-claim-state.js +572 -0
  67. package/dist/wu-claim-state.js.map +1 -0
  68. package/dist/wu-claim-validation.js +439 -0
  69. package/dist/wu-claim-validation.js.map +1 -0
  70. package/dist/wu-claim-worktree.js +221 -0
  71. package/dist/wu-claim-worktree.js.map +1 -0
  72. package/dist/wu-claim.js +54 -1402
  73. package/dist/wu-claim.js.map +1 -1
  74. package/dist/wu-create-content.js +254 -0
  75. package/dist/wu-create-content.js.map +1 -0
  76. package/dist/wu-create-readiness.js +57 -0
  77. package/dist/wu-create-readiness.js.map +1 -0
  78. package/dist/wu-create-validation.js +149 -0
  79. package/dist/wu-create-validation.js.map +1 -0
  80. package/dist/wu-create.js +39 -441
  81. package/dist/wu-create.js.map +1 -1
  82. package/dist/wu-done.js +144 -249
  83. package/dist/wu-done.js.map +1 -1
  84. package/dist/wu-edit-operations.js +432 -0
  85. package/dist/wu-edit-operations.js.map +1 -0
  86. package/dist/wu-edit-validators.js +280 -0
  87. package/dist/wu-edit-validators.js.map +1 -0
  88. package/dist/wu-edit.js +27 -713
  89. package/dist/wu-edit.js.map +1 -1
  90. package/dist/wu-prep.js +32 -2
  91. package/dist/wu-prep.js.map +1 -1
  92. package/dist/wu-repair.js +1 -1
  93. package/dist/wu-repair.js.map +1 -1
  94. package/dist/wu-spawn-prompt-builders.js +1123 -0
  95. package/dist/wu-spawn-prompt-builders.js.map +1 -0
  96. package/dist/wu-spawn-strategy-resolver.js +314 -0
  97. package/dist/wu-spawn-strategy-resolver.js.map +1 -0
  98. package/dist/wu-spawn.js +9 -1398
  99. package/dist/wu-spawn.js.map +1 -1
  100. package/package.json +10 -7
  101. package/templates/core/LUMENFLOW.md.template +29 -99
  102. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +1 -1
  103. package/templates/core/ai/onboarding/quick-ref-commands.md.template +29 -4
  104. package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +8 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wu-create-validation.js","sourceRoot":"","sources":["../src/wu-create-validation.ts"],"names":[],"mappings":"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"}
package/dist/wu-create.js CHANGED
@@ -1,9 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * WU Create Helper (WU-1262, WU-1439)
3
+ * WU Create Orchestrator (WU-1262, WU-1439, WU-1651)
4
4
  *
5
5
  * Race-safe WU creation using shared micro-worktree isolation.
6
6
  *
7
+ * WU-1651: Decomposed into focused modules:
8
+ * - wu-create-validation.ts: Spec validation and strict mode checks
9
+ * - wu-create-content.ts: YAML content building, backlog updates, plan templates
10
+ * - wu-create-readiness.ts: Post-create readiness summary display
11
+ * - wu-create-cloud.ts: Cloud mode context builder
12
+ *
13
+ * This file remains the orchestrator, coordinating CLI parsing, validation,
14
+ * content generation, and transaction execution.
15
+ *
7
16
  * Canonical sequence:
8
17
  * 1) Validate inputs (id, lane, title)
9
18
  * 2) Ensure on main branch
@@ -15,61 +24,37 @@
15
24
  * e) Push to origin/main
16
25
  * f) Cleanup temp branch and micro-worktree
17
26
  *
18
- * Benefits:
19
- * - Main checkout never switches branches (no impact on other agents)
20
- * - Race conditions handled via rebase+retry (up to 3 attempts)
21
- * - Cleanup guaranteed even on failure
22
- *
23
27
  * Usage:
24
28
  * pnpm wu:create --id WU-706 --lane Intelligence --title "Fix XYZ issue"
25
- *
26
- * Context: WU-705 (fix agent coordination failures), WU-1262 (micro-worktree isolation),
27
- * WU-1439 (refactor to shared helper)
28
29
  */
29
30
  import { getGitForCwd } from '@lumenflow/core/git-adapter';
30
31
  import { die } from '@lumenflow/core/error-handler';
31
- import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
32
+ import { existsSync } from 'node:fs';
32
33
  import { join } from 'node:path';
33
- // WU-1352: Use centralized YAML functions from wu-yaml.ts
34
- import { stringifyYAML } from '@lumenflow/core/wu-yaml';
35
- // WU-1428: Use date-utils for consistent YYYY-MM-DD format (library-first)
36
34
  import { todayISO } from '@lumenflow/core/date-utils';
37
35
  import { validateLaneFormat, extractParent } from '@lumenflow/core/lane-checker';
38
- // WU-2330: Import lane inference for sub-lane suggestions
39
36
  import { inferSubLane } from '@lumenflow/core/lane-inference';
40
- import { parseBacklogFrontmatter } from '@lumenflow/core/backlog-parser';
41
37
  import { createWUParser, WU_CREATE_OPTIONS, WU_OPTIONS } from '@lumenflow/core/arg-parser';
42
38
  import { WU_PATHS } from '@lumenflow/core/wu-paths';
43
39
  import { getConfig } from '@lumenflow/core/config';
44
- import { validateWU } from '@lumenflow/core/wu-schema';
45
- import { getPlanPath, getPlanProtocolRef, getPlansDir } from '@lumenflow/core/lumenflow-home';
46
- import { hasSpecRefs, validateSpecRefs } from '@lumenflow/core/wu-create-validators';
47
- import { COMMIT_FORMATS, FILE_SYSTEM, READINESS_UI, REMOTES, STRING_LITERALS, WU_TYPES, } from '@lumenflow/core/wu-constants';
48
- // WU-1593: Use centralized validateWUIDFormat (DRY)
40
+ import { validateSpecRefs, hasSpecRefs } from '@lumenflow/core/wu-create-validators';
41
+ import { COMMIT_FORMATS, REMOTES, STRING_LITERALS, WU_TYPES } from '@lumenflow/core/wu-constants';
49
42
  import { ensureOnMain, validateWUIDFormat } from '@lumenflow/core/wu-helpers';
50
- // WU-1439: Use shared micro-worktree helper
51
43
  import { withMicroWorktree } from '@lumenflow/core/micro-worktree';
52
- // WU-1246: Auto-generate WU IDs when --id not provided
53
44
  import { generateWuIdWithRetry } from '@lumenflow/core/wu-id-generator';
54
- // WU-1620: Import spec completeness validator for readiness summary
55
- import { validateSpecCompleteness } from '@lumenflow/core/wu-done-validators';
56
- // WU-1620: Import readWU to read back created YAML for validation
57
- import { readWU } from '@lumenflow/core/wu-yaml';
58
- // WU-2253: Import WU spec linter for acceptance/code_paths validation
59
45
  import { lintWUSpec, formatLintErrors } from '@lumenflow/core/wu-lint';
60
- // WU-1329: Import path existence validators for strict mode
61
- import { validateCodePathsExistence, validateTestPathsExistence, } from '@lumenflow/core/wu-preflight-validators';
62
- // WU-1025: Import placeholder validator for inline content validation
63
- import { validateNoPlaceholders, buildPlaceholderErrorMessage } from '@lumenflow/core/wu-validator';
64
- import { isCodeFile } from '@lumenflow/core/manual-test-validator';
65
46
  import { WU_CREATE_DEFAULTS } from '@lumenflow/core/wu-create-defaults';
66
- import { isDocsOrProcessType, hasAnyTests, hasManualTests } from '@lumenflow/core/wu-type-helpers';
67
- // WU-1211: Import initiative validation for phase check
47
+ import { isDocsOrProcessType } from '@lumenflow/core/wu-type-helpers';
68
48
  import { checkInitiativePhases, findInitiative } from '@lumenflow/initiatives';
69
- // WU-1590: Cloud create context builder for --cloud path
70
49
  import { buildCloudCreateContext } from './wu-create-cloud.js';
71
- // WU-1495: Cloud auto-detection from config-driven env signals
72
50
  import { detectCloudMode, resolveEffectiveCloudActivation, CLOUD_ACTIVATION_SOURCE, } from '@lumenflow/core/cloud-detect';
51
+ // WU-1651: Import from extracted modules
52
+ import { validateCreateSpec, containsCodeFiles, hasAnyItems, } from './wu-create-validation.js';
53
+ import { buildWUContent, truncateTitle, mergeSpecRefs, createPlanTemplate, createWUYamlInWorktree, updateBacklogInWorktree, getPlanProtocolRef, } from './wu-create-content.js';
54
+ import { displayReadinessSummary } from './wu-create-readiness.js';
55
+ // Re-export public API for backward compatibility (tests import from wu-create.js)
56
+ export { validateCreateSpec } from './wu-create-validation.js';
57
+ export { buildWUContent } from './wu-create-content.js';
73
58
  /** Log prefix for console output */
74
59
  const LOG_PREFIX = '[wu:create]';
75
60
  /** Micro-worktree operation name */
@@ -78,22 +63,8 @@ const OPERATION_NAME = 'wu-create';
78
63
  const DEFAULT_PRIORITY = 'P2';
79
64
  /** Default WU type */
80
65
  const DEFAULT_TYPE = WU_TYPES.FEATURE;
81
- /** Maximum title length before truncation */
82
- const MAX_TITLE_LENGTH = 60;
83
- /** Truncation suffix */
84
- const TRUNCATION_SUFFIX = '...';
85
- /** Truncated title length (MAX_TITLE_LENGTH - TRUNCATION_SUFFIX.length) */
86
- const TRUNCATED_TITLE_LENGTH = MAX_TITLE_LENGTH - TRUNCATION_SUFFIX.length;
87
66
  /** Minimum confidence threshold to show lane suggestion warning (WU-2438: lowered from 50 to 30) */
88
67
  const MIN_CONFIDENCE_FOR_WARNING = 30;
89
- function containsCodeFiles(codePaths) {
90
- if (!codePaths || codePaths.length === 0)
91
- return false;
92
- return codePaths.some((p) => isCodeFile(p));
93
- }
94
- function hasAnyItems(value) {
95
- return Array.isArray(value) && value.length > 0;
96
- }
97
68
  /**
98
69
  * Resolve branch-aware cloud activation for wu:create.
99
70
  *
@@ -185,379 +156,6 @@ function checkWUExists(id) {
185
156
  ` 3. Delete existing WU: pnpm wu:delete --id ${id} (if obsolete)`);
186
157
  }
187
158
  }
188
- /**
189
- * Truncate title for commit message if needed
190
- * @param {string} title - Original title
191
- * @returns {string} Truncated title
192
- */
193
- function truncateTitle(title) {
194
- return title.length > MAX_TITLE_LENGTH
195
- ? `${title.substring(0, TRUNCATED_TITLE_LENGTH)}${TRUNCATION_SUFFIX}`
196
- : title;
197
- }
198
- /**
199
- * WU-1620: Display readiness summary after create/edit
200
- *
201
- * Shows whether WU is ready for wu:claim based on spec completeness.
202
- * Non-blocking - just informational to help agents understand what's missing.
203
- *
204
- * @param {string} id - WU ID
205
- */
206
- function displayReadinessSummary(id) {
207
- try {
208
- const wuPath = WU_PATHS.WU(id);
209
- const wuDoc = readWU(wuPath, id);
210
- const { valid, errors } = validateSpecCompleteness(wuDoc, id);
211
- const { BOX, BOX_WIDTH, MESSAGES, ERROR_MAX_LENGTH, ERROR_TRUNCATE_LENGTH, TRUNCATION_SUFFIX, PADDING, } = READINESS_UI;
212
- console.log(`\n${BOX.TOP_LEFT}${BOX.HORIZONTAL.repeat(BOX_WIDTH)}${BOX.TOP_RIGHT}`);
213
- if (valid) {
214
- console.log(`${BOX.VERTICAL} ${MESSAGES.READY_YES}${''.padEnd(PADDING.READY_YES)}${BOX.VERTICAL}`);
215
- console.log(`${BOX.VERTICAL}${''.padEnd(BOX_WIDTH)}${BOX.VERTICAL}`);
216
- const claimCmd = `Run: pnpm wu:claim --id ${id}`;
217
- console.log(`${BOX.VERTICAL} ${claimCmd}${''.padEnd(BOX_WIDTH - claimCmd.length - 1)}${BOX.VERTICAL}`);
218
- }
219
- else {
220
- console.log(`${BOX.VERTICAL} ${MESSAGES.READY_NO}${''.padEnd(PADDING.READY_NO)}${BOX.VERTICAL}`);
221
- console.log(`${BOX.VERTICAL}${''.padEnd(BOX_WIDTH)}${BOX.VERTICAL}`);
222
- console.log(`${BOX.VERTICAL} ${MESSAGES.MISSING_HEADER}${''.padEnd(PADDING.MISSING_HEADER)}${BOX.VERTICAL}`);
223
- for (const error of errors) {
224
- // Truncate long error messages to fit box
225
- const truncated = error.length > ERROR_MAX_LENGTH
226
- ? `${error.substring(0, ERROR_TRUNCATE_LENGTH)}${TRUNCATION_SUFFIX}`
227
- : error;
228
- console.log(`${BOX.VERTICAL} ${MESSAGES.BULLET} ${truncated}${''.padEnd(Math.max(0, PADDING.ERROR_BULLET - truncated.length))}${BOX.VERTICAL}`);
229
- }
230
- console.log(`${BOX.VERTICAL}${''.padEnd(BOX_WIDTH)}${BOX.VERTICAL}`);
231
- const editCmd = `Run: pnpm wu:edit --id ${id} --help`;
232
- console.log(`${BOX.VERTICAL} ${editCmd}${''.padEnd(BOX_WIDTH - editCmd.length - 1)}${BOX.VERTICAL}`);
233
- }
234
- console.log(`${BOX.BOTTOM_LEFT}${BOX.HORIZONTAL.repeat(BOX_WIDTH)}${BOX.BOTTOM_RIGHT}`);
235
- }
236
- catch (err) {
237
- // Non-blocking - if validation fails, just warn
238
- console.warn(`${LOG_PREFIX} ⚠️ Could not validate readiness: ${err.message}`);
239
- }
240
- }
241
- function mergeSpecRefs(specRefs, extraRef) {
242
- const refs = specRefs ? [...specRefs] : [];
243
- if (extraRef && !refs.includes(extraRef)) {
244
- refs.push(extraRef);
245
- }
246
- return refs;
247
- }
248
- function createPlanTemplate(wuId, title) {
249
- const plansDir = getPlansDir();
250
- mkdirSync(plansDir, { recursive: true });
251
- const planPath = getPlanPath(wuId);
252
- if (existsSync(planPath)) {
253
- die(`Plan already exists: ${planPath}\n\n` +
254
- `Options:\n` +
255
- ` 1. Open the existing plan and continue editing\n` +
256
- ` 2. Delete or rename the existing plan before retrying\n` +
257
- ` 3. Run wu:create without --plan`);
258
- }
259
- const today = todayISO();
260
- const content = `# ${wuId} Plan — ${title}\n\n` +
261
- `Created: ${today}\n\n` +
262
- `## Goal\n\n` +
263
- `## Scope\n\n` +
264
- `## Approach\n\n` +
265
- `## Risks\n\n` +
266
- `## Open Questions\n`;
267
- writeFileSync(planPath, content, { encoding: FILE_SYSTEM.UTF8 });
268
- console.log(`${LOG_PREFIX} ✅ Created plan template: ${planPath}`);
269
- return planPath;
270
- }
271
- export function buildWUContent({ id, lane, title, priority, type, created, opts, }) {
272
- const { description, acceptance, notes, codePaths, testPathsManual, testPathsUnit, testPathsE2e, initiative, phase, blockedBy, blocks, labels, assignedTo, exposure, userJourney, uiPairingWus, specRefs, } = opts;
273
- // Arrays come directly from Commander.js repeatable options - no parsing needed
274
- const code_paths = codePaths ?? [];
275
- const tests = {
276
- manual: testPathsManual ?? [],
277
- unit: testPathsUnit ?? [],
278
- e2e: testPathsE2e ?? [],
279
- };
280
- // WU-1443: Auto-insert minimal manual test stub for plan-first specs when no tests are provided,
281
- // as long as code_paths does not include actual code files (automated tests still required for code).
282
- if (!isDocsOrProcessType(type) && !hasAnyTests(tests) && !containsCodeFiles(code_paths)) {
283
- tests.manual = [WU_CREATE_DEFAULTS.AUTO_MANUAL_TEST_PLACEHOLDER];
284
- }
285
- return {
286
- id,
287
- title,
288
- lane,
289
- type,
290
- status: 'ready',
291
- priority,
292
- created,
293
- description,
294
- acceptance,
295
- code_paths,
296
- tests,
297
- artifacts: [WU_PATHS.STAMP(id)],
298
- dependencies: [],
299
- risks: [],
300
- // WU-1443: Default notes to non-empty placeholder to avoid strict completeness failures.
301
- notes: typeof notes === 'string' && notes.trim().length > 0
302
- ? notes
303
- : WU_CREATE_DEFAULTS.AUTO_NOTES_PLACEHOLDER,
304
- requires_review: false,
305
- ...(initiative && { initiative }),
306
- ...(phase && { phase: parseInt(phase, 10) }),
307
- ...(blockedBy?.length && { blocked_by: blockedBy }),
308
- ...(blocks?.length && { blocks }),
309
- ...(labels?.length && { labels }),
310
- ...(assignedTo && { assigned_to: assignedTo }),
311
- ...(exposure && { exposure }),
312
- ...(userJourney && { user_journey: userJourney }),
313
- ...(uiPairingWus?.length && { ui_pairing_wus: uiPairingWus }),
314
- ...(specRefs?.length && { spec_refs: specRefs }),
315
- };
316
- }
317
- /**
318
- * Validate WU spec for creation
319
- *
320
- * WU-1329: Strict mode (default) validates that code_paths and test_paths exist on disk.
321
- * Use opts.strict = false to bypass path existence checks.
322
- *
323
- * @param params - Validation parameters
324
- * @returns {{ valid: boolean, errors: string[] }}
325
- */
326
- export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
327
- const errors = [];
328
- const effectiveType = type || DEFAULT_TYPE;
329
- // WU-1329: Strict mode is the default
330
- const strict = opts.strict !== false;
331
- // WU-1329: Log when strict validation is bypassed
332
- if (!strict) {
333
- console.warn(`${LOG_PREFIX} WARNING: strict validation bypassed (--no-strict). Path existence checks skipped.`);
334
- }
335
- if (!opts.description) {
336
- errors.push('--description is required');
337
- }
338
- if (!opts.acceptance || opts.acceptance.length === 0) {
339
- errors.push('--acceptance is required (repeatable)');
340
- }
341
- if (!opts.exposure) {
342
- errors.push('--exposure is required');
343
- }
344
- const hasTestPaths = hasAnyItems(opts.testPathsManual) ||
345
- hasAnyItems(opts.testPathsUnit) ||
346
- hasAnyItems(opts.testPathsE2e);
347
- const hasManualTestPaths = hasManualTests({ manual: opts.testPathsManual });
348
- if (!isDocsOrProcessType(effectiveType)) {
349
- const codePaths = opts.codePaths ?? [];
350
- if (codePaths.length === 0) {
351
- errors.push('--code-paths is required for non-documentation WUs');
352
- }
353
- // WU-1443: Plan-first WUs may not know tests yet.
354
- // Allow auto-manual stub ONLY when code_paths does not include code files.
355
- const canAutoAddManualTests = !hasTestPaths && codePaths.length > 0 && !containsCodeFiles(codePaths);
356
- if (!hasTestPaths && !canAutoAddManualTests) {
357
- errors.push('At least one test path flag is required (--test-paths-manual, --test-paths-unit, or --test-paths-e2e)');
358
- }
359
- if (!hasManualTestPaths && !canAutoAddManualTests) {
360
- errors.push('--test-paths-manual is required for non-documentation WUs');
361
- }
362
- }
363
- if (effectiveType === WU_TYPES.FEATURE && !hasSpecRefs(opts.specRefs)) {
364
- errors.push('--spec-refs is required for type: feature WUs\n' +
365
- ' Tip: Create a plan first with: pnpm plan:create --id <WU-ID> --title "..."\n' +
366
- ' Then use --plan flag or --spec-refs lumenflow://plans/<WU-ID>-plan.md');
367
- }
368
- // WU-1530: Single-pass validation — collect all errors before returning.
369
- // Always build WU content and run all validation stages, even when early fields are missing.
370
- // buildWUContent handles undefined gracefully; Zod catches missing required fields.
371
- // Stage 2b: Placeholder check (only meaningful if fields exist)
372
- if (opts.description && opts.acceptance && opts.acceptance.length > 0) {
373
- const placeholderResult = validateNoPlaceholders({
374
- description: opts.description,
375
- acceptance: opts.acceptance,
376
- });
377
- if (!placeholderResult.valid) {
378
- errors.push(buildPlaceholderErrorMessage('wu:create', placeholderResult));
379
- }
380
- }
381
- // Stage 2c-2d: Schema + completeness — always run to catch enum/format errors
382
- // even when required fields are missing (Zod reports both)
383
- const today = todayISO();
384
- const wuContent = buildWUContent({
385
- id,
386
- lane,
387
- title,
388
- priority,
389
- type: effectiveType,
390
- created: today,
391
- opts,
392
- });
393
- const schemaResult = validateWU(wuContent);
394
- if (!schemaResult.success) {
395
- // Deduplicate: skip schema errors already covered by field-level checks above
396
- const fieldErrorFields = new Set(['description', 'acceptance', 'code_paths', 'tests']);
397
- const schemaErrors = schemaResult.error.issues
398
- .filter((issue) => !fieldErrorFields.has(issue.path[0]) || errors.length === 0)
399
- .map((issue) => `${issue.path.join('.')}: ${issue.message}`);
400
- errors.push(...schemaErrors);
401
- }
402
- // Only run completeness if schema passed (it depends on well-formed data)
403
- if (schemaResult.success) {
404
- const completeness = validateSpecCompleteness(wuContent, id);
405
- if (!completeness.valid) {
406
- errors.push(...completeness.errors);
407
- }
408
- }
409
- // Stage 2e: Strict mode validates path existence
410
- if (strict) {
411
- const rootDir = process.cwd();
412
- if (opts.codePaths && opts.codePaths.length > 0) {
413
- const codePathsResult = validateCodePathsExistence(opts.codePaths, rootDir);
414
- if (!codePathsResult.valid) {
415
- errors.push(...codePathsResult.errors);
416
- }
417
- }
418
- const testsObj = {
419
- unit: opts.testPathsUnit || [],
420
- e2e: opts.testPathsE2e || [],
421
- };
422
- const testPathsResult = validateTestPathsExistence(testsObj, rootDir);
423
- if (!testPathsResult.valid) {
424
- errors.push(...testPathsResult.errors);
425
- }
426
- }
427
- if (errors.length > 0) {
428
- return { valid: false, errors };
429
- }
430
- return { valid: true, errors: [] };
431
- }
432
- /**
433
- * Create WU YAML file in micro-worktree
434
- *
435
- * @param {string} worktreePath - Path to micro-worktree
436
- * @param {string} id - WU ID
437
- * @param {string} lane - WU lane
438
- * @param {string} title - WU title
439
- * @param {string} priority - WU priority
440
- * @param {string} type - WU type
441
- * @param {Object} opts - Additional options
442
- * @returns {string} Relative path to created YAML file
443
- */
444
- function createWUYamlInWorktree(worktreePath, id, lane, title, priority, type, opts = {}) {
445
- const wuRelativePath = WU_PATHS.WU(id);
446
- const wuAbsolutePath = join(worktreePath, wuRelativePath);
447
- const wuDir = join(worktreePath, WU_PATHS.WU_DIR());
448
- mkdirSync(wuDir, { recursive: true });
449
- // WU-1428: Use todayISO() for consistent YYYY-MM-DD format (library-first)
450
- const today = todayISO();
451
- const wuContent = buildWUContent({
452
- id,
453
- lane,
454
- title,
455
- priority,
456
- type,
457
- created: today,
458
- opts,
459
- });
460
- // WU-1539: Validate WU structure before writing (fail-fast, no placeholders)
461
- // WU-1750: Zod transforms normalize embedded newlines in arrays and strings
462
- const validationResult = validateWU(wuContent);
463
- if (!validationResult.success) {
464
- const errors = validationResult.error.issues
465
- .map((issue) => ` • ${issue.path.join('.')}: ${issue.message}`)
466
- .join(STRING_LITERALS.NEWLINE);
467
- die(`${LOG_PREFIX} ❌ WU YAML validation failed:\n\n${errors}\n\n` +
468
- `Fix the issues above and retry.`);
469
- }
470
- const completenessResult = validateSpecCompleteness(wuContent, id);
471
- if (!completenessResult.valid) {
472
- const errorList = completenessResult.errors
473
- .map((error) => ` • ${error}`)
474
- .join(STRING_LITERALS.NEWLINE);
475
- die(`${LOG_PREFIX} ❌ WU SPEC INCOMPLETE:\n\n${errorList}\n\n` +
476
- `Provide the missing fields and retry.`);
477
- }
478
- // WU-2253: Validate acceptance/code_paths consistency and invariants compliance
479
- // This blocks WU creation if acceptance references paths not in code_paths
480
- // or if code_paths conflicts with tools/invariants.yml
481
- const invariantsPath = join(process.cwd(), 'tools/invariants.yml');
482
- const lintResult = lintWUSpec(wuContent, { invariantsPath });
483
- if (!lintResult.valid) {
484
- const formatted = formatLintErrors(lintResult.errors);
485
- die(`${LOG_PREFIX} ❌ WU SPEC LINT FAILED:\n\n${formatted}\n` +
486
- `Fix the issues above before creating this WU.`);
487
- }
488
- // WU-1352: Use centralized stringify (lineWidth: -1 = no wrapping for WU creation)
489
- // WU-1750: CRITICAL - Use validationResult.data (transformed) NOT wuContent (raw input)
490
- // This ensures embedded newlines are normalized before YAML output
491
- const yamlContent = stringifyYAML(validationResult.data, { lineWidth: -1 });
492
- writeFileSync(wuAbsolutePath, yamlContent, { encoding: FILE_SYSTEM.UTF8 });
493
- console.log(`${LOG_PREFIX} ✅ Created ${id}.yaml in micro-worktree`);
494
- return wuRelativePath;
495
- }
496
- /**
497
- * Update backlog.md in micro-worktree
498
- *
499
- * @param {string} worktreePath - Path to micro-worktree
500
- * @param {string} id - WU ID
501
- * @param {string} lane - WU lane
502
- * @param {string} title - WU title
503
- * @returns {string} Relative path to backlog.md
504
- */
505
- function updateBacklogInWorktree(worktreePath, id, lane, title) {
506
- const backlogRelativePath = WU_PATHS.BACKLOG();
507
- const backlogAbsolutePath = join(worktreePath, backlogRelativePath);
508
- if (!existsSync(backlogAbsolutePath)) {
509
- // WU-1311: Use config-based backlog path in error message
510
- die(`Backlog not found in micro-worktree: ${backlogAbsolutePath}\n\n` +
511
- `Options:\n` +
512
- ` 1. Ensure backlog.md exists at ${getConfig().directories.backlogPath}\n` +
513
- ` 2. Run from repository root directory`);
514
- }
515
- const { frontmatter, markdown } = parseBacklogFrontmatter(backlogAbsolutePath);
516
- if (!frontmatter) {
517
- die('Backlog frontmatter missing in micro-worktree.\n\n' +
518
- 'The backlog.md file requires YAML frontmatter to define section headings.\n\n' +
519
- 'Options:\n' +
520
- ' 1. Check backlog.md has valid YAML frontmatter between --- markers\n' +
521
- ' 2. Ensure sections.ready.heading is defined in frontmatter');
522
- }
523
- if (!frontmatter.sections?.ready?.heading) {
524
- die('Invalid backlog frontmatter: Missing sections.ready.heading\n\n' +
525
- 'Options:\n' +
526
- ' 1. Add sections.ready.heading to backlog.md frontmatter\n' +
527
- ' 2. Check frontmatter YAML structure');
528
- }
529
- const readyHeading = frontmatter.sections.ready.heading;
530
- const insertionStrategy = frontmatter.sections.ready.insertion || 'after_heading_blank_line';
531
- const lines = markdown.split(STRING_LITERALS.NEWLINE);
532
- const headingIndex = lines.findIndex((line) => line === readyHeading);
533
- if (headingIndex === -1) {
534
- die(`Could not find Ready section heading: '${readyHeading}'\n\n` +
535
- `Options:\n` +
536
- ` 1. Add the heading '${readyHeading}' to backlog.md\n` +
537
- ` 2. Update sections.ready.heading in backlog.md frontmatter`);
538
- }
539
- let insertionIndex;
540
- if (insertionStrategy === 'after_heading_blank_line') {
541
- const LINES_AFTER_HEADING = 2;
542
- insertionIndex = headingIndex + LINES_AFTER_HEADING;
543
- }
544
- else {
545
- die(`Unknown insertion strategy: ${insertionStrategy}\n\n` +
546
- `Options:\n` +
547
- ` 1. Use 'after_heading_blank_line' in backlog.md frontmatter\n` +
548
- ` 2. Check sections.ready.insertion value`);
549
- }
550
- const newEntry = `- [${id} — ${title}](wu/${id}.yaml) — ${lane}`;
551
- lines.splice(insertionIndex, 0, newEntry);
552
- const updatedMarkdown = lines.join(STRING_LITERALS.NEWLINE);
553
- // WU-1352: Use centralized stringify for frontmatter
554
- const updatedBacklog = `---\n${stringifyYAML(frontmatter, { lineWidth: -1 })}---\n${updatedMarkdown}`;
555
- writeFileSync(backlogAbsolutePath, updatedBacklog, {
556
- encoding: FILE_SYSTEM.UTF8,
557
- });
558
- console.log(`${LOG_PREFIX} ✅ Updated backlog.md in micro-worktree`);
559
- return backlogRelativePath;
560
- }
561
159
  /**
562
160
  * Get default assigned_to value from git config user.email (WU-1368)
563
161
  * @returns {Promise<string>} User email or empty string if not configured
@@ -568,7 +166,7 @@ async function getDefaultAssignedTo() {
568
166
  return email || '';
569
167
  }
570
168
  catch {
571
- console.warn(`${LOG_PREFIX} ⚠️ git config user.email not set - assigned_to will be empty`);
169
+ console.warn(`${LOG_PREFIX} git config user.email not set - assigned_to will be empty`);
572
170
  return '';
573
171
  }
574
172
  }
@@ -690,17 +288,17 @@ async function main() {
690
288
  // WU-1368: Get assigned_to from flag or git config user.email
691
289
  const assignedTo = args.assignedTo || (await getDefaultAssignedTo());
692
290
  if (!assignedTo) {
693
- console.warn(`${LOG_PREFIX} ⚠️ No assigned_to set - WU will need manual assignment`);
291
+ console.warn(`${LOG_PREFIX} No assigned_to set - WU will need manual assignment`);
694
292
  }
695
293
  const planSpecRef = args.plan ? getPlanProtocolRef(wuId) : undefined;
696
- const mergedSpecRefs = mergeSpecRefs(args.specRefs, planSpecRef);
294
+ const mergedRefs = mergeSpecRefs(args.specRefs, planSpecRef);
697
295
  // WU-1443: Apply resilient defaults so a plan-first WU doesn't immediately fail strict validation.
698
296
  const effectiveType = args.type || DEFAULT_TYPE;
699
297
  const resolvedNotes = typeof args.notes === 'string' && args.notes.trim().length > 0
700
298
  ? args.notes
701
299
  : WU_CREATE_DEFAULTS.AUTO_NOTES_PLACEHOLDER;
702
300
  if (resolvedNotes === WU_CREATE_DEFAULTS.AUTO_NOTES_PLACEHOLDER) {
703
- console.warn(`${LOG_PREFIX} ⚠️ No --notes provided; using placeholder notes (edit before done).`);
301
+ console.warn(`${LOG_PREFIX} No --notes provided; using placeholder notes (edit before done).`);
704
302
  }
705
303
  const hasProvidedTests = hasAnyItems(args.testPathsManual) ||
706
304
  hasAnyItems(args.testPathsUnit) ||
@@ -710,7 +308,7 @@ async function main() {
710
308
  ? [WU_CREATE_DEFAULTS.AUTO_MANUAL_TEST_PLACEHOLDER]
711
309
  : args.testPathsManual;
712
310
  if (canAutoAddManualTests) {
713
- console.warn(`${LOG_PREFIX} ⚠️ No test paths provided; inserting a minimal manual test stub (add automated tests before code changes).`);
311
+ console.warn(`${LOG_PREFIX} No test paths provided; inserting a minimal manual test stub (add automated tests before code changes).`);
714
312
  }
715
313
  const createSpecValidation = validateCreateSpec({
716
314
  id: wuId,
@@ -729,7 +327,7 @@ async function main() {
729
327
  exposure: args.exposure,
730
328
  userJourney: args.userJourney,
731
329
  uiPairingWus: args.uiPairingWus,
732
- specRefs: mergedSpecRefs,
330
+ specRefs: mergedRefs,
733
331
  initiative: args.initiative,
734
332
  phase: args.phase,
735
333
  blockedBy: args.blockedBy,
@@ -742,11 +340,11 @@ async function main() {
742
340
  });
743
341
  if (!createSpecValidation.valid) {
744
342
  const errorList = createSpecValidation.errors
745
- .map((error) => ` ${error}`)
343
+ .map((error) => ` - ${error}`)
746
344
  .join(STRING_LITERALS.NEWLINE);
747
- die(`${LOG_PREFIX} Spec validation failed:\n\n${errorList}`);
345
+ die(`${LOG_PREFIX} Spec validation failed:\n\n${errorList}`);
748
346
  }
749
- console.log(`${LOG_PREFIX} Spec validation passed`);
347
+ console.log(`${LOG_PREFIX} Spec validation passed`);
750
348
  // WU-1530: Run spec lint BEFORE micro-worktree creation.
751
349
  // Previously this ran inside createWUYamlInWorktree after worktree setup,
752
350
  // meaning lint errors only appeared after a ~10s worktree creation.
@@ -768,7 +366,7 @@ async function main() {
768
366
  exposure: args.exposure,
769
367
  userJourney: args.userJourney,
770
368
  uiPairingWus: args.uiPairingWus,
771
- specRefs: mergedSpecRefs,
369
+ specRefs: mergedRefs,
772
370
  initiative: args.initiative,
773
371
  phase: args.phase,
774
372
  blockedBy: args.blockedBy,
@@ -781,20 +379,20 @@ async function main() {
781
379
  const preflightLint = lintWUSpec(preflightWU, { invariantsPath });
782
380
  if (!preflightLint.valid) {
783
381
  const formatted = formatLintErrors(preflightLint.errors);
784
- die(`${LOG_PREFIX} WU SPEC LINT FAILED:\n\n${formatted}\n` +
382
+ die(`${LOG_PREFIX} WU SPEC LINT FAILED:\n\n${formatted}\n` +
785
383
  `Fix the issues above before creating this WU.`);
786
384
  }
787
- const specRefsList = mergedSpecRefs;
385
+ const specRefsList = mergedRefs;
788
386
  const specRefsValidation = validateSpecRefs(specRefsList);
789
387
  if (!specRefsValidation.valid) {
790
388
  const errorList = specRefsValidation.errors
791
- .map((error) => ` ${error}`)
389
+ .map((error) => ` - ${error}`)
792
390
  .join(STRING_LITERALS.NEWLINE);
793
- die(`${LOG_PREFIX} Spec reference validation failed:\n\n${errorList}`);
391
+ die(`${LOG_PREFIX} Spec reference validation failed:\n\n${errorList}`);
794
392
  }
795
393
  if (specRefsValidation.warnings.length > 0) {
796
394
  for (const warning of specRefsValidation.warnings) {
797
- console.warn(`${LOG_PREFIX} ⚠️ ${warning}`);
395
+ console.warn(`${LOG_PREFIX} ${warning}`);
798
396
  }
799
397
  }
800
398
  if (args.initiative) {
@@ -807,7 +405,7 @@ async function main() {
807
405
  specRefs: specRefsList,
808
406
  });
809
407
  for (const warning of warnings) {
810
- console.warn(`${LOG_PREFIX} ⚠️ ${warning}`);
408
+ console.warn(`${LOG_PREFIX} ${warning}`);
811
409
  }
812
410
  }
813
411
  }
@@ -841,7 +439,7 @@ async function main() {
841
439
  userJourney: args.userJourney,
842
440
  uiPairingWus: args.uiPairingWus,
843
441
  // WU-2320: Spec references
844
- specRefs: mergedSpecRefs,
442
+ specRefs: mergedRefs,
845
443
  };
846
444
  if (cloudCtx.skipMicroWorktree) {
847
445
  // WU-1590: Cloud path - write and commit directly on current branch
@@ -893,7 +491,7 @@ async function main() {
893
491
  }
894
492
  }
895
493
  }
896
- console.log(`\n${LOG_PREFIX} Transaction complete!`);
494
+ console.log(`\n${LOG_PREFIX} Transaction complete!`);
897
495
  console.log(`\nWU ${wuId} created successfully:`);
898
496
  console.log(` File: ${WU_PATHS.WU(wuId)}`);
899
497
  console.log(` Lane: ${args.lane}`);