@lumenflow/cli 2.12.0 ā 2.14.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/README.md +105 -105
- package/dist/gates-graceful-degradation.js +151 -0
- package/dist/gates-graceful-degradation.js.map +1 -0
- package/dist/gates.js +90 -5
- package/dist/gates.js.map +1 -1
- package/dist/hooks/enforcement-checks.js +104 -37
- package/dist/hooks/enforcement-checks.js.map +1 -1
- package/dist/hooks/enforcement-generator.js +229 -28
- package/dist/hooks/enforcement-generator.js.map +1 -1
- package/dist/hooks/enforcement-sync.js +4 -1
- package/dist/hooks/enforcement-sync.js.map +1 -1
- package/dist/init.js +160 -13
- package/dist/init.js.map +1 -1
- package/dist/initiative-edit.js +3 -2
- package/dist/initiative-edit.js.map +1 -1
- package/dist/lifecycle-regression-harness.js +179 -0
- package/dist/lifecycle-regression-harness.js.map +1 -0
- package/dist/mem-recover.js +0 -0
- package/dist/public-manifest.js +7 -0
- package/dist/public-manifest.js.map +1 -1
- package/dist/wu-claim-mode.js +80 -0
- package/dist/wu-claim-mode.js.map +1 -0
- package/dist/wu-claim.js +163 -9
- package/dist/wu-claim.js.map +1 -1
- package/dist/wu-create.js +5 -1
- package/dist/wu-create.js.map +1 -1
- package/dist/wu-delete.js +196 -60
- package/dist/wu-delete.js.map +1 -1
- package/dist/wu-done.js +99 -17
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-edit.js +5 -4
- package/dist/wu-edit.js.map +1 -1
- package/dist/wu-prep.js +122 -27
- package/dist/wu-prep.js.map +1 -1
- package/package.json +7 -6
- package/templates/vendors/claude/.claude/hooks/enforce-worktree.sh +78 -17
- package/templates/vendors/claude/.claude/hooks/session-start-recovery.sh +30 -0
package/README.md
CHANGED
|
@@ -51,130 +51,132 @@ This package provides CLI commands for the LumenFlow workflow framework, includi
|
|
|
51
51
|
|
|
52
52
|
### Work Unit Management
|
|
53
53
|
|
|
54
|
-
| Command | Description
|
|
55
|
-
| ---------------- |
|
|
56
|
-
| `wu-block` | Block
|
|
57
|
-
| `wu-claim` | Claim
|
|
58
|
-
| `wu-cleanup` |
|
|
59
|
-
| `wu-create` | Create
|
|
60
|
-
| `wu-delete` |
|
|
61
|
-
| `wu-deps` |
|
|
62
|
-
| `wu-done` | WU
|
|
63
|
-
| `wu-edit` | Edit WU spec
|
|
64
|
-
| `wu-infer-lane` |
|
|
65
|
-
| `wu-preflight` |
|
|
66
|
-
| `wu-prep` |
|
|
67
|
-
| `wu-proto` | Create
|
|
68
|
-
| `wu-prune` |
|
|
69
|
-
| `wu-recover` | Analyze and fix WU state inconsistencies
|
|
70
|
-
| `wu-release` | Release
|
|
71
|
-
| `wu-repair` |
|
|
72
|
-
| `wu-spawn` | Generate
|
|
73
|
-
| `wu-status` | Show WU status, location,
|
|
74
|
-
| `wu-unblock` | Unblock
|
|
75
|
-
| `wu-unlock-lane` |
|
|
76
|
-
| `wu-validate` | Validate WU
|
|
54
|
+
| Command | Description |
|
|
55
|
+
| ---------------- | --------------------------------------------- |
|
|
56
|
+
| `wu-block` | Block WU with reason |
|
|
57
|
+
| `wu-claim` | Claim WU and create worktree |
|
|
58
|
+
| `wu-cleanup` | Cleanup after PR merge |
|
|
59
|
+
| `wu-create` | Create new WU spec |
|
|
60
|
+
| `wu-delete` | Delete WU spec and cleanup |
|
|
61
|
+
| `wu-deps` | Show WU dependencies |
|
|
62
|
+
| `wu-done` | Complete WU (merge, stamp, cleanup) from main |
|
|
63
|
+
| `wu-edit` | Edit WU spec fields |
|
|
64
|
+
| `wu-infer-lane` | Infer lane from code paths/description |
|
|
65
|
+
| `wu-preflight` | Pre-flight checks before wu:done |
|
|
66
|
+
| `wu-prep` | Run gates in worktree, prep for wu:done |
|
|
67
|
+
| `wu-proto` | Create WU prototype |
|
|
68
|
+
| `wu-prune` | Clean stale worktrees |
|
|
69
|
+
| `wu-recover` | Analyze and fix WU state inconsistencies |
|
|
70
|
+
| `wu-release` | Release orphaned WU (in_progress to ready) |
|
|
71
|
+
| `wu-repair` | Repair WU state issues |
|
|
72
|
+
| `wu-spawn` | Generate sub-agent spawn prompt |
|
|
73
|
+
| `wu-status` | Show WU status, location, valid commands |
|
|
74
|
+
| `wu-unblock` | Unblock WU |
|
|
75
|
+
| `wu-unlock-lane` | Unlock stuck lane |
|
|
76
|
+
| `wu-validate` | Validate WU spec |
|
|
77
77
|
|
|
78
78
|
### Memory & Session
|
|
79
79
|
|
|
80
|
-
| Command | Description
|
|
81
|
-
| -------------------- |
|
|
82
|
-
| `agent-issues-query` | Query
|
|
83
|
-
| `agent-log-issue` | Log
|
|
84
|
-
| `agent-session` | Start
|
|
85
|
-
| `agent-session-end` | End
|
|
86
|
-
| `mem-checkpoint` |
|
|
87
|
-
| `mem-cleanup` |
|
|
88
|
-
| `mem-context` |
|
|
89
|
-
| `mem-create` | Create
|
|
90
|
-
| `mem-delete` | Delete memory
|
|
91
|
-
| `mem-export` | Export memory
|
|
92
|
-
| `mem-inbox` |
|
|
93
|
-
| `mem-init` | Initialize memory
|
|
94
|
-
| `mem-ready` |
|
|
95
|
-
| `mem-
|
|
96
|
-
| `mem-
|
|
97
|
-
| `mem-
|
|
98
|
-
| `mem-
|
|
80
|
+
| Command | Description |
|
|
81
|
+
| -------------------- | ------------------------------------------ |
|
|
82
|
+
| `agent-issues-query` | Query GitHub issues for agent work |
|
|
83
|
+
| `agent-log-issue` | Log issue during agent session |
|
|
84
|
+
| `agent-session` | Start agent session |
|
|
85
|
+
| `agent-session-end` | End agent session |
|
|
86
|
+
| `mem-checkpoint` | Save progress checkpoint |
|
|
87
|
+
| `mem-cleanup` | Clean up stale memory data |
|
|
88
|
+
| `mem-context` | Get context for current lane/WU |
|
|
89
|
+
| `mem-create` | Create memory node (bug discovery) |
|
|
90
|
+
| `mem-delete` | Delete/archive a memory node |
|
|
91
|
+
| `mem-export` | Export memory as markdown |
|
|
92
|
+
| `mem-inbox` | Check coordination signals |
|
|
93
|
+
| `mem-init` | Initialize memory for WU |
|
|
94
|
+
| `mem-ready` | Check pending memory nodes |
|
|
95
|
+
| `mem-recover` | Generate recovery context after compaction |
|
|
96
|
+
| `mem-signal` | Broadcast coordination signal |
|
|
97
|
+
| `mem-start` | Start a memory session |
|
|
98
|
+
| `mem-summarize` | Summarize memory context |
|
|
99
|
+
| `mem-triage` | Triage discovered bugs |
|
|
99
100
|
|
|
100
101
|
### Initiative Orchestration
|
|
101
102
|
|
|
102
|
-
| Command | Description
|
|
103
|
-
| ---------------------------- |
|
|
104
|
-
| `initiative-add-wu` |
|
|
105
|
-
| `initiative-bulk-assign-wus` | Bulk
|
|
106
|
-
| `initiative-create` | Create
|
|
107
|
-
| `initiative-edit` | Edit
|
|
108
|
-
| `initiative-list` | List all initiatives
|
|
109
|
-
| `initiative-plan` | Link
|
|
110
|
-
| `initiative-status` | Show
|
|
111
|
-
| `orchestrate-init-status` |
|
|
112
|
-
| `orchestrate-initiative` | Orchestrate initiative execution
|
|
113
|
-
| `orchestrate-monitor` | Monitor
|
|
114
|
-
| `spawn-list` |
|
|
103
|
+
| Command | Description |
|
|
104
|
+
| ---------------------------- | -------------------------------- |
|
|
105
|
+
| `initiative-add-wu` | Add WU to initiative |
|
|
106
|
+
| `initiative-bulk-assign-wus` | Bulk assign WUs to initiative |
|
|
107
|
+
| `initiative-create` | Create new initiative |
|
|
108
|
+
| `initiative-edit` | Edit initiative fields |
|
|
109
|
+
| `initiative-list` | List all initiatives |
|
|
110
|
+
| `initiative-plan` | Link plan to initiative |
|
|
111
|
+
| `initiative-status` | Show initiative status |
|
|
112
|
+
| `orchestrate-init-status` | Compact initiative progress view |
|
|
113
|
+
| `orchestrate-initiative` | Orchestrate initiative execution |
|
|
114
|
+
| `orchestrate-monitor` | Monitor spawn/agent activity |
|
|
115
|
+
| `spawn-list` | List active spawned agents |
|
|
115
116
|
|
|
116
117
|
### Metrics & Analytics
|
|
117
118
|
|
|
118
|
-
| Command | Description
|
|
119
|
-
| ------------------ |
|
|
120
|
-
| `flow-bottlenecks` | Identify
|
|
121
|
-
| `flow-report` | Generate
|
|
122
|
-
| `metrics` |
|
|
123
|
-
| `metrics-snapshot` | Capture
|
|
119
|
+
| Command | Description |
|
|
120
|
+
| ------------------ | ---------------------------- |
|
|
121
|
+
| `flow-bottlenecks` | Identify flow bottlenecks |
|
|
122
|
+
| `flow-report` | Generate flow metrics report |
|
|
123
|
+
| `metrics` | View workflow metrics |
|
|
124
|
+
| `metrics-snapshot` | Capture metrics snapshot |
|
|
124
125
|
|
|
125
126
|
### Lane Tooling
|
|
126
127
|
|
|
127
|
-
| Command | Description
|
|
128
|
-
| -------------- |
|
|
129
|
-
| `lane-health` | Check lane
|
|
130
|
-
| `lane-suggest` | Suggest lane
|
|
128
|
+
| Command | Description |
|
|
129
|
+
| -------------- | --------------------------- |
|
|
130
|
+
| `lane-health` | Check lane config health |
|
|
131
|
+
| `lane-suggest` | Suggest lane for code paths |
|
|
131
132
|
|
|
132
133
|
### Verification & Gates
|
|
133
134
|
|
|
134
|
-
| Command
|
|
135
|
-
|
|
|
136
|
-
| `gates`
|
|
135
|
+
| Command | Description |
|
|
136
|
+
| -------------------- | ----------------------------- |
|
|
137
|
+
| `gates` | Run all quality gates |
|
|
138
|
+
| `lumenflow-gates` | Run all quality gates (alias) |
|
|
139
|
+
| `lumenflow-validate` | Run validation checks (alias) |
|
|
140
|
+
| `validate` | Run validation checks |
|
|
137
141
|
|
|
138
142
|
### System & Setup
|
|
139
143
|
|
|
140
|
-
| Command | Description
|
|
141
|
-
| -------------------------- |
|
|
142
|
-
| `backlog-prune` |
|
|
143
|
-
| `init-plan` | Link
|
|
144
|
-
| `lumenflow` | Initialize LumenFlow in a project
|
|
145
|
-
| `lumenflow-commands` | List all available
|
|
146
|
-
| `lumenflow-docs-sync` | Sync agent
|
|
147
|
-
| `lumenflow-doctor` |
|
|
148
|
-
| `lumenflow-init` | Initialize LumenFlow in a project
|
|
149
|
-
| `lumenflow-integrate` |
|
|
150
|
-
| `lumenflow-metrics` |
|
|
151
|
-
| `lumenflow-release` |
|
|
152
|
-
| `lumenflow-sync-templates` | Sync
|
|
153
|
-
| `lumenflow-upgrade` |
|
|
154
|
-
| `
|
|
155
|
-
| `plan-
|
|
156
|
-
| `plan-
|
|
157
|
-
| `plan-
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `state-
|
|
161
|
-
| `state-
|
|
162
|
-
| `
|
|
163
|
-
| `sync-templates` | Sync internal docs to CLI templates for release-cycle maintenance |
|
|
164
|
-
| `validate` | |
|
|
144
|
+
| Command | Description |
|
|
145
|
+
| -------------------------- | ----------------------------------------- |
|
|
146
|
+
| `backlog-prune` | Clean stale backlog entries |
|
|
147
|
+
| `init-plan` | Link plan to initiative (alias) |
|
|
148
|
+
| `lumenflow` | Initialize LumenFlow in a project |
|
|
149
|
+
| `lumenflow-commands` | List all available CLI commands |
|
|
150
|
+
| `lumenflow-docs-sync` | Sync agent docs (for upgrades) (alias) |
|
|
151
|
+
| `lumenflow-doctor` | Diagnose LumenFlow configuration |
|
|
152
|
+
| `lumenflow-init` | Initialize LumenFlow in a project (alias) |
|
|
153
|
+
| `lumenflow-integrate` | Generate enforcement hooks for client |
|
|
154
|
+
| `lumenflow-metrics` | View workflow metrics (alias) |
|
|
155
|
+
| `lumenflow-release` | Run release workflow |
|
|
156
|
+
| `lumenflow-sync-templates` | Sync templates to project |
|
|
157
|
+
| `lumenflow-upgrade` | Upgrade LumenFlow packages |
|
|
158
|
+
| `plan-create` | Create a new plan |
|
|
159
|
+
| `plan-edit` | Edit plan content |
|
|
160
|
+
| `plan-link` | Link plan to WU or initiative |
|
|
161
|
+
| `plan-promote` | Promote plan to WU |
|
|
162
|
+
| `signal-cleanup` | Clean up stale signals |
|
|
163
|
+
| `state-bootstrap` | Bootstrap state store |
|
|
164
|
+
| `state-cleanup` | Clean up stale state data |
|
|
165
|
+
| `state-doctor` | Diagnose state store issues |
|
|
166
|
+
| `sync-templates` | Sync templates to project (alias) |
|
|
165
167
|
|
|
166
168
|
### File & Git Operations
|
|
167
169
|
|
|
168
|
-
| Command | Description
|
|
169
|
-
| ------------- |
|
|
170
|
-
| `file-delete` |
|
|
171
|
-
| `file-edit` |
|
|
172
|
-
| `file-read` |
|
|
173
|
-
| `file-write` |
|
|
174
|
-
| `git-branch` |
|
|
175
|
-
| `git-diff` |
|
|
176
|
-
| `git-log` |
|
|
177
|
-
| `git-status` |
|
|
170
|
+
| Command | Description |
|
|
171
|
+
| ------------- | -------------------------------- |
|
|
172
|
+
| `file-delete` | Delete file with audit trail |
|
|
173
|
+
| `file-edit` | Edit file with audit trail |
|
|
174
|
+
| `file-read` | Read file with audit trail |
|
|
175
|
+
| `file-write` | Write file with audit trail |
|
|
176
|
+
| `git-branch` | Show git branch with audit trail |
|
|
177
|
+
| `git-diff` | Show git diff with audit trail |
|
|
178
|
+
| `git-log` | Show git log with audit trail |
|
|
179
|
+
| `git-status` | Show git status with audit trail |
|
|
178
180
|
|
|
179
181
|
<!-- END AUTO-GENERATED SECTION -->
|
|
180
182
|
|
|
@@ -279,5 +281,3 @@ For detailed upgrade instructions, migration guides, and troubleshooting, see [U
|
|
|
279
281
|
## License
|
|
280
282
|
|
|
281
283
|
Apache-2.0
|
|
282
|
-
|
|
283
|
-
<!-- MODIFIED -->
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gates Graceful Degradation
|
|
3
|
+
*
|
|
4
|
+
* WU-1520: When gate scripts (format:check, lint, typecheck, spec:linter)
|
|
5
|
+
* are missing from package.json, emit a warning and skip instead of failing.
|
|
6
|
+
*
|
|
7
|
+
* Defense in depth: even if scaffold adds scripts, gates should degrade
|
|
8
|
+
* gracefully for any missing script.
|
|
9
|
+
*
|
|
10
|
+
* @module gates-graceful-degradation
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
/**
|
|
15
|
+
* Scripts that can be skipped when missing from package.json.
|
|
16
|
+
* These are optional tooling scripts that not every project configures.
|
|
17
|
+
*/
|
|
18
|
+
export const SKIPPABLE_GATE_SCRIPTS = [
|
|
19
|
+
'format:check',
|
|
20
|
+
'lint',
|
|
21
|
+
'typecheck',
|
|
22
|
+
'spec:linter',
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Gates that are never skippable, regardless of configuration.
|
|
26
|
+
* These enforce critical invariants and must always run.
|
|
27
|
+
*/
|
|
28
|
+
export const NON_SKIPPABLE_GATES = ['invariants'];
|
|
29
|
+
/**
|
|
30
|
+
* Check whether a script exists in a package.json scripts object.
|
|
31
|
+
*
|
|
32
|
+
* @param scriptName - The script name to check (e.g., 'lint', 'format:check')
|
|
33
|
+
* @param scripts - The scripts object from package.json, or undefined
|
|
34
|
+
* @returns true if the script exists
|
|
35
|
+
*/
|
|
36
|
+
export function checkScriptExists(scriptName, scripts) {
|
|
37
|
+
if (!scripts)
|
|
38
|
+
return false;
|
|
39
|
+
return Object.prototype.hasOwnProperty.call(scripts, scriptName);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Load the scripts object from a package.json file.
|
|
43
|
+
*
|
|
44
|
+
* @param projectRoot - Project root directory containing package.json
|
|
45
|
+
* @returns The scripts object, or undefined if package.json is missing or unreadable
|
|
46
|
+
*/
|
|
47
|
+
export function loadPackageJsonScripts(projectRoot) {
|
|
48
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
49
|
+
if (!existsSync(packageJsonPath))
|
|
50
|
+
return undefined;
|
|
51
|
+
try {
|
|
52
|
+
const content = readFileSync(packageJsonPath, 'utf8');
|
|
53
|
+
const pkg = JSON.parse(content);
|
|
54
|
+
return pkg.scripts;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build a human-readable warning message for a missing gate script.
|
|
62
|
+
* Includes instructions on how to add the missing script.
|
|
63
|
+
*
|
|
64
|
+
* @param scriptName - The missing script name
|
|
65
|
+
* @returns Warning message string
|
|
66
|
+
*/
|
|
67
|
+
export function buildMissingScriptWarning(scriptName) {
|
|
68
|
+
const suggestions = {
|
|
69
|
+
'format:check': '"format:check": "prettier --check ."',
|
|
70
|
+
lint: '"lint": "eslint ."',
|
|
71
|
+
typecheck: '"typecheck": "tsc --noEmit"',
|
|
72
|
+
'spec:linter': '"spec:linter": "node tools/spec-linter.js"',
|
|
73
|
+
};
|
|
74
|
+
const suggestion = suggestions[scriptName] ?? `"${scriptName}": "<your-command>"`;
|
|
75
|
+
return [
|
|
76
|
+
`Warning: "${scriptName}" script not found in package.json - skipping gate.`,
|
|
77
|
+
` To enable this gate, add to your package.json scripts:`,
|
|
78
|
+
` ${suggestion}`,
|
|
79
|
+
].join('\n');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Determine whether a gate should be skipped due to a missing script.
|
|
83
|
+
*
|
|
84
|
+
* @param gateName - The gate name (e.g., 'lint', 'invariants')
|
|
85
|
+
* @param scriptName - The underlying script name, or null for non-script gates
|
|
86
|
+
* @param scripts - The scripts object from package.json
|
|
87
|
+
* @param strict - When true, missing scripts cause a hard failure instead of skip
|
|
88
|
+
* @returns 'skip' if the gate should be skipped, 'run' if it should run, 'fail' if strict mode failure
|
|
89
|
+
*/
|
|
90
|
+
export function resolveGateAction(gateName, scriptName, scripts, strict) {
|
|
91
|
+
// Non-skippable gates always run
|
|
92
|
+
if (NON_SKIPPABLE_GATES.includes(gateName)) {
|
|
93
|
+
return 'run';
|
|
94
|
+
}
|
|
95
|
+
// If no script name is associated (e.g., custom run functions), always run
|
|
96
|
+
if (!scriptName) {
|
|
97
|
+
return 'run';
|
|
98
|
+
}
|
|
99
|
+
// If script exists, run it
|
|
100
|
+
if (checkScriptExists(scriptName, scripts)) {
|
|
101
|
+
return 'run';
|
|
102
|
+
}
|
|
103
|
+
// Script is missing
|
|
104
|
+
if (strict) {
|
|
105
|
+
return 'fail';
|
|
106
|
+
}
|
|
107
|
+
return 'skip';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Format a summary of gate results showing passed, skipped, and failed gates.
|
|
111
|
+
*
|
|
112
|
+
* @param results - Array of gate results
|
|
113
|
+
* @returns Formatted summary string
|
|
114
|
+
*/
|
|
115
|
+
export function formatGateSummary(results) {
|
|
116
|
+
if (results.length === 0) {
|
|
117
|
+
return 'No gates were executed.';
|
|
118
|
+
}
|
|
119
|
+
const passed = results.filter((r) => r.status === 'passed');
|
|
120
|
+
const skipped = results.filter((r) => r.status === 'skipped');
|
|
121
|
+
const failed = results.filter((r) => r.status === 'failed');
|
|
122
|
+
const warned = results.filter((r) => r.status === 'warned');
|
|
123
|
+
const lines = [];
|
|
124
|
+
lines.push('Gate Summary:');
|
|
125
|
+
lines.push('');
|
|
126
|
+
for (const result of results) {
|
|
127
|
+
const statusIcon = result.status === 'passed'
|
|
128
|
+
? 'PASS'
|
|
129
|
+
: result.status === 'skipped'
|
|
130
|
+
? 'SKIP'
|
|
131
|
+
: result.status === 'warned'
|
|
132
|
+
? 'WARN'
|
|
133
|
+
: 'FAIL';
|
|
134
|
+
const duration = result.durationMs > 0 ? ` (${result.durationMs}ms)` : '';
|
|
135
|
+
const reason = result.reason ? ` - ${result.reason}` : '';
|
|
136
|
+
lines.push(` [${statusIcon}] ${result.name}${duration}${reason}`);
|
|
137
|
+
}
|
|
138
|
+
lines.push('');
|
|
139
|
+
const parts = [];
|
|
140
|
+
if (passed.length > 0)
|
|
141
|
+
parts.push(`${passed.length} passed`);
|
|
142
|
+
if (skipped.length > 0)
|
|
143
|
+
parts.push(`${skipped.length} skipped`);
|
|
144
|
+
if (warned.length > 0)
|
|
145
|
+
parts.push(`${warned.length} warned`);
|
|
146
|
+
if (failed.length > 0)
|
|
147
|
+
parts.push(`${failed.length} failed`);
|
|
148
|
+
lines.push(parts.join(', '));
|
|
149
|
+
return lines.join('\n');
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=gates-graceful-degradation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gates-graceful-degradation.js","sourceRoot":"","sources":["../src/gates-graceful-degradation.ts"],"names":[],"mappings":"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"}
|
package/dist/gates.js
CHANGED
|
@@ -71,6 +71,8 @@ import { runLaneHealthCheck } from './lane-health.js';
|
|
|
71
71
|
// WU-1315: Onboarding smoke test
|
|
72
72
|
import { runOnboardingSmokeTestGate } from './onboarding-smoke-test.js';
|
|
73
73
|
import { BRANCHES, PACKAGES, PKG_MANAGER, ESLINT_FLAGS, ESLINT_COMMANDS, ESLINT_DEFAULTS, SCRIPTS, CACHE_STRATEGIES, DIRECTORIES, GATE_NAMES, GATE_COMMANDS, CLI_MODES, EXIT_CODES, FILE_SYSTEM, PRETTIER_ARGS, PRETTIER_FLAGS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
74
|
+
// WU-1520: Gates graceful degradation for missing optional scripts
|
|
75
|
+
import { checkScriptExists, buildMissingScriptWarning, loadPackageJsonScripts, resolveGateAction, formatGateSummary, SKIPPABLE_GATE_SCRIPTS, } from './gates-graceful-degradation.js';
|
|
74
76
|
/**
|
|
75
77
|
* WU-1087: Gates-specific option definitions for createWUParser.
|
|
76
78
|
* Exported for testing and consistency with other CLI commands.
|
|
@@ -107,6 +109,12 @@ export const GATES_OPTIONS = {
|
|
|
107
109
|
flags: '--verbose',
|
|
108
110
|
description: 'Stream output in agent mode instead of logging to file',
|
|
109
111
|
},
|
|
112
|
+
// WU-1520: --strict flag makes missing scripts a hard failure for CI
|
|
113
|
+
strict: {
|
|
114
|
+
name: 'strict',
|
|
115
|
+
flags: '--strict',
|
|
116
|
+
description: 'Fail on missing gate scripts instead of skipping (for CI enforcement)',
|
|
117
|
+
},
|
|
110
118
|
};
|
|
111
119
|
/**
|
|
112
120
|
* WU-1087: Parse gates options using createWUParser for consistency.
|
|
@@ -142,6 +150,7 @@ export function parseGatesOptions() {
|
|
|
142
150
|
fullCoverage: opts.fullCoverage,
|
|
143
151
|
coverageMode: opts.coverageMode ?? 'block',
|
|
144
152
|
verbose: opts.verbose,
|
|
153
|
+
strict: opts.strict,
|
|
145
154
|
};
|
|
146
155
|
}
|
|
147
156
|
finally {
|
|
@@ -1114,6 +1123,11 @@ async function executeGates(opts) {
|
|
|
1114
1123
|
const laneHealthMode = loadLaneHealthConfig(process.cwd());
|
|
1115
1124
|
// WU-1356: Resolve configured gates commands for test execution
|
|
1116
1125
|
const configuredGatesCommands = resolveGatesCommands(process.cwd());
|
|
1126
|
+
// WU-1520: Strict mode and script existence checking for graceful degradation
|
|
1127
|
+
const isStrict = opts.strict || false;
|
|
1128
|
+
const packageJsonScripts = loadPackageJsonScripts(process.cwd());
|
|
1129
|
+
// WU-1520: Track gate results for summary
|
|
1130
|
+
const gateResults = [];
|
|
1117
1131
|
if (useAgentMode) {
|
|
1118
1132
|
console.log(`š§¾ gates (agent mode): output -> ${agentLog.logPath} (use --verbose for streaming)\n`);
|
|
1119
1133
|
}
|
|
@@ -1153,12 +1167,17 @@ async function executeGates(opts) {
|
|
|
1153
1167
|
}
|
|
1154
1168
|
// Determine which gates to run
|
|
1155
1169
|
// WU-2252: Invariants gate runs FIRST and is included in both docs-only and regular modes
|
|
1170
|
+
// WU-1520: scriptName field maps gates to their package.json script for existence checking
|
|
1156
1171
|
const gates = effectiveDocsOnly
|
|
1157
1172
|
? [
|
|
1158
1173
|
// WU-2252: Invariants check runs first (non-bypassable)
|
|
1159
1174
|
{ name: GATE_NAMES.INVARIANTS, cmd: GATE_COMMANDS.INVARIANTS },
|
|
1160
|
-
{
|
|
1161
|
-
|
|
1175
|
+
{
|
|
1176
|
+
name: GATE_NAMES.FORMAT_CHECK,
|
|
1177
|
+
run: runFormatCheckGate,
|
|
1178
|
+
scriptName: SCRIPTS.FORMAT_CHECK,
|
|
1179
|
+
},
|
|
1180
|
+
{ name: GATE_NAMES.SPEC_LINTER, run: runSpecLinterGate, scriptName: SCRIPTS.SPEC_LINTER },
|
|
1162
1181
|
// WU-1467: prompts:lint removed -- was a stub (exit 0), not an authoritative gate
|
|
1163
1182
|
{ name: GATE_NAMES.BACKLOG_SYNC, run: runBacklogSyncGate },
|
|
1164
1183
|
// WU-2315: System map validation (warn-only until orphan docs are indexed)
|
|
@@ -1201,13 +1220,22 @@ async function executeGates(opts) {
|
|
|
1201
1220
|
: [
|
|
1202
1221
|
// WU-2252: Invariants check runs first (non-bypassable)
|
|
1203
1222
|
{ name: GATE_NAMES.INVARIANTS, cmd: GATE_COMMANDS.INVARIANTS },
|
|
1204
|
-
{
|
|
1223
|
+
{
|
|
1224
|
+
name: GATE_NAMES.FORMAT_CHECK,
|
|
1225
|
+
run: runFormatCheckGate,
|
|
1226
|
+
scriptName: SCRIPTS.FORMAT_CHECK,
|
|
1227
|
+
},
|
|
1205
1228
|
{
|
|
1206
1229
|
name: GATE_NAMES.LINT,
|
|
1207
1230
|
cmd: isFullLint ? pnpmCmd(SCRIPTS.LINT) : GATE_COMMANDS.INCREMENTAL,
|
|
1231
|
+
scriptName: SCRIPTS.LINT,
|
|
1232
|
+
},
|
|
1233
|
+
{
|
|
1234
|
+
name: GATE_NAMES.TYPECHECK,
|
|
1235
|
+
cmd: pnpmCmd(SCRIPTS.TYPECHECK),
|
|
1236
|
+
scriptName: SCRIPTS.TYPECHECK,
|
|
1208
1237
|
},
|
|
1209
|
-
{ name: GATE_NAMES.
|
|
1210
|
-
{ name: GATE_NAMES.SPEC_LINTER, run: runSpecLinterGate },
|
|
1238
|
+
{ name: GATE_NAMES.SPEC_LINTER, run: runSpecLinterGate, scriptName: SCRIPTS.SPEC_LINTER },
|
|
1211
1239
|
// WU-1467: prompts:lint removed -- was a stub (exit 0), not an authoritative gate
|
|
1212
1240
|
{ name: GATE_NAMES.BACKLOG_SYNC, run: runBacklogSyncGate },
|
|
1213
1241
|
{ name: GATE_NAMES.SUPABASE_DOCS_LINTER, run: runSupabaseDocsGate },
|
|
@@ -1278,6 +1306,32 @@ async function executeGates(opts) {
|
|
|
1278
1306
|
let lastFormatCheckFiles = null;
|
|
1279
1307
|
for (const gate of gates) {
|
|
1280
1308
|
let result;
|
|
1309
|
+
// WU-1520: Check if the gate's underlying script exists in package.json
|
|
1310
|
+
const gateScriptName = gate.scriptName ?? null;
|
|
1311
|
+
const gateAction = resolveGateAction(gate.name, gateScriptName, packageJsonScripts, isStrict);
|
|
1312
|
+
if (gateAction === 'skip') {
|
|
1313
|
+
const logLine = makeGateLogger({ agentLog, useAgentMode });
|
|
1314
|
+
const warningMsg = buildMissingScriptWarning(gateScriptName);
|
|
1315
|
+
logLine(`\n${warningMsg}\n`);
|
|
1316
|
+
gateResults.push({
|
|
1317
|
+
name: gate.name,
|
|
1318
|
+
status: 'skipped',
|
|
1319
|
+
durationMs: 0,
|
|
1320
|
+
reason: 'script not found in package.json',
|
|
1321
|
+
});
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
if (gateAction === 'fail') {
|
|
1325
|
+
const logLine = makeGateLogger({ agentLog, useAgentMode });
|
|
1326
|
+
logLine(`\nā "${gateScriptName}" script not found in package.json (--strict mode)\n`);
|
|
1327
|
+
gateResults.push({
|
|
1328
|
+
name: gate.name,
|
|
1329
|
+
status: 'failed',
|
|
1330
|
+
durationMs: 0,
|
|
1331
|
+
reason: 'script not found in package.json (strict mode)',
|
|
1332
|
+
});
|
|
1333
|
+
die(`${gate.name} failed: missing script "${gateScriptName}" in package.json (--strict mode requires all gate scripts)`);
|
|
1334
|
+
}
|
|
1281
1335
|
if (gate.run) {
|
|
1282
1336
|
result = await gate.run({ agentLog, useAgentMode });
|
|
1283
1337
|
if (gate.name === GATE_NAMES.FORMAT_CHECK) {
|
|
@@ -1328,6 +1382,13 @@ async function executeGates(opts) {
|
|
|
1328
1382
|
else {
|
|
1329
1383
|
writeSync(agentLog.logFd, `\n${msg}\n\n`);
|
|
1330
1384
|
}
|
|
1385
|
+
// WU-1520: Track skipped coverage gate in summary
|
|
1386
|
+
gateResults.push({
|
|
1387
|
+
name: gate.name,
|
|
1388
|
+
status: 'skipped',
|
|
1389
|
+
durationMs: 0,
|
|
1390
|
+
reason: 'changed tests - coverage is partial',
|
|
1391
|
+
});
|
|
1331
1392
|
continue;
|
|
1332
1393
|
}
|
|
1333
1394
|
// WU-1433: Special handling for coverage gate
|
|
@@ -1382,11 +1443,26 @@ async function executeGates(opts) {
|
|
|
1382
1443
|
else {
|
|
1383
1444
|
writeSync(agentLog.logFd, `\n${warnMsg}\n\n`);
|
|
1384
1445
|
}
|
|
1446
|
+
// WU-1520: Track warned gates in summary
|
|
1447
|
+
gateResults.push({
|
|
1448
|
+
name: gate.name,
|
|
1449
|
+
status: 'warned',
|
|
1450
|
+
durationMs: result.duration,
|
|
1451
|
+
});
|
|
1385
1452
|
continue;
|
|
1386
1453
|
}
|
|
1387
1454
|
if (gate.name === GATE_NAMES.FORMAT_CHECK) {
|
|
1388
1455
|
emitFormatCheckGuidance({ agentLog, useAgentMode, files: lastFormatCheckFiles });
|
|
1389
1456
|
}
|
|
1457
|
+
// WU-1520: Track failed gate before dying
|
|
1458
|
+
gateResults.push({
|
|
1459
|
+
name: gate.name,
|
|
1460
|
+
status: 'failed',
|
|
1461
|
+
durationMs: result.duration,
|
|
1462
|
+
});
|
|
1463
|
+
// WU-1520: Print summary before failing
|
|
1464
|
+
const logLine = makeGateLogger({ agentLog, useAgentMode });
|
|
1465
|
+
logLine(`\n${formatGateSummary(gateResults)}\n`);
|
|
1390
1466
|
if (useAgentMode) {
|
|
1391
1467
|
const tail = readLogTail(agentLog.logPath);
|
|
1392
1468
|
console.error(`\nā ${gate.name} failed (agent mode). Log: ${agentLog.logPath}\n`);
|
|
@@ -1396,11 +1472,20 @@ async function executeGates(opts) {
|
|
|
1396
1472
|
}
|
|
1397
1473
|
die(`${gate.name} failed`);
|
|
1398
1474
|
}
|
|
1475
|
+
// WU-1520: Track passed gate
|
|
1476
|
+
gateResults.push({
|
|
1477
|
+
name: gate.name,
|
|
1478
|
+
status: 'passed',
|
|
1479
|
+
durationMs: result.duration,
|
|
1480
|
+
});
|
|
1399
1481
|
}
|
|
1400
1482
|
// WU-2064: Create/update gates-latest.log symlink for easy agent access
|
|
1401
1483
|
if (agentLog) {
|
|
1402
1484
|
updateGatesLatestSymlink({ logPath: agentLog.logPath, cwd: process.cwd(), env: process.env });
|
|
1403
1485
|
}
|
|
1486
|
+
// WU-1520: Print gate summary showing passed/skipped/failed/warned
|
|
1487
|
+
const summaryLogLine = makeGateLogger({ agentLog, useAgentMode });
|
|
1488
|
+
summaryLogLine(`\n${formatGateSummary(gateResults)}`);
|
|
1404
1489
|
if (!useAgentMode) {
|
|
1405
1490
|
console.log('\nā
All gates passed!\n');
|
|
1406
1491
|
}
|