@lumenflow/core 1.0.0 → 1.3.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.
- package/dist/arg-parser.js +31 -1
- package/dist/backlog-generator.js +1 -1
- package/dist/backlog-sync-validator.js +3 -3
- package/dist/branch-check.d.ts +21 -0
- package/dist/branch-check.js +77 -0
- package/dist/cli/is-agent-branch.d.ts +11 -0
- package/dist/cli/is-agent-branch.js +15 -0
- package/dist/code-paths-overlap.js +2 -2
- package/dist/error-handler.d.ts +1 -0
- package/dist/error-handler.js +4 -1
- package/dist/git-adapter.d.ts +16 -0
- package/dist/git-adapter.js +23 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/lane-checker.d.ts +36 -3
- package/dist/lane-checker.js +128 -17
- package/dist/lane-inference.js +3 -4
- package/dist/lumenflow-config-schema.d.ts +125 -0
- package/dist/lumenflow-config-schema.js +76 -0
- package/dist/orchestration-rules.d.ts +1 -1
- package/dist/orchestration-rules.js +2 -2
- package/dist/path-classifiers.d.ts +1 -1
- package/dist/path-classifiers.js +1 -1
- package/dist/rebase-artifact-cleanup.d.ts +17 -0
- package/dist/rebase-artifact-cleanup.js +49 -8
- package/dist/spawn-strategy.d.ts +53 -0
- package/dist/spawn-strategy.js +106 -0
- package/dist/stamp-utils.d.ts +10 -0
- package/dist/stamp-utils.js +17 -19
- package/dist/token-counter.js +2 -2
- package/dist/wu-consistency-checker.js +5 -5
- package/dist/wu-constants.d.ts +21 -3
- package/dist/wu-constants.js +28 -3
- package/dist/wu-done-branch-utils.d.ts +10 -0
- package/dist/wu-done-branch-utils.js +31 -0
- package/dist/wu-done-cleanup.d.ts +8 -0
- package/dist/wu-done-cleanup.js +122 -0
- package/dist/wu-done-docs-only.d.ts +20 -0
- package/dist/wu-done-docs-only.js +65 -0
- package/dist/wu-done-errors.d.ts +17 -0
- package/dist/wu-done-errors.js +24 -0
- package/dist/wu-done-inputs.d.ts +12 -0
- package/dist/wu-done-inputs.js +51 -0
- package/dist/wu-done-metadata.d.ts +100 -0
- package/dist/wu-done-metadata.js +193 -0
- package/dist/wu-done-paths.d.ts +69 -0
- package/dist/wu-done-paths.js +237 -0
- package/dist/wu-done-preflight.d.ts +48 -0
- package/dist/wu-done-preflight.js +185 -0
- package/dist/wu-done-validation.d.ts +82 -0
- package/dist/wu-done-validation.js +340 -0
- package/dist/wu-done-validators.d.ts +13 -409
- package/dist/wu-done-validators.js +9 -1225
- package/dist/wu-done-worktree.d.ts +0 -1
- package/dist/wu-done-worktree.js +12 -30
- package/dist/wu-schema.js +1 -3
- package/dist/wu-spawn-skills.d.ts +19 -0
- package/dist/wu-spawn-skills.js +148 -0
- package/dist/wu-spawn.d.ts +17 -4
- package/dist/wu-spawn.js +99 -176
- package/dist/wu-validation.d.ts +1 -0
- package/dist/wu-validation.js +21 -1
- package/dist/wu-validator.d.ts +51 -0
- package/dist/wu-validator.js +108 -0
- package/package.json +11 -8
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core validation helpers for wu:done.
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
7
|
+
import { parseYAML } from './wu-yaml.js';
|
|
8
|
+
import { BRANCHES, EMOJI, FILE_SYSTEM, GIT_COMMANDS, LOG_PREFIX, STRING_LITERALS, TEST_TYPES, VALIDATION, WU_TYPES, } from './wu-constants.js';
|
|
9
|
+
import { PLACEHOLDER_SENTINEL } from './wu-schema.js';
|
|
10
|
+
import { resolveExposureDefault } from './wu-validation.js';
|
|
11
|
+
import { validateAutomatedTestRequirement } from './manual-test-validator.js';
|
|
12
|
+
import { isDocumentationPath } from './file-classifiers.js';
|
|
13
|
+
export function applyExposureDefaults(doc) {
|
|
14
|
+
if (!doc || typeof doc !== 'object') {
|
|
15
|
+
return { applied: false };
|
|
16
|
+
}
|
|
17
|
+
if (typeof doc.exposure === 'string' && doc.exposure.trim().length > 0) {
|
|
18
|
+
return { applied: false, exposure: doc.exposure };
|
|
19
|
+
}
|
|
20
|
+
const exposureDefault = resolveExposureDefault(doc.lane);
|
|
21
|
+
if (!exposureDefault) {
|
|
22
|
+
return { applied: false };
|
|
23
|
+
}
|
|
24
|
+
doc.exposure = exposureDefault;
|
|
25
|
+
return { applied: true, exposure: exposureDefault };
|
|
26
|
+
}
|
|
27
|
+
export async function validateCodePathsExist(doc, id, options = {}) {
|
|
28
|
+
const { targetBranch = BRANCHES.MAIN, worktreePath = null } = options;
|
|
29
|
+
const errors = [];
|
|
30
|
+
const missing = [];
|
|
31
|
+
const codePaths = doc.code_paths || [];
|
|
32
|
+
// Skip validation for WUs without code_paths (docs-only, process WUs)
|
|
33
|
+
if (codePaths.length === 0) {
|
|
34
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} No code_paths to validate for ${id}`);
|
|
35
|
+
return { valid: true, errors: [], missing: [] };
|
|
36
|
+
}
|
|
37
|
+
console.log(`${LOG_PREFIX.DONE} Validating ${codePaths.length} code_paths exist...`);
|
|
38
|
+
// For worktree mode, check files exist in the worktree (will be merged)
|
|
39
|
+
// For branch-only mode or post-merge validation, check files exist on target branch
|
|
40
|
+
if (worktreePath && existsSync(worktreePath)) {
|
|
41
|
+
// Worktree mode: validate files exist in worktree
|
|
42
|
+
for (const filePath of codePaths) {
|
|
43
|
+
const fullPath = path.join(worktreePath, filePath);
|
|
44
|
+
if (!existsSync(fullPath)) {
|
|
45
|
+
missing.push(filePath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (missing.length > 0) {
|
|
49
|
+
errors.push(`code_paths validation failed - ${missing.length} file(s) not found in worktree:\n${missing
|
|
50
|
+
.map((p) => ` - ${p}`)
|
|
51
|
+
.join(STRING_LITERALS.NEWLINE)}\n\nEnsure all files listed in code_paths exist before running wu:done.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Branch-only or post-merge: use git ls-tree to check files on target branch
|
|
56
|
+
try {
|
|
57
|
+
const gitAdapter = getGitForCwd();
|
|
58
|
+
for (const filePath of codePaths) {
|
|
59
|
+
try {
|
|
60
|
+
// git ls-tree returns empty for non-existent files
|
|
61
|
+
const result = await gitAdapter.raw([GIT_COMMANDS.LS_TREE, targetBranch, '--', filePath]);
|
|
62
|
+
if (!result || result.trim() === '') {
|
|
63
|
+
missing.push(filePath);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// git ls-tree fails for non-existent paths
|
|
68
|
+
missing.push(filePath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (missing.length > 0) {
|
|
72
|
+
errors.push(`code_paths validation failed - ${missing.length} file(s) not found on ${targetBranch}:\n${missing
|
|
73
|
+
.map((p) => ` - ${p}`)
|
|
74
|
+
.join(STRING_LITERALS.NEWLINE)}\n\n❌ POTENTIAL FALSE COMPLETION DETECTED\n\n` +
|
|
75
|
+
`These files are listed in code_paths but do not exist on ${targetBranch}.\n` +
|
|
76
|
+
`This prevents creating a stamp for incomplete work.\n\n` +
|
|
77
|
+
`Fix options:\n` +
|
|
78
|
+
` 1. Ensure all code is committed and merged to ${targetBranch}\n` +
|
|
79
|
+
` 2. Update code_paths in ${id}.yaml to match actual files\n` +
|
|
80
|
+
` 3. Remove files that were intentionally not created\n\n` +
|
|
81
|
+
`Context: WU-1351 prevents false completions from INIT-WORKFLOW-INTEGRITY`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
// Non-fatal: warn but don't block if git command fails
|
|
86
|
+
console.warn(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Could not validate code_paths: ${err.message}`);
|
|
87
|
+
return { valid: true, errors: [], missing: [] };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (errors.length > 0) {
|
|
91
|
+
return { valid: false, errors, missing };
|
|
92
|
+
}
|
|
93
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} All ${codePaths.length} code_paths verified`);
|
|
94
|
+
return { valid: true, errors: [], missing: [] };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate WU spec completeness (WU-1162, WU-1280)
|
|
98
|
+
*
|
|
99
|
+
* Ensures WU specifications are complete before allowing wu:done to proceed.
|
|
100
|
+
* Prevents placeholder WUs from being marked as done.
|
|
101
|
+
*/
|
|
102
|
+
export function validateSpecCompleteness(doc, _id) {
|
|
103
|
+
const errors = [];
|
|
104
|
+
// Check for placeholder text in description
|
|
105
|
+
if (doc.description && doc.description.includes(PLACEHOLDER_SENTINEL)) {
|
|
106
|
+
errors.push(`Description contains ${PLACEHOLDER_SENTINEL} marker`);
|
|
107
|
+
}
|
|
108
|
+
// Handle both array and object formats for acceptance criteria
|
|
109
|
+
if (doc.acceptance) {
|
|
110
|
+
const hasPlaceholder = (value) => {
|
|
111
|
+
if (typeof value === 'string') {
|
|
112
|
+
return value.includes(PLACEHOLDER_SENTINEL);
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(value)) {
|
|
115
|
+
return value.some((item) => hasPlaceholder(item));
|
|
116
|
+
}
|
|
117
|
+
if (typeof value === 'object' && value !== null) {
|
|
118
|
+
return Object.values(value).some((item) => hasPlaceholder(item));
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
};
|
|
122
|
+
if (hasPlaceholder(doc.acceptance)) {
|
|
123
|
+
errors.push(`Acceptance criteria contain ${PLACEHOLDER_SENTINEL} markers`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Check minimum description length
|
|
127
|
+
if (!doc.description || doc.description.trim().length < VALIDATION.MIN_DESCRIPTION_LENGTH) {
|
|
128
|
+
errors.push(`Description too short (${doc.description?.trim().length || 0} chars, minimum ${VALIDATION.MIN_DESCRIPTION_LENGTH})`);
|
|
129
|
+
}
|
|
130
|
+
// Check code_paths for non-documentation WUs
|
|
131
|
+
if (doc.type !== WU_TYPES.DOCUMENTATION && doc.type !== WU_TYPES.PROCESS) {
|
|
132
|
+
if (!doc.code_paths || doc.code_paths.length === 0) {
|
|
133
|
+
errors.push('Code paths required for non-documentation WUs');
|
|
134
|
+
}
|
|
135
|
+
// WU-1280: Check tests array for non-documentation WUs
|
|
136
|
+
// Support both tests: (current) and test_paths: (legacy)
|
|
137
|
+
const testObj = doc.tests || doc.test_paths || {};
|
|
138
|
+
// Helper to check if array has items
|
|
139
|
+
const hasItems = (arr) => Array.isArray(arr) && arr.length > 0;
|
|
140
|
+
const hasUnitTests = hasItems(testObj[TEST_TYPES.UNIT]);
|
|
141
|
+
const hasE2ETests = hasItems(testObj[TEST_TYPES.E2E]);
|
|
142
|
+
const hasManualTests = hasItems(testObj[TEST_TYPES.MANUAL]);
|
|
143
|
+
const hasIntegrationTests = hasItems(testObj[TEST_TYPES.INTEGRATION]);
|
|
144
|
+
if (!(hasUnitTests || hasE2ETests || hasManualTests || hasIntegrationTests)) {
|
|
145
|
+
errors.push('At least one test path required (unit, e2e, integration, or manual)');
|
|
146
|
+
}
|
|
147
|
+
// WU-2332: Require automated tests for code file changes
|
|
148
|
+
// Manual-only tests are not sufficient when code_paths contain actual code files
|
|
149
|
+
const automatedTestResult = validateAutomatedTestRequirement(doc);
|
|
150
|
+
if (!automatedTestResult.valid) {
|
|
151
|
+
errors.push(...automatedTestResult.errors);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { valid: errors.length === 0, errors };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* WU-1617: Post-mutation validation for wu:done
|
|
158
|
+
*
|
|
159
|
+
* Validates that metadata files written by tx.commit() are valid:
|
|
160
|
+
* 1. WU YAML has completed_at field with valid ISO datetime
|
|
161
|
+
* 2. WU YAML has locked: true
|
|
162
|
+
* 3. Stamp file exists
|
|
163
|
+
*/
|
|
164
|
+
export function validatePostMutation({ id, wuPath, stampPath }) {
|
|
165
|
+
const errors = [];
|
|
166
|
+
// Check stamp file exists
|
|
167
|
+
if (!existsSync(stampPath)) {
|
|
168
|
+
errors.push(`Stamp file not created: ${stampPath}`);
|
|
169
|
+
}
|
|
170
|
+
// Read and validate WU YAML after mutation
|
|
171
|
+
if (!existsSync(wuPath)) {
|
|
172
|
+
errors.push(`WU YAML not found after mutation: ${wuPath}`);
|
|
173
|
+
return { valid: false, errors };
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const content = readFileSync(wuPath, { encoding: FILE_SYSTEM.ENCODING });
|
|
177
|
+
const doc = parseYAML(content);
|
|
178
|
+
// Verify completed_at exists and is valid ISO datetime
|
|
179
|
+
if (!doc.completed_at) {
|
|
180
|
+
errors.push(`Missing required field 'completed_at' in ${id}.yaml`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Validate ISO datetime format (YYYY-MM-DDTHH:mm:ss.sssZ or similar)
|
|
184
|
+
const timestamp = new Date(doc.completed_at);
|
|
185
|
+
if (isNaN(timestamp.getTime())) {
|
|
186
|
+
errors.push(`Invalid completed_at timestamp: ${doc.completed_at}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Verify locked is true
|
|
190
|
+
if (doc.locked !== true) {
|
|
191
|
+
errors.push(`Missing or invalid 'locked' field in ${id}.yaml (expected: true, got: ${doc.locked})`);
|
|
192
|
+
}
|
|
193
|
+
// Verify status is done
|
|
194
|
+
if (doc.status !== 'done') {
|
|
195
|
+
errors.push(`Invalid status in ${id}.yaml (expected: 'done', got: '${doc.status}')`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
errors.push(`Failed to parse WU YAML after mutation: ${err.message}`);
|
|
200
|
+
}
|
|
201
|
+
return { valid: errors.length === 0, errors };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* WU-2242: Validate that test_paths is required for non-doc WUs
|
|
205
|
+
*
|
|
206
|
+
* Enforces that WUs with code changes (non-documentation types with code_paths
|
|
207
|
+
* that contain actual code) have at least one test path specified.
|
|
208
|
+
*/
|
|
209
|
+
export function validateTestPathsRequired(wu) {
|
|
210
|
+
// Skip validation for documentation and process WUs
|
|
211
|
+
if (wu.type === WU_TYPES.DOCUMENTATION || wu.type === WU_TYPES.PROCESS) {
|
|
212
|
+
return { valid: true };
|
|
213
|
+
}
|
|
214
|
+
// Skip if code_paths is empty or undefined
|
|
215
|
+
const codePaths = wu.code_paths || [];
|
|
216
|
+
if (codePaths.length === 0) {
|
|
217
|
+
return { valid: true };
|
|
218
|
+
}
|
|
219
|
+
// Skip if all code_paths are documentation paths
|
|
220
|
+
const hasCodeChanges = codePaths.some((p) => !isDocumentationPath(p));
|
|
221
|
+
if (!hasCodeChanges) {
|
|
222
|
+
return { valid: true };
|
|
223
|
+
}
|
|
224
|
+
// Check if tests object exists and has at least one test
|
|
225
|
+
const testObj = wu.tests || {};
|
|
226
|
+
// Helper to check if array has items
|
|
227
|
+
const hasItems = (arr) => Array.isArray(arr) && arr.length > 0;
|
|
228
|
+
const hasUnitTests = hasItems(testObj[TEST_TYPES.UNIT]);
|
|
229
|
+
const hasE2ETests = hasItems(testObj[TEST_TYPES.E2E]);
|
|
230
|
+
const hasManualTests = hasItems(testObj[TEST_TYPES.MANUAL]);
|
|
231
|
+
const hasIntegrationTests = hasItems(testObj[TEST_TYPES.INTEGRATION]);
|
|
232
|
+
// No tests at all - fail
|
|
233
|
+
if (!(hasUnitTests || hasE2ETests || hasManualTests || hasIntegrationTests)) {
|
|
234
|
+
return {
|
|
235
|
+
valid: false,
|
|
236
|
+
error: `${wu.id} requires test_paths: WU has code_paths but no tests specified. Add unit, e2e, integration, or manual tests.`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
// WU-2332: If we have tests, also check automated test requirement for code files
|
|
240
|
+
// Manual-only tests are not sufficient for code changes
|
|
241
|
+
const automatedTestResult = validateAutomatedTestRequirement(wu);
|
|
242
|
+
if (!automatedTestResult.valid) {
|
|
243
|
+
// Extract the first error line for the single-error format of this function
|
|
244
|
+
const errorSummary = automatedTestResult.errors[0]?.split('\n')[0] || 'Automated tests required';
|
|
245
|
+
return {
|
|
246
|
+
valid: false,
|
|
247
|
+
error: `${wu.id}: ${errorSummary}`,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return { valid: true };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* WU-2310: Allowed path patterns for documentation WUs.
|
|
254
|
+
* Mirrors the patterns in gates-pre-commit.mjs gateDocsOnlyPathEnforcement()
|
|
255
|
+
* to enable early validation at preflight (before transaction starts).
|
|
256
|
+
*
|
|
257
|
+
* @constant {RegExp[]}
|
|
258
|
+
*/
|
|
259
|
+
const DOCS_ONLY_ALLOWED_PATTERNS = [
|
|
260
|
+
/^memory-bank\//i,
|
|
261
|
+
/^docs\//i,
|
|
262
|
+
/\.md$/i,
|
|
263
|
+
/^\.beacon\/stamps\//i,
|
|
264
|
+
/^\.claude\//i,
|
|
265
|
+
/^ai\//i,
|
|
266
|
+
/^README\.md$/i,
|
|
267
|
+
/^CLAUDE\.md$/i,
|
|
268
|
+
];
|
|
269
|
+
/**
|
|
270
|
+
* WU-2310: Check if a path is allowed for documentation WUs.
|
|
271
|
+
*
|
|
272
|
+
* @param {string} filePath - File path to check
|
|
273
|
+
* @returns {boolean} True if path is allowed for docs WUs
|
|
274
|
+
*/
|
|
275
|
+
function isAllowedDocsPath(filePath) {
|
|
276
|
+
if (!filePath || typeof filePath !== 'string')
|
|
277
|
+
return false;
|
|
278
|
+
return DOCS_ONLY_ALLOWED_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* WU-2310: Validate type vs code_paths at preflight (before transaction starts).
|
|
282
|
+
*/
|
|
283
|
+
export function validateTypeVsCodePathsPreflight(wu) {
|
|
284
|
+
const errors = [];
|
|
285
|
+
const blockedPaths = [];
|
|
286
|
+
// Only validate documentation WUs
|
|
287
|
+
if (wu.type !== WU_TYPES.DOCUMENTATION) {
|
|
288
|
+
return { valid: true, errors: [], blockedPaths: [], abortedBeforeTransaction: false };
|
|
289
|
+
}
|
|
290
|
+
// Skip if no code_paths
|
|
291
|
+
const codePaths = wu.code_paths;
|
|
292
|
+
if (!codePaths || !Array.isArray(codePaths) || codePaths.length === 0) {
|
|
293
|
+
return { valid: true, errors: [], blockedPaths: [], abortedBeforeTransaction: false };
|
|
294
|
+
}
|
|
295
|
+
// Check each code_path against allowed patterns
|
|
296
|
+
for (const filePath of codePaths) {
|
|
297
|
+
if (!isAllowedDocsPath(filePath)) {
|
|
298
|
+
blockedPaths.push(filePath);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (blockedPaths.length > 0) {
|
|
302
|
+
const pathsList = blockedPaths.map((p) => ` - ${p}`).join('\n');
|
|
303
|
+
errors.push(`Documentation WU ${wu.id} has code_paths that would fail pre-commit hook:\n${pathsList}`);
|
|
304
|
+
return { valid: false, errors, blockedPaths, abortedBeforeTransaction: true };
|
|
305
|
+
}
|
|
306
|
+
return { valid: true, errors: [], blockedPaths: [], abortedBeforeTransaction: false };
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* WU-2310: Build error message for type vs code_paths preflight failure.
|
|
310
|
+
*/
|
|
311
|
+
export function buildTypeVsCodePathsErrorMessage(id, blockedPaths) {
|
|
312
|
+
return `
|
|
313
|
+
PREFLIGHT VALIDATION FAILED (WU-2310)
|
|
314
|
+
|
|
315
|
+
WU ${id} is type: documentation but has code_paths that are not allowed:
|
|
316
|
+
|
|
317
|
+
${blockedPaths.map((p) => ` - ${p}`).join('\n')}
|
|
318
|
+
|
|
319
|
+
This would fail at git commit time (pre-commit hook: gateDocsOnlyPathEnforcement).
|
|
320
|
+
Aborting BEFORE transaction to prevent inconsistent state.
|
|
321
|
+
|
|
322
|
+
Fix options:
|
|
323
|
+
|
|
324
|
+
1. Change WU type to 'engineering' (or 'feature', 'bug', etc.):
|
|
325
|
+
pnpm wu:edit --id ${id} --type engineering
|
|
326
|
+
|
|
327
|
+
2. Update code_paths to only include documentation files:
|
|
328
|
+
pnpm wu:edit --id ${id} --code-paths "docs/..." "*.md"
|
|
329
|
+
|
|
330
|
+
Allowed paths for documentation WUs:
|
|
331
|
+
- docs/
|
|
332
|
+
- ai/
|
|
333
|
+
- .claude/
|
|
334
|
+
- memory-bank/
|
|
335
|
+
- .beacon/stamps/
|
|
336
|
+
- *.md files
|
|
337
|
+
|
|
338
|
+
After fixing, retry: pnpm wu:done --id ${id}
|
|
339
|
+
`;
|
|
340
|
+
}
|