@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.
Files changed (84) hide show
  1. package/README.md +121 -105
  2. package/dist/__tests__/agent-spawn-coordination.test.js +451 -0
  3. package/dist/__tests__/commands/integrate.test.js +165 -0
  4. package/dist/__tests__/commands.test.js +75 -0
  5. package/dist/__tests__/doctor.test.js +510 -0
  6. package/dist/__tests__/gates-config.test.js +0 -1
  7. package/dist/__tests__/hooks/enforcement.test.js +279 -0
  8. package/dist/__tests__/init-greenfield.test.js +247 -0
  9. package/dist/__tests__/init-quick-ref.test.js +0 -1
  10. package/dist/__tests__/init-template-portability.test.js +0 -1
  11. package/dist/__tests__/init.test.js +249 -0
  12. package/dist/__tests__/initiative-e2e.test.js +442 -0
  13. package/dist/__tests__/initiative-plan-replacement.test.js +0 -1
  14. package/dist/__tests__/memory-integration.test.js +333 -0
  15. package/dist/__tests__/release.test.js +1 -1
  16. package/dist/__tests__/safe-git.test.js +0 -1
  17. package/dist/__tests__/state-doctor.test.js +54 -0
  18. package/dist/__tests__/sync-templates.test.js +255 -0
  19. package/dist/__tests__/wu-create-required-fields.test.js +121 -0
  20. package/dist/__tests__/wu-done-auto-cleanup.test.js +135 -0
  21. package/dist/__tests__/wu-lifecycle-integration.test.js +388 -0
  22. package/dist/backlog-prune.js +0 -1
  23. package/dist/cli-entry-point.js +0 -1
  24. package/dist/commands/integrate.js +229 -0
  25. package/dist/commands.js +171 -0
  26. package/dist/docs-sync.js +46 -0
  27. package/dist/doctor.js +479 -10
  28. package/dist/gates.js +0 -7
  29. package/dist/hooks/enforcement-checks.js +209 -0
  30. package/dist/hooks/enforcement-generator.js +365 -0
  31. package/dist/hooks/enforcement-sync.js +243 -0
  32. package/dist/hooks/index.js +7 -0
  33. package/dist/init.js +502 -17
  34. package/dist/initiative-add-wu.js +0 -2
  35. package/dist/initiative-create.js +0 -3
  36. package/dist/initiative-edit.js +0 -5
  37. package/dist/initiative-plan.js +0 -1
  38. package/dist/initiative-remove-wu.js +0 -2
  39. package/dist/lane-health.js +0 -2
  40. package/dist/lane-suggest.js +0 -1
  41. package/dist/mem-checkpoint.js +0 -2
  42. package/dist/mem-cleanup.js +0 -2
  43. package/dist/mem-context.js +0 -3
  44. package/dist/mem-create.js +0 -2
  45. package/dist/mem-delete.js +0 -3
  46. package/dist/mem-inbox.js +0 -2
  47. package/dist/mem-index.js +0 -1
  48. package/dist/mem-init.js +0 -2
  49. package/dist/mem-profile.js +0 -1
  50. package/dist/mem-promote.js +0 -1
  51. package/dist/mem-ready.js +0 -2
  52. package/dist/mem-signal.js +0 -2
  53. package/dist/mem-start.js +0 -2
  54. package/dist/mem-summarize.js +0 -2
  55. package/dist/metrics-cli.js +1 -1
  56. package/dist/metrics-snapshot.js +1 -1
  57. package/dist/onboarding-smoke-test.js +0 -5
  58. package/dist/orchestrate-init-status.js +0 -1
  59. package/dist/orchestrate-initiative.js +0 -1
  60. package/dist/orchestrate-monitor.js +0 -1
  61. package/dist/plan-create.js +0 -2
  62. package/dist/plan-edit.js +0 -2
  63. package/dist/plan-link.js +0 -2
  64. package/dist/plan-promote.js +0 -2
  65. package/dist/signal-cleanup.js +0 -4
  66. package/dist/state-bootstrap.js +0 -1
  67. package/dist/state-cleanup.js +0 -4
  68. package/dist/state-doctor-fix.js +5 -8
  69. package/dist/state-doctor.js +0 -11
  70. package/dist/sync-templates.js +188 -34
  71. package/dist/wu-block.js +100 -48
  72. package/dist/wu-claim.js +1 -22
  73. package/dist/wu-cleanup.js +0 -1
  74. package/dist/wu-create.js +0 -2
  75. package/dist/wu-done-auto-cleanup.js +139 -0
  76. package/dist/wu-done.js +11 -4
  77. package/dist/wu-edit.js +0 -12
  78. package/dist/wu-preflight.js +0 -1
  79. package/dist/wu-prep.js +0 -1
  80. package/dist/wu-proto.js +0 -1
  81. package/dist/wu-spawn.js +0 -3
  82. package/dist/wu-unblock.js +0 -2
  83. package/dist/wu-validate.js +0 -1
  84. package/package.json +9 -7
@@ -1,6 +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
2
  /**
5
3
  * Initiative Add WU Command (WU-1389)
6
4
  *
@@ -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
  *
@@ -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 {
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable security/detect-non-literal-fs-filename */
3
2
  /**
4
3
  * Initiative Plan Command (WU-1105, renamed in WU-1193)
5
4
  *
@@ -1,6 +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
2
  /**
5
3
  * Initiative Remove WU Command (WU-1328)
6
4
  *
@@ -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
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console */
3
2
  /**
4
3
  * lane:suggest CLI Command (WU-1189, WU-1190)
5
4
  *
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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
@@ -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 Index CLI (WU-1235)
5
4
  *
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 {
@@ -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 Profile CLI (WU-1237)
5
4
  *
@@ -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 Promote CLI (WU-1237)
5
4
  *
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 {
@@ -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 {
@@ -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 {
@@ -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)[\(:]?/i);
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,
@@ -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)[\(:]?/i);
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',
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console -- CLI tool requires console output */
3
2
  /**
4
3
  * Orchestrate Initiative Status CLI
5
4
  *
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console -- CLI tool requires console output */
3
2
  /**
4
3
  * Orchestrate Initiative CLI
5
4
  *
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console -- CLI tool requires console output */
3
2
  /**
4
3
  * Orchestrate Monitor CLI (WU-1241)
5
4
  *
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console -- CLI tool requires console output */
3
- /* eslint-disable security/detect-non-literal-fs-filename */
4
2
  /**
5
3
  * Plan Create Command (WU-1313)
6
4
  *
package/dist/plan-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 security/detect-non-literal-fs-filename */
4
2
  /**
5
3
  * Plan Edit Command (WU-1313)
6
4
  *
package/dist/plan-link.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 security/detect-non-literal-fs-filename */
4
2
  /**
5
3
  * Plan Link Command (WU-1313)
6
4
  *
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable no-console -- CLI tool requires console output */
3
- /* eslint-disable security/detect-non-literal-fs-filename */
4
2
  /**
5
3
  * Plan Promote Command (WU-1313)
6
4
  *
@@ -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)) {
@@ -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
  /**
@@ -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)) {
@@ -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}`,
@@ -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,