@lumenflow/cli 2.7.0 → 2.9.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 +121 -105
- package/dist/__tests__/agent-spawn-coordination.test.js +451 -0
- package/dist/__tests__/commands/integrate.test.js +165 -0
- package/dist/__tests__/commands.test.js +75 -0
- package/dist/__tests__/doctor.test.js +510 -0
- package/dist/__tests__/gates-config.test.js +0 -1
- package/dist/__tests__/hooks/enforcement.test.js +279 -0
- package/dist/__tests__/init-greenfield.test.js +247 -0
- package/dist/__tests__/init-quick-ref.test.js +0 -1
- package/dist/__tests__/init-template-portability.test.js +0 -1
- package/dist/__tests__/init.test.js +249 -0
- package/dist/__tests__/initiative-e2e.test.js +442 -0
- package/dist/__tests__/initiative-plan-replacement.test.js +0 -1
- package/dist/__tests__/memory-integration.test.js +333 -0
- package/dist/__tests__/release.test.js +1 -1
- package/dist/__tests__/safe-git.test.js +0 -1
- package/dist/__tests__/state-doctor.test.js +54 -0
- package/dist/__tests__/sync-templates.test.js +255 -0
- package/dist/__tests__/wu-create-required-fields.test.js +121 -0
- package/dist/__tests__/wu-done-auto-cleanup.test.js +135 -0
- package/dist/__tests__/wu-lifecycle-integration.test.js +388 -0
- package/dist/backlog-prune.js +0 -1
- package/dist/cli-entry-point.js +0 -1
- package/dist/commands/integrate.js +229 -0
- package/dist/commands.js +171 -0
- package/dist/docs-sync.js +46 -0
- package/dist/doctor.js +479 -10
- package/dist/gates.js +0 -7
- package/dist/hooks/enforcement-checks.js +209 -0
- package/dist/hooks/enforcement-generator.js +365 -0
- package/dist/hooks/enforcement-sync.js +243 -0
- package/dist/hooks/index.js +7 -0
- package/dist/init.js +502 -17
- package/dist/initiative-add-wu.js +0 -2
- package/dist/initiative-create.js +0 -3
- package/dist/initiative-edit.js +0 -5
- package/dist/initiative-plan.js +0 -1
- package/dist/initiative-remove-wu.js +0 -2
- package/dist/lane-health.js +0 -2
- package/dist/lane-suggest.js +0 -1
- package/dist/mem-checkpoint.js +0 -2
- package/dist/mem-cleanup.js +0 -2
- package/dist/mem-context.js +0 -3
- package/dist/mem-create.js +0 -2
- package/dist/mem-delete.js +0 -3
- package/dist/mem-inbox.js +0 -2
- package/dist/mem-index.js +0 -1
- package/dist/mem-init.js +0 -2
- package/dist/mem-profile.js +0 -1
- package/dist/mem-promote.js +0 -1
- package/dist/mem-ready.js +0 -2
- package/dist/mem-signal.js +0 -2
- package/dist/mem-start.js +0 -2
- package/dist/mem-summarize.js +0 -2
- package/dist/metrics-cli.js +1 -1
- package/dist/metrics-snapshot.js +1 -1
- package/dist/onboarding-smoke-test.js +0 -5
- package/dist/orchestrate-init-status.js +0 -1
- package/dist/orchestrate-initiative.js +0 -1
- package/dist/orchestrate-monitor.js +0 -1
- package/dist/plan-create.js +0 -2
- package/dist/plan-edit.js +0 -2
- package/dist/plan-link.js +0 -2
- package/dist/plan-promote.js +0 -2
- package/dist/signal-cleanup.js +0 -4
- package/dist/state-bootstrap.js +0 -1
- package/dist/state-cleanup.js +0 -4
- package/dist/state-doctor-fix.js +5 -8
- package/dist/state-doctor.js +0 -11
- package/dist/sync-templates.js +188 -34
- package/dist/wu-block.js +100 -48
- package/dist/wu-claim.js +1 -22
- package/dist/wu-cleanup.js +0 -1
- package/dist/wu-create.js +0 -2
- package/dist/wu-done-auto-cleanup.js +139 -0
- package/dist/wu-done.js +11 -4
- package/dist/wu-edit.js +0 -12
- package/dist/wu-preflight.js +0 -1
- package/dist/wu-prep.js +0 -1
- package/dist/wu-proto.js +0 -1
- package/dist/wu-spawn.js +0 -3
- package/dist/wu-unblock.js +0 -2
- package/dist/wu-validate.js +0 -1
- package/package.json +9 -7
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
3
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
4
|
-
/* eslint-disable @typescript-eslint/explicit-function-return-type -- CLI tool uses dynamic YAML types */
|
|
5
2
|
/**
|
|
6
3
|
* Initiative Create Helper (WU-1247, WU-1439)
|
|
7
4
|
*
|
package/dist/initiative-edit.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
|
-
/* eslint-disable @typescript-eslint/explicit-function-return-type -- CLI tool uses dynamic YAML types */
|
|
4
2
|
/**
|
|
5
3
|
* Initiative Edit Helper
|
|
6
4
|
*
|
|
@@ -225,12 +223,10 @@ function validateCreatedDate(date) {
|
|
|
225
223
|
*/
|
|
226
224
|
function loadInitiative(id) {
|
|
227
225
|
const initPath = INIT_PATHS.INITIATIVE(id);
|
|
228
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool validates init files
|
|
229
226
|
if (!existsSync(initPath)) {
|
|
230
227
|
die(`Initiative ${id} not found at ${initPath}\n\n` +
|
|
231
228
|
`Ensure the Initiative exists and you're in the repo root.`);
|
|
232
229
|
}
|
|
233
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool validates init files
|
|
234
230
|
const content = readFileSync(initPath, { encoding: FILE_SYSTEM.ENCODING });
|
|
235
231
|
return parseYAML(content);
|
|
236
232
|
}
|
|
@@ -428,7 +424,6 @@ async function main() {
|
|
|
428
424
|
// Write updated Initiative to micro-worktree
|
|
429
425
|
const initPath = join(worktreePath, INIT_PATHS.INITIATIVE(id));
|
|
430
426
|
const yamlContent = stringifyYAML(updatedInit);
|
|
431
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes init files
|
|
432
427
|
writeFileSync(initPath, yamlContent, { encoding: FILE_SYSTEM.ENCODING });
|
|
433
428
|
console.log(`${PREFIX} Updated ${id}.yaml in micro-worktree`);
|
|
434
429
|
return {
|
package/dist/initiative-plan.js
CHANGED
package/dist/lane-health.js
CHANGED
|
@@ -301,9 +301,7 @@ export function formatLaneHealthReport(report) {
|
|
|
301
301
|
// CLI Entry Point
|
|
302
302
|
// ============================================================================
|
|
303
303
|
/** Logger for CLI output */
|
|
304
|
-
// eslint-disable-next-line no-console
|
|
305
304
|
const log = console.log.bind(console);
|
|
306
|
-
// eslint-disable-next-line no-console
|
|
307
305
|
const warn = console.warn.bind(console);
|
|
308
306
|
/**
|
|
309
307
|
* Run lane health check
|
package/dist/lane-suggest.js
CHANGED
package/dist/mem-checkpoint.js
CHANGED
|
@@ -76,10 +76,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
76
76
|
try {
|
|
77
77
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
78
78
|
const logDir = path.dirname(logPath);
|
|
79
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
80
79
|
await fs.mkdir(logDir, { recursive: true });
|
|
81
80
|
const line = `${JSON.stringify(entry)}\n`;
|
|
82
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
83
81
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
84
82
|
}
|
|
85
83
|
catch {
|
package/dist/mem-cleanup.js
CHANGED
|
@@ -88,10 +88,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
88
88
|
try {
|
|
89
89
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
90
90
|
const logDir = path.dirname(logPath);
|
|
91
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
92
91
|
await fs.mkdir(logDir, { recursive: true });
|
|
93
92
|
const line = `${JSON.stringify(entry)}\n`;
|
|
94
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
95
93
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
96
94
|
}
|
|
97
95
|
catch {
|
package/dist/mem-context.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
2
|
/**
|
|
4
3
|
* Memory Context CLI (WU-1234, WU-1292)
|
|
5
4
|
*
|
|
@@ -96,10 +95,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
96
95
|
try {
|
|
97
96
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
98
97
|
const logDir = path.dirname(logPath);
|
|
99
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
100
98
|
await fs.mkdir(logDir, { recursive: true });
|
|
101
99
|
const line = `${JSON.stringify(entry)}\n`;
|
|
102
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
103
100
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
104
101
|
}
|
|
105
102
|
catch {
|
package/dist/mem-create.js
CHANGED
|
@@ -83,10 +83,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
83
83
|
try {
|
|
84
84
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
85
85
|
const logDir = path.dirname(logPath);
|
|
86
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
87
86
|
await fs.mkdir(logDir, { recursive: true });
|
|
88
87
|
const line = `${JSON.stringify(entry)}\n`;
|
|
89
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
90
88
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
91
89
|
}
|
|
92
90
|
catch {
|
package/dist/mem-delete.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI command uses console for status output */
|
|
3
2
|
/**
|
|
4
3
|
* Memory Delete CLI (WU-1284)
|
|
5
4
|
*
|
|
@@ -81,10 +80,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
81
80
|
try {
|
|
82
81
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
83
82
|
const logDir = path.dirname(logPath);
|
|
84
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
85
83
|
await fs.mkdir(logDir, { recursive: true });
|
|
86
84
|
const line = `${JSON.stringify(entry)}\n`;
|
|
87
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
88
85
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
89
86
|
}
|
|
90
87
|
catch {
|
package/dist/mem-inbox.js
CHANGED
|
@@ -77,10 +77,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
77
77
|
try {
|
|
78
78
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
79
79
|
const logDir = path.dirname(logPath);
|
|
80
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
81
80
|
await fs.mkdir(logDir, { recursive: true });
|
|
82
81
|
const line = `${JSON.stringify(entry)}\n`;
|
|
83
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
84
82
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
85
83
|
}
|
|
86
84
|
catch {
|
package/dist/mem-index.js
CHANGED
package/dist/mem-init.js
CHANGED
|
@@ -36,11 +36,9 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
36
36
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
37
37
|
const logDir = path.dirname(logPath);
|
|
38
38
|
// Ensure telemetry directory exists
|
|
39
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
40
39
|
await fs.mkdir(logDir, { recursive: true });
|
|
41
40
|
// Append NDJSON entry
|
|
42
41
|
const line = `${JSON.stringify(entry)}\n`;
|
|
43
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
44
42
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
45
43
|
}
|
|
46
44
|
catch {
|
package/dist/mem-profile.js
CHANGED
package/dist/mem-promote.js
CHANGED
package/dist/mem-ready.js
CHANGED
|
@@ -62,10 +62,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
62
62
|
try {
|
|
63
63
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
64
64
|
const logDir = path.dirname(logPath);
|
|
65
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
66
65
|
await fs.mkdir(logDir, { recursive: true });
|
|
67
66
|
const line = `${JSON.stringify(entry)}\n`;
|
|
68
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
69
67
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
70
68
|
}
|
|
71
69
|
catch {
|
package/dist/mem-signal.js
CHANGED
|
@@ -51,10 +51,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
51
51
|
try {
|
|
52
52
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
53
53
|
const logDir = path.dirname(logPath);
|
|
54
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
55
54
|
await fs.mkdir(logDir, { recursive: true });
|
|
56
55
|
const line = `${JSON.stringify(entry)}\n`;
|
|
57
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
58
56
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
59
57
|
}
|
|
60
58
|
catch {
|
package/dist/mem-start.js
CHANGED
|
@@ -37,11 +37,9 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
37
37
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
38
38
|
const logDir = path.dirname(logPath);
|
|
39
39
|
// Ensure telemetry directory exists
|
|
40
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
41
40
|
await fs.mkdir(logDir, { recursive: true });
|
|
42
41
|
// Append NDJSON entry
|
|
43
42
|
const line = `${JSON.stringify(entry)}\n`;
|
|
44
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
45
43
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
46
44
|
}
|
|
47
45
|
catch {
|
package/dist/mem-summarize.js
CHANGED
|
@@ -72,10 +72,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
72
72
|
try {
|
|
73
73
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
74
74
|
const logDir = path.dirname(logPath);
|
|
75
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
76
75
|
await fs.mkdir(logDir, { recursive: true });
|
|
77
76
|
const line = `${JSON.stringify(entry)}\n`;
|
|
78
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
79
77
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
80
78
|
}
|
|
81
79
|
catch {
|
package/dist/metrics-cli.js
CHANGED
|
@@ -158,7 +158,7 @@ async function loadGitCommits(weekStart, weekEnd) {
|
|
|
158
158
|
const message = entry.message;
|
|
159
159
|
const wuIdMatch = message.match(/\b(WU-\d+)\b/i);
|
|
160
160
|
const wuId = wuIdMatch ? wuIdMatch[1].toUpperCase() : undefined;
|
|
161
|
-
const typeMatch = message.match(/^(feat|fix|docs|chore|refactor|test|style|perf|ci)[
|
|
161
|
+
const typeMatch = message.match(/^(feat|fix|docs|chore|refactor|test|style|perf|ci)[(:]?/i);
|
|
162
162
|
const type = typeMatch ? typeMatch[1].toLowerCase() : undefined;
|
|
163
163
|
commits.push({
|
|
164
164
|
hash: entry.hash,
|
package/dist/metrics-snapshot.js
CHANGED
|
@@ -145,7 +145,7 @@ async function loadGitCommits(weekStart, weekEnd) {
|
|
|
145
145
|
const wuIdMatch = message.match(/\b(WU-\d+)\b/i);
|
|
146
146
|
const wuId = wuIdMatch ? wuIdMatch[1].toUpperCase() : undefined;
|
|
147
147
|
// Determine commit type from conventional commit prefix
|
|
148
|
-
const typeMatch = message.match(/^(feat|fix|docs|chore|refactor|test|style|perf|ci)[
|
|
148
|
+
const typeMatch = message.match(/^(feat|fix|docs|chore|refactor|test|style|perf|ci)[(:]?/i);
|
|
149
149
|
const type = typeMatch ? typeMatch[1].toLowerCase() : undefined;
|
|
150
150
|
commits.push({
|
|
151
151
|
hash: entry.hash,
|
|
@@ -174,22 +174,17 @@ export function validateLaneInferenceFormat(options) {
|
|
|
174
174
|
* Initialize a git repository in the given directory
|
|
175
175
|
*/
|
|
176
176
|
function initializeGitRepo(projectDir) {
|
|
177
|
-
// eslint-disable-next-line sonarjs/no-os-command-from-path -- Git binary from PATH is acceptable for smoke tests
|
|
178
177
|
execFileSync(GIT_BINARY, ['init'], { cwd: projectDir, stdio: 'pipe' });
|
|
179
|
-
// eslint-disable-next-line sonarjs/no-os-command-from-path -- Git binary from PATH is acceptable for smoke tests
|
|
180
178
|
execFileSync(GIT_BINARY, ['config', 'user.email', 'test@example.com'], {
|
|
181
179
|
cwd: projectDir,
|
|
182
180
|
stdio: 'pipe',
|
|
183
181
|
});
|
|
184
|
-
// eslint-disable-next-line sonarjs/no-os-command-from-path -- Git binary from PATH is acceptable for smoke tests
|
|
185
182
|
execFileSync(GIT_BINARY, ['config', 'user.name', 'Test User'], {
|
|
186
183
|
cwd: projectDir,
|
|
187
184
|
stdio: 'pipe',
|
|
188
185
|
});
|
|
189
186
|
// Create initial commit
|
|
190
|
-
// eslint-disable-next-line sonarjs/no-os-command-from-path -- Git binary from PATH is acceptable for smoke tests
|
|
191
187
|
execFileSync(GIT_BINARY, ['add', '-A'], { cwd: projectDir, stdio: 'pipe' });
|
|
192
|
-
// eslint-disable-next-line sonarjs/no-os-command-from-path -- Git binary from PATH is acceptable for smoke tests
|
|
193
188
|
execFileSync(GIT_BINARY, ['commit', '-m', 'Initial commit', '--allow-empty'], {
|
|
194
189
|
cwd: projectDir,
|
|
195
190
|
stdio: 'pipe',
|
package/dist/plan-create.js
CHANGED
package/dist/plan-edit.js
CHANGED
package/dist/plan-link.js
CHANGED
package/dist/plan-promote.js
CHANGED
package/dist/signal-cleanup.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
2
|
/**
|
|
4
3
|
* Signal Cleanup CLI (WU-1204)
|
|
5
4
|
*
|
|
@@ -94,10 +93,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
94
93
|
try {
|
|
95
94
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
96
95
|
const logDir = path.dirname(logPath);
|
|
97
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
98
96
|
await fs.mkdir(logDir, { recursive: true });
|
|
99
97
|
const line = `${JSON.stringify(entry)}\n`;
|
|
100
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
101
98
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
102
99
|
}
|
|
103
100
|
catch {
|
|
@@ -142,7 +139,6 @@ async function getActiveWuIds(baseDir) {
|
|
|
142
139
|
for (const file of wuFiles) {
|
|
143
140
|
try {
|
|
144
141
|
const filePath = path.join(wuDir, file);
|
|
145
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
146
142
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
147
143
|
const wu = parseYaml(content);
|
|
148
144
|
if (wu.id && wu.status && ACTIVE_WU_STATUSES.includes(wu.status)) {
|
package/dist/state-bootstrap.js
CHANGED
|
@@ -17,7 +17,6 @@ import { parse as parseYaml } from 'yaml';
|
|
|
17
17
|
import { readFileSync } from 'node:fs';
|
|
18
18
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
19
19
|
import { CLI_FLAGS, EXIT_CODES, EMOJI, STRING_LITERALS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
20
|
-
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
21
20
|
/** Log prefix for consistent output */
|
|
22
21
|
const LOG_PREFIX = '[state-bootstrap]';
|
|
23
22
|
/**
|
package/dist/state-cleanup.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
2
|
/**
|
|
4
3
|
* Unified State Cleanup CLI (WU-1208)
|
|
5
4
|
*
|
|
@@ -111,10 +110,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
111
110
|
try {
|
|
112
111
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
113
112
|
const logDir = path.dirname(logPath);
|
|
114
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
115
113
|
await fs.mkdir(logDir, { recursive: true });
|
|
116
114
|
const line = `${JSON.stringify(entry)}\n`;
|
|
117
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
118
115
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
119
116
|
}
|
|
120
117
|
catch {
|
|
@@ -150,7 +147,6 @@ async function getActiveWuIds(baseDir) {
|
|
|
150
147
|
for (const file of wuFiles) {
|
|
151
148
|
try {
|
|
152
149
|
const filePath = path.join(wuDir, file);
|
|
153
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
154
150
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
155
151
|
const wu = parseYaml(content);
|
|
156
152
|
if (wu.id && wu.status && ACTIVE_WU_STATUSES.includes(wu.status)) {
|
package/dist/state-doctor-fix.js
CHANGED
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
* 1. No direct file modifications on main branch
|
|
8
8
|
* 2. Removal of stale WU references from backlog.md and status.md
|
|
9
9
|
* 3. All changes pushed via merge, not direct file modification
|
|
10
|
+
* 4. WU-1362: Retry logic for push failures (inherited from withMicroWorktree)
|
|
11
|
+
*
|
|
12
|
+
* Retry behavior is configured via .lumenflow.config.yaml git.push_retry section.
|
|
13
|
+
* Default: 3 retries with exponential backoff and jitter.
|
|
10
14
|
*
|
|
11
15
|
* @see {@link ./state-doctor.ts} - Main CLI that uses these deps
|
|
12
|
-
* @see {@link @lumenflow/core/dist/micro-worktree.js} - Micro-worktree infrastructure
|
|
16
|
+
* @see {@link @lumenflow/core/dist/micro-worktree.js} - Micro-worktree infrastructure with retry logic
|
|
13
17
|
*/
|
|
14
18
|
import fs from 'node:fs/promises';
|
|
15
19
|
import path from 'node:path';
|
|
@@ -56,7 +60,6 @@ function removeWuReferences(content, wuId) {
|
|
|
56
60
|
*/
|
|
57
61
|
async function readFileSafe(filePath) {
|
|
58
62
|
try {
|
|
59
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path from config
|
|
60
63
|
return await fs.readFile(filePath, 'utf-8');
|
|
61
64
|
}
|
|
62
65
|
catch {
|
|
@@ -100,7 +103,6 @@ export function createStateDoctorFixDeps(_baseDir) {
|
|
|
100
103
|
return true; // Keep malformed lines
|
|
101
104
|
}
|
|
102
105
|
});
|
|
103
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path
|
|
104
106
|
await fs.writeFile(signalsPath, lines.join('\n') + '\n', 'utf-8');
|
|
105
107
|
return {
|
|
106
108
|
commitMessage: `fix(state-doctor): remove dangling signal ${id}`,
|
|
@@ -139,7 +141,6 @@ export function createStateDoctorFixDeps(_baseDir) {
|
|
|
139
141
|
return true; // Keep malformed lines
|
|
140
142
|
}
|
|
141
143
|
});
|
|
142
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path
|
|
143
144
|
await fs.writeFile(eventsPath, lines.join('\n') + '\n', 'utf-8');
|
|
144
145
|
modifiedFiles.push(WU_EVENTS_FILE);
|
|
145
146
|
}
|
|
@@ -148,7 +149,6 @@ export function createStateDoctorFixDeps(_baseDir) {
|
|
|
148
149
|
const backlogContent = await readFileSafe(backlogPath);
|
|
149
150
|
if (backlogContent && backlogContent.includes(wuId)) {
|
|
150
151
|
const updatedBacklog = removeWuReferences(backlogContent, wuId);
|
|
151
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path
|
|
152
152
|
await fs.writeFile(backlogPath, updatedBacklog, 'utf-8');
|
|
153
153
|
modifiedFiles.push(BACKLOG_FILE);
|
|
154
154
|
}
|
|
@@ -157,7 +157,6 @@ export function createStateDoctorFixDeps(_baseDir) {
|
|
|
157
157
|
const statusContent = await readFileSafe(statusPath);
|
|
158
158
|
if (statusContent && statusContent.includes(wuId)) {
|
|
159
159
|
const updatedStatus = removeWuReferences(statusContent, wuId);
|
|
160
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path
|
|
161
160
|
await fs.writeFile(statusPath, updatedStatus, 'utf-8');
|
|
162
161
|
modifiedFiles.push(STATUS_FILE);
|
|
163
162
|
}
|
|
@@ -179,12 +178,10 @@ export function createStateDoctorFixDeps(_baseDir) {
|
|
|
179
178
|
pushOnly: true,
|
|
180
179
|
execute: async ({ worktreePath }) => {
|
|
181
180
|
const stampsDir = path.join(worktreePath, '.lumenflow/stamps');
|
|
182
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
183
181
|
await fs.mkdir(stampsDir, { recursive: true });
|
|
184
182
|
// Create stamp file in micro-worktree
|
|
185
183
|
const stampPath = path.join(stampsDir, `${wuId}.done`);
|
|
186
184
|
const stampContent = `# ${wuId} Done\n\nTitle: ${title}\nCreated by: state:doctor --fix\nTimestamp: ${new Date().toISOString()}\n`;
|
|
187
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Validated path
|
|
188
185
|
await fs.writeFile(stampPath, stampContent, 'utf-8');
|
|
189
186
|
return {
|
|
190
187
|
commitMessage: `fix(state-doctor): create missing stamp for ${wuId}`,
|
package/dist/state-doctor.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console -- CLI tool requires console output */
|
|
3
2
|
/**
|
|
4
3
|
* State Doctor CLI (WU-1209)
|
|
5
4
|
*
|
|
@@ -101,10 +100,8 @@ async function writeAuditLog(baseDir, entry) {
|
|
|
101
100
|
try {
|
|
102
101
|
const logPath = path.join(baseDir, LUMENFLOW_PATHS.AUDIT_LOG);
|
|
103
102
|
const logDir = path.dirname(logPath);
|
|
104
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
105
103
|
await fs.mkdir(logDir, { recursive: true });
|
|
106
104
|
const line = `${JSON.stringify(entry)}\n`;
|
|
107
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes audit log
|
|
108
105
|
await fs.appendFile(logPath, line, 'utf-8');
|
|
109
106
|
}
|
|
110
107
|
catch {
|
|
@@ -146,7 +143,6 @@ async function createDeps(baseDir) {
|
|
|
146
143
|
for (const file of wuFiles) {
|
|
147
144
|
try {
|
|
148
145
|
const filePath = path.join(wuDir, file);
|
|
149
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
150
146
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
151
147
|
const wu = parseYaml(content);
|
|
152
148
|
if (wu.id && wu.status) {
|
|
@@ -189,7 +185,6 @@ async function createDeps(baseDir) {
|
|
|
189
185
|
listSignals: async () => {
|
|
190
186
|
try {
|
|
191
187
|
const signalsPath = path.join(baseDir, SIGNALS_FILE);
|
|
192
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
193
188
|
const content = await fs.readFile(signalsPath, 'utf-8');
|
|
194
189
|
const signals = [];
|
|
195
190
|
for (const line of content.split('\n')) {
|
|
@@ -223,7 +218,6 @@ async function createDeps(baseDir) {
|
|
|
223
218
|
listEvents: async () => {
|
|
224
219
|
try {
|
|
225
220
|
const eventsPath = path.join(baseDir, WU_EVENTS_FILE);
|
|
226
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
227
221
|
const content = await fs.readFile(eventsPath, 'utf-8');
|
|
228
222
|
const events = [];
|
|
229
223
|
for (const line of content.split('\n')) {
|
|
@@ -255,7 +249,6 @@ async function createDeps(baseDir) {
|
|
|
255
249
|
*/
|
|
256
250
|
removeSignal: async (id) => {
|
|
257
251
|
const signalsPath = path.join(baseDir, SIGNALS_FILE);
|
|
258
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
259
252
|
const content = await fs.readFile(signalsPath, 'utf-8');
|
|
260
253
|
const lines = content.split('\n').filter((line) => {
|
|
261
254
|
if (!line.trim())
|
|
@@ -268,7 +261,6 @@ async function createDeps(baseDir) {
|
|
|
268
261
|
return true; // Keep malformed lines
|
|
269
262
|
}
|
|
270
263
|
});
|
|
271
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes known path
|
|
272
264
|
await fs.writeFile(signalsPath, lines.join('\n') + '\n', 'utf-8');
|
|
273
265
|
},
|
|
274
266
|
/**
|
|
@@ -276,7 +268,6 @@ async function createDeps(baseDir) {
|
|
|
276
268
|
*/
|
|
277
269
|
removeEvent: async (wuId) => {
|
|
278
270
|
const eventsPath = path.join(baseDir, WU_EVENTS_FILE);
|
|
279
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known path
|
|
280
271
|
const content = await fs.readFile(eventsPath, 'utf-8');
|
|
281
272
|
const lines = content.split('\n').filter((line) => {
|
|
282
273
|
if (!line.trim())
|
|
@@ -289,7 +280,6 @@ async function createDeps(baseDir) {
|
|
|
289
280
|
return true; // Keep malformed lines
|
|
290
281
|
}
|
|
291
282
|
});
|
|
292
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool writes known path
|
|
293
283
|
await fs.writeFile(eventsPath, lines.join('\n') + '\n', 'utf-8');
|
|
294
284
|
},
|
|
295
285
|
/**
|
|
@@ -297,7 +287,6 @@ async function createDeps(baseDir) {
|
|
|
297
287
|
*/
|
|
298
288
|
createStamp: async (wuId, title) => {
|
|
299
289
|
const stampsDir = path.join(baseDir, LUMENFLOW_PATHS.STAMPS_DIR);
|
|
300
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates known directory
|
|
301
290
|
await fs.mkdir(stampsDir, { recursive: true });
|
|
302
291
|
await createStamp({
|
|
303
292
|
id: wuId,
|