@lumenflow/cli 2.5.1 → 2.7.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/dist/__tests__/gates-config.test.js +304 -0
- package/dist/__tests__/wu-proto.test.js +97 -0
- package/dist/gates.js +64 -15
- package/dist/init.js +13 -1
- package/dist/wu-proto.js +330 -0
- package/package.json +7 -6
- package/templates/core/.husky/pre-commit.template +93 -0
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +27 -0
- package/templates/core/ai/onboarding/rapid-prototyping.md +143 -0
- package/templates/core/ai/onboarding/starting-prompt.md.template +3 -3
- package/templates/vendors/claude/.claude/CLAUDE.md.template +25 -0
- package/templates/vendors/claude/.claude/hooks/enforce-worktree.sh +135 -0
package/dist/wu-proto.js
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
|
+
/**
|
|
4
|
+
* WU Proto Helper (WU-1359)
|
|
5
|
+
*
|
|
6
|
+
* Convenience command for rapid prototyping that creates a WU with
|
|
7
|
+
* type: prototype and relaxed validation, then immediately claims it.
|
|
8
|
+
*
|
|
9
|
+
* Key differences from wu:create:
|
|
10
|
+
* - type: prototype (not feature)
|
|
11
|
+
* - No --acceptance required
|
|
12
|
+
* - No --exposure required
|
|
13
|
+
* - No --code-paths required
|
|
14
|
+
* - No --test-paths required
|
|
15
|
+
* - No --spec-refs required
|
|
16
|
+
* - Automatically claims the WU after creation
|
|
17
|
+
* - Prints cd command to worktree
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* pnpm wu:proto --lane "Framework: CLI" --title "Quick experiment"
|
|
21
|
+
*
|
|
22
|
+
* Context: WU-1359 (enhance init output and add wu:proto command)
|
|
23
|
+
*/
|
|
24
|
+
import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
25
|
+
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
26
|
+
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import { stringifyYAML } from '@lumenflow/core/dist/wu-yaml.js';
|
|
29
|
+
import { todayISO } from '@lumenflow/core/dist/date-utils.js';
|
|
30
|
+
import { validateLaneFormat } from '@lumenflow/core/dist/lane-checker.js';
|
|
31
|
+
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
32
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
33
|
+
import { validateWU } from '@lumenflow/core/dist/wu-schema.js';
|
|
34
|
+
import { COMMIT_FORMATS, FILE_SYSTEM, STRING_LITERALS } from '@lumenflow/core/dist/wu-constants.js';
|
|
35
|
+
import { ensureOnMain } from '@lumenflow/core/dist/wu-helpers.js';
|
|
36
|
+
import { withMicroWorktree } from '@lumenflow/core/dist/micro-worktree.js';
|
|
37
|
+
import { generateWuIdWithRetry } from '@lumenflow/core/dist/wu-id-generator.js';
|
|
38
|
+
import { parseBacklogFrontmatter } from '@lumenflow/core/dist/backlog-parser.js';
|
|
39
|
+
import { execFileSync } from 'node:child_process';
|
|
40
|
+
/** Log prefix for console output */
|
|
41
|
+
const LOG_PREFIX = '[wu:proto]';
|
|
42
|
+
/** Micro-worktree operation name */
|
|
43
|
+
const OPERATION_NAME = 'wu-proto';
|
|
44
|
+
/** Default priority for prototype WUs */
|
|
45
|
+
const DEFAULT_PRIORITY = 'P3';
|
|
46
|
+
/** Prototype WU type */
|
|
47
|
+
const PROTOTYPE_TYPE = 'prototype';
|
|
48
|
+
/**
|
|
49
|
+
* Validate prototype WU spec (relaxed validation)
|
|
50
|
+
*
|
|
51
|
+
* Unlike wu:create, this has minimal requirements:
|
|
52
|
+
* - lane is required
|
|
53
|
+
* - title is required
|
|
54
|
+
* - Everything else is optional
|
|
55
|
+
*
|
|
56
|
+
* @param params - Validation parameters
|
|
57
|
+
* @returns {{ valid: boolean, errors: string[] }}
|
|
58
|
+
*/
|
|
59
|
+
export function validateProtoSpec({ id: _id, lane, title, opts: _opts = {}, }) {
|
|
60
|
+
const errors = [];
|
|
61
|
+
if (!lane || lane.trim() === '') {
|
|
62
|
+
errors.push('--lane is required');
|
|
63
|
+
}
|
|
64
|
+
if (!title || title.trim() === '') {
|
|
65
|
+
errors.push('--title is required');
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
valid: errors.length === 0,
|
|
69
|
+
errors,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build prototype WU content
|
|
74
|
+
* @returns WU content object for YAML serialization
|
|
75
|
+
*/
|
|
76
|
+
function buildProtoWUContent({ id, lane, title, priority, created, opts, }) {
|
|
77
|
+
const { description, codePaths, labels, assignedTo } = opts;
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
title,
|
|
81
|
+
lane,
|
|
82
|
+
type: PROTOTYPE_TYPE,
|
|
83
|
+
status: 'ready',
|
|
84
|
+
priority,
|
|
85
|
+
created,
|
|
86
|
+
description: description || '',
|
|
87
|
+
// Prototype WUs have minimal default acceptance
|
|
88
|
+
acceptance: ['Prototype demonstrates concept'],
|
|
89
|
+
code_paths: codePaths ?? [],
|
|
90
|
+
tests: {
|
|
91
|
+
manual: [],
|
|
92
|
+
unit: [],
|
|
93
|
+
e2e: [],
|
|
94
|
+
},
|
|
95
|
+
artifacts: [`.lumenflow/stamps/${id}.done`],
|
|
96
|
+
dependencies: [],
|
|
97
|
+
risks: [],
|
|
98
|
+
notes: 'Prototype WU - relaxed validation applies',
|
|
99
|
+
requires_review: false,
|
|
100
|
+
...(labels?.length && { labels }),
|
|
101
|
+
...(assignedTo && { assigned_to: assignedTo }),
|
|
102
|
+
// WU-1359: Prototype WUs set exposure to backend-only by default
|
|
103
|
+
exposure: 'backend-only',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create prototype WU YAML in micro-worktree
|
|
108
|
+
* @returns Relative path to created WU YAML file
|
|
109
|
+
*/
|
|
110
|
+
function createProtoWUYamlInWorktree(worktreePath, id, lane, title, priority, opts) {
|
|
111
|
+
const wuRelativePath = WU_PATHS.WU(id);
|
|
112
|
+
const wuAbsolutePath = join(worktreePath, wuRelativePath);
|
|
113
|
+
const wuDir = join(worktreePath, WU_PATHS.WU_DIR());
|
|
114
|
+
if (!existsSync(wuDir)) {
|
|
115
|
+
mkdirSync(wuDir, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
const today = todayISO();
|
|
118
|
+
const wuContent = buildProtoWUContent({
|
|
119
|
+
id,
|
|
120
|
+
lane,
|
|
121
|
+
title,
|
|
122
|
+
priority,
|
|
123
|
+
created: today,
|
|
124
|
+
opts,
|
|
125
|
+
});
|
|
126
|
+
// Validate WU structure before writing
|
|
127
|
+
const validationResult = validateWU(wuContent);
|
|
128
|
+
if (!validationResult.success) {
|
|
129
|
+
const errors = validationResult.error.issues
|
|
130
|
+
.map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)
|
|
131
|
+
.join(STRING_LITERALS.NEWLINE);
|
|
132
|
+
die(`${LOG_PREFIX} WU validation failed:\n\n${errors}`);
|
|
133
|
+
}
|
|
134
|
+
const yamlContent = stringifyYAML(validationResult.data, { lineWidth: -1 });
|
|
135
|
+
writeFileSync(wuAbsolutePath, yamlContent, { encoding: FILE_SYSTEM.UTF8 });
|
|
136
|
+
console.log(`${LOG_PREFIX} Created ${id}.yaml in micro-worktree`);
|
|
137
|
+
return wuRelativePath;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Update backlog.md in micro-worktree
|
|
141
|
+
* @returns Relative path to updated backlog file
|
|
142
|
+
*/
|
|
143
|
+
function updateBacklogInWorktree(worktreePath, id, lane, title) {
|
|
144
|
+
const backlogRelativePath = WU_PATHS.BACKLOG();
|
|
145
|
+
const backlogAbsolutePath = join(worktreePath, backlogRelativePath);
|
|
146
|
+
if (!existsSync(backlogAbsolutePath)) {
|
|
147
|
+
die(`Backlog not found: ${backlogAbsolutePath}`);
|
|
148
|
+
}
|
|
149
|
+
const { frontmatter, markdown } = parseBacklogFrontmatter(backlogAbsolutePath);
|
|
150
|
+
if (!frontmatter?.sections?.ready?.heading) {
|
|
151
|
+
die('Invalid backlog frontmatter: Missing sections.ready.heading');
|
|
152
|
+
}
|
|
153
|
+
const readyHeading = frontmatter.sections.ready.heading;
|
|
154
|
+
const lines = markdown.split(STRING_LITERALS.NEWLINE);
|
|
155
|
+
const headingIndex = lines.findIndex((line) => line === readyHeading);
|
|
156
|
+
if (headingIndex === -1) {
|
|
157
|
+
die(`Could not find Ready section heading: '${readyHeading}'`);
|
|
158
|
+
}
|
|
159
|
+
const insertionIndex = headingIndex + 2;
|
|
160
|
+
const newEntry = `- [${id} - ${title}](wu/${id}.yaml) - ${lane}`;
|
|
161
|
+
lines.splice(insertionIndex, 0, newEntry);
|
|
162
|
+
const updatedMarkdown = lines.join(STRING_LITERALS.NEWLINE);
|
|
163
|
+
const updatedBacklog = `---\n${stringifyYAML(frontmatter, { lineWidth: -1 })}---\n${updatedMarkdown}`;
|
|
164
|
+
writeFileSync(backlogAbsolutePath, updatedBacklog, {
|
|
165
|
+
encoding: FILE_SYSTEM.UTF8,
|
|
166
|
+
});
|
|
167
|
+
console.log(`${LOG_PREFIX} Updated backlog.md in micro-worktree`);
|
|
168
|
+
return backlogRelativePath;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get default assigned_to value from git config user.email
|
|
172
|
+
*/
|
|
173
|
+
async function getDefaultAssignedTo() {
|
|
174
|
+
try {
|
|
175
|
+
const email = await getGitForCwd().getConfigValue('user.email');
|
|
176
|
+
return email || '';
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return '';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Regex to extract worktree path from wu:claim output */
|
|
183
|
+
const WORKTREE_PATH_REGEX = /Worktree:\s*(\S+)/;
|
|
184
|
+
/**
|
|
185
|
+
* Claim the WU after creation using execFileSync (safe from shell injection)
|
|
186
|
+
* @returns Path to the created worktree
|
|
187
|
+
*/
|
|
188
|
+
function claimWU(wuId, lane) {
|
|
189
|
+
console.log(`${LOG_PREFIX} Claiming WU ${wuId}...`);
|
|
190
|
+
try {
|
|
191
|
+
// Use execFileSync for safety (no shell injection risk)
|
|
192
|
+
// Use process.execPath to get absolute path to node, then run pnpm via npx
|
|
193
|
+
const result = execFileSync(process.execPath, [
|
|
194
|
+
'--no-warnings',
|
|
195
|
+
'--experimental-import-meta-resolve',
|
|
196
|
+
...process.execArgv.filter((a) => !a.startsWith('--inspect')),
|
|
197
|
+
require.resolve('.bin/wu-claim'),
|
|
198
|
+
'--id',
|
|
199
|
+
wuId,
|
|
200
|
+
'--lane',
|
|
201
|
+
lane,
|
|
202
|
+
], {
|
|
203
|
+
encoding: 'utf-8',
|
|
204
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
205
|
+
cwd: process.cwd(),
|
|
206
|
+
});
|
|
207
|
+
// Extract worktree path from output using regex exec (sonarjs/prefer-regexp-exec)
|
|
208
|
+
const worktreeMatch = WORKTREE_PATH_REGEX.exec(result);
|
|
209
|
+
if (worktreeMatch) {
|
|
210
|
+
return worktreeMatch[1];
|
|
211
|
+
}
|
|
212
|
+
// Fallback: construct expected worktree path
|
|
213
|
+
const laneSuffix = lane.toLowerCase().replace(/[:\s]+/g, '-');
|
|
214
|
+
return `worktrees/${laneSuffix}-${wuId.toLowerCase()}`;
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
die(`Failed to claim WU: ${error.message}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function main() {
|
|
221
|
+
const args = createWUParser({
|
|
222
|
+
name: 'wu-proto',
|
|
223
|
+
description: 'Create and claim a prototype WU with relaxed validation (rapid prototyping)',
|
|
224
|
+
options: [
|
|
225
|
+
WU_OPTIONS.lane,
|
|
226
|
+
WU_OPTIONS.title,
|
|
227
|
+
WU_OPTIONS.description,
|
|
228
|
+
WU_OPTIONS.codePaths,
|
|
229
|
+
WU_OPTIONS.labels,
|
|
230
|
+
WU_OPTIONS.assignedTo,
|
|
231
|
+
],
|
|
232
|
+
required: ['lane', 'title'],
|
|
233
|
+
allowPositionalId: false,
|
|
234
|
+
});
|
|
235
|
+
console.log(`${LOG_PREFIX} Creating prototype WU in ${args.lane} lane...`);
|
|
236
|
+
// Validate lane format
|
|
237
|
+
try {
|
|
238
|
+
validateLaneFormat(args.lane);
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
die(`Invalid lane format: ${error.message}`);
|
|
242
|
+
}
|
|
243
|
+
await ensureOnMain(getGitForCwd());
|
|
244
|
+
// Auto-generate WU ID
|
|
245
|
+
console.log(`${LOG_PREFIX} Auto-generating WU ID...`);
|
|
246
|
+
let wuId;
|
|
247
|
+
try {
|
|
248
|
+
wuId = await generateWuIdWithRetry();
|
|
249
|
+
console.log(`${LOG_PREFIX} Generated WU ID: ${wuId}`);
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
die(`Failed to auto-generate WU ID: ${error.message}`);
|
|
253
|
+
}
|
|
254
|
+
// Check if WU already exists
|
|
255
|
+
const wuPath = WU_PATHS.WU(wuId);
|
|
256
|
+
if (existsSync(wuPath)) {
|
|
257
|
+
die(`WU already exists: ${wuPath}`);
|
|
258
|
+
}
|
|
259
|
+
// Get assigned_to from flag or git config
|
|
260
|
+
const assignedTo = args.assignedTo || (await getDefaultAssignedTo());
|
|
261
|
+
// Validate proto spec
|
|
262
|
+
const validation = validateProtoSpec({
|
|
263
|
+
id: wuId,
|
|
264
|
+
lane: args.lane,
|
|
265
|
+
title: args.title,
|
|
266
|
+
opts: {
|
|
267
|
+
description: args.description,
|
|
268
|
+
codePaths: args.codePaths,
|
|
269
|
+
labels: args.labels,
|
|
270
|
+
assignedTo,
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
if (!validation.valid) {
|
|
274
|
+
const errorList = validation.errors.map((e) => ` - ${e}`).join(STRING_LITERALS.NEWLINE);
|
|
275
|
+
die(`${LOG_PREFIX} Validation failed:\n\n${errorList}`);
|
|
276
|
+
}
|
|
277
|
+
// WU-1255: Set LUMENFLOW_WU_TOOL to allow pre-push hook bypass
|
|
278
|
+
const previousWuTool = process.env.LUMENFLOW_WU_TOOL;
|
|
279
|
+
process.env.LUMENFLOW_WU_TOOL = OPERATION_NAME;
|
|
280
|
+
try {
|
|
281
|
+
await withMicroWorktree({
|
|
282
|
+
operation: OPERATION_NAME,
|
|
283
|
+
id: wuId,
|
|
284
|
+
logPrefix: LOG_PREFIX,
|
|
285
|
+
execute: async ({ worktreePath }) => {
|
|
286
|
+
// Create WU YAML
|
|
287
|
+
const wuRelativePath = createProtoWUYamlInWorktree(worktreePath, wuId, args.lane, args.title, DEFAULT_PRIORITY, {
|
|
288
|
+
description: args.description,
|
|
289
|
+
codePaths: args.codePaths,
|
|
290
|
+
labels: args.labels,
|
|
291
|
+
assignedTo,
|
|
292
|
+
});
|
|
293
|
+
// Update backlog
|
|
294
|
+
const backlogPath = updateBacklogInWorktree(worktreePath, wuId, args.lane, args.title);
|
|
295
|
+
return {
|
|
296
|
+
commitMessage: COMMIT_FORMATS.CREATE(wuId, args.title),
|
|
297
|
+
files: [wuRelativePath, backlogPath],
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
console.log(`\n${LOG_PREFIX} WU created!`);
|
|
302
|
+
console.log(` ID: ${wuId}`);
|
|
303
|
+
console.log(` Title: ${args.title}`);
|
|
304
|
+
console.log(` Lane: ${args.lane}`);
|
|
305
|
+
console.log(` Type: ${PROTOTYPE_TYPE}`);
|
|
306
|
+
console.log(` File: ${WU_PATHS.WU(wuId)}`);
|
|
307
|
+
// Immediately claim the WU
|
|
308
|
+
const worktreePath = claimWU(wuId, args.lane);
|
|
309
|
+
console.log(`\n${LOG_PREFIX} WU claimed and worktree created!`);
|
|
310
|
+
console.log(`\nNext step:`);
|
|
311
|
+
console.log(` cd ${worktreePath}`);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
die(`Transaction failed: ${error.message}`);
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
// Restore LUMENFLOW_WU_TOOL
|
|
318
|
+
if (previousWuTool === undefined) {
|
|
319
|
+
delete process.env.LUMENFLOW_WU_TOOL;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
process.env.LUMENFLOW_WU_TOOL = previousWuTool;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Run CLI
|
|
327
|
+
import { runCLI } from './cli-entry-point.js';
|
|
328
|
+
if (import.meta.main) {
|
|
329
|
+
void runCLI(main);
|
|
330
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumenflow/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Command-line interface for LumenFlow workflow framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lumenflow",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"wu-block": "./dist/wu-block.js",
|
|
41
41
|
"wu-unblock": "./dist/wu-unblock.js",
|
|
42
42
|
"wu-create": "./dist/wu-create.js",
|
|
43
|
+
"wu-proto": "./dist/wu-proto.js",
|
|
43
44
|
"wu-edit": "./dist/wu-edit.js",
|
|
44
45
|
"wu-spawn": "./dist/wu-spawn.js",
|
|
45
46
|
"wu-validate": "./dist/wu-validate.js",
|
|
@@ -148,11 +149,11 @@
|
|
|
148
149
|
"pretty-ms": "^9.2.0",
|
|
149
150
|
"simple-git": "^3.30.0",
|
|
150
151
|
"yaml": "^2.8.2",
|
|
151
|
-
"@lumenflow/
|
|
152
|
-
"@lumenflow/
|
|
153
|
-
"@lumenflow/
|
|
154
|
-
"@lumenflow/
|
|
155
|
-
"@lumenflow/
|
|
152
|
+
"@lumenflow/core": "2.7.0",
|
|
153
|
+
"@lumenflow/memory": "2.7.0",
|
|
154
|
+
"@lumenflow/metrics": "2.7.0",
|
|
155
|
+
"@lumenflow/initiatives": "2.7.0",
|
|
156
|
+
"@lumenflow/agent": "2.7.0"
|
|
156
157
|
},
|
|
157
158
|
"devDependencies": {
|
|
158
159
|
"@vitest/coverage-v8": "^4.0.17",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# LumenFlow Pre-Commit Hook (Vendor-Agnostic)
|
|
4
|
+
#
|
|
5
|
+
# This hook enforces worktree discipline for all users and AI agents.
|
|
6
|
+
# It blocks direct commits to main/master branches.
|
|
7
|
+
#
|
|
8
|
+
# Rules:
|
|
9
|
+
# 1. BLOCK commits to main/master (use WU workflow instead)
|
|
10
|
+
# 2. ALLOW commits on lane branches (lane/*/wu-*)
|
|
11
|
+
# 3. ALLOW commits on tmp/* branches (CLI micro-worktrees)
|
|
12
|
+
#
|
|
13
|
+
# Escape hatch (logged, emergency only):
|
|
14
|
+
# LUMENFLOW_FORCE=1 LUMENFLOW_FORCE_REASON="reason" git commit ...
|
|
15
|
+
#
|
|
16
|
+
# Configuration:
|
|
17
|
+
# Package manager is configured in .lumenflow.config.yaml (package_manager)
|
|
18
|
+
# Default: pnpm (examples below use pnpm - adjust for your project)
|
|
19
|
+
#
|
|
20
|
+
# For documentation on the WU workflow, see:
|
|
21
|
+
# - LUMENFLOW.md
|
|
22
|
+
# - docs/_frameworks/lumenflow/agent/onboarding/starting-prompt.md
|
|
23
|
+
#
|
|
24
|
+
|
|
25
|
+
# Skip on tmp/* branches (CLI micro-worktrees in /tmp with no node_modules)
|
|
26
|
+
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
27
|
+
case "$BRANCH" in tmp/*) exit 0 ;; esac
|
|
28
|
+
|
|
29
|
+
# Check for force bypass (logged for audit)
|
|
30
|
+
if [ "$LUMENFLOW_FORCE" = "1" ]; then
|
|
31
|
+
if [ -z "$LUMENFLOW_FORCE_REASON" ]; then
|
|
32
|
+
echo "" >&2
|
|
33
|
+
echo "[pre-commit] Warning: LUMENFLOW_FORCE_REASON not set." >&2
|
|
34
|
+
echo "Consider: LUMENFLOW_FORCE_REASON=\"reason\" LUMENFLOW_FORCE=1 git commit ..." >&2
|
|
35
|
+
echo "" >&2
|
|
36
|
+
fi
|
|
37
|
+
# Log bypass to .beacon/ for audit trail
|
|
38
|
+
BEACON_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/.beacon"
|
|
39
|
+
if [ -n "$BEACON_DIR" ]; then
|
|
40
|
+
mkdir -p "$BEACON_DIR"
|
|
41
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
42
|
+
USER=$(git config user.name 2>/dev/null || echo "unknown")
|
|
43
|
+
echo "${TIMESTAMP} | pre-commit | ${USER} | ${BRANCH} | ${LUMENFLOW_FORCE_REASON:-no reason} | $(pwd)" >> "${BEACON_DIR}/force-bypasses.log"
|
|
44
|
+
fi
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Block direct commits to main/master
|
|
49
|
+
case "$BRANCH" in
|
|
50
|
+
main|master)
|
|
51
|
+
echo "" >&2
|
|
52
|
+
echo "==================================================================" >&2
|
|
53
|
+
echo " DIRECT COMMIT TO ${BRANCH} BLOCKED" >&2
|
|
54
|
+
echo "==================================================================" >&2
|
|
55
|
+
echo "" >&2
|
|
56
|
+
echo "WHY THIS HAPPENS" >&2
|
|
57
|
+
echo "------------------------------------------------------------------" >&2
|
|
58
|
+
echo "LumenFlow protects main from direct commits to ensure:" >&2
|
|
59
|
+
echo " - All work is tracked in Work Units (WUs)" >&2
|
|
60
|
+
echo " - Changes can be reviewed and coordinated" >&2
|
|
61
|
+
echo " - Parallel work across lanes stays isolated" >&2
|
|
62
|
+
echo "" >&2
|
|
63
|
+
echo "WHAT TO DO" >&2
|
|
64
|
+
echo "------------------------------------------------------------------" >&2
|
|
65
|
+
echo "" >&2
|
|
66
|
+
echo "1. If you have a Work Unit to implement:" >&2
|
|
67
|
+
echo " pnpm wu:claim --id WU-XXXX --lane \"<Lane>\"" >&2
|
|
68
|
+
echo " cd worktrees/<lane>-wu-xxxx" >&2
|
|
69
|
+
echo " Then make your commits in the worktree" >&2
|
|
70
|
+
echo "" >&2
|
|
71
|
+
echo "2. If you need to create a new Work Unit:" >&2
|
|
72
|
+
echo " pnpm wu:create --lane \"<Lane>\" --title \"Your task\"" >&2
|
|
73
|
+
echo " This generates a WU ID, then claim it as above" >&2
|
|
74
|
+
echo "" >&2
|
|
75
|
+
echo "NEED HELP?" >&2
|
|
76
|
+
echo "------------------------------------------------------------------" >&2
|
|
77
|
+
echo " - Read: LUMENFLOW.md (workflow overview)" >&2
|
|
78
|
+
echo " - Read: docs/_frameworks/lumenflow/agent/onboarding/" >&2
|
|
79
|
+
echo " - Run: pnpm wu:help" >&2
|
|
80
|
+
echo "" >&2
|
|
81
|
+
echo "------------------------------------------------------------------" >&2
|
|
82
|
+
echo "EMERGENCY BYPASS (last resort, logged)" >&2
|
|
83
|
+
echo "------------------------------------------------------------------" >&2
|
|
84
|
+
echo "Bypasses are audit-logged. Only use for genuine emergencies." >&2
|
|
85
|
+
echo " LUMENFLOW_FORCE=1 LUMENFLOW_FORCE_REASON=\"<reason>\" git commit ..." >&2
|
|
86
|
+
echo "------------------------------------------------------------------" >&2
|
|
87
|
+
echo "" >&2
|
|
88
|
+
exit 1
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
|
|
92
|
+
# Allow commits on lane branches and other branches
|
|
93
|
+
exit 0
|
|
@@ -6,6 +6,33 @@ Complete reference for all CLI commands. Organized by category for quick discove
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## Quick Start (Essential Commands)
|
|
10
|
+
|
|
11
|
+
Most common workflow in 4 commands:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Claim WU and create isolated workspace
|
|
15
|
+
pnpm wu:claim --id WU-XXX --lane "Lane Name"
|
|
16
|
+
cd worktrees/<lane>-wu-xxx
|
|
17
|
+
|
|
18
|
+
# 2. Work in worktree, then run gates
|
|
19
|
+
pnpm gates # For code changes
|
|
20
|
+
pnpm gates --docs-only # For documentation only
|
|
21
|
+
|
|
22
|
+
# 3. Prepare for completion (from worktree)
|
|
23
|
+
pnpm wu:prep --id WU-XXX
|
|
24
|
+
|
|
25
|
+
# 4. Complete (from main - copy command from wu:prep output)
|
|
26
|
+
cd /path/to/main && pnpm wu:done --id WU-XXX
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Key rules:**
|
|
30
|
+
- Always work in worktrees, never on main
|
|
31
|
+
- Always run `wu:done` to complete (not just documenting it)
|
|
32
|
+
- Use `wu:prep` first (runs gates), then `wu:done` (merges)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
9
36
|
## Setup & Development
|
|
10
37
|
|
|
11
38
|
**For this monorepo (development):**
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Rapid Prototyping with LumenFlow
|
|
2
|
+
|
|
3
|
+
**Last updated:** {{DATE}}
|
|
4
|
+
|
|
5
|
+
This guide explains how to move fast WITHIN the LumenFlow workflow, not by bypassing it.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Wrong Way: Skipping the Workflow
|
|
10
|
+
|
|
11
|
+
When asked to "prototype quickly" or "just get something working," agents often:
|
|
12
|
+
|
|
13
|
+
1. Skip WU creation ("let's just commit directly")
|
|
14
|
+
2. Work on main branch ("worktrees slow us down")
|
|
15
|
+
3. Skip tests ("we'll add them later")
|
|
16
|
+
4. Bypass gates ("pre-commit hooks are annoying")
|
|
17
|
+
|
|
18
|
+
**This creates technical debt, breaks workflow tracking, and causes merge conflicts.**
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## The Right Way: Speed Through Parallelism
|
|
23
|
+
|
|
24
|
+
LumenFlow enables speed through **parallel WUs across lanes**, not by skipping steps.
|
|
25
|
+
|
|
26
|
+
### Speed Strategy 1: Multiple Small WUs
|
|
27
|
+
|
|
28
|
+
Instead of one large WU, create multiple focused WUs:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# SLOW: One massive WU
|
|
32
|
+
pnpm wu:create --lane "Framework: Core" --title "Build entire auth system"
|
|
33
|
+
# Takes 4 hours, blocks the lane
|
|
34
|
+
|
|
35
|
+
# FAST: Multiple parallel WUs
|
|
36
|
+
pnpm wu:create --lane "Framework: Core" --title "Add user model"
|
|
37
|
+
pnpm wu:create --lane "Framework: API" --title "Add auth endpoints"
|
|
38
|
+
pnpm wu:create --lane "Experience: UI" --title "Add login form"
|
|
39
|
+
# Each takes 1 hour, run in parallel across 3 lanes
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Speed Strategy 2: Spawn Sub-Agents
|
|
43
|
+
|
|
44
|
+
For complex work, spawn sub-agents to work in parallel:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Generate spawn prompt for parallel agent
|
|
48
|
+
pnpm wu:spawn --id WU-123 --client claude-code
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Sub-agents work on different aspects simultaneously:
|
|
52
|
+
|
|
53
|
+
- Agent 1: Core business logic
|
|
54
|
+
- Agent 2: API endpoints
|
|
55
|
+
- Agent 3: UI components
|
|
56
|
+
- Agent 4: Tests
|
|
57
|
+
|
|
58
|
+
### Speed Strategy 3: Wave-Based Execution
|
|
59
|
+
|
|
60
|
+
Orchestrate initiatives in waves:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# View what can run in parallel
|
|
64
|
+
pnpm orchestrate:init-status --id INIT-001
|
|
65
|
+
|
|
66
|
+
# Spawn wave of WUs
|
|
67
|
+
pnpm orchestrate:initiative --id INIT-001 --wave 1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Speed Strategy 4: Docs-Only Fast Path
|
|
71
|
+
|
|
72
|
+
For documentation changes, use the fast path:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Skip lint/typecheck/tests for docs
|
|
76
|
+
pnpm gates --docs-only
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Time Comparison
|
|
82
|
+
|
|
83
|
+
| Approach | Perceived Speed | Actual Time | Technical Debt |
|
|
84
|
+
| --------------- | --------------- | ----------------------- | -------------- |
|
|
85
|
+
| Skip workflow | "Instant" | +2h later fixing issues | High |
|
|
86
|
+
| Single large WU | Slow | 4h blocked | Low |
|
|
87
|
+
| Parallel WUs | Fast | 1h each, parallel | None |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Quick Reference: Fast But Safe
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Fast: Create focused WU
|
|
95
|
+
pnpm wu:create --lane "Framework: Core" --title "Specific task"
|
|
96
|
+
|
|
97
|
+
# Fast: Claim and work
|
|
98
|
+
pnpm wu:claim --id WU-XXX --lane "Framework: Core"
|
|
99
|
+
cd worktrees/framework-core-wu-xxx
|
|
100
|
+
|
|
101
|
+
# Fast: Minimal viable implementation
|
|
102
|
+
# Write ONE test, implement, pass
|
|
103
|
+
|
|
104
|
+
# Fast: Complete
|
|
105
|
+
pnpm wu:prep --id WU-XXX
|
|
106
|
+
cd /path/to/main && pnpm wu:done --id WU-XXX
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## What to Say When Asked to "Skip the Workflow"
|
|
112
|
+
|
|
113
|
+
When a user says "just prototype this quickly":
|
|
114
|
+
|
|
115
|
+
1. **Acknowledge the urgency**: "I understand you want this fast."
|
|
116
|
+
2. **Explain the approach**: "I'll create focused WUs that can run in parallel."
|
|
117
|
+
3. **Deliver value quickly**: "Here's the first deliverable in 30 minutes."
|
|
118
|
+
|
|
119
|
+
**Never say**: "Let me skip the workflow to save time."
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Anti-Patterns to Avoid
|
|
124
|
+
|
|
125
|
+
| Anti-Pattern | Why It's Slow | Better Alternative |
|
|
126
|
+
| ---------------------- | ----------------------------- | ----------------------- |
|
|
127
|
+
| Direct commits to main | Merge conflicts, broken gates | Use worktrees |
|
|
128
|
+
| One massive WU | Blocks lane for hours | Split into parallel WUs |
|
|
129
|
+
| Skip tests | Bugs found late, rework | TDD from start |
|
|
130
|
+
| "We'll document later" | Context lost, debt | Capture as you go |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Summary
|
|
135
|
+
|
|
136
|
+
**Speed in LumenFlow comes from parallelism, not shortcuts.**
|
|
137
|
+
|
|
138
|
+
- Multiple small WUs across lanes
|
|
139
|
+
- Sub-agents for complex work
|
|
140
|
+
- Wave-based orchestration
|
|
141
|
+
- Docs-only fast path when applicable
|
|
142
|
+
|
|
143
|
+
The workflow exists to prevent the slowdowns that come from technical debt, merge conflicts, and broken builds.
|
|
@@ -10,7 +10,7 @@ This is the complete onboarding document for AI agents working with LumenFlow. R
|
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
# 1. Check your assigned WU
|
|
13
|
-
cat
|
|
13
|
+
cat {{DOCS_TASKS_PATH}}/wu/WU-XXXX.yaml
|
|
14
14
|
|
|
15
15
|
# 2. Claim the WU (creates isolated worktree)
|
|
16
16
|
pnpm wu:claim --id WU-XXXX --lane "Lane Name"
|
|
@@ -160,7 +160,7 @@ git add . && git commit -m "your message"
|
|
|
160
160
|
**Fix:** Regenerate the backlog or manually add the missing WU:
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
|
-
# In worktree, edit
|
|
163
|
+
# In worktree, edit {{DOCS_TASKS_PATH}}/backlog.md
|
|
164
164
|
# Add the missing WU reference in the appropriate section
|
|
165
165
|
```
|
|
166
166
|
|
|
@@ -266,7 +266,7 @@ pnpm wu:spawn --id WU-XXXX --client <client-type>
|
|
|
266
266
|
|
|
267
267
|
```
|
|
268
268
|
/path/to/repo/
|
|
269
|
-
├──
|
|
269
|
+
├── {{DOCS_TASKS_PATH}}/
|
|
270
270
|
│ ├── backlog.md # All WUs listed here
|
|
271
271
|
│ └── wu/WU-XXXX.yaml # Individual WU specs
|
|
272
272
|
├── worktrees/
|
|
@@ -36,6 +36,31 @@ See [LUMENFLOW.md](../LUMENFLOW.md) and [ai/onboarding/troubleshooting-wu-done.m
|
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
+
## Orchestration & Memory Commands
|
|
40
|
+
|
|
41
|
+
Essential commands for multi-agent coordination and context management:
|
|
42
|
+
|
|
43
|
+
| Command | Description |
|
|
44
|
+
| ------------------------------------------ | --------------------------------- |
|
|
45
|
+
| `pnpm orchestrate:init-status -i INIT-XXX` | View initiative progress |
|
|
46
|
+
| `pnpm orchestrate:monitor` | Monitor spawn/agent activity |
|
|
47
|
+
| `pnpm mem:checkpoint --wu WU-XXX` | Save progress checkpoint |
|
|
48
|
+
| `pnpm mem:inbox --since 30m` | Check coordination signals |
|
|
49
|
+
| `pnpm mem:signal "msg" --wu WU-XXX` | Broadcast signal to other agents |
|
|
50
|
+
| `pnpm mem:create "msg" --wu WU-XXX` | Create memory node (bug capture) |
|
|
51
|
+
| `pnpm wu:spawn --id WU-XXX --client claude-code` | Spawn sub-agent prompt |
|
|
52
|
+
|
|
53
|
+
**When to checkpoint:**
|
|
54
|
+
- After each acceptance criterion completed
|
|
55
|
+
- Before running gates
|
|
56
|
+
- Every 30+ tool calls
|
|
57
|
+
|
|
58
|
+
**When to check inbox:**
|
|
59
|
+
- Before starting complex work (parallel agents may have signals)
|
|
60
|
+
- When blocked (other agents may have completed dependencies)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
39
64
|
## Claude-Specific Settings
|
|
40
65
|
|
|
41
66
|
This directory contains Claude Code-specific configuration:
|