@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.
- package/dist/arg-parser.d.ts +6 -0
- package/dist/arg-parser.js +57 -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 +23 -0
- package/dist/git-adapter.js +38 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -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/lumenflow-home.d.ts +130 -0
- package/dist/lumenflow-home.js +208 -0
- package/dist/manual-test-validator.js +1 -1
- package/dist/orchestration-rules.d.ts +1 -1
- package/dist/orchestration-rules.js +2 -2
- package/dist/orphan-detector.d.ts +16 -0
- package/dist/orphan-detector.js +24 -0
- 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/spec-branch-helpers.d.ts +118 -0
- package/dist/spec-branch-helpers.js +192 -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.d.ts +2 -0
- package/dist/wu-consistency-checker.js +40 -6
- package/dist/wu-constants.d.ts +98 -3
- package/dist/wu-constants.js +108 -3
- package/dist/wu-create-validators.d.ts +40 -2
- package/dist/wu-create-validators.js +76 -2
- package/dist/wu-done-branch-only.js +9 -0
- 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-generate.d.ts +73 -0
- package/dist/wu-done-docs-generate.js +108 -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 +24 -30
- package/dist/wu-schema.js +4 -4
- 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 +113 -177
- 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 +12 -8
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file wu-done-docs-generate.ts
|
|
3
|
+
* @description Documentation regeneration utilities for wu:done
|
|
4
|
+
*
|
|
5
|
+
* WU-1061: Integrate docs:generate into wu:done for @lumenflow/* changes
|
|
6
|
+
*
|
|
7
|
+
* Detects changes to files that affect generated documentation and triggers
|
|
8
|
+
* regeneration during wu:done (after gates pass, before metadata commit).
|
|
9
|
+
*/
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
12
|
+
import { STDIO } from './wu-constants.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pathspecs for files that affect generated documentation.
|
|
15
|
+
* When any of these files change, docs:generate should be run.
|
|
16
|
+
*
|
|
17
|
+
* Based on .husky/hooks/docs-sync.mjs patterns, expanded to match
|
|
18
|
+
* all files that can affect CLI/config documentation.
|
|
19
|
+
*/
|
|
20
|
+
export const DOC_SOURCE_PATHSPECS = [
|
|
21
|
+
'tools/generate-cli-docs.ts',
|
|
22
|
+
'packages/@lumenflow/core/src/arg-parser.ts',
|
|
23
|
+
'packages/@lumenflow/core/src/lumenflow-config-schema.ts',
|
|
24
|
+
'packages/@lumenflow/core/src/index.ts',
|
|
25
|
+
'packages/@lumenflow/cli/package.json',
|
|
26
|
+
'packages/@lumenflow/cli/src/',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Output files generated by docs:generate.
|
|
30
|
+
* These files are staged before the metadata commit.
|
|
31
|
+
*/
|
|
32
|
+
export const DOC_OUTPUT_FILES = [
|
|
33
|
+
'apps/docs/src/content/docs/reference/cli.mdx',
|
|
34
|
+
'apps/docs/src/content/docs/reference/config.mdx',
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Check if any doc-source files changed compared to the base branch.
|
|
38
|
+
* Uses git diff with pathspecs for efficient detection.
|
|
39
|
+
*
|
|
40
|
+
* @param baseBranch - Base branch for comparison (e.g., 'main', 'origin/main')
|
|
41
|
+
* @returns Promise<boolean> - True if doc-source files changed
|
|
42
|
+
*/
|
|
43
|
+
export async function hasDocSourceChanges(baseBranch) {
|
|
44
|
+
try {
|
|
45
|
+
const gitAdapter = getGitForCwd();
|
|
46
|
+
const diff = await gitAdapter.raw([
|
|
47
|
+
'diff',
|
|
48
|
+
`${baseBranch}...HEAD`,
|
|
49
|
+
'--name-only',
|
|
50
|
+
'--',
|
|
51
|
+
...DOC_SOURCE_PATHSPECS,
|
|
52
|
+
]);
|
|
53
|
+
return diff.trim().length > 0;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Fail-safe: don't regenerate on git errors
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stage doc output files for the metadata commit.
|
|
62
|
+
*
|
|
63
|
+
* @returns Promise<void>
|
|
64
|
+
*/
|
|
65
|
+
export async function stageDocOutputs() {
|
|
66
|
+
const gitAdapter = getGitForCwd();
|
|
67
|
+
await gitAdapter.add([...DOC_OUTPUT_FILES]);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Run turbo docs:generate to regenerate documentation.
|
|
71
|
+
* Turbo handles build dependencies and caching.
|
|
72
|
+
*
|
|
73
|
+
* @param repoRoot - Repository root directory
|
|
74
|
+
* @returns void
|
|
75
|
+
*/
|
|
76
|
+
export function runDocsGenerate(repoRoot) {
|
|
77
|
+
execSync('pnpm turbo docs:generate', {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
stdio: STDIO.INHERIT,
|
|
80
|
+
encoding: 'utf-8',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Detect doc-source changes and regenerate docs if needed.
|
|
85
|
+
* This is the main integration point for wu:done.
|
|
86
|
+
*
|
|
87
|
+
* Call this BEFORE stageAndFormatMetadata() to include doc outputs
|
|
88
|
+
* in the single atomic commit.
|
|
89
|
+
*
|
|
90
|
+
* @param options - Detection and regeneration options
|
|
91
|
+
* @returns Promise<DocsRegenerationResult> - Whether docs changed and were regenerated
|
|
92
|
+
*/
|
|
93
|
+
export async function maybeRegenerateAndStageDocs(options) {
|
|
94
|
+
const { baseBranch, repoRoot } = options;
|
|
95
|
+
// Check if doc-source files changed
|
|
96
|
+
const docsChanged = await hasDocSourceChanges(baseBranch);
|
|
97
|
+
if (!docsChanged) {
|
|
98
|
+
console.log('[wu:done] No doc-source changes detected, skipping docs:generate');
|
|
99
|
+
return { docsChanged: false, regenerated: false };
|
|
100
|
+
}
|
|
101
|
+
console.log('[wu:done] Doc-source changes detected, running turbo docs:generate...');
|
|
102
|
+
// Run turbo docs:generate (Turbo handles caching and dependencies)
|
|
103
|
+
runDocsGenerate(repoRoot);
|
|
104
|
+
// Stage the doc output files
|
|
105
|
+
await stageDocOutputs();
|
|
106
|
+
console.log('[wu:done] Documentation regenerated and staged');
|
|
107
|
+
return { docsChanged: true, regenerated: true };
|
|
108
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs-only detection utilities for wu:done
|
|
3
|
+
*
|
|
4
|
+
* WU-1234 + WU-1255 + WU-1539: Detect docs-only WUs from code_paths.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Detect docs-only WU from code_paths.
|
|
8
|
+
* Returns true if all code_paths are documentation paths only.
|
|
9
|
+
*
|
|
10
|
+
* Docs-only paths: docs/, ai/, .claude/, memory-bank/, README*, CLAUDE*.md
|
|
11
|
+
* NOT docs-only: tools/, scripts/ (these are code, not documentation)
|
|
12
|
+
*
|
|
13
|
+
* WU-1539: Fixed misclassification where tools/ was treated as docs-only
|
|
14
|
+
* but then rejected by validateDocsOnly(). tools/ should skip web tests
|
|
15
|
+
* but NOT be classified as docs-only.
|
|
16
|
+
*
|
|
17
|
+
* @param {string[]|null|undefined} codePaths - Array of file paths from WU YAML
|
|
18
|
+
* @returns {boolean} True if WU is docs-only (all paths are documentation)
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectDocsOnlyByPaths(codePaths: any): boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs-only detection utilities for wu:done
|
|
3
|
+
*
|
|
4
|
+
* WU-1234 + WU-1255 + WU-1539: Detect docs-only WUs from code_paths.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Prefixes for paths that qualify as "docs-only" (no code changes).
|
|
8
|
+
* Unlike SKIP_TESTS_PREFIXES, this excludes tools/ and scripts/ because
|
|
9
|
+
* those contain code files that require full gate validation.
|
|
10
|
+
*
|
|
11
|
+
* WU-1539: Split from shouldSkipWebTests to fix docs-only misclassification.
|
|
12
|
+
* @constant {string[]}
|
|
13
|
+
*/
|
|
14
|
+
const DOCS_ONLY_PREFIXES = Object.freeze(['docs/', 'ai/', '.claude/', 'memory-bank/']);
|
|
15
|
+
/**
|
|
16
|
+
* Root file patterns that qualify as docs-only.
|
|
17
|
+
* @constant {string[]}
|
|
18
|
+
*/
|
|
19
|
+
const DOCS_ONLY_ROOT_FILES = Object.freeze(['readme', 'claude']);
|
|
20
|
+
/**
|
|
21
|
+
* Detect docs-only WU from code_paths.
|
|
22
|
+
* Returns true if all code_paths are documentation paths only.
|
|
23
|
+
*
|
|
24
|
+
* Docs-only paths: docs/, ai/, .claude/, memory-bank/, README*, CLAUDE*.md
|
|
25
|
+
* NOT docs-only: tools/, scripts/ (these are code, not documentation)
|
|
26
|
+
*
|
|
27
|
+
* WU-1539: Fixed misclassification where tools/ was treated as docs-only
|
|
28
|
+
* but then rejected by validateDocsOnly(). tools/ should skip web tests
|
|
29
|
+
* but NOT be classified as docs-only.
|
|
30
|
+
*
|
|
31
|
+
* @param {string[]|null|undefined} codePaths - Array of file paths from WU YAML
|
|
32
|
+
* @returns {boolean} True if WU is docs-only (all paths are documentation)
|
|
33
|
+
*/
|
|
34
|
+
export function detectDocsOnlyByPaths(codePaths) {
|
|
35
|
+
if (!codePaths || !Array.isArray(codePaths) || codePaths.length === 0) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return codePaths.every((filePath) => {
|
|
39
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const path = filePath.trim();
|
|
43
|
+
if (path.length === 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
// Check docs-only prefixes (docs/, ai/, .claude/, memory-bank/)
|
|
47
|
+
for (const prefix of DOCS_ONLY_PREFIXES) {
|
|
48
|
+
if (path.startsWith(prefix)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Check if it's a markdown file (*.md)
|
|
53
|
+
if (path.endsWith('.md')) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Check root file patterns (README*, CLAUDE*.md)
|
|
57
|
+
const lowerPath = path.toLowerCase();
|
|
58
|
+
for (const pattern of DOCS_ONLY_ROOT_FILES) {
|
|
59
|
+
if (lowerPath.startsWith(pattern)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error helpers for wu:done validators
|
|
3
|
+
*
|
|
4
|
+
* WU-1049: Standardize error handling patterns across wu-done validator paths.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create a validation error for wu:done validators.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createValidationError(message: any, details?: {}): import("./error-handler.js").WUError;
|
|
10
|
+
/**
|
|
11
|
+
* Create a file-not-found error for wu:done validators.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createFileNotFoundError(message: any, details?: {}): import("./error-handler.js").WUError;
|
|
14
|
+
/**
|
|
15
|
+
* Create a recovery error for wu:done recovery flows.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createRecoveryError(message: any, details?: {}): import("./error-handler.js").WUError;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error helpers for wu:done validators
|
|
3
|
+
*
|
|
4
|
+
* WU-1049: Standardize error handling patterns across wu-done validator paths.
|
|
5
|
+
*/
|
|
6
|
+
import { createError, ErrorCodes } from './error-handler.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a validation error for wu:done validators.
|
|
9
|
+
*/
|
|
10
|
+
export function createValidationError(message, details = {}) {
|
|
11
|
+
return createError(ErrorCodes.VALIDATION_ERROR, message, details);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a file-not-found error for wu:done validators.
|
|
15
|
+
*/
|
|
16
|
+
export function createFileNotFoundError(message, details = {}) {
|
|
17
|
+
return createError(ErrorCodes.FILE_NOT_FOUND, message, details);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a recovery error for wu:done recovery flows.
|
|
21
|
+
*/
|
|
22
|
+
export function createRecoveryError(message, details = {}) {
|
|
23
|
+
return createError(ErrorCodes.RECOVERY_ERROR, message, details);
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input parsing for wu:done validators.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validates command-line inputs and WU ID format
|
|
6
|
+
* @param {string[]} argv - Process arguments
|
|
7
|
+
* @returns {{ args: object, id: string }} Parsed args and validated WU ID
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateInputs(argv: any): {
|
|
10
|
+
args: import("commander").OptionValues;
|
|
11
|
+
id: any;
|
|
12
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input parsing for wu:done validators.
|
|
3
|
+
*/
|
|
4
|
+
import { parseWUArgs } from './arg-parser.js';
|
|
5
|
+
import { die } from './error-handler.js';
|
|
6
|
+
import { EXIT_CODES, PATTERNS } from './wu-constants.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validates command-line inputs and WU ID format
|
|
9
|
+
* @param {string[]} argv - Process arguments
|
|
10
|
+
* @returns {{ args: object, id: string }} Parsed args and validated WU ID
|
|
11
|
+
*/
|
|
12
|
+
export function validateInputs(argv) {
|
|
13
|
+
const args = parseWUArgs(argv);
|
|
14
|
+
if (args.help || !args.id) {
|
|
15
|
+
console.log('Usage: pnpm wu:done --id WU-334 [OPTIONS]\n\n' +
|
|
16
|
+
'Options:\n' +
|
|
17
|
+
' --worktree <path> Override worktree path (default: worktrees/<lane>-<wu-id>)\n' +
|
|
18
|
+
' --no-auto Skip auto-updating YAML/backlog/status (you staged manually)\n' +
|
|
19
|
+
' --no-remove Skip worktree removal\n' +
|
|
20
|
+
' --no-merge Skip auto-merging lane branch to main\n' +
|
|
21
|
+
' --delete-branch Delete lane branch after merge (both local and remote)\n' +
|
|
22
|
+
' --create-pr Create PR instead of auto-merge (requires gh CLI)\n' +
|
|
23
|
+
' --pr-draft Create PR as draft (use with --create-pr)\n' +
|
|
24
|
+
' --skip-gates Skip gates check (USE WITH EXTREME CAUTION)\n' +
|
|
25
|
+
' --docs-only Run docs-only gates (requires exposure: documentation)\n' +
|
|
26
|
+
' --reason "<text>" Required with --skip-gates or --override-owner\n' +
|
|
27
|
+
' --fix-wu WU-{id} Required with --skip-gates: WU ID that will fix the failures\n' +
|
|
28
|
+
' --allow-todo Allow TODO comments in code (requires justification in WU notes)\n' +
|
|
29
|
+
' --override-owner Override ownership check (requires --reason, audited)\n' +
|
|
30
|
+
' --no-auto-rebase Disable auto-rebase on branch divergence (WU-1303)\n' +
|
|
31
|
+
' --require-agents Block completion if mandatory agents not invoked (WU-1542)\n' +
|
|
32
|
+
' --help, -h Show this help\n\n' +
|
|
33
|
+
'⚠️ SKIP-GATES WARNING:\n' +
|
|
34
|
+
' Only use --skip-gates when:\n' +
|
|
35
|
+
' • Test failures are confirmed pre-existing (not introduced by your WU)\n' +
|
|
36
|
+
' • A separate WU exists to fix those failures (specify with --fix-wu)\n' +
|
|
37
|
+
' • Your WU work is genuinely complete\n\n' +
|
|
38
|
+
' NEVER use --skip-gates for failures introduced by your WU!\n' +
|
|
39
|
+
' All skip-gates events are logged to .beacon/skip-gates-audit.log\n\n' +
|
|
40
|
+
'📝 WU VALIDATOR:\n' +
|
|
41
|
+
' Automatically scans code_paths for:\n' +
|
|
42
|
+
' • TODO/FIXME/HACK/XXX comments (fails validation unless --allow-todo)\n' +
|
|
43
|
+
' • Mock/Stub/Fake classes in production code (warning only)\n' +
|
|
44
|
+
' Use --allow-todo only for legitimate cases with justification in WU notes.\n');
|
|
45
|
+
process.exit(args.help ? EXIT_CODES.SUCCESS : EXIT_CODES.ERROR);
|
|
46
|
+
}
|
|
47
|
+
const id = args.id.toUpperCase();
|
|
48
|
+
if (!PATTERNS.WU_ID.test(id))
|
|
49
|
+
die(`Invalid WU id '${args.id}'. Expected format WU-123`);
|
|
50
|
+
return { args, id };
|
|
51
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata update helpers for wu:done.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generate commit message for WU completion
|
|
6
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
7
|
+
* @param {string} id - WU ID (e.g., "WU-1215")
|
|
8
|
+
* @param {string} title - WU title
|
|
9
|
+
* @param {number} maxLength - Maximum commit header length from commitlint config
|
|
10
|
+
* @returns {string} Formatted commit message
|
|
11
|
+
* @throws {Error} If generated message exceeds maxLength
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateCommitMessage(id: any, title: any, maxLength?: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Validate that required metadata files exist before updating
|
|
16
|
+
* WU-1275: Fail fast before mutations to prevent partial state
|
|
17
|
+
*
|
|
18
|
+
* @param {object} params - Parameters object
|
|
19
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
20
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
21
|
+
* @throws {WUError} If any required file is missing
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateMetadataFilesExist({ statusPath, backlogPath }: {
|
|
24
|
+
statusPath: any;
|
|
25
|
+
backlogPath: any;
|
|
26
|
+
}): void;
|
|
27
|
+
/**
|
|
28
|
+
* Update all metadata files for WU completion
|
|
29
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
30
|
+
* WU-1572: Made async for WUStateStore integration
|
|
31
|
+
* @param {object} params - Parameters object
|
|
32
|
+
* @param {string} params.id - WU ID
|
|
33
|
+
* @param {string} params.title - WU title
|
|
34
|
+
* @param {object} params.doc - WU YAML document to update
|
|
35
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
36
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
37
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
38
|
+
*/
|
|
39
|
+
export declare function updateMetadataFiles({ id, title, doc, wuPath, statusPath, backlogPath }: {
|
|
40
|
+
id: any;
|
|
41
|
+
title: any;
|
|
42
|
+
doc: any;
|
|
43
|
+
wuPath: any;
|
|
44
|
+
statusPath: any;
|
|
45
|
+
backlogPath: any;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Collect metadata updates to a transaction (WU-1369: Atomic pattern)
|
|
49
|
+
*
|
|
50
|
+
* This is the atomic version of updateMetadataFiles.
|
|
51
|
+
* Instead of writing files immediately, it collects all changes
|
|
52
|
+
* into a WUTransaction object for atomic commit.
|
|
53
|
+
*
|
|
54
|
+
* Usage:
|
|
55
|
+
* ```js
|
|
56
|
+
* const tx = new WUTransaction(id);
|
|
57
|
+
* collectMetadataToTransaction({ id, title, doc, wuPath, statusPath, backlogPath, stampPath, transaction: tx });
|
|
58
|
+
* // All changes are now in tx.pendingWrites
|
|
59
|
+
* // Validate, then commit or abort
|
|
60
|
+
* tx.commit();
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @param {object} params - Parameters object
|
|
64
|
+
* @param {string} params.id - WU ID
|
|
65
|
+
* @param {string} params.title - WU title
|
|
66
|
+
* @param {object} params.doc - WU YAML document to update (will be mutated)
|
|
67
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
68
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
69
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
70
|
+
* @param {string} params.stampPath - Path to stamp file
|
|
71
|
+
* @param {WUTransaction} params.transaction - Transaction to add writes to
|
|
72
|
+
*/
|
|
73
|
+
export declare function collectMetadataToTransaction({ id, title, doc, wuPath, statusPath, backlogPath, stampPath, transaction, }: {
|
|
74
|
+
id: any;
|
|
75
|
+
title: any;
|
|
76
|
+
doc: any;
|
|
77
|
+
wuPath: any;
|
|
78
|
+
statusPath: any;
|
|
79
|
+
backlogPath: any;
|
|
80
|
+
stampPath: any;
|
|
81
|
+
transaction: any;
|
|
82
|
+
}): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Stage and format metadata files
|
|
85
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
86
|
+
* @param {object} params - Parameters object
|
|
87
|
+
* @param {string} params.id - WU ID (for error reporting)
|
|
88
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
89
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
90
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
91
|
+
* @param {string} params.stampsDir - Path to stamps directory
|
|
92
|
+
* @throws {Error} If formatting fails
|
|
93
|
+
*/
|
|
94
|
+
export declare function stageAndFormatMetadata({ id, wuPath, statusPath, backlogPath, stampsDir }: {
|
|
95
|
+
id: any;
|
|
96
|
+
wuPath: any;
|
|
97
|
+
statusPath: any;
|
|
98
|
+
backlogPath: any;
|
|
99
|
+
stampsDir: any;
|
|
100
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata update helpers for wu:done.
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { exec as execCallback } from 'node:child_process';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
9
|
+
import { updateStatusRemoveInProgress, addToStatusCompleted } from './wu-status-updater.js';
|
|
10
|
+
import { moveWUToDoneBacklog } from './wu-backlog-updater.js';
|
|
11
|
+
import { createStamp } from './stamp-utils.js';
|
|
12
|
+
import { WU_EVENTS_FILE_NAME } from './wu-state-store.js';
|
|
13
|
+
import { computeWUYAMLContent, computeStatusContent, computeBacklogContent, computeWUEventsContentAfterComplete, computeStampContent, } from './wu-transaction-collectors.js';
|
|
14
|
+
import { DEFAULTS, LOG_PREFIX, EMOJI, PKG_MANAGER, SCRIPTS, PRETTIER_FLAGS, BEACON_PATHS, } from './wu-constants.js';
|
|
15
|
+
import { applyExposureDefaults } from './wu-done-validation.js';
|
|
16
|
+
import { createFileNotFoundError, createValidationError } from './wu-done-errors.js';
|
|
17
|
+
import { writeWU } from './wu-yaml.js';
|
|
18
|
+
const execAsync = promisify(execCallback);
|
|
19
|
+
/**
|
|
20
|
+
* Generate commit message for WU completion
|
|
21
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
22
|
+
* @param {string} id - WU ID (e.g., "WU-1215")
|
|
23
|
+
* @param {string} title - WU title
|
|
24
|
+
* @param {number} maxLength - Maximum commit header length from commitlint config
|
|
25
|
+
* @returns {string} Formatted commit message
|
|
26
|
+
* @throws {Error} If generated message exceeds maxLength
|
|
27
|
+
*/
|
|
28
|
+
export function generateCommitMessage(id, title, maxLength = DEFAULTS.MAX_COMMIT_SUBJECT) {
|
|
29
|
+
const prefix = `wu(${id.toLowerCase()}): done - `;
|
|
30
|
+
const safe = String(title).trim().toLowerCase().replace(/\s+/g, ' ');
|
|
31
|
+
const room = Math.max(0, maxLength - prefix.length);
|
|
32
|
+
const short = safe.length > room ? `${safe.slice(0, room - 1)}…` : safe;
|
|
33
|
+
const msg = `${prefix}${short}`;
|
|
34
|
+
if (msg.length > maxLength) {
|
|
35
|
+
const error = new Error(`Commit message too long (${msg.length}/${maxLength}).\n` +
|
|
36
|
+
`Fix: Shorten WU title\n` +
|
|
37
|
+
`Current title: "${title}" (${title.length} chars)\n` +
|
|
38
|
+
`Suggested max: ~${maxLength - prefix.length} chars`);
|
|
39
|
+
error.code = 'COMMIT_MESSAGE_TOO_LONG';
|
|
40
|
+
error.data = {
|
|
41
|
+
title,
|
|
42
|
+
titleLength: title.length,
|
|
43
|
+
messageLength: msg.length,
|
|
44
|
+
maxLength,
|
|
45
|
+
suggestedMax: maxLength - prefix.length,
|
|
46
|
+
};
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
return msg;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validate that required metadata files exist before updating
|
|
53
|
+
* WU-1275: Fail fast before mutations to prevent partial state
|
|
54
|
+
*
|
|
55
|
+
* @param {object} params - Parameters object
|
|
56
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
57
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
58
|
+
* @throws {WUError} If any required file is missing
|
|
59
|
+
*/
|
|
60
|
+
export function validateMetadataFilesExist({ statusPath, backlogPath }) {
|
|
61
|
+
const missing = [];
|
|
62
|
+
if (!existsSync(statusPath)) {
|
|
63
|
+
missing.push(`Status: ${statusPath}`);
|
|
64
|
+
}
|
|
65
|
+
if (!existsSync(backlogPath)) {
|
|
66
|
+
missing.push(`Backlog: ${backlogPath}`);
|
|
67
|
+
}
|
|
68
|
+
if (missing.length > 0) {
|
|
69
|
+
throw createFileNotFoundError(`Required metadata files missing:\n ${missing.join('\n ')}\n\nCannot complete WU - verify worktree has latest metadata files.`, { missingFiles: missing });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Update all metadata files for WU completion
|
|
74
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
75
|
+
* WU-1572: Made async for WUStateStore integration
|
|
76
|
+
* @param {object} params - Parameters object
|
|
77
|
+
* @param {string} params.id - WU ID
|
|
78
|
+
* @param {string} params.title - WU title
|
|
79
|
+
* @param {object} params.doc - WU YAML document to update
|
|
80
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
81
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
82
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
83
|
+
*/
|
|
84
|
+
export async function updateMetadataFiles({ id, title, doc, wuPath, statusPath, backlogPath }) {
|
|
85
|
+
// WU-1275: Fail fast before any mutations
|
|
86
|
+
validateMetadataFilesExist({ statusPath, backlogPath });
|
|
87
|
+
const exposureUpdate = applyExposureDefaults(doc);
|
|
88
|
+
if (exposureUpdate.applied) {
|
|
89
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} Auto-set exposure to ${exposureUpdate.exposure} for ${id}`);
|
|
90
|
+
}
|
|
91
|
+
// Update WU YAML (mark as done, lock, set completion timestamp)
|
|
92
|
+
doc.status = 'done';
|
|
93
|
+
doc.locked = true;
|
|
94
|
+
doc.completed_at = new Date().toISOString();
|
|
95
|
+
writeWU(wuPath, doc);
|
|
96
|
+
// Update status.md (remove from In Progress, add to Completed)
|
|
97
|
+
updateStatusRemoveInProgress(statusPath, id);
|
|
98
|
+
addToStatusCompleted(statusPath, id, title);
|
|
99
|
+
// Update backlog.md (move to Done section)
|
|
100
|
+
// WU-1572: Now async for state store integration
|
|
101
|
+
await moveWUToDoneBacklog(backlogPath, id, title);
|
|
102
|
+
// Create completion stamp
|
|
103
|
+
createStamp({ id, title });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Collect metadata updates to a transaction (WU-1369: Atomic pattern)
|
|
107
|
+
*
|
|
108
|
+
* This is the atomic version of updateMetadataFiles.
|
|
109
|
+
* Instead of writing files immediately, it collects all changes
|
|
110
|
+
* into a WUTransaction object for atomic commit.
|
|
111
|
+
*
|
|
112
|
+
* Usage:
|
|
113
|
+
* ```js
|
|
114
|
+
* const tx = new WUTransaction(id);
|
|
115
|
+
* collectMetadataToTransaction({ id, title, doc, wuPath, statusPath, backlogPath, stampPath, transaction: tx });
|
|
116
|
+
* // All changes are now in tx.pendingWrites
|
|
117
|
+
* // Validate, then commit or abort
|
|
118
|
+
* tx.commit();
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @param {object} params - Parameters object
|
|
122
|
+
* @param {string} params.id - WU ID
|
|
123
|
+
* @param {string} params.title - WU title
|
|
124
|
+
* @param {object} params.doc - WU YAML document to update (will be mutated)
|
|
125
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
126
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
127
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
128
|
+
* @param {string} params.stampPath - Path to stamp file
|
|
129
|
+
* @param {WUTransaction} params.transaction - Transaction to add writes to
|
|
130
|
+
*/
|
|
131
|
+
// WU-1574: Made async for computeBacklogContent
|
|
132
|
+
export async function collectMetadataToTransaction({ id, title, doc, wuPath, statusPath, backlogPath, stampPath, transaction, }) {
|
|
133
|
+
// WU-1369: Fail fast before any computations
|
|
134
|
+
validateMetadataFilesExist({ statusPath, backlogPath });
|
|
135
|
+
const exposureUpdate = applyExposureDefaults(doc);
|
|
136
|
+
if (exposureUpdate.applied) {
|
|
137
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.INFO} Auto-set exposure to ${exposureUpdate.exposure} for ${id}`);
|
|
138
|
+
}
|
|
139
|
+
// Compute WU YAML content (mutates doc, returns YAML string)
|
|
140
|
+
const wuYAMLContent = computeWUYAMLContent(doc);
|
|
141
|
+
transaction.addWrite(wuPath, wuYAMLContent, 'WU YAML');
|
|
142
|
+
// Compute status.md content
|
|
143
|
+
const statusContent = computeStatusContent(statusPath, id, title);
|
|
144
|
+
transaction.addWrite(statusPath, statusContent, 'status.md');
|
|
145
|
+
// Compute backlog.md content (WU-1574: now async)
|
|
146
|
+
const backlogContent = await computeBacklogContent(backlogPath, id, title);
|
|
147
|
+
transaction.addWrite(backlogPath, backlogContent, 'backlog.md');
|
|
148
|
+
const wuEventsUpdate = await computeWUEventsContentAfterComplete(backlogPath, id);
|
|
149
|
+
if (wuEventsUpdate) {
|
|
150
|
+
transaction.addWrite(wuEventsUpdate.eventsPath, wuEventsUpdate.content, 'wu-events.jsonl');
|
|
151
|
+
}
|
|
152
|
+
// Compute stamp content
|
|
153
|
+
const stampContent = computeStampContent(id, title);
|
|
154
|
+
transaction.addWrite(stampPath, stampContent, 'completion stamp');
|
|
155
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Collected ${transaction.size} metadata updates for atomic commit`);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Stage and format metadata files
|
|
159
|
+
* Extracted from wu-done.mjs (WU-1215 Phase 2 Extraction #1 Helper)
|
|
160
|
+
* @param {object} params - Parameters object
|
|
161
|
+
* @param {string} params.id - WU ID (for error reporting)
|
|
162
|
+
* @param {string} params.wuPath - Path to WU YAML file
|
|
163
|
+
* @param {string} params.statusPath - Path to status.md file
|
|
164
|
+
* @param {string} params.backlogPath - Path to backlog.md file
|
|
165
|
+
* @param {string} params.stampsDir - Path to stamps directory
|
|
166
|
+
* @throws {Error} If formatting fails
|
|
167
|
+
*/
|
|
168
|
+
export async function stageAndFormatMetadata({ id, wuPath, statusPath, backlogPath, stampsDir }) {
|
|
169
|
+
// WU-1235: Use getGitForCwd() to capture current directory (worktree after chdir)
|
|
170
|
+
// The singleton git adapter captures cwd at import time, which is wrong after process.chdir()
|
|
171
|
+
const gitCwd = getGitForCwd();
|
|
172
|
+
// Stage files
|
|
173
|
+
const wuEventsPath = path.join(BEACON_PATHS.STATE_DIR, WU_EVENTS_FILE_NAME);
|
|
174
|
+
const filesToStage = [wuPath, statusPath, backlogPath, stampsDir];
|
|
175
|
+
if (existsSync(wuEventsPath)) {
|
|
176
|
+
filesToStage.push(wuEventsPath);
|
|
177
|
+
}
|
|
178
|
+
await gitCwd.add(filesToStage);
|
|
179
|
+
// Format documentation
|
|
180
|
+
console.log(`${LOG_PREFIX.DONE} Formatting auto-generated documentation...`);
|
|
181
|
+
try {
|
|
182
|
+
const prettierCmd = `${PKG_MANAGER} ${SCRIPTS.PRETTIER} ${PRETTIER_FLAGS.WRITE} "${wuPath}" "${statusPath}" "${backlogPath}"`;
|
|
183
|
+
await execAsync(prettierCmd);
|
|
184
|
+
await gitCwd.add([wuPath, statusPath, backlogPath]);
|
|
185
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Documentation formatted`);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
throw createValidationError(`Failed to format documentation: ${err.message}`, {
|
|
189
|
+
wuId: id,
|
|
190
|
+
error: err.message,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path and workspace detection helpers for wu:done.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Read WU YAML preferring worktree version over main version
|
|
6
|
+
*
|
|
7
|
+
* WU-1584 Fix #4: Added diagnostic logging to confirm which YAML file is being
|
|
8
|
+
* read for code_paths validation. This helps debug issues where worktree YAML
|
|
9
|
+
* differs from main checkout YAML.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} id - WU ID
|
|
12
|
+
* @param {string|null} worktreePath - Worktree path (null if branch-only mode)
|
|
13
|
+
* @param {string} mainWUPath - Path to WU YAML in main checkout
|
|
14
|
+
* @returns {object} Parsed WU document
|
|
15
|
+
*/
|
|
16
|
+
export declare function readWUPreferWorktree(id: any, worktreePath: any, mainWUPath: any): any;
|
|
17
|
+
/**
|
|
18
|
+
* Detect if currently running inside a worktree
|
|
19
|
+
* Checks for .git file (not directory) which indicates a worktree
|
|
20
|
+
* @returns {string|null} Current directory path if inside worktree, null otherwise
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectCurrentWorktree(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve worktree path from WU YAML
|
|
25
|
+
* Originally implemented in WU-1226, extracted to validators module in WU-1215
|
|
26
|
+
* Priority:
|
|
27
|
+
* 1. Read worktree_path field (set at claim time, immune to lane field changes)
|
|
28
|
+
* 2. Fall back to calculating from lane field (for old WUs without worktree_path)
|
|
29
|
+
* 3. Use git worktree list to find actual path (defensive fallback)
|
|
30
|
+
* @param {object} doc - WU YAML document
|
|
31
|
+
* @returns {Promise<string|null>} - Worktree path or null if not found
|
|
32
|
+
*/
|
|
33
|
+
export declare function defaultWorktreeFrom(doc: any): Promise<any>;
|
|
34
|
+
/**
|
|
35
|
+
* Detect workspace mode from WU YAML
|
|
36
|
+
* @param {object} doc - WU YAML document
|
|
37
|
+
* @returns {'worktree' | 'branch-only'}
|
|
38
|
+
*/
|
|
39
|
+
export declare function detectWorkspaceMode(doc: any): string;
|
|
40
|
+
/**
|
|
41
|
+
* Calculate lane branch name from WU YAML
|
|
42
|
+
* @param {object} doc - WU YAML document
|
|
43
|
+
* @returns {string|null} Lane branch name (e.g., lane/operations-tooling/wu-1215)
|
|
44
|
+
*/
|
|
45
|
+
export declare function defaultBranchFrom(doc: any): string;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a branch exists
|
|
48
|
+
* @param {string} branch - Branch name to check
|
|
49
|
+
* @returns {Promise<boolean>} True if branch exists
|
|
50
|
+
*/
|
|
51
|
+
export declare function branchExists(branch: any): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Detect workspace mode and calculate all relevant paths
|
|
54
|
+
* @param {string} id - WU ID
|
|
55
|
+
* @param {object} args - Parsed command-line arguments
|
|
56
|
+
* @returns {Promise<object>} Object containing paths, mode info, and WU document
|
|
57
|
+
*/
|
|
58
|
+
export declare function detectModeAndPaths(id: any, args: any): Promise<{
|
|
59
|
+
WU_PATH: string;
|
|
60
|
+
STATUS_PATH: string;
|
|
61
|
+
BACKLOG_PATH: string;
|
|
62
|
+
STAMPS_DIR: string;
|
|
63
|
+
docMain: any;
|
|
64
|
+
workspaceMode: string;
|
|
65
|
+
isBranchOnly: boolean;
|
|
66
|
+
derivedWorktree: any;
|
|
67
|
+
docForValidation: any;
|
|
68
|
+
isDocsOnly: boolean;
|
|
69
|
+
}>;
|