@lumenflow/cli 1.3.6 → 1.5.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 +31 -2
- package/dist/cli-entry-point.js +6 -0
- package/dist/docs-sync.js +467 -0
- package/dist/gates.js +77 -20
- package/dist/index.js +10 -0
- package/dist/init.js +860 -16
- package/dist/release.js +12 -6
- package/dist/wu-done.js +33 -0
- package/package.json +20 -7
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# @lumenflow/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@lumenflow/cli)
|
|
4
|
+
[](https://www.npmjs.com/package/@lumenflow/cli)
|
|
5
|
+
[](https://github.com/hellmai/os/blob/main/LICENSE)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
|
|
8
|
+
> Command-line interface for LumenFlow workflow framework
|
|
4
9
|
|
|
5
10
|
## Installation
|
|
6
11
|
|
|
@@ -63,6 +68,13 @@ This package provides CLI commands for the LumenFlow workflow framework, includi
|
|
|
63
68
|
| `initiative-status` | Show initiative status and progress |
|
|
64
69
|
| `initiative-add-wu` | Link a WU to an initiative |
|
|
65
70
|
|
|
71
|
+
### Setup Commands
|
|
72
|
+
|
|
73
|
+
| Command | Description |
|
|
74
|
+
| ----------- | --------------------------------------------------- |
|
|
75
|
+
| `init` | Scaffold LumenFlow into a project |
|
|
76
|
+
| `docs-sync` | Sync agent onboarding docs (for upgrading projects) |
|
|
77
|
+
|
|
66
78
|
### Other Commands
|
|
67
79
|
|
|
68
80
|
| Command | Description |
|
|
@@ -98,6 +110,23 @@ npx wu-claim --id WU-123 --lane operations
|
|
|
98
110
|
npx gates
|
|
99
111
|
```
|
|
100
112
|
|
|
113
|
+
## Global Flags
|
|
114
|
+
|
|
115
|
+
All commands support these flags:
|
|
116
|
+
|
|
117
|
+
| Flag | Description |
|
|
118
|
+
| ----------------- | ------------------------- |
|
|
119
|
+
| `--help`, `-h` | Show help for the command |
|
|
120
|
+
| `--version`, `-V` | Show version number |
|
|
121
|
+
| `--no-color` | Disable colored output |
|
|
122
|
+
|
|
123
|
+
## Environment Variables
|
|
124
|
+
|
|
125
|
+
| Variable | Description |
|
|
126
|
+
| ------------- | -------------------------------------------------------------------------------------- |
|
|
127
|
+
| `NO_COLOR` | Disable colored output when set (any value, per [no-color.org](https://no-color.org/)) |
|
|
128
|
+
| `FORCE_COLOR` | Override color level: `0` (disabled), `1` (basic), `2` (256 colors), `3` (16m colors) |
|
|
129
|
+
|
|
101
130
|
## Integration
|
|
102
131
|
|
|
103
132
|
The CLI integrates with other LumenFlow packages:
|
|
@@ -109,7 +138,7 @@ The CLI integrates with other LumenFlow packages:
|
|
|
109
138
|
|
|
110
139
|
## Documentation
|
|
111
140
|
|
|
112
|
-
For complete documentation, see
|
|
141
|
+
For complete documentation, see [lumenflow.dev](https://lumenflow.dev/reference/cli).
|
|
113
142
|
|
|
114
143
|
## License
|
|
115
144
|
|
package/dist/cli-entry-point.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* path but import.meta.url resolves to the real path - they never match
|
|
11
11
|
* so main() is never called.
|
|
12
12
|
*
|
|
13
|
+
* WU-1085: Initializes color support respecting NO_COLOR/FORCE_COLOR/--no-color
|
|
14
|
+
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```typescript
|
|
15
17
|
* // At the bottom of each CLI file:
|
|
@@ -21,13 +23,17 @@
|
|
|
21
23
|
* ```
|
|
22
24
|
*/
|
|
23
25
|
import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
|
|
26
|
+
import { initColorSupport } from '@lumenflow/core';
|
|
24
27
|
/**
|
|
25
28
|
* Wraps an async main function with proper error handling.
|
|
29
|
+
* WU-1085: Also initializes color support based on NO_COLOR/FORCE_COLOR/--no-color
|
|
26
30
|
*
|
|
27
31
|
* @param main - The async main function to execute
|
|
28
32
|
* @returns Promise that resolves when main completes (or after error handling)
|
|
29
33
|
*/
|
|
30
34
|
export async function runCLI(main) {
|
|
35
|
+
// WU-1085: Initialize color support before running command
|
|
36
|
+
initColorSupport();
|
|
31
37
|
try {
|
|
32
38
|
await main();
|
|
33
39
|
}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file docs-sync.ts
|
|
3
|
+
* LumenFlow docs:sync command for syncing agent docs to existing projects (WU-1083)
|
|
4
|
+
* WU-1085: Added createWUParser for proper --help support
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { createWUParser, WU_OPTIONS } from '@lumenflow/core';
|
|
9
|
+
/**
|
|
10
|
+
* WU-1085: CLI option definitions for docs-sync command
|
|
11
|
+
*/
|
|
12
|
+
const DOCS_SYNC_OPTIONS = {
|
|
13
|
+
vendor: {
|
|
14
|
+
name: 'vendor',
|
|
15
|
+
flags: '--vendor <type>',
|
|
16
|
+
description: 'Vendor type (claude, cursor, aider, all, none)',
|
|
17
|
+
default: 'claude',
|
|
18
|
+
},
|
|
19
|
+
force: WU_OPTIONS.force,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* WU-1085: Parse docs-sync command options using createWUParser
|
|
23
|
+
* Provides proper --help, --version, and option parsing
|
|
24
|
+
*/
|
|
25
|
+
export function parseDocsSyncOptions() {
|
|
26
|
+
const opts = createWUParser({
|
|
27
|
+
name: 'lumenflow-docs-sync',
|
|
28
|
+
description: 'Sync agent onboarding docs to existing projects (skips existing files by default)',
|
|
29
|
+
options: Object.values(DOCS_SYNC_OPTIONS),
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
force: opts.force ?? false,
|
|
33
|
+
vendor: opts.vendor ?? 'claude',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get current date in YYYY-MM-DD format
|
|
38
|
+
*/
|
|
39
|
+
function getCurrentDate() {
|
|
40
|
+
return new Date().toISOString().split('T')[0];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Process template content by replacing placeholders
|
|
44
|
+
*/
|
|
45
|
+
function processTemplate(content, tokens) {
|
|
46
|
+
let output = content;
|
|
47
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
48
|
+
output = output.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
|
|
49
|
+
}
|
|
50
|
+
return output;
|
|
51
|
+
}
|
|
52
|
+
function getRelativePath(targetDir, filePath) {
|
|
53
|
+
return path.relative(targetDir, filePath).split(path.sep).join('/');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create a directory if missing
|
|
57
|
+
*/
|
|
58
|
+
async function createDirectory(dirPath, result, targetDir) {
|
|
59
|
+
if (!fs.existsSync(dirPath)) {
|
|
60
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
61
|
+
result.created.push(getRelativePath(targetDir, dirPath));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a file, respecting force option
|
|
66
|
+
*/
|
|
67
|
+
async function createFile(filePath, content, force, result, targetDir) {
|
|
68
|
+
const relativePath = getRelativePath(targetDir, filePath);
|
|
69
|
+
if (fs.existsSync(filePath) && !force) {
|
|
70
|
+
result.skipped.push(relativePath);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const parentDir = path.dirname(filePath);
|
|
74
|
+
if (!fs.existsSync(parentDir)) {
|
|
75
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
fs.writeFileSync(filePath, content);
|
|
78
|
+
result.created.push(relativePath);
|
|
79
|
+
}
|
|
80
|
+
// Agent onboarding docs templates (duplicated from init.ts for modularity)
|
|
81
|
+
const QUICK_REF_COMMANDS_TEMPLATE = `# Quick Reference: LumenFlow Commands
|
|
82
|
+
|
|
83
|
+
**Last updated:** {{DATE}}
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Project Setup
|
|
88
|
+
|
|
89
|
+
| Command | Description |
|
|
90
|
+
| --------------------------------------------- | --------------------------------------- |
|
|
91
|
+
| \`pnpm exec lumenflow init\` | Scaffold minimal LumenFlow core |
|
|
92
|
+
| \`pnpm exec lumenflow init --full\` | Add docs/04-operations task scaffolding |
|
|
93
|
+
| \`pnpm exec lumenflow init --framework <name>\` | Add framework hint + overlay docs |
|
|
94
|
+
| \`pnpm exec lumenflow init --force\` | Overwrite existing files |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## WU Management
|
|
99
|
+
|
|
100
|
+
| Command | Description |
|
|
101
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
102
|
+
| \`pnpm wu:create --id WU-XXX --lane <Lane> --title "Title" --description "..." --acceptance "..." --code-paths "path" --test-paths-unit "path" --exposure backend-only --spec-refs "~/.lumenflow/plans/WU-XXX.md"\` | Create new WU |
|
|
103
|
+
| \`pnpm wu:claim --id WU-XXX --lane <Lane>\` | Claim WU (creates worktree) |
|
|
104
|
+
| \`pnpm wu:done --id WU-XXX\` | Complete WU (merge, stamp, cleanup) |
|
|
105
|
+
| \`pnpm wu:block --id WU-XXX --reason "Reason"\` | Block a WU |
|
|
106
|
+
| \`pnpm wu:unblock --id WU-XXX\` | Unblock a WU |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Gates
|
|
111
|
+
|
|
112
|
+
| Command | Description |
|
|
113
|
+
| ------------------------ | -------------------------- |
|
|
114
|
+
| \`pnpm gates\` | Run all quality gates |
|
|
115
|
+
| \`pnpm gates --docs-only\` | Run gates for docs changes |
|
|
116
|
+
| \`pnpm format\` | Format all files |
|
|
117
|
+
| \`pnpm lint\` | Run linter |
|
|
118
|
+
| \`pnpm typecheck\` | Run TypeScript check |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## File Paths
|
|
123
|
+
|
|
124
|
+
| Path | Description |
|
|
125
|
+
| ----------------------------------------- | -------------------- |
|
|
126
|
+
| \`docs/04-operations/tasks/wu/WU-XXX.yaml\` | WU specification |
|
|
127
|
+
| \`docs/04-operations/tasks/status.md\` | Current status board |
|
|
128
|
+
| \`.lumenflow/stamps/WU-XXX.done\` | Completion stamp |
|
|
129
|
+
| \`worktrees/<lane>-wu-xxx/\` | Worktree directory |
|
|
130
|
+
`;
|
|
131
|
+
const FIRST_WU_MISTAKES_TEMPLATE = `# First WU Mistakes
|
|
132
|
+
|
|
133
|
+
**Last updated:** {{DATE}}
|
|
134
|
+
|
|
135
|
+
Common mistakes agents make on their first WU, and how to avoid them.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Mistake 1: Not Using Worktrees
|
|
140
|
+
|
|
141
|
+
### Wrong
|
|
142
|
+
|
|
143
|
+
\`\`\`bash
|
|
144
|
+
# Working directly in main
|
|
145
|
+
vim src/feature.ts
|
|
146
|
+
git commit -m "feat: add feature"
|
|
147
|
+
git push origin main
|
|
148
|
+
\`\`\`
|
|
149
|
+
|
|
150
|
+
### Right
|
|
151
|
+
|
|
152
|
+
\`\`\`bash
|
|
153
|
+
# Claim first, then work in worktree
|
|
154
|
+
pnpm wu:claim --id WU-123 --lane Core
|
|
155
|
+
cd worktrees/core-wu-123
|
|
156
|
+
vim src/feature.ts
|
|
157
|
+
git commit -m "feat: add feature"
|
|
158
|
+
git push origin lane/core/wu-123
|
|
159
|
+
cd /path/to/main
|
|
160
|
+
pnpm wu:done --id WU-123
|
|
161
|
+
\`\`\`
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Mistake 2: Forgetting to Run wu:done
|
|
166
|
+
|
|
167
|
+
**TL;DR:** After gates pass, ALWAYS run \`pnpm wu:done --id WU-XXX\`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Mistake 3: Working Outside code_paths
|
|
172
|
+
|
|
173
|
+
Only edit files within the specified \`code_paths\`.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Quick Checklist
|
|
178
|
+
|
|
179
|
+
- [ ] Claim the WU with \`pnpm wu:claim\`
|
|
180
|
+
- [ ] cd to the worktree IMMEDIATELY
|
|
181
|
+
- [ ] Work only in the worktree
|
|
182
|
+
- [ ] Run gates before wu:done
|
|
183
|
+
- [ ] ALWAYS run wu:done
|
|
184
|
+
`;
|
|
185
|
+
const TROUBLESHOOTING_WU_DONE_TEMPLATE = `# Troubleshooting: wu:done Not Run
|
|
186
|
+
|
|
187
|
+
**Last updated:** {{DATE}}
|
|
188
|
+
|
|
189
|
+
This is the most common mistake agents make.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## The Fix
|
|
194
|
+
|
|
195
|
+
### Rule: ALWAYS Run wu:done
|
|
196
|
+
|
|
197
|
+
After gates pass, you MUST run:
|
|
198
|
+
|
|
199
|
+
\`\`\`bash
|
|
200
|
+
cd /path/to/main
|
|
201
|
+
pnpm wu:done --id WU-XXX
|
|
202
|
+
\`\`\`
|
|
203
|
+
|
|
204
|
+
Do NOT:
|
|
205
|
+
|
|
206
|
+
- Ask "Should I run wu:done?"
|
|
207
|
+
- Write "To Complete: pnpm wu:done"
|
|
208
|
+
- Wait for permission
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## What wu:done Does
|
|
213
|
+
|
|
214
|
+
1. Validates the worktree exists and has commits
|
|
215
|
+
2. Runs gates in the worktree (not main)
|
|
216
|
+
3. Fast-forward merges to main
|
|
217
|
+
4. Creates the done stamp
|
|
218
|
+
5. Updates status and backlog docs
|
|
219
|
+
6. Removes the worktree
|
|
220
|
+
7. Pushes to origin
|
|
221
|
+
`;
|
|
222
|
+
const AGENT_SAFETY_CARD_TEMPLATE = `# Agent Safety Card
|
|
223
|
+
|
|
224
|
+
**Last updated:** {{DATE}}
|
|
225
|
+
|
|
226
|
+
Quick reference for AI agents working in LumenFlow projects.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Stop and Ask When
|
|
231
|
+
|
|
232
|
+
- Same error repeats 3 times
|
|
233
|
+
- Auth or permissions changes needed
|
|
234
|
+
- PII/PHI/secrets involved
|
|
235
|
+
- Cloud spend decisions
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Never Do
|
|
240
|
+
|
|
241
|
+
| Action | Why |
|
|
242
|
+
| ------------------------ | ---------------- |
|
|
243
|
+
| \`git reset --hard\` | Data loss |
|
|
244
|
+
| \`git push --force\` | History rewrite |
|
|
245
|
+
| \`--no-verify\` | Bypasses safety |
|
|
246
|
+
| Work in main after claim | Breaks isolation |
|
|
247
|
+
| Skip wu:done | Incomplete WU |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Always Do
|
|
252
|
+
|
|
253
|
+
| Action | Why |
|
|
254
|
+
| -------------------------- | ---------------- |
|
|
255
|
+
| Read WU spec first | Understand scope |
|
|
256
|
+
| cd to worktree after claim | Isolation |
|
|
257
|
+
| Write tests before code | TDD |
|
|
258
|
+
| Run gates before wu:done | Quality |
|
|
259
|
+
| Run wu:done | Complete WU |
|
|
260
|
+
`;
|
|
261
|
+
const WU_CREATE_CHECKLIST_TEMPLATE = `# WU Creation Checklist
|
|
262
|
+
|
|
263
|
+
**Last updated:** {{DATE}}
|
|
264
|
+
|
|
265
|
+
Before running \`pnpm wu:create\`, verify these items.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Step 1: Check Valid Lanes
|
|
270
|
+
|
|
271
|
+
\`\`\`bash
|
|
272
|
+
grep -A 30 "lanes:" .lumenflow.config.yaml
|
|
273
|
+
\`\`\`
|
|
274
|
+
|
|
275
|
+
**Format:** \`"Parent: Sublane"\` (colon + single space)
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Step 2: Required Fields
|
|
280
|
+
|
|
281
|
+
| Field | Required For | Example |
|
|
282
|
+
|-------|--------------|---------|
|
|
283
|
+
| \`--id\` | All | \`WU-1234\` |
|
|
284
|
+
| \`--lane\` | All | \`"Experience: Chat"\` |
|
|
285
|
+
| \`--title\` | All | \`"Add feature"\` |
|
|
286
|
+
| \`--description\` | All | \`"Context: ... Problem: ... Solution: ..."\` |
|
|
287
|
+
| \`--acceptance\` | All | \`--acceptance "Works"\` (repeatable) |
|
|
288
|
+
| \`--exposure\` | All | \`ui\`, \`api\`, \`backend-only\`, \`documentation\` |
|
|
289
|
+
| \`--code-paths\` | Code WUs | \`"src/a.ts,src/b.ts"\` |
|
|
290
|
+
| \`--test-paths-unit\` | Code WUs | \`"src/__tests__/a.test.ts"\` |
|
|
291
|
+
| \`--spec-refs\` | Feature WUs | \`"~/.lumenflow/plans/WU-XXX.md"\` |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Step 3: Plan Storage
|
|
296
|
+
|
|
297
|
+
Plans go in \`~/.lumenflow/plans/\` (NOT in project):
|
|
298
|
+
|
|
299
|
+
\`\`\`bash
|
|
300
|
+
mkdir -p ~/.lumenflow/plans
|
|
301
|
+
vim ~/.lumenflow/plans/WU-XXX-plan.md
|
|
302
|
+
\`\`\`
|
|
303
|
+
|
|
304
|
+
Reference in wu:create:
|
|
305
|
+
\`\`\`bash
|
|
306
|
+
--spec-refs "~/.lumenflow/plans/WU-XXX-plan.md"
|
|
307
|
+
\`\`\`
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Step 4: Validate First
|
|
312
|
+
|
|
313
|
+
\`\`\`bash
|
|
314
|
+
pnpm wu:create --id WU-XXX ... --validate
|
|
315
|
+
\`\`\`
|
|
316
|
+
|
|
317
|
+
Fix errors, then remove \`--validate\` to create.
|
|
318
|
+
`;
|
|
319
|
+
// Claude skills templates
|
|
320
|
+
const WU_LIFECYCLE_SKILL_TEMPLATE = `---
|
|
321
|
+
name: wu-lifecycle
|
|
322
|
+
description: Work Unit claim/block/done workflow automation.
|
|
323
|
+
version: 1.0.0
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
# WU Lifecycle Skill
|
|
327
|
+
|
|
328
|
+
## State Machine
|
|
329
|
+
|
|
330
|
+
\`\`\`
|
|
331
|
+
ready -> in_progress -> waiting/blocked -> done
|
|
332
|
+
\`\`\`
|
|
333
|
+
|
|
334
|
+
## Core Commands
|
|
335
|
+
|
|
336
|
+
\`\`\`bash
|
|
337
|
+
# Claim WU
|
|
338
|
+
pnpm wu:claim --id WU-XXX --lane <lane>
|
|
339
|
+
cd worktrees/<lane>-wu-xxx # IMMEDIATELY
|
|
340
|
+
|
|
341
|
+
# Complete WU (from main)
|
|
342
|
+
cd ../..
|
|
343
|
+
pnpm wu:done --id WU-XXX
|
|
344
|
+
\`\`\`
|
|
345
|
+
`;
|
|
346
|
+
const WORKTREE_DISCIPLINE_SKILL_TEMPLATE = `---
|
|
347
|
+
name: worktree-discipline
|
|
348
|
+
description: Prevents the "absolute path trap" in Write/Edit/Read tools.
|
|
349
|
+
version: 1.0.0
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
# Worktree Discipline: Absolute Path Trap Prevention
|
|
353
|
+
|
|
354
|
+
**Purpose**: Prevent AI agents from bypassing worktree isolation via absolute file paths.
|
|
355
|
+
|
|
356
|
+
## The Absolute Path Trap
|
|
357
|
+
|
|
358
|
+
**Problem**: AI agents using Write/Edit/Read tools can bypass worktree isolation by passing absolute paths.
|
|
359
|
+
|
|
360
|
+
## Golden Rules
|
|
361
|
+
|
|
362
|
+
1. **Always verify pwd** before file operations
|
|
363
|
+
2. **Never use absolute paths** in Write/Edit/Read tools
|
|
364
|
+
3. **When in doubt, use relative paths**
|
|
365
|
+
`;
|
|
366
|
+
const LUMENFLOW_GATES_SKILL_TEMPLATE = `---
|
|
367
|
+
name: lumenflow-gates
|
|
368
|
+
description: Quality gates troubleshooting (format, lint, typecheck, tests).
|
|
369
|
+
version: 1.0.0
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
# LumenFlow Gates Skill
|
|
373
|
+
|
|
374
|
+
## Gate Sequence
|
|
375
|
+
|
|
376
|
+
\`\`\`
|
|
377
|
+
pnpm gates = format:check -> lint -> typecheck -> spec:linter -> tests
|
|
378
|
+
\`\`\`
|
|
379
|
+
|
|
380
|
+
## Fix Patterns
|
|
381
|
+
|
|
382
|
+
| Gate | Auto-fix | Manual |
|
|
383
|
+
| --------- | --------------- | ----------------------------------- |
|
|
384
|
+
| Format | \`pnpm format\` | - |
|
|
385
|
+
| Lint | \`pnpm lint:fix\` | Fix reported issues |
|
|
386
|
+
| Typecheck | - | Fix type errors (first error first) |
|
|
387
|
+
| Tests | - | Debug, fix mocks, update snapshots |
|
|
388
|
+
`;
|
|
389
|
+
/**
|
|
390
|
+
* Sync agent onboarding docs to an existing project
|
|
391
|
+
*/
|
|
392
|
+
export async function syncAgentDocs(targetDir, options) {
|
|
393
|
+
const result = {
|
|
394
|
+
created: [],
|
|
395
|
+
skipped: [],
|
|
396
|
+
};
|
|
397
|
+
const tokens = {
|
|
398
|
+
DATE: getCurrentDate(),
|
|
399
|
+
};
|
|
400
|
+
const onboardingDir = path.join(targetDir, 'docs', '04-operations', '_frameworks', 'lumenflow', 'agent', 'onboarding');
|
|
401
|
+
await createDirectory(onboardingDir, result, targetDir);
|
|
402
|
+
await createFile(path.join(onboardingDir, 'quick-ref-commands.md'), processTemplate(QUICK_REF_COMMANDS_TEMPLATE, tokens), options.force, result, targetDir);
|
|
403
|
+
await createFile(path.join(onboardingDir, 'first-wu-mistakes.md'), processTemplate(FIRST_WU_MISTAKES_TEMPLATE, tokens), options.force, result, targetDir);
|
|
404
|
+
await createFile(path.join(onboardingDir, 'troubleshooting-wu-done.md'), processTemplate(TROUBLESHOOTING_WU_DONE_TEMPLATE, tokens), options.force, result, targetDir);
|
|
405
|
+
await createFile(path.join(onboardingDir, 'agent-safety-card.md'), processTemplate(AGENT_SAFETY_CARD_TEMPLATE, tokens), options.force, result, targetDir);
|
|
406
|
+
await createFile(path.join(onboardingDir, 'wu-create-checklist.md'), processTemplate(WU_CREATE_CHECKLIST_TEMPLATE, tokens), options.force, result, targetDir);
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Sync Claude skills to an existing project
|
|
411
|
+
*/
|
|
412
|
+
export async function syncSkills(targetDir, options) {
|
|
413
|
+
const result = {
|
|
414
|
+
created: [],
|
|
415
|
+
skipped: [],
|
|
416
|
+
};
|
|
417
|
+
const vendor = options.vendor ?? 'none';
|
|
418
|
+
if (vendor !== 'claude' && vendor !== 'all') {
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
const tokens = {
|
|
422
|
+
DATE: getCurrentDate(),
|
|
423
|
+
};
|
|
424
|
+
const skillsDir = path.join(targetDir, '.claude', 'skills');
|
|
425
|
+
// wu-lifecycle skill
|
|
426
|
+
const wuLifecycleDir = path.join(skillsDir, 'wu-lifecycle');
|
|
427
|
+
await createDirectory(wuLifecycleDir, result, targetDir);
|
|
428
|
+
await createFile(path.join(wuLifecycleDir, 'SKILL.md'), processTemplate(WU_LIFECYCLE_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
|
|
429
|
+
// worktree-discipline skill
|
|
430
|
+
const worktreeDir = path.join(skillsDir, 'worktree-discipline');
|
|
431
|
+
await createDirectory(worktreeDir, result, targetDir);
|
|
432
|
+
await createFile(path.join(worktreeDir, 'SKILL.md'), processTemplate(WORKTREE_DISCIPLINE_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
|
|
433
|
+
// lumenflow-gates skill
|
|
434
|
+
const gatesDir = path.join(skillsDir, 'lumenflow-gates');
|
|
435
|
+
await createDirectory(gatesDir, result, targetDir);
|
|
436
|
+
await createFile(path.join(gatesDir, 'SKILL.md'), processTemplate(LUMENFLOW_GATES_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* CLI entry point for docs:sync command
|
|
441
|
+
* WU-1085: Updated to use parseDocsSyncOptions for proper --help support
|
|
442
|
+
*/
|
|
443
|
+
export async function main() {
|
|
444
|
+
const opts = parseDocsSyncOptions();
|
|
445
|
+
const targetDir = process.cwd();
|
|
446
|
+
console.log('[lumenflow docs:sync] Syncing agent documentation...');
|
|
447
|
+
console.log(` Vendor: ${opts.vendor}`);
|
|
448
|
+
console.log(` Force: ${opts.force}`);
|
|
449
|
+
const docsResult = await syncAgentDocs(targetDir, { force: opts.force });
|
|
450
|
+
const skillsResult = await syncSkills(targetDir, { force: opts.force, vendor: opts.vendor });
|
|
451
|
+
const created = [...docsResult.created, ...skillsResult.created];
|
|
452
|
+
const skipped = [...docsResult.skipped, ...skillsResult.skipped];
|
|
453
|
+
if (created.length > 0) {
|
|
454
|
+
console.log('\nCreated:');
|
|
455
|
+
created.forEach((f) => console.log(` + ${f}`));
|
|
456
|
+
}
|
|
457
|
+
if (skipped.length > 0) {
|
|
458
|
+
console.log('\nSkipped (already exists, use --force to overwrite):');
|
|
459
|
+
skipped.forEach((f) => console.log(` - ${f}`));
|
|
460
|
+
}
|
|
461
|
+
console.log('\n[lumenflow docs:sync] Done!');
|
|
462
|
+
}
|
|
463
|
+
// CLI entry point (WU-1071 pattern: import.meta.main)
|
|
464
|
+
import { runCLI } from './cli-entry-point.js';
|
|
465
|
+
if (import.meta.main) {
|
|
466
|
+
runCLI(main);
|
|
467
|
+
}
|
package/dist/gates.js
CHANGED
|
@@ -54,35 +54,92 @@ import { buildGatesLogPath, shouldUseGatesAgentMode, updateGatesLatestSymlink, }
|
|
|
54
54
|
import { detectRiskTier, RISK_TIERS, } from '@lumenflow/core/dist/risk-detector.js';
|
|
55
55
|
// WU-2252: Import invariants runner for first-check validation
|
|
56
56
|
import { runInvariants } from '@lumenflow/core/dist/invariants-runner.js';
|
|
57
|
-
import {
|
|
57
|
+
import { createWUParser } from '@lumenflow/core/dist/arg-parser.js';
|
|
58
58
|
import { BRANCHES, PACKAGES, PKG_MANAGER, PKG_FLAGS, ESLINT_FLAGS, ESLINT_COMMANDS, ESLINT_DEFAULTS, SCRIPTS, CACHE_STRATEGIES, DIRECTORIES, GATE_NAMES, GATE_COMMANDS, TOOL_PATHS, CLI_MODES, EXIT_CODES, FILE_SYSTEM, PRETTIER_ARGS, PRETTIER_FLAGS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
/**
|
|
60
|
+
* WU-1087: Gates-specific option definitions for createWUParser.
|
|
61
|
+
* Exported for testing and consistency with other CLI commands.
|
|
62
|
+
*/
|
|
63
|
+
export const GATES_OPTIONS = {
|
|
64
|
+
docsOnly: {
|
|
65
|
+
name: 'docsOnly',
|
|
66
|
+
flags: '--docs-only',
|
|
67
|
+
description: 'Run docs-only gates (format, spec-linter, prompts-lint, backlog-sync)',
|
|
68
|
+
},
|
|
69
|
+
fullLint: {
|
|
70
|
+
name: 'fullLint',
|
|
71
|
+
flags: '--full-lint',
|
|
72
|
+
description: 'Run full lint instead of incremental',
|
|
73
|
+
},
|
|
74
|
+
fullTests: {
|
|
75
|
+
name: 'fullTests',
|
|
76
|
+
flags: '--full-tests',
|
|
77
|
+
description: 'Run full test suite instead of incremental',
|
|
78
|
+
},
|
|
79
|
+
fullCoverage: {
|
|
80
|
+
name: 'fullCoverage',
|
|
81
|
+
flags: '--full-coverage',
|
|
82
|
+
description: 'Force full test suite and coverage gate (implies --full-tests)',
|
|
83
|
+
},
|
|
84
|
+
coverageMode: {
|
|
85
|
+
name: 'coverageMode',
|
|
86
|
+
flags: '--coverage-mode <mode>',
|
|
87
|
+
description: 'Coverage gate mode: "warn" logs warnings, "block" fails gate',
|
|
88
|
+
default: 'block',
|
|
89
|
+
},
|
|
90
|
+
verbose: {
|
|
91
|
+
name: 'verbose',
|
|
92
|
+
flags: '--verbose',
|
|
93
|
+
description: 'Stream output in agent mode instead of logging to file',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* WU-1087: Parse gates options using createWUParser for consistency.
|
|
98
|
+
* Handles pnpm's `--` separator and provides automatic --help support.
|
|
99
|
+
*
|
|
100
|
+
* @returns Parsed options object
|
|
101
|
+
*/
|
|
102
|
+
export function parseGatesOptions() {
|
|
61
103
|
// WU-2465: Pre-filter argv to handle pnpm's `--` separator
|
|
62
104
|
// When invoked via `pnpm gates -- --docs-only`, pnpm passes ["--", "--docs-only"]
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
// Remove it if it's followed by an option (starts with -)
|
|
105
|
+
// createWUParser's default filtering removes all `--`, but we need smarter handling:
|
|
106
|
+
// Remove `--` only if it's followed by an option (starts with -)
|
|
107
|
+
const originalArgv = process.argv;
|
|
108
|
+
const filteredArgv = originalArgv.filter((arg, index, arr) => {
|
|
68
109
|
if (arg === '--') {
|
|
69
110
|
const nextArg = arr[index + 1];
|
|
70
111
|
return nextArg && !nextArg.startsWith('-');
|
|
71
112
|
}
|
|
72
113
|
return true;
|
|
73
114
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
115
|
+
// Temporarily replace process.argv for createWUParser
|
|
116
|
+
process.argv = filteredArgv;
|
|
117
|
+
try {
|
|
118
|
+
const opts = createWUParser({
|
|
119
|
+
name: 'gates',
|
|
120
|
+
description: 'Run quality gates with support for docs-only mode, incremental linting, and tiered testing',
|
|
121
|
+
options: Object.values(GATES_OPTIONS),
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
docsOnly: opts.docsOnly,
|
|
125
|
+
fullLint: opts.fullLint,
|
|
126
|
+
fullTests: opts.fullTests,
|
|
127
|
+
fullCoverage: opts.fullCoverage,
|
|
128
|
+
coverageMode: opts.coverageMode ?? 'block',
|
|
129
|
+
verbose: opts.verbose,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
// Restore original process.argv
|
|
134
|
+
process.argv = originalArgv;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* @deprecated Use parseGatesOptions() instead (WU-1087)
|
|
139
|
+
* Kept for backward compatibility during migration.
|
|
140
|
+
*/
|
|
141
|
+
function parseGatesArgs(argv = process.argv) {
|
|
142
|
+
return parseGatesOptions();
|
|
86
143
|
}
|
|
87
144
|
/**
|
|
88
145
|
* Build a pnpm command string
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lumenflow/cli - Command-line interface for LumenFlow workflow framework
|
|
3
|
+
*
|
|
4
|
+
* This package provides CLI commands for the LumenFlow workflow framework.
|
|
5
|
+
* Most functionality is exposed via bin commands, but the cli-entry-point
|
|
6
|
+
* helper is exported for use in custom CLI wrappers.
|
|
7
|
+
*
|
|
8
|
+
* @see https://lumenflow.dev/reference/cli
|
|
9
|
+
*/
|
|
10
|
+
export { runCLI } from './cli-entry-point.js';
|