@lumenflow/core 1.0.0 → 1.3.2

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 (79) hide show
  1. package/dist/arg-parser.d.ts +6 -0
  2. package/dist/arg-parser.js +57 -1
  3. package/dist/backlog-generator.js +1 -1
  4. package/dist/backlog-sync-validator.js +3 -3
  5. package/dist/branch-check.d.ts +21 -0
  6. package/dist/branch-check.js +77 -0
  7. package/dist/cli/is-agent-branch.d.ts +11 -0
  8. package/dist/cli/is-agent-branch.js +15 -0
  9. package/dist/code-paths-overlap.js +2 -2
  10. package/dist/error-handler.d.ts +1 -0
  11. package/dist/error-handler.js +4 -1
  12. package/dist/git-adapter.d.ts +23 -0
  13. package/dist/git-adapter.js +38 -2
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +5 -0
  16. package/dist/lane-checker.d.ts +36 -3
  17. package/dist/lane-checker.js +128 -17
  18. package/dist/lane-inference.js +3 -4
  19. package/dist/lumenflow-config-schema.d.ts +125 -0
  20. package/dist/lumenflow-config-schema.js +76 -0
  21. package/dist/lumenflow-home.d.ts +130 -0
  22. package/dist/lumenflow-home.js +208 -0
  23. package/dist/manual-test-validator.js +1 -1
  24. package/dist/orchestration-rules.d.ts +1 -1
  25. package/dist/orchestration-rules.js +2 -2
  26. package/dist/orphan-detector.d.ts +16 -0
  27. package/dist/orphan-detector.js +24 -0
  28. package/dist/path-classifiers.d.ts +1 -1
  29. package/dist/path-classifiers.js +1 -1
  30. package/dist/rebase-artifact-cleanup.d.ts +17 -0
  31. package/dist/rebase-artifact-cleanup.js +49 -8
  32. package/dist/spawn-strategy.d.ts +53 -0
  33. package/dist/spawn-strategy.js +106 -0
  34. package/dist/spec-branch-helpers.d.ts +118 -0
  35. package/dist/spec-branch-helpers.js +192 -0
  36. package/dist/stamp-utils.d.ts +10 -0
  37. package/dist/stamp-utils.js +17 -19
  38. package/dist/token-counter.js +2 -2
  39. package/dist/wu-consistency-checker.d.ts +2 -0
  40. package/dist/wu-consistency-checker.js +40 -6
  41. package/dist/wu-constants.d.ts +98 -3
  42. package/dist/wu-constants.js +108 -3
  43. package/dist/wu-create-validators.d.ts +40 -2
  44. package/dist/wu-create-validators.js +76 -2
  45. package/dist/wu-done-branch-only.js +9 -0
  46. package/dist/wu-done-branch-utils.d.ts +10 -0
  47. package/dist/wu-done-branch-utils.js +31 -0
  48. package/dist/wu-done-cleanup.d.ts +8 -0
  49. package/dist/wu-done-cleanup.js +122 -0
  50. package/dist/wu-done-docs-generate.d.ts +73 -0
  51. package/dist/wu-done-docs-generate.js +108 -0
  52. package/dist/wu-done-docs-only.d.ts +20 -0
  53. package/dist/wu-done-docs-only.js +65 -0
  54. package/dist/wu-done-errors.d.ts +17 -0
  55. package/dist/wu-done-errors.js +24 -0
  56. package/dist/wu-done-inputs.d.ts +12 -0
  57. package/dist/wu-done-inputs.js +51 -0
  58. package/dist/wu-done-metadata.d.ts +100 -0
  59. package/dist/wu-done-metadata.js +193 -0
  60. package/dist/wu-done-paths.d.ts +69 -0
  61. package/dist/wu-done-paths.js +237 -0
  62. package/dist/wu-done-preflight.d.ts +48 -0
  63. package/dist/wu-done-preflight.js +185 -0
  64. package/dist/wu-done-validation.d.ts +82 -0
  65. package/dist/wu-done-validation.js +340 -0
  66. package/dist/wu-done-validators.d.ts +13 -409
  67. package/dist/wu-done-validators.js +9 -1225
  68. package/dist/wu-done-worktree.d.ts +0 -1
  69. package/dist/wu-done-worktree.js +24 -30
  70. package/dist/wu-schema.js +4 -4
  71. package/dist/wu-spawn-skills.d.ts +19 -0
  72. package/dist/wu-spawn-skills.js +148 -0
  73. package/dist/wu-spawn.d.ts +17 -4
  74. package/dist/wu-spawn.js +113 -177
  75. package/dist/wu-validation.d.ts +1 -0
  76. package/dist/wu-validation.js +21 -1
  77. package/dist/wu-validator.d.ts +51 -0
  78. package/dist/wu-validator.js +108 -0
  79. package/package.json +12 -8
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Path and workspace detection helpers for wu:done.
3
+ */
4
+ import path from 'node:path';
5
+ import { existsSync, readFileSync, statSync } from 'node:fs';
6
+ import { access } from 'node:fs/promises';
7
+ import { getGitForCwd } from './git-adapter.js';
8
+ import { WU_PATHS } from './wu-paths.js';
9
+ import { parseYAML, readWU } from './wu-yaml.js';
10
+ import { CLAIMED_MODES, EMOJI, LOG_PREFIX, STRING_LITERALS, toKebab } from './wu-constants.js';
11
+ import { detectDocsOnlyByPaths } from './wu-done-docs-only.js';
12
+ /**
13
+ * Read WU YAML preferring worktree version over main version
14
+ *
15
+ * WU-1584 Fix #4: Added diagnostic logging to confirm which YAML file is being
16
+ * read for code_paths validation. This helps debug issues where worktree YAML
17
+ * differs from main checkout YAML.
18
+ *
19
+ * @param {string} id - WU ID
20
+ * @param {string|null} worktreePath - Worktree path (null if branch-only mode)
21
+ * @param {string} mainWUPath - Path to WU YAML in main checkout
22
+ * @returns {object} Parsed WU document
23
+ */
24
+ export function readWUPreferWorktree(id, worktreePath, mainWUPath) {
25
+ if (worktreePath) {
26
+ const wtWUPath = path.join(worktreePath, WU_PATHS.WU(id));
27
+ if (existsSync(wtWUPath)) {
28
+ try {
29
+ const text = readFileSync(wtWUPath, { encoding: 'utf-8' });
30
+ const doc = parseYAML(text);
31
+ if (doc && doc.id === id) {
32
+ // WU-1584: Log source file for validation debugging
33
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} Reading WU YAML from worktree: ${wtWUPath}`);
34
+ if (doc.code_paths && doc.code_paths.length > 0) {
35
+ console.log(`${LOG_PREFIX.DONE} code_paths source: worktree (${doc.code_paths.length} path(s))`);
36
+ }
37
+ return doc;
38
+ }
39
+ // If ID mismatch, log warning but continue
40
+ console.warn(`${LOG_PREFIX.DONE} Warning: Worktree YAML ID mismatch (expected ${id}, got ${doc?.id})`);
41
+ }
42
+ catch (err) {
43
+ // Log parse errors for debugging
44
+ console.warn(`${LOG_PREFIX.DONE} Warning: Failed to read worktree YAML: ${err.message}`);
45
+ }
46
+ }
47
+ else {
48
+ // Log missing worktree YAML for debugging
49
+ console.warn(`${LOG_PREFIX.DONE} Warning: Worktree YAML not found at ${wtWUPath}`);
50
+ }
51
+ }
52
+ // WU-1584: Log when falling back to main checkout YAML
53
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} Reading WU YAML from main: ${mainWUPath}`);
54
+ const doc = readWU(mainWUPath, id);
55
+ if (doc.code_paths && doc.code_paths.length > 0) {
56
+ console.log(`${LOG_PREFIX.DONE} code_paths source: main checkout (${doc.code_paths.length} path(s))`);
57
+ }
58
+ return doc;
59
+ }
60
+ /**
61
+ * Detect if currently running inside a worktree
62
+ * Checks for .git file (not directory) which indicates a worktree
63
+ * @returns {string|null} Current directory path if inside worktree, null otherwise
64
+ */
65
+ export function detectCurrentWorktree() {
66
+ const cwd = process.cwd();
67
+ const gitPath = path.join(cwd, '.git');
68
+ // Check if .git exists and is a file (worktrees have .git file, main has .git directory)
69
+ if (!existsSync(gitPath))
70
+ return null;
71
+ try {
72
+ const stats = statSync(gitPath);
73
+ if (stats.isFile()) {
74
+ // Parse .git file to verify it points to main repo's worktrees
75
+ const gitContent = readFileSync(gitPath, { encoding: 'utf-8' });
76
+ const match = gitContent.match(/^gitdir:\s*(.+)$/m);
77
+ if (match && match[1].includes('.git/worktrees/')) {
78
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.TARGET} Auto-detected worktree from process.cwd(): ${cwd}`);
79
+ return cwd;
80
+ }
81
+ }
82
+ }
83
+ catch (err) {
84
+ // Ignore errors, fall back to calculated path
85
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Failed to detect worktree: ${err.message}`);
86
+ }
87
+ return null;
88
+ }
89
+ /**
90
+ * Resolve worktree path from WU YAML
91
+ * Originally implemented in WU-1226, extracted to validators module in WU-1215
92
+ * Priority:
93
+ * 1. Read worktree_path field (set at claim time, immune to lane field changes)
94
+ * 2. Fall back to calculating from lane field (for old WUs without worktree_path)
95
+ * 3. Use git worktree list to find actual path (defensive fallback)
96
+ * @param {object} doc - WU YAML document
97
+ * @returns {Promise<string|null>} - Worktree path or null if not found
98
+ */
99
+ export async function defaultWorktreeFrom(doc) {
100
+ // Priority 1 - use recorded worktree_path if available
101
+ if (doc.worktree_path) {
102
+ return doc.worktree_path;
103
+ }
104
+ // Priority 2 - calculate from current lane field (legacy behavior)
105
+ const lane = (doc.lane || '').toString();
106
+ const laneK = toKebab(lane);
107
+ const idK = (doc.id || '').toLowerCase();
108
+ if (!laneK || !idK)
109
+ return null;
110
+ const calculated = `worktrees/${laneK}-${idK}`;
111
+ // Priority 3 - verify calculated path exists, or find actual path via git worktree list
112
+ let calculatedExists = true;
113
+ try {
114
+ await access(calculated);
115
+ }
116
+ catch {
117
+ calculatedExists = false;
118
+ }
119
+ if (!calculatedExists) {
120
+ try {
121
+ const worktreeList = await getGitForCwd().worktreeList();
122
+ const lines = worktreeList.split(STRING_LITERALS.NEWLINE);
123
+ const branch = `lane/${laneK}/${idK}`;
124
+ for (let i = 0; i < lines.length; i++) {
125
+ if (lines[i].startsWith('branch ') && lines[i].includes(branch)) {
126
+ // Found the branch, now get the worktree path from previous line
127
+ for (let j = i - 1; j >= 0; j--) {
128
+ if (lines[j].startsWith('worktree ')) {
129
+ const fullPath = lines[j].substring('worktree '.length);
130
+ // Convert absolute path to relative path from repo root
131
+ const repoRoot = process.cwd();
132
+ const relativePath = path.relative(repoRoot, fullPath);
133
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Worktree path mismatch detected:\n` +
134
+ ` Expected: ${calculated}\n` +
135
+ ` Actual: ${relativePath}\n` +
136
+ ` Using actual path from git worktree list`);
137
+ return relativePath;
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ catch (e) {
144
+ console.warn(`${LOG_PREFIX.DONE} Could not query git worktree list: ${e.message}`);
145
+ }
146
+ }
147
+ return calculated;
148
+ }
149
+ /**
150
+ * Detect workspace mode from WU YAML
151
+ * @param {object} doc - WU YAML document
152
+ * @returns {'worktree' | 'branch-only'}
153
+ */
154
+ export function detectWorkspaceMode(doc) {
155
+ // Explicit mode field takes precedence
156
+ if (doc.claimed_mode === CLAIMED_MODES.BRANCH_ONLY)
157
+ return CLAIMED_MODES.BRANCH_ONLY;
158
+ if (doc.claimed_mode === CLAIMED_MODES.WORKTREE)
159
+ return CLAIMED_MODES.WORKTREE;
160
+ // Backward compatibility: if claimed_mode is missing, assume worktree mode
161
+ // (all WUs claimed before WU-510 used worktree mode)
162
+ return CLAIMED_MODES.WORKTREE;
163
+ }
164
+ /**
165
+ * Calculate lane branch name from WU YAML
166
+ * @param {object} doc - WU YAML document
167
+ * @returns {string|null} Lane branch name (e.g., lane/operations-tooling/wu-1215)
168
+ */
169
+ export function defaultBranchFrom(doc) {
170
+ const lane = (doc.lane || '').toString();
171
+ const laneK = toKebab(lane);
172
+ const idK = (doc.id || '').toLowerCase();
173
+ if (!laneK || !idK)
174
+ return null;
175
+ return `lane/${laneK}/${idK}`;
176
+ }
177
+ /**
178
+ * Check if a branch exists
179
+ * @param {string} branch - Branch name to check
180
+ * @returns {Promise<boolean>} True if branch exists
181
+ */
182
+ export async function branchExists(branch) {
183
+ return await getGitForCwd().branchExists(branch);
184
+ }
185
+ /**
186
+ * Detect workspace mode and calculate all relevant paths
187
+ * @param {string} id - WU ID
188
+ * @param {object} args - Parsed command-line arguments
189
+ * @returns {Promise<object>} Object containing paths, mode info, and WU document
190
+ */
191
+ export async function detectModeAndPaths(id, args) {
192
+ const WU_PATH = WU_PATHS.WU(id);
193
+ const STATUS_PATH = WU_PATHS.STATUS();
194
+ const BACKLOG_PATH = WU_PATHS.BACKLOG();
195
+ const STAMPS_DIR = WU_PATHS.STAMPS_DIR();
196
+ // Read WU YAML to detect workspace mode
197
+ const docMain = readWU(WU_PATH, id);
198
+ const workspaceMode = detectWorkspaceMode(docMain);
199
+ const isBranchOnly = workspaceMode === CLAIMED_MODES.BRANCH_ONLY;
200
+ console.log(`\n${LOG_PREFIX.DONE} Detected workspace mode: ${workspaceMode}`);
201
+ // Determine candidate worktree path early (only relevant for Worktree mode)
202
+ // Priority: 1) Auto-detect from cwd 2) Explicit --worktree arg 3) Calculate from YAML
203
+ const detectedWorktree = detectCurrentWorktree();
204
+ const worktreePathGuess = args.worktree || null;
205
+ // For Worktree mode: prefer auto-detected worktree, then explicit arg, then calculated path
206
+ // For Branch-Only mode: use main checkout version (no worktree exists)
207
+ const derivedWorktree = isBranchOnly
208
+ ? null
209
+ : detectedWorktree || worktreePathGuess || (await defaultWorktreeFrom(docMain));
210
+ if (!isBranchOnly && derivedWorktree && !detectedWorktree) {
211
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.FOLDER} Calculated worktree path from YAML: ${derivedWorktree}`);
212
+ }
213
+ // Read the actual WU YAML for validation (prefer worktree version over main)
214
+ const docForValidation = isBranchOnly
215
+ ? docMain
216
+ : readWUPreferWorktree(id, derivedWorktree, WU_PATH);
217
+ // WU-1234: Detect docs-only by type OR by code_paths
218
+ // Auto-detect if all code_paths are under docs/, ai/, .claude/, or are README/CLAUDE files
219
+ const isDocsOnlyByType = docForValidation.type === 'documentation';
220
+ const isDocsOnlyByPaths = detectDocsOnlyByPaths(docForValidation.code_paths);
221
+ const isDocsOnly = isDocsOnlyByType || isDocsOnlyByPaths;
222
+ if (isDocsOnlyByPaths && !isDocsOnlyByType) {
223
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} Auto-detected docs-only WU from code_paths (type: ${docForValidation.type || 'unset'})`);
224
+ }
225
+ return {
226
+ WU_PATH,
227
+ STATUS_PATH,
228
+ BACKLOG_PATH,
229
+ STAMPS_DIR,
230
+ docMain,
231
+ workspaceMode,
232
+ isBranchOnly,
233
+ derivedWorktree,
234
+ docForValidation,
235
+ isDocsOnly,
236
+ };
237
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Preflight validation helpers for wu:done.
3
+ */
4
+ import { execSync as execSyncImport } from 'node:child_process';
5
+ import { validatePreflight } from './wu-preflight-validators.js';
6
+ /**
7
+ * WU-1781: Build preflight error message with actionable guidance
8
+ */
9
+ export declare function buildPreflightErrorMessage(id: any, errors: any): string;
10
+ /**
11
+ * WU-1805: Execute preflight code_paths and test_paths validation
12
+ */
13
+ export interface ExecutePreflightCodePathValidationOptions {
14
+ /** Override validatePreflight for testing */
15
+ validatePreflightFn?: typeof validatePreflight;
16
+ }
17
+ export declare function executePreflightCodePathValidation(id: any, paths: any, options?: ExecutePreflightCodePathValidationOptions): Promise<{
18
+ valid: boolean;
19
+ errors: any[];
20
+ missingCodePaths: any[];
21
+ missingTestPaths: any[];
22
+ abortedBeforeGates: boolean;
23
+ }>;
24
+ /**
25
+ * WU-1805: Build preflight code_paths error message with actionable guidance
26
+ */
27
+ export declare function buildPreflightCodePathErrorMessage(id: any, result: any): string;
28
+ /**
29
+ * WU-1781: Run tasks:validate as preflight check before any git operations
30
+ */
31
+ export interface ExecSyncOverrideOptions {
32
+ /** Override execSync for testing (default: child_process.execSync) */
33
+ execSyncFn?: typeof execSyncImport;
34
+ }
35
+ export declare function runPreflightTasksValidation(id: any, options?: ExecSyncOverrideOptions): {
36
+ valid: boolean;
37
+ errors: any;
38
+ abortedBeforeMerge: boolean;
39
+ localMainModified: boolean;
40
+ hasStampStatusError: any;
41
+ };
42
+ /**
43
+ * WU-2308: Validate all pre-commit hooks with worktree context
44
+ */
45
+ export declare function validateAllPreCommitHooks(id: any, worktreePath?: any, options?: ExecSyncOverrideOptions): {
46
+ valid: boolean;
47
+ errors: any[];
48
+ };
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Preflight validation helpers for wu:done.
3
+ */
4
+ import { execSync as execSyncImport } from 'node:child_process';
5
+ import { validatePreflight } from './wu-preflight-validators.js';
6
+ import { LOG_PREFIX, EMOJI, STDIO } from './wu-constants.js';
7
+ /**
8
+ * WU-1781: Build preflight error message with actionable guidance
9
+ */
10
+ export function buildPreflightErrorMessage(id, errors) {
11
+ const hasStampStatusError = errors.some((e) => e.includes('stamp but status is not done'));
12
+ let message = `
13
+ ❌ PREFLIGHT VALIDATION FAILED
14
+
15
+ tasks:validate found errors that would block pre-push hooks.
16
+ Aborting wu:done BEFORE any merge operations to prevent deadlocks.
17
+
18
+ Errors:
19
+ ${errors.map((e) => ` - ${e}`).join('\n')}
20
+
21
+ Fix options:
22
+ `;
23
+ if (hasStampStatusError) {
24
+ message += `
25
+ For stamp-status mismatch errors:
26
+ 1. Fix the WU status to match the stamp (set status: done, locked: true)
27
+ 2. Or add the WU ID to .lumenflow.config.yaml > exemptions > stamp_status_mismatch
28
+
29
+ `;
30
+ }
31
+ message += `
32
+ General fixes:
33
+ 1. Run: pnpm tasks:validate to see full errors
34
+ 2. Fix the validation errors
35
+ 3. Retry: pnpm wu:done --id ${id}
36
+
37
+ This preflight check prevents wu:done from leaving main in a stuck state
38
+ where husky pre-push would block all further operations.
39
+ `;
40
+ return message;
41
+ }
42
+ export async function executePreflightCodePathValidation(id, paths, options = {}) {
43
+ // Use injected validator for testability, default to actual implementation
44
+ const validatePreflightFn = options.validatePreflightFn || validatePreflight;
45
+ console.log(`\n${LOG_PREFIX.DONE} 🔍 Preflight: validating code_paths and test paths...`);
46
+ const result = await validatePreflightFn(id, {
47
+ rootDir: paths.rootDir,
48
+ worktreePath: paths.worktreePath,
49
+ });
50
+ if (result.valid) {
51
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Preflight code_paths validation passed`);
52
+ return {
53
+ valid: true,
54
+ errors: [],
55
+ missingCodePaths: [],
56
+ missingTestPaths: [],
57
+ abortedBeforeGates: false,
58
+ };
59
+ }
60
+ console.error(`\n${LOG_PREFIX.DONE} ${EMOJI.FAILURE} Preflight code_paths validation failed`);
61
+ return {
62
+ valid: false,
63
+ errors: result.errors,
64
+ missingCodePaths: result.missingCodePaths || [],
65
+ missingTestPaths: result.missingTestPaths || [],
66
+ abortedBeforeGates: true,
67
+ };
68
+ }
69
+ /**
70
+ * WU-1805: Build preflight code_paths error message with actionable guidance
71
+ */
72
+ export function buildPreflightCodePathErrorMessage(id, result) {
73
+ const { errors, missingCodePaths = [], missingTestPaths = [] } = result;
74
+ let message = `
75
+ ❌ PREFLIGHT CODE_PATHS VALIDATION FAILED
76
+
77
+ code_paths/test_paths validation found errors that would cause gates to fail.
78
+ Aborting wu:done BEFORE running gates to save time.
79
+
80
+ Errors:
81
+ ${errors.map((e) => ` ${e}`).join('\n')}
82
+
83
+ `;
84
+ if (missingCodePaths.length > 0) {
85
+ message += `
86
+ Fix options for missing code_paths:
87
+ 1. Create the missing files in your worktree
88
+ 2. Update code_paths in ${id}.yaml using: pnpm wu:edit --id ${id} --code-paths "<corrected-paths>"
89
+ 3. Remove paths that were intentionally not created
90
+
91
+ `;
92
+ }
93
+ if (missingTestPaths.length > 0) {
94
+ message += `
95
+ Fix options for missing test_paths:
96
+ 1. Create the missing test files
97
+ 2. Update test paths in ${id}.yaml using wu:edit
98
+ 3. Use tests.manual for descriptions instead of file paths
99
+
100
+ `;
101
+ }
102
+ message += `
103
+ After fixing, retry:
104
+ pnpm wu:done --id ${id}
105
+
106
+ This preflight check runs BEFORE gates to catch YAML mismatches early.
107
+ See: docs/04-operations/_frameworks/lumenflow/agent/onboarding/troubleshooting-wu-done.md for more recovery options.
108
+ `;
109
+ return message;
110
+ }
111
+ export function runPreflightTasksValidation(id, options = {}) {
112
+ // Use injected execSync for testability, default to node's child_process
113
+ const execSyncFn = options.execSyncFn || execSyncImport;
114
+ console.log(`\n${LOG_PREFIX.DONE} 🔍 Preflight: running tasks:validate...`);
115
+ try {
116
+ // Run tasks:validate with WU_ID context (single-WU validation mode)
117
+ execSyncFn('node tools/validate.js', {
118
+ stdio: STDIO.PIPE,
119
+ encoding: 'utf-8',
120
+ env: { ...process.env, WU_ID: id },
121
+ });
122
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Preflight tasks:validate passed`);
123
+ return {
124
+ valid: true,
125
+ errors: [],
126
+ abortedBeforeMerge: false,
127
+ localMainModified: false,
128
+ hasStampStatusError: false,
129
+ };
130
+ }
131
+ catch (err) {
132
+ // Validation failed - extract errors from output
133
+ const output = err.stdout || err.message || 'Unknown validation error';
134
+ const errors = output
135
+ .split('\n')
136
+ .filter((line) => line.includes('[') && line.includes(']'))
137
+ .map((line) => line.trim());
138
+ const hasStampStatusError = errors.some((e) => e.includes('stamp but status is not done'));
139
+ console.error(`\n${LOG_PREFIX.DONE} ${EMOJI.FAILURE} Preflight tasks:validate failed`);
140
+ return {
141
+ valid: false,
142
+ errors: errors.length > 0 ? errors : [output],
143
+ abortedBeforeMerge: true,
144
+ localMainModified: false,
145
+ hasStampStatusError,
146
+ };
147
+ }
148
+ }
149
+ /**
150
+ * WU-2308: Validate all pre-commit hooks with worktree context
151
+ */
152
+ export function validateAllPreCommitHooks(id, worktreePath = null, options = {}) {
153
+ const execSyncFn = options.execSyncFn || execSyncImport;
154
+ console.log(`\n${LOG_PREFIX.DONE} 🔍 Pre-flight: validating all pre-commit hooks...`);
155
+ const errors = [];
156
+ try {
157
+ // WU-2308: Run from worktree context when provided to ensure audit checks
158
+ // the worktree's dependencies (with fixes) not main's stale dependencies
159
+ const execOptions = {
160
+ stdio: STDIO.INHERIT,
161
+ encoding: 'utf-8',
162
+ };
163
+ // Only set cwd when worktreePath is provided
164
+ if (worktreePath) {
165
+ execOptions.cwd = worktreePath;
166
+ }
167
+ // Run the gates-pre-commit script that contains all validation gates
168
+ execSyncFn('node tools/gates-pre-commit.js', execOptions);
169
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} All pre-commit hooks passed`);
170
+ return { valid: true, errors: [] };
171
+ }
172
+ catch {
173
+ // Pre-commit hooks failed
174
+ errors.push('Pre-commit hook validation failed. Fix these issues before wu:done:');
175
+ errors.push('');
176
+ errors.push('Common fixes:');
177
+ errors.push(' • Formatting issues: Run pnpm format');
178
+ errors.push(' • Lint errors: Run pnpm lint:fix');
179
+ errors.push(' • Type errors: Check pnpm typecheck output');
180
+ errors.push(' • Audit issues: Check pnpm audit output');
181
+ errors.push('');
182
+ errors.push(`After fixing, re-run: pnpm wu:done --id ${id}`);
183
+ return { valid: false, errors };
184
+ }
185
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Core validation helpers for wu:done.
3
+ */
4
+ interface ExposureDefaultResult {
5
+ applied: boolean;
6
+ exposure?: string;
7
+ }
8
+ export declare function applyExposureDefaults(doc: any): ExposureDefaultResult;
9
+ /**
10
+ * WU-1351: Validate code_paths files exist on main branch
11
+ *
12
+ * Prevents false completions by ensuring all code_paths entries
13
+ * actually exist on the target branch (main or lane branch).
14
+ *
15
+ * This guards against:
16
+ * - Stamps being created for WUs where code never merged
17
+ * - Metadata becoming desynchronized from actual code
18
+ */
19
+ export interface ValidateCodePathsExistOptions {
20
+ /** Branch to check files against (default: 'main') */
21
+ targetBranch?: string;
22
+ /** Worktree path for worktree mode */
23
+ worktreePath?: string | null;
24
+ }
25
+ export declare function validateCodePathsExist(doc: any, id: any, options?: ValidateCodePathsExistOptions): Promise<{
26
+ valid: boolean;
27
+ errors: any[];
28
+ missing: any[];
29
+ }>;
30
+ /**
31
+ * Validate WU spec completeness (WU-1162, WU-1280)
32
+ *
33
+ * Ensures WU specifications are complete before allowing wu:done to proceed.
34
+ * Prevents placeholder WUs from being marked as done.
35
+ */
36
+ export declare function validateSpecCompleteness(doc: any, _id: any): {
37
+ valid: boolean;
38
+ errors: any[];
39
+ };
40
+ /**
41
+ * WU-1617: Post-mutation validation for wu:done
42
+ *
43
+ * Validates that metadata files written by tx.commit() are valid:
44
+ * 1. WU YAML has completed_at field with valid ISO datetime
45
+ * 2. WU YAML has locked: true
46
+ * 3. Stamp file exists
47
+ */
48
+ export declare function validatePostMutation({ id, wuPath, stampPath }: {
49
+ id: any;
50
+ wuPath: any;
51
+ stampPath: any;
52
+ }): {
53
+ valid: boolean;
54
+ errors: any[];
55
+ };
56
+ /**
57
+ * WU-2242: Validate that test_paths is required for non-doc WUs
58
+ *
59
+ * Enforces that WUs with code changes (non-documentation types with code_paths
60
+ * that contain actual code) have at least one test path specified.
61
+ */
62
+ export declare function validateTestPathsRequired(wu: any): {
63
+ valid: boolean;
64
+ error?: undefined;
65
+ } | {
66
+ valid: boolean;
67
+ error: string;
68
+ };
69
+ /**
70
+ * WU-2310: Validate type vs code_paths at preflight (before transaction starts).
71
+ */
72
+ export declare function validateTypeVsCodePathsPreflight(wu: any): {
73
+ valid: boolean;
74
+ errors: any[];
75
+ blockedPaths: any[];
76
+ abortedBeforeTransaction: boolean;
77
+ };
78
+ /**
79
+ * WU-2310: Build error message for type vs code_paths preflight failure.
80
+ */
81
+ export declare function buildTypeVsCodePathsErrorMessage(id: any, blockedPaths: any): string;
82
+ export {};