@lumenflow/core 2.2.2 → 2.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/active-wu-detector.d.ts +1 -1
- package/dist/active-wu-detector.js +1 -1
- package/dist/arg-parser.js +51 -18
- package/dist/backlog-generator.d.ts +4 -4
- package/dist/backlog-generator.js +4 -4
- package/dist/backlog-sync-validator.js +1 -1
- package/dist/cleanup-lock.d.ts +9 -2
- package/dist/cleanup-lock.js +17 -7
- package/dist/code-path-validator.d.ts +3 -3
- package/dist/code-path-validator.js +3 -3
- package/dist/compliance-parser.d.ts +1 -1
- package/dist/compliance-parser.js +1 -1
- package/dist/constants/backlog-patterns.d.ts +1 -1
- package/dist/constants/backlog-patterns.js +1 -1
- package/dist/constants/dora-constants.d.ts +1 -1
- package/dist/constants/dora-constants.js +1 -1
- package/dist/constants/gate-constants.d.ts +1 -1
- package/dist/constants/gate-constants.js +1 -1
- package/dist/constants/linter-constants.d.ts +1 -1
- package/dist/constants/linter-constants.js +1 -1
- package/dist/constants/tokenizer-constants.d.ts +1 -1
- package/dist/constants/tokenizer-constants.js +1 -1
- package/dist/context/location-resolver.js +2 -1
- package/dist/context-validation-integration.d.ts +1 -0
- package/dist/core/scope-checker.d.ts +3 -3
- package/dist/core/scope-checker.js +3 -3
- package/dist/core/tool-runner.d.ts +5 -5
- package/dist/core/tool-runner.js +5 -5
- package/dist/core/tool.constants.d.ts +1 -1
- package/dist/core/tool.constants.js +1 -1
- package/dist/core/tool.schemas.d.ts +2 -2
- package/dist/core/tool.schemas.js +1 -1
- package/dist/core/worktree-guard.d.ts +1 -1
- package/dist/core/worktree-guard.js +1 -1
- package/dist/coverage-gate.d.ts +12 -3
- package/dist/coverage-gate.js +15 -8
- package/dist/date-utils.d.ts +4 -4
- package/dist/date-utils.js +4 -4
- package/dist/dependency-graph.d.ts +6 -0
- package/dist/dependency-graph.js +43 -2
- package/dist/dependency-guard.d.ts +2 -2
- package/dist/dependency-guard.js +3 -3
- package/dist/dependency-validator.d.ts +4 -4
- package/dist/dependency-validator.js +4 -7
- package/dist/domain/orchestration.constants.d.ts +31 -10
- package/dist/domain/orchestration.constants.js +45 -16
- package/dist/domain/orchestration.schemas.d.ts +54 -28
- package/dist/domain/orchestration.schemas.js +2 -2
- package/dist/domain/orchestration.types.d.ts +2 -2
- package/dist/domain/orchestration.types.js +2 -2
- package/dist/error-handler.d.ts +10 -10
- package/dist/error-handler.js +10 -10
- package/dist/file-classifiers.d.ts +6 -6
- package/dist/file-classifiers.js +6 -6
- package/dist/gates-config.d.ts +74 -0
- package/dist/gates-config.js +209 -2
- package/dist/git-adapter.d.ts +11 -11
- package/dist/git-adapter.js +11 -11
- package/dist/git-context-extractor.d.ts +112 -0
- package/dist/git-context-extractor.js +559 -0
- package/dist/hardcoded-strings.d.ts +1 -1
- package/dist/hardcoded-strings.js +1 -1
- package/dist/incremental-lint.d.ts +1 -1
- package/dist/incremental-lint.js +2 -2
- package/dist/incremental-test.d.ts +1 -1
- package/dist/incremental-test.js +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +25 -0
- package/dist/invariants/check-automated-tests.d.ts +2 -2
- package/dist/invariants/check-automated-tests.js +3 -3
- package/dist/lane-checker.d.ts +28 -7
- package/dist/lane-checker.js +316 -159
- package/dist/lane-suggest-prompt.d.ts +108 -0
- package/dist/lane-suggest-prompt.js +359 -0
- package/dist/lane-validator.d.ts +3 -3
- package/dist/lane-validator.js +3 -3
- package/dist/logs-lib.d.ts +1 -1
- package/dist/logs-lib.js +1 -1
- package/dist/lumenflow-config-schema.d.ts +162 -0
- package/dist/lumenflow-config-schema.js +180 -0
- package/dist/manual-test-validator.d.ts +2 -2
- package/dist/manual-test-validator.js +3 -3
- package/dist/merge-lock.d.ts +8 -1
- package/dist/merge-lock.js +16 -7
- package/dist/micro-worktree.d.ts +81 -13
- package/dist/micro-worktree.js +98 -17
- package/dist/migration-deployer.d.ts +1 -1
- package/dist/migration-deployer.js +1 -1
- package/dist/orchestration-advisory-loader.d.ts +2 -2
- package/dist/orchestration-advisory-loader.js +10 -6
- package/dist/orchestration-advisory.d.ts +3 -3
- package/dist/orchestration-advisory.js +4 -4
- package/dist/orchestration-di.d.ts +4 -4
- package/dist/orchestration-di.js +4 -4
- package/dist/orchestration-rules.d.ts +4 -4
- package/dist/orchestration-rules.js +18 -10
- package/dist/orphan-detector.d.ts +3 -3
- package/dist/orphan-detector.js +3 -3
- package/dist/patrol-loop.d.ts +170 -0
- package/dist/patrol-loop.js +186 -0
- package/dist/process-detector.d.ts +5 -5
- package/dist/process-detector.js +5 -5
- package/dist/rebase-artifact-cleanup.d.ts +3 -3
- package/dist/rebase-artifact-cleanup.js +3 -3
- package/dist/resolve-policy.d.ts +195 -0
- package/dist/resolve-policy.js +203 -0
- package/dist/risk-detector.d.ts +2 -2
- package/dist/risk-detector.js +2 -2
- package/dist/rollback-utils.d.ts +1 -1
- package/dist/rollback-utils.js +1 -1
- package/dist/section-headings.d.ts +1 -1
- package/dist/section-headings.js +1 -1
- package/dist/spawn-escalation.d.ts +4 -4
- package/dist/spawn-escalation.js +3 -3
- package/dist/spawn-monitor.d.ts +4 -4
- package/dist/spawn-monitor.js +4 -4
- package/dist/spawn-recovery.d.ts +3 -3
- package/dist/spawn-recovery.js +3 -3
- package/dist/spawn-registry-schema.d.ts +2 -2
- package/dist/spawn-registry-schema.js +2 -2
- package/dist/spawn-registry-store.d.ts +2 -2
- package/dist/spawn-registry-store.js +2 -2
- package/dist/spawn-strategy.d.ts +17 -11
- package/dist/spawn-strategy.js +47 -44
- package/dist/spawn-tree.d.ts +3 -3
- package/dist/spawn-tree.js +3 -3
- package/dist/state-cleanup-core.d.ts +205 -0
- package/dist/state-cleanup-core.js +240 -0
- package/dist/state-doctor-core.d.ts +168 -0
- package/dist/state-doctor-core.js +251 -0
- package/dist/stream-error-handler.d.ts +67 -0
- package/dist/stream-error-handler.js +94 -0
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.js +1 -1
- package/dist/template-loader.d.ts +162 -0
- package/dist/template-loader.js +372 -0
- package/dist/test-baseline.d.ts +176 -0
- package/dist/test-baseline.js +282 -0
- package/dist/usecases/get-suggestions.usecase.d.ts +1 -1
- package/dist/validation/command-registry.js +37 -0
- package/dist/validators/backlog-sync.js +4 -2
- package/dist/worktree-scanner.d.ts +1 -1
- package/dist/worktree-scanner.js +1 -1
- package/dist/worktree-symlink.d.ts +3 -3
- package/dist/worktree-symlink.js +3 -3
- package/dist/wu-backlog-updater.d.ts +1 -1
- package/dist/wu-backlog-updater.js +1 -1
- package/dist/wu-claim-helpers.d.ts +1 -1
- package/dist/wu-claim-helpers.js +1 -1
- package/dist/wu-claim-resume.d.ts +1 -1
- package/dist/wu-claim-resume.js +1 -1
- package/dist/wu-consistency-checker.d.ts +1 -1
- package/dist/wu-consistency-checker.js +17 -11
- package/dist/wu-constants.d.ts +73 -21
- package/dist/wu-constants.js +65 -22
- package/dist/wu-done-branch-only.d.ts +1 -1
- package/dist/wu-done-branch-only.js +1 -1
- package/dist/wu-done-docs-generate.d.ts +1 -1
- package/dist/wu-done-docs-generate.js +1 -1
- package/dist/wu-done-messages.d.ts +2 -2
- package/dist/wu-done-messages.js +2 -2
- package/dist/wu-done-metadata.d.ts +3 -3
- package/dist/wu-done-metadata.js +3 -3
- package/dist/wu-done-pr.d.ts +1 -1
- package/dist/wu-done-pr.js +4 -2
- package/dist/wu-done-preflight.d.ts +8 -0
- package/dist/wu-done-preflight.js +18 -2
- package/dist/wu-done-ui.d.ts +3 -3
- package/dist/wu-done-ui.js +3 -3
- package/dist/wu-done-validation.d.ts +30 -0
- package/dist/wu-done-validation.js +106 -1
- package/dist/wu-done-worktree.d.ts +1 -1
- package/dist/wu-done-worktree.js +11 -1
- package/dist/wu-events-cleanup.d.ts +148 -0
- package/dist/wu-events-cleanup.js +401 -0
- package/dist/wu-helpers.d.ts +2 -2
- package/dist/wu-helpers.js +2 -2
- package/dist/wu-id-generator.d.ts +58 -0
- package/dist/wu-id-generator.js +103 -0
- package/dist/wu-lint.js +1 -1
- package/dist/wu-preflight-validators.d.ts +13 -1
- package/dist/wu-preflight-validators.js +56 -1
- package/dist/wu-recovery.d.ts +2 -2
- package/dist/wu-recovery.js +4 -4
- package/dist/wu-repair-core.d.ts +5 -5
- package/dist/wu-repair-core.js +6 -6
- package/dist/wu-schema-normalization.d.ts +1 -1
- package/dist/wu-schema-normalization.js +1 -1
- package/dist/wu-schema.d.ts +7 -7
- package/dist/wu-schema.js +8 -8
- package/dist/wu-spawn-context.d.ts +87 -0
- package/dist/wu-spawn-context.js +175 -0
- package/dist/wu-spawn-helpers.d.ts +1 -1
- package/dist/wu-spawn-helpers.js +1 -1
- package/dist/wu-spawn.d.ts +177 -4
- package/dist/wu-spawn.js +694 -72
- package/dist/wu-state-schema.d.ts +1 -1
- package/dist/wu-state-schema.js +1 -1
- package/dist/wu-state-store.d.ts +3 -3
- package/dist/wu-state-store.js +3 -3
- package/dist/wu-status-transition.d.ts +1 -1
- package/dist/wu-status-transition.js +1 -1
- package/dist/wu-status-updater.d.ts +3 -3
- package/dist/wu-status-updater.js +3 -3
- package/dist/wu-validation-constants.d.ts +2 -2
- package/dist/wu-validation-constants.js +2 -2
- package/dist/wu-validation.d.ts +3 -3
- package/dist/wu-validation.js +3 -3
- package/dist/wu-yaml-fixer.d.ts +2 -2
- package/dist/wu-yaml-fixer.js +3 -3
- package/dist/wu-yaml.d.ts +23 -0
- package/dist/wu-yaml.js +76 -2
- package/package.json +5 -2
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Baseline - Test Ratchet Pattern (WU-1253)
|
|
3
|
+
*
|
|
4
|
+
* Implements a "ratchet" pattern for test failures:
|
|
5
|
+
* - Track known failures in a baseline file (.lumenflow/test-baseline.json)
|
|
6
|
+
* - Block NEW failures (not in baseline)
|
|
7
|
+
* - Allow pre-existing failures with warning
|
|
8
|
+
* - Auto-update baseline when tests are fixed (ratchet forward)
|
|
9
|
+
*
|
|
10
|
+
* This enables agents to work on WUs without being blocked by unrelated
|
|
11
|
+
* test failures, while still preventing introduction of NEW failures.
|
|
12
|
+
*
|
|
13
|
+
* @see https://lumenflow.dev/reference/test-ratchet/
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { parseISO, isValid } from 'date-fns';
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Constants
|
|
19
|
+
// ============================================================================
|
|
20
|
+
/** Default path for the test baseline file */
|
|
21
|
+
export const DEFAULT_BASELINE_PATH = '.lumenflow/test-baseline.json';
|
|
22
|
+
/** Environment variable to override baseline path */
|
|
23
|
+
export const BASELINE_PATH_ENV = 'LUMENFLOW_TEST_BASELINE';
|
|
24
|
+
/** Current schema version */
|
|
25
|
+
export const BASELINE_VERSION = 1;
|
|
26
|
+
/**
|
|
27
|
+
* Zod schema for ISO8601 datetime strings.
|
|
28
|
+
* Uses date-fns (well-maintained library) for validation instead of regex.
|
|
29
|
+
*/
|
|
30
|
+
const isoDateTimeString = z.string().refine((val) => {
|
|
31
|
+
const parsed = parseISO(val);
|
|
32
|
+
return isValid(parsed);
|
|
33
|
+
}, { message: 'Invalid ISO8601 datetime string' });
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Schema Definitions
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Schema for a known test failure entry
|
|
39
|
+
*/
|
|
40
|
+
export const KnownFailureSchema = z.object({
|
|
41
|
+
/** Name of the failing test (describe > it format) */
|
|
42
|
+
test_name: z.string().min(1),
|
|
43
|
+
/** Path to the test file */
|
|
44
|
+
file_path: z.string().min(1),
|
|
45
|
+
/** Why this failure is in the baseline */
|
|
46
|
+
failure_reason: z.string().min(1),
|
|
47
|
+
/** When this failure was added to baseline */
|
|
48
|
+
added_at: isoDateTimeString,
|
|
49
|
+
/** Which WU added this to baseline */
|
|
50
|
+
added_by_wu: z.string().regex(/^WU-\d+$/),
|
|
51
|
+
/** WU expected to fix this failure (optional) */
|
|
52
|
+
expected_fix_wu: z
|
|
53
|
+
.string()
|
|
54
|
+
.regex(/^WU-\d+$/)
|
|
55
|
+
.optional(),
|
|
56
|
+
/** Optional reason for skipping this test */
|
|
57
|
+
skip_reason: z.string().optional(),
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Schema for baseline statistics
|
|
61
|
+
*/
|
|
62
|
+
export const BaselineStatsSchema = z.object({
|
|
63
|
+
/** Total number of known failures */
|
|
64
|
+
total_known_failures: z.number().int().min(0),
|
|
65
|
+
/** Last time the baseline ratcheted forward (tests fixed) */
|
|
66
|
+
last_ratchet_forward: isoDateTimeString.optional(),
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Schema for the complete test baseline file
|
|
70
|
+
*/
|
|
71
|
+
export const TestBaselineSchema = z.object({
|
|
72
|
+
/** Schema version for future migrations */
|
|
73
|
+
version: z.literal(BASELINE_VERSION),
|
|
74
|
+
/** When the baseline was last updated */
|
|
75
|
+
updated_at: isoDateTimeString,
|
|
76
|
+
/** Which WU last updated the baseline */
|
|
77
|
+
updated_by: z.string().regex(/^WU-\d+$/),
|
|
78
|
+
/** List of known test failures */
|
|
79
|
+
known_failures: z.array(KnownFailureSchema),
|
|
80
|
+
/** Baseline statistics */
|
|
81
|
+
stats: BaselineStatsSchema,
|
|
82
|
+
});
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Core Functions
|
|
85
|
+
// ============================================================================
|
|
86
|
+
/**
|
|
87
|
+
* Parse a test baseline JSON string
|
|
88
|
+
*
|
|
89
|
+
* @param json - JSON string content of baseline file
|
|
90
|
+
* @returns Parse result with baseline data or error
|
|
91
|
+
*/
|
|
92
|
+
export function parseTestBaseline(json) {
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = JSON.parse(json);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
error: `Invalid JSON: ${e instanceof Error ? e.message : 'Unknown error'}`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const result = TestBaselineSchema.safeParse(parsed);
|
|
104
|
+
if (!result.success) {
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: `Schema validation failed: ${result.error.message}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { success: true, data: result.data };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a new test baseline
|
|
114
|
+
*
|
|
115
|
+
* @param wuId - WU creating the baseline
|
|
116
|
+
* @param initialFailures - Optional initial failures to add
|
|
117
|
+
* @returns New test baseline
|
|
118
|
+
*/
|
|
119
|
+
export function createTestBaseline(wuId, initialFailures) {
|
|
120
|
+
const now = new Date().toISOString();
|
|
121
|
+
const knownFailures = (initialFailures ?? []).map((f) => ({
|
|
122
|
+
test_name: f.test_name,
|
|
123
|
+
file_path: f.file_path,
|
|
124
|
+
failure_reason: f.failure_reason,
|
|
125
|
+
added_at: now,
|
|
126
|
+
added_by_wu: wuId,
|
|
127
|
+
expected_fix_wu: f.expected_fix_wu,
|
|
128
|
+
}));
|
|
129
|
+
return {
|
|
130
|
+
version: BASELINE_VERSION,
|
|
131
|
+
updated_at: now,
|
|
132
|
+
updated_by: wuId,
|
|
133
|
+
known_failures: knownFailures,
|
|
134
|
+
stats: {
|
|
135
|
+
total_known_failures: knownFailures.length,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Compare current test results against the baseline
|
|
141
|
+
*
|
|
142
|
+
* This is the core ratchet logic:
|
|
143
|
+
* - NEW failures (not in baseline) block the gate
|
|
144
|
+
* - Pre-existing failures (in baseline) show warning
|
|
145
|
+
* - Fixed tests (in baseline but now passing) trigger ratchet forward
|
|
146
|
+
*
|
|
147
|
+
* @param baseline - The test baseline
|
|
148
|
+
* @param currentFailures - Current test failures from test run
|
|
149
|
+
* @returns Comparison result
|
|
150
|
+
*/
|
|
151
|
+
export function compareTestResults(baseline, currentFailures) {
|
|
152
|
+
const failingTests = currentFailures.filter((t) => !t.passed);
|
|
153
|
+
// Build lookup sets for efficient comparison
|
|
154
|
+
const baselineTestNames = new Set(baseline.known_failures.map((f) => f.test_name));
|
|
155
|
+
const currentFailingNames = new Set(failingTests.map((f) => f.test_name));
|
|
156
|
+
// Find NEW failures (in current failures, NOT in baseline)
|
|
157
|
+
const newFailures = failingTests.filter((f) => !baselineTestNames.has(f.test_name));
|
|
158
|
+
// Find pre-existing failures (in current failures AND in baseline)
|
|
159
|
+
const preExistingFailures = baseline.known_failures.filter((f) => currentFailingNames.has(f.test_name));
|
|
160
|
+
// Find fixed tests (in baseline but NOT in current failures)
|
|
161
|
+
const fixedTests = baseline.known_failures.filter((f) => !currentFailingNames.has(f.test_name));
|
|
162
|
+
return {
|
|
163
|
+
newFailures,
|
|
164
|
+
preExistingFailures,
|
|
165
|
+
fixedTests,
|
|
166
|
+
shouldBlock: newFailures.length > 0,
|
|
167
|
+
hasWarnings: preExistingFailures.length > 0,
|
|
168
|
+
shouldRatchetForward: fixedTests.length > 0,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Update the baseline (ratchet forward or add new known failures)
|
|
173
|
+
*
|
|
174
|
+
* @param baseline - Current baseline
|
|
175
|
+
* @param wuId - WU making the update
|
|
176
|
+
* @param options - Update options
|
|
177
|
+
* @returns Updated baseline (immutable)
|
|
178
|
+
*/
|
|
179
|
+
export function updateBaseline(baseline, wuId, options) {
|
|
180
|
+
const now = new Date().toISOString();
|
|
181
|
+
const { fixedTests = [], newKnownFailures = [] } = options;
|
|
182
|
+
// Remove fixed tests (ratchet forward)
|
|
183
|
+
const fixedTestSet = new Set(fixedTests);
|
|
184
|
+
let knownFailures = baseline.known_failures.filter((f) => !fixedTestSet.has(f.test_name));
|
|
185
|
+
// Add new known failures
|
|
186
|
+
const newEntries = newKnownFailures.map((f) => ({
|
|
187
|
+
test_name: f.test_name,
|
|
188
|
+
file_path: f.file_path,
|
|
189
|
+
failure_reason: f.failure_reason,
|
|
190
|
+
added_at: now,
|
|
191
|
+
added_by_wu: wuId,
|
|
192
|
+
expected_fix_wu: f.expected_fix_wu,
|
|
193
|
+
}));
|
|
194
|
+
knownFailures = [...knownFailures, ...newEntries];
|
|
195
|
+
const stats = {
|
|
196
|
+
total_known_failures: knownFailures.length,
|
|
197
|
+
};
|
|
198
|
+
// Record ratchet forward if we removed tests
|
|
199
|
+
if (fixedTests.length > 0) {
|
|
200
|
+
stats.last_ratchet_forward = now;
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
version: BASELINE_VERSION,
|
|
204
|
+
updated_at: now,
|
|
205
|
+
updated_by: wuId,
|
|
206
|
+
known_failures: knownFailures,
|
|
207
|
+
stats,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// Formatting Functions
|
|
212
|
+
// ============================================================================
|
|
213
|
+
/**
|
|
214
|
+
* Format a warning message for pre-existing failures
|
|
215
|
+
*
|
|
216
|
+
* @param preExisting - Pre-existing failures from baseline
|
|
217
|
+
* @returns Formatted warning string
|
|
218
|
+
*/
|
|
219
|
+
export function formatBaselineWarning(preExisting) {
|
|
220
|
+
const lines = [
|
|
221
|
+
'',
|
|
222
|
+
'='.repeat(70),
|
|
223
|
+
' Pre-existing test failures (from baseline)',
|
|
224
|
+
'='.repeat(70),
|
|
225
|
+
'',
|
|
226
|
+
` These failures are tracked in .lumenflow/test-baseline.json`,
|
|
227
|
+
' They do not block your WU, but should be fixed eventually.',
|
|
228
|
+
'',
|
|
229
|
+
];
|
|
230
|
+
for (const failure of preExisting) {
|
|
231
|
+
lines.push(` - ${failure.test_name}`);
|
|
232
|
+
lines.push(` File: ${failure.file_path}`);
|
|
233
|
+
lines.push(` Reason: ${failure.failure_reason}`);
|
|
234
|
+
if (failure.expected_fix_wu) {
|
|
235
|
+
lines.push(` Expected fix: ${failure.expected_fix_wu}`);
|
|
236
|
+
}
|
|
237
|
+
lines.push('');
|
|
238
|
+
}
|
|
239
|
+
lines.push('='.repeat(70));
|
|
240
|
+
return lines.join('\n');
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Format an error message for new failures
|
|
244
|
+
*
|
|
245
|
+
* @param newFailures - New test failures
|
|
246
|
+
* @returns Formatted error string
|
|
247
|
+
*/
|
|
248
|
+
export function formatNewFailureError(newFailures) {
|
|
249
|
+
const lines = [
|
|
250
|
+
'',
|
|
251
|
+
'='.repeat(70),
|
|
252
|
+
' NEW test failure(s) detected!',
|
|
253
|
+
'='.repeat(70),
|
|
254
|
+
'',
|
|
255
|
+
' The following tests failed and are NOT in the baseline.',
|
|
256
|
+
' This blocks your WU from completion.',
|
|
257
|
+
'',
|
|
258
|
+
' Options:',
|
|
259
|
+
' 1. Fix the test or add to baseline with:',
|
|
260
|
+
' pnpm baseline:add --test "<test_name>" --reason "<why>" --fix-wu WU-XXXX',
|
|
261
|
+
' 2. If this is a pre-existing failure on main, it should be in the baseline.',
|
|
262
|
+
'',
|
|
263
|
+
];
|
|
264
|
+
for (const failure of newFailures) {
|
|
265
|
+
lines.push(` - ${failure.test_name}`);
|
|
266
|
+
lines.push(` File: ${failure.file_path}`);
|
|
267
|
+
if (failure.error_message) {
|
|
268
|
+
lines.push(` Error: ${failure.error_message.substring(0, 100)}...`);
|
|
269
|
+
}
|
|
270
|
+
lines.push('');
|
|
271
|
+
}
|
|
272
|
+
lines.push('='.repeat(70));
|
|
273
|
+
return lines.join('\n');
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get the path to the test baseline file
|
|
277
|
+
*
|
|
278
|
+
* @returns Baseline file path
|
|
279
|
+
*/
|
|
280
|
+
export function getBaselineFilePath() {
|
|
281
|
+
return process.env[BASELINE_PATH_ENV] ?? DEFAULT_BASELINE_PATH;
|
|
282
|
+
}
|
|
@@ -29,7 +29,7 @@ export interface GetSuggestionsOptions {
|
|
|
29
29
|
* When provided, suggestions for high-impact WUs are ranked higher
|
|
30
30
|
* within the same priority level.
|
|
31
31
|
*
|
|
32
|
-
* @see flow-bottlenecks.
|
|
32
|
+
* @see flow-bottlenecks.ts for score calculation
|
|
33
33
|
*/
|
|
34
34
|
bottleneckScores?: BottleneckScores;
|
|
35
35
|
}
|
|
@@ -92,8 +92,44 @@ const wuClaim = {
|
|
|
92
92
|
];
|
|
93
93
|
},
|
|
94
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* Predicate: Check if worktree has no uncommitted changes.
|
|
97
|
+
* For wu:prep running from worktree itself.
|
|
98
|
+
*/
|
|
99
|
+
const gitCleanPredicate = {
|
|
100
|
+
id: 'git-clean',
|
|
101
|
+
description: 'Worktree must not have uncommitted changes',
|
|
102
|
+
severity: SEVERITY.ERROR,
|
|
103
|
+
check: (context) => !context.git.isDirty,
|
|
104
|
+
getFixMessage: () => 'Commit or stash changes in worktree before running wu:prep',
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Command definition for wu:prep (WU-1223).
|
|
108
|
+
*
|
|
109
|
+
* Runs gates and generates docs in the worktree, then prints copy-paste
|
|
110
|
+
* instruction to run wu:done from main checkout for merge/cleanup.
|
|
111
|
+
*/
|
|
112
|
+
const wuPrep = {
|
|
113
|
+
name: COMMANDS.WU_PREP,
|
|
114
|
+
description: 'Run gates + docs in worktree, prepare for wu:done',
|
|
115
|
+
requiredLocation: LOCATION_TYPES.WORKTREE,
|
|
116
|
+
requiredWuStatus: WU_STATUS.IN_PROGRESS,
|
|
117
|
+
predicates: [gitCleanPredicate, stateConsistentPredicate],
|
|
118
|
+
getNextSteps: (context) => {
|
|
119
|
+
const mainPath = context.location.mainCheckout || '/path/to/main';
|
|
120
|
+
const wuId = context.wu?.id || 'WU-XXX';
|
|
121
|
+
return [
|
|
122
|
+
`1. Gates and docs generated in worktree`,
|
|
123
|
+
`2. Return to main checkout and complete:`,
|
|
124
|
+
` cd ${mainPath} && pnpm wu:done --id ${wuId}`,
|
|
125
|
+
];
|
|
126
|
+
},
|
|
127
|
+
};
|
|
95
128
|
/**
|
|
96
129
|
* Command definition for wu:done.
|
|
130
|
+
*
|
|
131
|
+
* WU-1223: Now requires main checkout (merge + cleanup only).
|
|
132
|
+
* Use wu:prep from worktree for gates and docs generation.
|
|
97
133
|
*/
|
|
98
134
|
const wuDone = {
|
|
99
135
|
name: COMMANDS.WU_DONE,
|
|
@@ -161,6 +197,7 @@ const wuRecover = {
|
|
|
161
197
|
export const COMMAND_REGISTRY = new Map([
|
|
162
198
|
[COMMANDS.WU_CREATE, wuCreate],
|
|
163
199
|
[COMMANDS.WU_CLAIM, wuClaim],
|
|
200
|
+
[COMMANDS.WU_PREP, wuPrep],
|
|
164
201
|
[COMMANDS.WU_DONE, wuDone],
|
|
165
202
|
[COMMANDS.WU_BLOCK, wuBlock],
|
|
166
203
|
[COMMANDS.WU_UNBLOCK, wuUnblock],
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { FILE_SYSTEM } from '../wu-constants.js';
|
|
8
|
+
import { createWuPaths } from '../wu-paths.js';
|
|
8
9
|
function extractWUIDsFromBacklog(content) {
|
|
9
10
|
const wuIds = [];
|
|
10
11
|
const pattern = /WU-\d+/gi;
|
|
@@ -29,8 +30,9 @@ export async function validateBacklogSync(options = {}) {
|
|
|
29
30
|
const { cwd = process.cwd() } = options;
|
|
30
31
|
const errors = [];
|
|
31
32
|
const warnings = [];
|
|
32
|
-
const
|
|
33
|
-
const
|
|
33
|
+
const paths = createWuPaths({ projectRoot: cwd });
|
|
34
|
+
const backlogPath = path.join(cwd, paths.BACKLOG());
|
|
35
|
+
const wuDir = path.join(cwd, paths.WU_DIR());
|
|
34
36
|
if (!existsSync(backlogPath)) {
|
|
35
37
|
errors.push(`Backlog file not found: ${backlogPath}`);
|
|
36
38
|
return { valid: false, errors, warnings, wuCount: 0, backlogCount: 0 };
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - Reports last activity timestamp
|
|
11
11
|
* - Identifies potentially abandoned WUs
|
|
12
12
|
*
|
|
13
|
-
* @see {@link
|
|
13
|
+
* @see {@link packages/@lumenflow/cli/src/lib/__tests__/worktree-scanner.test.ts} - Tests
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* @typedef {object} WorktreeInfo
|
package/dist/worktree-scanner.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - Reports last activity timestamp
|
|
11
11
|
* - Identifies potentially abandoned WUs
|
|
12
12
|
*
|
|
13
|
-
* @see {@link
|
|
13
|
+
* @see {@link packages/@lumenflow/cli/src/lib/__tests__/worktree-scanner.test.ts} - Tests
|
|
14
14
|
*/
|
|
15
15
|
import { exec } from 'node:child_process';
|
|
16
16
|
import { promisify } from 'node:util';
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* auto-create the node_modules symlink pointing to the main repo's
|
|
11
11
|
* node_modules directory, including nested package node_modules.
|
|
12
12
|
*
|
|
13
|
-
* @module tools/lib/worktree-symlink.
|
|
13
|
+
* @module tools/lib/worktree-symlink.ts
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* List of nested package/app paths that have their own node_modules
|
|
@@ -55,7 +55,7 @@ export declare function hasWorktreePathSymlinks(nodeModulesPath: any): {
|
|
|
55
55
|
* @returns {{created: boolean, skipped: boolean, refused?: boolean, reason?: string, error?: Error}}
|
|
56
56
|
*
|
|
57
57
|
* @example
|
|
58
|
-
* // In wu-claim.
|
|
58
|
+
* // In wu-claim.ts after worktree creation:
|
|
59
59
|
* symlinkNodeModules('/path/to/worktrees/operations-tooling-wu-1443');
|
|
60
60
|
*/
|
|
61
61
|
export declare function symlinkNodeModules(worktreePath: any, logger?: Console, mainRepoPath?: any): {
|
|
@@ -90,7 +90,7 @@ export declare function symlinkNodeModules(worktreePath: any, logger?: Console,
|
|
|
90
90
|
* @returns {{created: number, skipped: number, errors: Error[]}}
|
|
91
91
|
*
|
|
92
92
|
* @example
|
|
93
|
-
* // In wu-claim.
|
|
93
|
+
* // In wu-claim.ts after worktree creation:
|
|
94
94
|
* symlinkNestedNodeModules(
|
|
95
95
|
* '/path/to/worktrees/operations-tooling-wu-1579',
|
|
96
96
|
* '/path/to/main-repo'
|
package/dist/worktree-symlink.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* auto-create the node_modules symlink pointing to the main repo's
|
|
11
11
|
* node_modules directory, including nested package node_modules.
|
|
12
12
|
*
|
|
13
|
-
* @module tools/lib/worktree-symlink.
|
|
13
|
+
* @module tools/lib/worktree-symlink.ts
|
|
14
14
|
*/
|
|
15
15
|
import fs from 'node:fs';
|
|
16
16
|
import path from 'node:path';
|
|
@@ -202,7 +202,7 @@ function checkMainNodeModulesHealth(mainRepoPath, logger) {
|
|
|
202
202
|
* @returns {{created: boolean, skipped: boolean, refused?: boolean, reason?: string, error?: Error}}
|
|
203
203
|
*
|
|
204
204
|
* @example
|
|
205
|
-
* // In wu-claim.
|
|
205
|
+
* // In wu-claim.ts after worktree creation:
|
|
206
206
|
* symlinkNodeModules('/path/to/worktrees/operations-tooling-wu-1443');
|
|
207
207
|
*/
|
|
208
208
|
export function symlinkNodeModules(worktreePath, logger = console, mainRepoPath = null) {
|
|
@@ -310,7 +310,7 @@ function handleExistingNestedNodeModules(targetNodeModules, pkgPath, logger, err
|
|
|
310
310
|
* @returns {{created: number, skipped: number, errors: Error[]}}
|
|
311
311
|
*
|
|
312
312
|
* @example
|
|
313
|
-
* // In wu-claim.
|
|
313
|
+
* // In wu-claim.ts after worktree creation:
|
|
314
314
|
* symlinkNestedNodeModules(
|
|
315
315
|
* '/path/to/worktrees/operations-tooling-wu-1579',
|
|
316
316
|
* '/path/to/main-repo'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Backlog.md Update Utilities
|
|
3
3
|
*
|
|
4
|
-
* Centralized backlog.md update functions (extracted from wu-done.
|
|
4
|
+
* Centralized backlog.md update functions (extracted from wu-done.ts)
|
|
5
5
|
* Refactored to use BacklogManager (WU-1212) for AST-based manipulation
|
|
6
6
|
*
|
|
7
7
|
* Used by both main wu:done flow AND recovery mode (DRY principle)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Backlog.md Update Utilities
|
|
3
3
|
*
|
|
4
|
-
* Centralized backlog.md update functions (extracted from wu-done.
|
|
4
|
+
* Centralized backlog.md update functions (extracted from wu-done.ts)
|
|
5
5
|
* Refactored to use BacklogManager (WU-1212) for AST-based manipulation
|
|
6
6
|
*
|
|
7
7
|
* Used by both main wu:done flow AND recovery mode (DRY principle)
|
package/dist/wu-claim-helpers.js
CHANGED
package/dist/wu-claim-resume.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - ORPHAN_WORKTREE_DONE: Done WU still has worktree
|
|
11
11
|
* - STAMP_EXISTS_YAML_NOT_DONE: Stamp exists but YAML status is not done (WU-2412)
|
|
12
12
|
*
|
|
13
|
-
* @see {@link ../wu-repair.
|
|
13
|
+
* @see {@link ../wu-repair.ts} CLI interface
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* Check a single WU for state inconsistencies
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
* - ORPHAN_WORKTREE_DONE: Done WU still has worktree
|
|
11
11
|
* - STAMP_EXISTS_YAML_NOT_DONE: Stamp exists but YAML status is not done (WU-2412)
|
|
12
12
|
*
|
|
13
|
-
* @see {@link ../wu-repair.
|
|
13
|
+
* @see {@link ../wu-repair.ts} CLI interface
|
|
14
14
|
*/
|
|
15
15
|
import { readFile, writeFile, readdir, mkdir, access } from 'node:fs/promises';
|
|
16
16
|
import { constants, existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { parseYAML, stringifyYAML } from './wu-yaml.js';
|
|
19
|
-
import { WU_PATHS } from './wu-paths.js';
|
|
19
|
+
import { createWuPaths, WU_PATHS } from './wu-paths.js';
|
|
20
20
|
import { CONSISTENCY_TYPES, CONSISTENCY_MESSAGES, LOG_PREFIX, REMOTES, STRING_LITERALS, toKebab, WU_STATUS, YAML_OPTIONS, } from './wu-constants.js';
|
|
21
21
|
import { todayISO } from './date-utils.js';
|
|
22
22
|
import { createGitForPath } from './git-adapter.js';
|
|
@@ -30,10 +30,11 @@ import { withMicroWorktree } from './micro-worktree.js';
|
|
|
30
30
|
*/
|
|
31
31
|
export async function checkWUConsistency(id, projectRoot = process.cwd()) {
|
|
32
32
|
const errors = [];
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
33
|
+
const paths = createWuPaths({ projectRoot });
|
|
34
|
+
const wuPath = path.join(projectRoot, paths.WU(id));
|
|
35
|
+
const stampPath = path.join(projectRoot, paths.STAMP(id));
|
|
36
|
+
const backlogPath = path.join(projectRoot, paths.BACKLOG());
|
|
37
|
+
const statusPath = path.join(projectRoot, paths.STATUS());
|
|
37
38
|
// Handle missing WU YAML gracefully
|
|
38
39
|
try {
|
|
39
40
|
await access(wuPath, constants.R_OK);
|
|
@@ -166,7 +167,8 @@ export async function checkWUConsistency(id, projectRoot = process.cwd()) {
|
|
|
166
167
|
* @returns {Promise<object>} Aggregated report with valid, errors, and checked count
|
|
167
168
|
*/
|
|
168
169
|
export async function checkAllWUConsistency(projectRoot = process.cwd()) {
|
|
169
|
-
const
|
|
170
|
+
const paths = createWuPaths({ projectRoot });
|
|
171
|
+
const wuDir = path.join(projectRoot, paths.WU_DIR());
|
|
170
172
|
try {
|
|
171
173
|
await access(wuDir, constants.R_OK);
|
|
172
174
|
}
|
|
@@ -195,7 +197,8 @@ export async function checkAllWUConsistency(projectRoot = process.cwd()) {
|
|
|
195
197
|
* @returns {Promise<object>} Result with valid, orphans list, and reports
|
|
196
198
|
*/
|
|
197
199
|
export async function checkLaneForOrphanDoneWU(lane, excludeId, projectRoot = process.cwd()) {
|
|
198
|
-
const
|
|
200
|
+
const paths = createWuPaths({ projectRoot });
|
|
201
|
+
const wuDir = path.join(projectRoot, paths.WU_DIR());
|
|
199
202
|
try {
|
|
200
203
|
await access(wuDir, constants.R_OK);
|
|
201
204
|
}
|
|
@@ -486,7 +489,8 @@ async function createStampInProject(id, title, projectRoot) {
|
|
|
486
489
|
* @returns {Promise<string[]>} List of files modified (relative paths)
|
|
487
490
|
*/
|
|
488
491
|
async function updateYamlToDoneInWorktree(id, worktreePath, projectRoot) {
|
|
489
|
-
const
|
|
492
|
+
const paths = createWuPaths({ projectRoot });
|
|
493
|
+
const wuRelPath = paths.WU(id);
|
|
490
494
|
const wuSrcPath = path.join(projectRoot, wuRelPath);
|
|
491
495
|
const wuDestPath = path.join(worktreePath, wuRelPath);
|
|
492
496
|
// Read current YAML from project root
|
|
@@ -522,7 +526,8 @@ async function updateYamlToDoneInWorktree(id, worktreePath, projectRoot) {
|
|
|
522
526
|
* @returns {Promise<void>}
|
|
523
527
|
*/
|
|
524
528
|
async function updateYamlToDone(id, projectRoot) {
|
|
525
|
-
const
|
|
529
|
+
const paths = createWuPaths({ projectRoot });
|
|
530
|
+
const wuPath = path.join(projectRoot, paths.WU(id));
|
|
526
531
|
// Read current YAML
|
|
527
532
|
const content = await readFile(wuPath, { encoding: 'utf-8' });
|
|
528
533
|
const wuDoc = parseYAML(content);
|
|
@@ -690,7 +695,8 @@ async function removeOrphanWorktree(id, lane, projectRoot) {
|
|
|
690
695
|
// Worktree doesn't exist, that's fine
|
|
691
696
|
}
|
|
692
697
|
// 🚨 SAFETY GUARD 3: Check stamp exists (not rollback state)
|
|
693
|
-
const
|
|
698
|
+
const paths = createWuPaths({ projectRoot });
|
|
699
|
+
const stampPath = path.join(projectRoot, paths.STAMP(id));
|
|
694
700
|
try {
|
|
695
701
|
await access(stampPath, constants.R_OK);
|
|
696
702
|
}
|