@lumenflow/cli 3.11.1 → 3.12.1

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.
@@ -1,233 +0,0 @@
1
- // Copyright (c) 2026 Hellmai Ltd
2
- // SPDX-License-Identifier: AGPL-3.0-only
3
- /**
4
- * @file init-lane-validation.ts
5
- * Lane config drift detection against inference taxonomy.
6
- *
7
- * WU-1745: Validate lane config against inference hierarchy at init time.
8
- * WU-2326: Inference taxonomy is derived metadata and never blocks
9
- * workspace-defined lane validation.
10
- *
11
- * Cross-checks lane definitions in workspace.yaml software_delivery against
12
- * .lumenflow.lane-inference.yaml parents and emits non-blocking guidance
13
- * when taxonomy drifts from workspace definitions.
14
- */
15
- import * as fs from 'node:fs';
16
- import * as path from 'node:path';
17
- import * as yaml from 'yaml';
18
- import { WORKSPACE_CONFIG_FILE_NAME } from '@lumenflow/core/config';
19
- import { WORKSPACE_V2_KEYS } from '@lumenflow/core/config-schema';
20
- import { CONFIG_FILES } from '@lumenflow/core/wu-constants';
21
- /** Separator between parent and sublane in lane names */
22
- const LANE_NAME_SEPARATOR = ': ';
23
- const SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
24
- /**
25
- * Extract the parent name from a "Parent: Sublane" lane name.
26
- *
27
- * @param laneName - Lane name in "Parent: Sublane" format
28
- * @returns The parent portion, or null if no separator found
29
- */
30
- function extractParentName(laneName) {
31
- const separatorIndex = laneName.indexOf(LANE_NAME_SEPARATOR);
32
- if (separatorIndex === -1) {
33
- return null;
34
- }
35
- return laneName.substring(0, separatorIndex);
36
- }
37
- function extractSubLaneName(laneName) {
38
- const separatorIndex = laneName.indexOf(LANE_NAME_SEPARATOR);
39
- if (separatorIndex === -1) {
40
- return null;
41
- }
42
- const subLane = laneName.substring(separatorIndex + LANE_NAME_SEPARATOR.length).trim();
43
- return subLane.length > 0 ? subLane : null;
44
- }
45
- function sortMapValues(map) {
46
- const sorted = {};
47
- for (const [parent, subLanes] of Object.entries(map)) {
48
- sorted[parent] = [...subLanes].sort((left, right) => left.localeCompare(right));
49
- }
50
- return sorted;
51
- }
52
- /**
53
- * Detect parent drift between workspace lane definitions and inference taxonomy.
54
- *
55
- * Workspace definitions are the source of truth. Inference taxonomy drift is
56
- * reported as warnings only and does not populate invalidLanes.
57
- *
58
- * @param configLanes - Lane definitions from workspace.yaml software_delivery
59
- * @param inferenceParents - Valid parent names from .lumenflow.lane-inference.yaml
60
- * @returns Validation result with warnings and invalid lane names
61
- */
62
- export function validateLaneConfigAgainstInference(configLanes, inferenceParents) {
63
- const warnings = [];
64
- const invalidLanes = [];
65
- if (configLanes.length === 0 || inferenceParents.length === 0) {
66
- return { warnings, invalidLanes };
67
- }
68
- const validParentSet = new Set(inferenceParents);
69
- for (const lane of configLanes) {
70
- const parent = extractParentName(lane.name);
71
- if (parent === null) {
72
- // Parent-only lanes are allowed and validated from workspace.yaml elsewhere.
73
- continue;
74
- }
75
- if (!validParentSet.has(parent)) {
76
- warnings.push(`Lane "${lane.name}" uses parent "${parent}" which is missing from ${CONFIG_FILES.LANE_INFERENCE}. ` +
77
- `workspace.yaml is authoritative for lane validation. ` +
78
- `Regenerate inference taxonomy with: pnpm lane:suggest --output ${CONFIG_FILES.LANE_INFERENCE}`);
79
- }
80
- }
81
- return { warnings, invalidLanes };
82
- }
83
- /**
84
- * Extract top-level parent names from a lane inference YAML file.
85
- *
86
- * The lane inference file uses hierarchical format:
87
- * Parent:
88
- * Sublane:
89
- * code_paths: [...]
90
- *
91
- * This function returns the top-level keys (parent names).
92
- *
93
- * @param laneInferencePath - Path to .lumenflow.lane-inference.yaml
94
- * @returns Array of parent names, or empty array if file doesn't exist/is invalid
95
- */
96
- export function extractInferenceParents(laneInferencePath) {
97
- if (!fs.existsSync(laneInferencePath)) {
98
- return [];
99
- }
100
- try {
101
- const content = fs.readFileSync(laneInferencePath, 'utf-8');
102
- const parsed = yaml.parse(content);
103
- if (!parsed || typeof parsed !== 'object') {
104
- return [];
105
- }
106
- // Top-level keys are parent names
107
- return Object.keys(parsed);
108
- }
109
- catch {
110
- return [];
111
- }
112
- }
113
- export function extractInferenceTaxonomy(laneInferencePath) {
114
- if (!fs.existsSync(laneInferencePath)) {
115
- return {};
116
- }
117
- try {
118
- const content = fs.readFileSync(laneInferencePath, 'utf-8');
119
- const parsed = yaml.parse(content);
120
- if (!parsed || typeof parsed !== 'object') {
121
- return {};
122
- }
123
- const taxonomy = {};
124
- for (const [parent, subLanesRaw] of Object.entries(parsed)) {
125
- if (!subLanesRaw || typeof subLanesRaw !== 'object' || Array.isArray(subLanesRaw)) {
126
- taxonomy[parent] = [];
127
- continue;
128
- }
129
- taxonomy[parent] = Object.keys(subLanesRaw);
130
- }
131
- return sortMapValues(taxonomy);
132
- }
133
- catch {
134
- return {};
135
- }
136
- }
137
- export function extractConfigTaxonomy(configLanes) {
138
- if (configLanes.length === 0) {
139
- return {};
140
- }
141
- const byParent = new Map();
142
- for (const lane of configLanes) {
143
- const parent = extractParentName(lane.name);
144
- const subLane = extractSubLaneName(lane.name);
145
- if (!parent || !subLane) {
146
- continue;
147
- }
148
- const existing = byParent.get(parent) ?? new Set();
149
- existing.add(subLane);
150
- byParent.set(parent, existing);
151
- }
152
- const taxonomy = {};
153
- for (const [parent, subLanes] of byParent.entries()) {
154
- taxonomy[parent] = [...subLanes].sort((left, right) => left.localeCompare(right));
155
- }
156
- return taxonomy;
157
- }
158
- export function detectLaneTaxonomyDrift(configLanes, inferenceTaxonomy) {
159
- const configTaxonomy = extractConfigTaxonomy(configLanes);
160
- const allParents = new Set([...Object.keys(configTaxonomy), ...Object.keys(inferenceTaxonomy)]);
161
- const missingInInference = {};
162
- const extraInInference = {};
163
- for (const parent of allParents) {
164
- const configSubLanes = new Set(configTaxonomy[parent] ?? []);
165
- const inferenceSubLanes = new Set(inferenceTaxonomy[parent] ?? []);
166
- const missing = [...configSubLanes]
167
- .filter((subLane) => !inferenceSubLanes.has(subLane))
168
- .sort((left, right) => left.localeCompare(right));
169
- const extra = [...inferenceSubLanes]
170
- .filter((subLane) => !configSubLanes.has(subLane))
171
- .sort((left, right) => left.localeCompare(right));
172
- if (missing.length > 0) {
173
- missingInInference[parent] = missing;
174
- }
175
- if (extra.length > 0) {
176
- extraInInference[parent] = extra;
177
- }
178
- }
179
- return {
180
- hasDrift: Object.keys(missingInInference).length > 0 || Object.keys(extraInInference).length > 0,
181
- missingInInference,
182
- extraInInference,
183
- };
184
- }
185
- /**
186
- * Extract lane definitions from a workspace YAML file.
187
- *
188
- * @param configPath - Path to workspace.yaml
189
- * @returns Array of lane definitions, or empty array if not found
190
- */
191
- export function extractConfigLanes(configPath) {
192
- if (!fs.existsSync(configPath)) {
193
- return [];
194
- }
195
- try {
196
- const content = fs.readFileSync(configPath, 'utf-8');
197
- const parsed = yaml.parse(content);
198
- if (!parsed || typeof parsed !== 'object') {
199
- return [];
200
- }
201
- const softwareDelivery = parsed[SOFTWARE_DELIVERY_KEY];
202
- const lanes = softwareDelivery?.lanes;
203
- const definitions = lanes?.definitions;
204
- if (!Array.isArray(definitions)) {
205
- return [];
206
- }
207
- return definitions;
208
- }
209
- catch {
210
- return [];
211
- }
212
- }
213
- /**
214
- * Run lane validation for a project directory.
215
- *
216
- * Reads both workspace.yaml and .lumenflow.lane-inference.yaml,
217
- * then validates that all lane parents exist in the inference hierarchy.
218
- *
219
- * @param targetDir - Project root directory
220
- * @returns Validation result with warnings and invalid lane names
221
- */
222
- export function validateLanesForProject(targetDir) {
223
- const configPath = path.join(targetDir, WORKSPACE_CONFIG_FILE_NAME);
224
- const inferencePath = path.join(targetDir, CONFIG_FILES.LANE_INFERENCE);
225
- const configLanes = extractConfigLanes(configPath);
226
- const inferenceParents = extractInferenceParents(inferencePath);
227
- // Without config lanes or inference parents there is no drift check to run.
228
- if (configLanes.length === 0 || inferenceParents.length === 0) {
229
- return { warnings: [], invalidLanes: [] };
230
- }
231
- return validateLaneConfigAgainstInference(configLanes, inferenceParents);
232
- }
233
- //# sourceMappingURL=init-lane-validation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"init-lane-validation.js","sourceRoot":"","sources":["../src/init-lane-validation.ts"],"names":[],"mappings":"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"}
@@ -1,64 +0,0 @@
1
- # Lane Inference
2
-
3
- **Last updated:** {{DATE}}
4
-
5
- Lanes define which area of the system a WU belongs to. Use the lane tools before creating or reshaping work.
6
-
7
- ---
8
-
9
- ## The Two Inputs
10
-
11
- Lane fit is driven by:
12
-
13
- 1. The WU `code_paths`
14
- 2. The implementation description or acceptance criteria
15
-
16
- If those disagree with the assigned lane, fix the lane or split the WU.
17
-
18
- ---
19
-
20
- ## Runtime Checks
21
-
22
- ```bash
23
- pnpm wu:infer-lane --id WU-XXX
24
- pnpm lane:status
25
- ```
26
-
27
- Use `wu:infer-lane` for a WU-level recommendation and `lane:status` for current lifecycle state.
28
-
29
- ---
30
-
31
- ## Taxonomy Source
32
-
33
- Lane metadata is stored in `.lumenflow.lane-inference.yaml`.
34
-
35
- Regenerate it when taxonomy drifts from `workspace.yaml`:
36
-
37
- ```bash
38
- pnpm lane:suggest --output .lumenflow.lane-inference.yaml
39
- pnpm lane:validate
40
- ```
41
-
42
- ---
43
-
44
- ## Before Delivery WUs
45
-
46
- Lane lifecycle must be complete before the first delivery WU:
47
-
48
- ```bash
49
- pnpm lane:setup
50
- pnpm lane:validate
51
- pnpm lane:lock
52
- ```
53
-
54
- `locked` means delivery WUs can be created safely.
55
-
56
- ---
57
-
58
- ## Common Failure Mode
59
-
60
- If a WU touches files outside the assigned lane's code paths, do not just keep coding.
61
-
62
- - Propose a lane change if the WU is genuinely in the wrong lane.
63
- - Split the WU if the work spans multiple lanes.
64
- - Update the taxonomy only when the lane model itself is outdated.