@lumenflow/cli 2.2.2 → 2.3.1

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 (118) hide show
  1. package/README.md +147 -57
  2. package/dist/__tests__/agent-log-issue.test.js +56 -0
  3. package/dist/__tests__/cli-entry-point.test.js +66 -17
  4. package/dist/__tests__/cli-subprocess.test.js +25 -0
  5. package/dist/__tests__/init.test.js +298 -0
  6. package/dist/__tests__/initiative-plan.test.js +340 -0
  7. package/dist/__tests__/mem-cleanup-execution.test.js +19 -0
  8. package/dist/__tests__/merge-block.test.js +220 -0
  9. package/dist/__tests__/safe-git.test.js +191 -0
  10. package/dist/__tests__/state-doctor.test.js +274 -0
  11. package/dist/__tests__/wu-done.test.js +36 -0
  12. package/dist/__tests__/wu-edit.test.js +119 -0
  13. package/dist/__tests__/wu-prep.test.js +108 -0
  14. package/dist/agent-issues-query.js +4 -3
  15. package/dist/agent-log-issue.js +25 -4
  16. package/dist/backlog-prune.js +5 -4
  17. package/dist/cli-entry-point.js +11 -1
  18. package/dist/doctor.js +368 -0
  19. package/dist/flow-bottlenecks.js +6 -5
  20. package/dist/flow-report.js +4 -3
  21. package/dist/gates.js +356 -101
  22. package/dist/guard-locked.js +4 -3
  23. package/dist/guard-worktree-commit.js +4 -3
  24. package/dist/init.js +508 -86
  25. package/dist/initiative-add-wu.js +4 -3
  26. package/dist/initiative-bulk-assign-wus.js +8 -5
  27. package/dist/initiative-create.js +73 -37
  28. package/dist/initiative-edit.js +37 -21
  29. package/dist/initiative-list.js +4 -3
  30. package/dist/initiative-plan.js +337 -0
  31. package/dist/initiative-status.js +4 -3
  32. package/dist/lane-health.js +377 -0
  33. package/dist/lane-suggest.js +382 -0
  34. package/dist/mem-checkpoint.js +2 -2
  35. package/dist/mem-cleanup.js +2 -2
  36. package/dist/mem-context.js +306 -0
  37. package/dist/mem-create.js +2 -2
  38. package/dist/mem-delete.js +293 -0
  39. package/dist/mem-inbox.js +2 -2
  40. package/dist/mem-index.js +211 -0
  41. package/dist/mem-init.js +1 -1
  42. package/dist/mem-profile.js +207 -0
  43. package/dist/mem-promote.js +254 -0
  44. package/dist/mem-ready.js +2 -2
  45. package/dist/mem-signal.js +2 -2
  46. package/dist/mem-start.js +2 -2
  47. package/dist/mem-summarize.js +2 -2
  48. package/dist/mem-triage.js +2 -2
  49. package/dist/merge-block.js +222 -0
  50. package/dist/metrics-cli.js +7 -4
  51. package/dist/metrics-snapshot.js +4 -3
  52. package/dist/orchestrate-initiative.js +10 -4
  53. package/dist/orchestrate-monitor.js +379 -31
  54. package/dist/signal-cleanup.js +296 -0
  55. package/dist/spawn-list.js +6 -5
  56. package/dist/state-bootstrap.js +5 -4
  57. package/dist/state-cleanup.js +360 -0
  58. package/dist/state-doctor-fix.js +196 -0
  59. package/dist/state-doctor.js +501 -0
  60. package/dist/validate-agent-skills.js +4 -3
  61. package/dist/validate-agent-sync.js +4 -3
  62. package/dist/validate-backlog-sync.js +4 -3
  63. package/dist/validate-skills-spec.js +4 -3
  64. package/dist/validate.js +4 -3
  65. package/dist/wu-block.js +3 -3
  66. package/dist/wu-claim.js +208 -98
  67. package/dist/wu-cleanup.js +5 -4
  68. package/dist/wu-create.js +71 -46
  69. package/dist/wu-delete.js +88 -60
  70. package/dist/wu-deps.js +6 -5
  71. package/dist/wu-done-check.js +34 -0
  72. package/dist/wu-done.js +39 -12
  73. package/dist/wu-edit.js +63 -28
  74. package/dist/wu-infer-lane.js +7 -6
  75. package/dist/wu-preflight.js +23 -81
  76. package/dist/wu-prep.js +125 -0
  77. package/dist/wu-prune.js +4 -3
  78. package/dist/wu-recover.js +88 -22
  79. package/dist/wu-repair.js +7 -6
  80. package/dist/wu-spawn.js +226 -270
  81. package/dist/wu-status.js +4 -3
  82. package/dist/wu-unblock.js +5 -5
  83. package/dist/wu-unlock-lane.js +4 -3
  84. package/dist/wu-validate.js +5 -4
  85. package/package.json +16 -7
  86. package/templates/core/.lumenflow/constraints.md.template +192 -0
  87. package/templates/core/.lumenflow/rules/git-safety.md.template +27 -0
  88. package/templates/core/.lumenflow/rules/wu-workflow.md.template +48 -0
  89. package/templates/core/AGENTS.md.template +60 -0
  90. package/templates/core/LUMENFLOW.md.template +255 -0
  91. package/templates/core/UPGRADING.md.template +121 -0
  92. package/templates/core/ai/onboarding/agent-safety-card.md.template +106 -0
  93. package/templates/core/ai/onboarding/first-wu-mistakes.md.template +198 -0
  94. package/templates/core/ai/onboarding/quick-ref-commands.md.template +186 -0
  95. package/templates/core/ai/onboarding/release-process.md.template +362 -0
  96. package/templates/core/ai/onboarding/troubleshooting-wu-done.md.template +159 -0
  97. package/templates/core/ai/onboarding/wu-create-checklist.md.template +117 -0
  98. package/templates/vendors/aider/.aider.conf.yml.template +27 -0
  99. package/templates/vendors/claude/.claude/CLAUDE.md.template +52 -0
  100. package/templates/vendors/claude/.claude/settings.json.template +49 -0
  101. package/templates/vendors/claude/.claude/skills/bug-classification/SKILL.md.template +192 -0
  102. package/templates/vendors/claude/.claude/skills/code-quality/SKILL.md.template +152 -0
  103. package/templates/vendors/claude/.claude/skills/context-management/SKILL.md.template +155 -0
  104. package/templates/vendors/claude/.claude/skills/execution-memory/SKILL.md.template +304 -0
  105. package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +131 -0
  106. package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +164 -0
  107. package/templates/vendors/claude/.claude/skills/library-first/SKILL.md.template +98 -0
  108. package/templates/vendors/claude/.claude/skills/lumenflow-gates/SKILL.md.template +87 -0
  109. package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +84 -0
  110. package/templates/vendors/claude/.claude/skills/ops-maintenance/SKILL.md.template +254 -0
  111. package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +189 -0
  112. package/templates/vendors/claude/.claude/skills/tdd-workflow/SKILL.md.template +139 -0
  113. package/templates/vendors/claude/.claude/skills/worktree-discipline/SKILL.md.template +138 -0
  114. package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +106 -0
  115. package/templates/vendors/cline/.clinerules.template +53 -0
  116. package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +34 -0
  117. package/templates/vendors/cursor/.cursor/rules.md.template +28 -0
  118. package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +34 -0
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+ /**
4
+ * lane:suggest CLI Command (WU-1189, WU-1190)
5
+ *
6
+ * LLM-driven lane generation based on codebase context.
7
+ * Analyzes project structure and uses LLM to suggest appropriate lane definitions.
8
+ *
9
+ * Usage:
10
+ * pnpm lane:suggest # Generate suggestions
11
+ * pnpm lane:suggest --dry-run # Preview without LLM call
12
+ * pnpm lane:suggest --interactive # Accept/skip/edit each suggestion
13
+ * pnpm lane:suggest --output lanes.yaml # Write to file
14
+ * pnpm lane:suggest --include-git # Add git history context (WU-1190)
15
+ */
16
+ import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
17
+ import * as readline from 'node:readline';
18
+ import path from 'node:path';
19
+ import YAML from 'yaml';
20
+ import chalk from 'chalk';
21
+ import { findProjectRoot, createWUParser } from '@lumenflow/core';
22
+ import { gatherProjectContext, generateSystemPrompt, generateUserPrompt, getDefaultSuggestions, isValidLaneFormat, } from '@lumenflow/core/dist/lane-suggest-prompt.js';
23
+ import { extractGitContext, summarizeGitContext, } from '@lumenflow/core/dist/git-context-extractor.js';
24
+ import { runCLI } from './cli-entry-point.js';
25
+ /**
26
+ * CLI option definitions
27
+ */
28
+ const LANE_SUGGEST_OPTIONS = {
29
+ dryRun: {
30
+ name: 'dryRun',
31
+ flags: '--dry-run',
32
+ description: 'Show what would be suggested without making LLM call',
33
+ },
34
+ interactive: {
35
+ name: 'interactive',
36
+ flags: '--interactive, -i',
37
+ description: 'Interactively accept/skip/edit each suggestion',
38
+ },
39
+ output: {
40
+ name: 'output',
41
+ flags: '--output, -o <file>',
42
+ description: 'Write suggestions to YAML file',
43
+ },
44
+ json: {
45
+ name: 'json',
46
+ flags: '--json',
47
+ description: 'Output suggestions as JSON',
48
+ },
49
+ noLlm: {
50
+ name: 'noLlm',
51
+ flags: '--no-llm',
52
+ description: 'Use heuristic-based suggestions (no LLM)',
53
+ },
54
+ includeGit: {
55
+ name: 'includeGit',
56
+ flags: '--include-git',
57
+ description: 'Add git history context (co-occurrence, ownership, churn) to LLM prompt',
58
+ },
59
+ };
60
+ /**
61
+ * Parse CLI options
62
+ */
63
+ function parseOptions() {
64
+ const opts = createWUParser({
65
+ name: 'lane-suggest',
66
+ description: 'Suggest lane definitions based on codebase context',
67
+ options: Object.values(LANE_SUGGEST_OPTIONS),
68
+ });
69
+ return {
70
+ dryRun: opts.dryRun ?? false,
71
+ interactive: opts.interactive ?? false,
72
+ output: opts.output,
73
+ json: opts.json ?? false,
74
+ noLlm: opts.noLlm ?? false,
75
+ includeGit: opts.includeGit ?? false,
76
+ };
77
+ }
78
+ /**
79
+ * Format a lane suggestion for terminal output
80
+ */
81
+ function formatSuggestion(suggestion, index) {
82
+ const lines = [];
83
+ lines.push(chalk.bold.cyan(`\n[${index + 1}] ${suggestion.lane}`));
84
+ lines.push(chalk.gray(` Description: ${suggestion.description}`));
85
+ lines.push(chalk.gray(` Rationale: ${suggestion.rationale}`));
86
+ lines.push(chalk.gray(` Code Paths:`));
87
+ for (const cp of suggestion.code_paths) {
88
+ lines.push(chalk.gray(` - ${cp}`));
89
+ }
90
+ lines.push(chalk.gray(` Keywords: ${suggestion.keywords.join(', ')}`));
91
+ return lines.join('\n');
92
+ }
93
+ /**
94
+ * Interactive mode: prompt user for each suggestion
95
+ */
96
+ async function interactiveMode(suggestions) {
97
+ const accepted = [];
98
+ const rl = readline.createInterface({
99
+ input: process.stdin,
100
+ output: process.stdout,
101
+ });
102
+ const question = (prompt) => {
103
+ return new Promise((resolve) => {
104
+ rl.question(prompt, resolve);
105
+ });
106
+ };
107
+ console.log(chalk.bold('\nInteractive Mode'));
108
+ console.log(chalk.gray('For each suggestion, choose: (a)ccept, (s)kip, (e)dit, (q)uit\n'));
109
+ for (let i = 0; i < suggestions.length; i++) {
110
+ const suggestion = suggestions[i];
111
+ console.log(formatSuggestion(suggestion, i));
112
+ const answer = await question(chalk.yellow('\n Action [a/s/e/q]: '));
113
+ switch (answer.toLowerCase().trim()) {
114
+ case 'a':
115
+ case 'accept':
116
+ case '': // Default to accept
117
+ accepted.push(suggestion);
118
+ console.log(chalk.green(' Accepted'));
119
+ break;
120
+ case 's':
121
+ case 'skip':
122
+ console.log(chalk.gray(' Skipped'));
123
+ break;
124
+ case 'e':
125
+ case 'edit': {
126
+ const newLane = await question(chalk.yellow(` New lane name [${suggestion.lane}]: `));
127
+ const newDesc = await question(chalk.yellow(` New description [${suggestion.description}]: `));
128
+ const edited = {
129
+ ...suggestion,
130
+ lane: newLane.trim() || suggestion.lane,
131
+ description: newDesc.trim() || suggestion.description,
132
+ };
133
+ // Validate lane format
134
+ if (!isValidLaneFormat(edited.lane)) {
135
+ console.log(chalk.red(' Invalid lane format. Expected "Parent: Sublane"'));
136
+ console.log(chalk.gray(' Using original lane name'));
137
+ edited.lane = suggestion.lane;
138
+ }
139
+ accepted.push(edited);
140
+ console.log(chalk.green(' Edited and accepted'));
141
+ break;
142
+ }
143
+ case 'q':
144
+ case 'quit':
145
+ console.log(chalk.gray(' Quitting interactive mode'));
146
+ rl.close();
147
+ return accepted;
148
+ default:
149
+ console.log(chalk.gray(' Unknown action, skipping'));
150
+ break;
151
+ }
152
+ }
153
+ rl.close();
154
+ return accepted;
155
+ }
156
+ /**
157
+ * Generate lane inference YAML from suggestions
158
+ */
159
+ function generateLaneInferenceYAML(suggestions) {
160
+ // Group suggestions by parent lane
161
+ const grouped = {};
162
+ for (const suggestion of suggestions) {
163
+ const [parent, sublane] = suggestion.lane.split(': ');
164
+ if (!parent || !sublane)
165
+ continue;
166
+ if (!grouped[parent]) {
167
+ grouped[parent] = {};
168
+ }
169
+ grouped[parent][sublane] = {
170
+ description: suggestion.description,
171
+ code_paths: suggestion.code_paths,
172
+ keywords: suggestion.keywords,
173
+ };
174
+ }
175
+ const header = `# Lane Inference Configuration
176
+ # Generated by: pnpm lane:suggest
177
+ # Customize this file to match your project structure
178
+
179
+ `;
180
+ return header + YAML.stringify(grouped);
181
+ }
182
+ /**
183
+ * Display dry-run information
184
+ */
185
+ function displayDryRun(context, systemPrompt, userPrompt, gitContext, gitSummary) {
186
+ console.log(chalk.bold.cyan('\n=== DRY RUN MODE ===\n'));
187
+ console.log(chalk.gray('This shows what would be sent to the LLM.\n'));
188
+ console.log(chalk.bold('Project Context:'));
189
+ console.log(chalk.gray(` - Monorepo: ${context.isMonorepo}`));
190
+ console.log(chalk.gray(` - Packages: ${context.packageNames.length}`));
191
+ console.log(chalk.gray(` - Has docs/: ${context.hasDocsDir}`));
192
+ console.log(chalk.gray(` - Has apps/: ${context.hasAppsDir}`));
193
+ console.log(chalk.gray(` - Existing lanes: ${context.existingLanes.length}`));
194
+ if (context.packageNames.length > 0) {
195
+ console.log(chalk.bold('\nPackages Found:'));
196
+ for (const pkg of context.packageNames) {
197
+ console.log(chalk.gray(` - ${pkg}`));
198
+ }
199
+ }
200
+ if (context.directoryStructure.length > 0) {
201
+ console.log(chalk.bold('\nDirectory Structure:'));
202
+ for (const dir of context.directoryStructure) {
203
+ console.log(chalk.gray(` - ${dir}/`));
204
+ }
205
+ }
206
+ // Display git context if available (WU-1190)
207
+ if (gitContext && gitSummary) {
208
+ console.log(chalk.bold('\nGit History Context (--include-git):'));
209
+ if (gitContext.hasLimitedHistory) {
210
+ console.log(chalk.yellow(` Limited history: ${gitContext.error ?? 'sparse commit history'}`));
211
+ }
212
+ else {
213
+ console.log(chalk.gray(` - Co-occurrences: ${gitContext.coOccurrences.length} pairs found`));
214
+ console.log(chalk.gray(` - Ownership signals: ${gitContext.ownership.length} paths analyzed`));
215
+ console.log(chalk.gray(` - Churn hotspots: ${gitContext.churn.length} files identified`));
216
+ }
217
+ console.log(chalk.bold('\nGit Summary (for LLM):'));
218
+ console.log(chalk.gray(gitSummary.slice(0, 500) + (gitSummary.length > 500 ? '...' : '')));
219
+ }
220
+ console.log(chalk.bold('\nSystem Prompt Preview:'));
221
+ console.log(chalk.gray(systemPrompt.slice(0, 500) + '...'));
222
+ console.log(chalk.bold('\nUser Prompt Preview:'));
223
+ console.log(chalk.gray(userPrompt.slice(0, 1000) + '...'));
224
+ console.log(chalk.bold('\nDefault Suggestions (without LLM):'));
225
+ const defaults = getDefaultSuggestions(context);
226
+ for (let i = 0; i < defaults.length; i++) {
227
+ console.log(formatSuggestion(defaults[i], i));
228
+ }
229
+ console.log(chalk.cyan('\n=== END DRY RUN ==='));
230
+ console.log(chalk.gray('\nTo generate actual suggestions, run without --dry-run'));
231
+ }
232
+ /**
233
+ * Get suggestions using heuristics (LLM deferred per WU-1189)
234
+ */
235
+ function getSuggestions(context, noLlm) {
236
+ if (noLlm) {
237
+ console.log(chalk.gray(' Using heuristic-based suggestions (--no-llm)'));
238
+ }
239
+ else {
240
+ console.log(chalk.yellow(' Note: LLM integration requires API configuration'));
241
+ console.log(chalk.gray(' Using heuristic-based suggestions as fallback'));
242
+ console.log(chalk.gray(' Set OPENAI_API_KEY or use --no-llm for explicit heuristics\n'));
243
+ }
244
+ // NOTE: LLM call implementation deferred per WU-1189 scope
245
+ return getDefaultSuggestions(context);
246
+ }
247
+ /**
248
+ * Output suggestions as JSON
249
+ */
250
+ function outputAsJson(suggestions, context) {
251
+ const result = {
252
+ suggestions,
253
+ context: {
254
+ packageCount: context.packageNames.length,
255
+ docsFound: context.hasDocsDir,
256
+ existingConfig: context.existingLanes.length > 0,
257
+ },
258
+ };
259
+ console.log(chalk.bold('\nJSON Output:'));
260
+ console.log(JSON.stringify(result, null, 2));
261
+ }
262
+ /**
263
+ * Write suggestions to YAML file
264
+ */
265
+ function writeToFile(suggestions, outputFile, projectRoot) {
266
+ const outputPath = path.isAbsolute(outputFile) ? outputFile : path.join(projectRoot, outputFile);
267
+ const yamlContent = generateLaneInferenceYAML(suggestions);
268
+ const outputDir = path.dirname(outputPath);
269
+ if (!existsSync(outputDir)) {
270
+ mkdirSync(outputDir, { recursive: true });
271
+ }
272
+ writeFileSync(outputPath, yamlContent);
273
+ console.log(chalk.green(`\nLane configuration written to: ${outputPath}`));
274
+ }
275
+ /**
276
+ * Display suggestions in terminal
277
+ */
278
+ function displaySuggestions(suggestions) {
279
+ suggestions.forEach((s, i) => console.log(formatSuggestion(s, i)));
280
+ }
281
+ /**
282
+ * Show save instructions
283
+ */
284
+ function showSaveInstructions() {
285
+ console.log(chalk.bold('\nTo save these suggestions:'));
286
+ console.log(chalk.gray(' pnpm lane:suggest --output .lumenflow.lane-inference.yaml'));
287
+ console.log(chalk.gray(' pnpm lane:suggest --interactive --output lanes.yaml'));
288
+ console.log(chalk.gray(' pnpm lane:suggest --json > lanes.json'));
289
+ }
290
+ /**
291
+ * Generate user prompt with optional git context (WU-1190)
292
+ */
293
+ function generateEnrichedUserPrompt(context, gitSummary) {
294
+ let prompt = generateUserPrompt(context);
295
+ if (gitSummary) {
296
+ // Insert git context before the instructions section
297
+ const instructionsMarker = '## Instructions';
298
+ const insertionPoint = prompt.indexOf(instructionsMarker);
299
+ if (insertionPoint !== -1) {
300
+ const gitSection = `## Git History Analysis
301
+
302
+ The following insights were extracted from the repository's git history.
303
+ Use these to understand which files are often changed together (suggesting shared ownership),
304
+ who the primary contributors are for different areas, and which files have high churn (potential complexity).
305
+
306
+ ${gitSummary}
307
+
308
+ `;
309
+ prompt = prompt.slice(0, insertionPoint) + gitSection + prompt.slice(insertionPoint);
310
+ }
311
+ else {
312
+ // Fallback: append at the end
313
+ prompt += `\n\n## Git History Analysis\n\n${gitSummary}`;
314
+ }
315
+ }
316
+ return prompt;
317
+ }
318
+ /**
319
+ * Main entry point
320
+ */
321
+ async function main() {
322
+ const opts = parseOptions();
323
+ const projectRoot = findProjectRoot();
324
+ console.log(chalk.bold('[lane:suggest] Analyzing project structure...'));
325
+ console.log(chalk.gray(` Project root: ${projectRoot}`));
326
+ const context = gatherProjectContext(projectRoot);
327
+ // Extract git context if requested (WU-1190)
328
+ let gitContext;
329
+ let gitSummary;
330
+ if (opts.includeGit) {
331
+ console.log(chalk.gray(' Extracting git history context...'));
332
+ gitContext = extractGitContext(projectRoot);
333
+ if (gitContext.hasLimitedHistory) {
334
+ console.log(chalk.yellow(` Git history limited: ${gitContext.error ?? 'sparse history'}`));
335
+ }
336
+ else {
337
+ console.log(chalk.gray(` - ${gitContext.coOccurrences.length} co-occurrence pairs`));
338
+ console.log(chalk.gray(` - ${gitContext.ownership.length} ownership signals`));
339
+ console.log(chalk.gray(` - ${gitContext.churn.length} churn hotspots`));
340
+ }
341
+ // Summarize for LLM prompt (respecting token limits)
342
+ gitSummary = summarizeGitContext(gitContext, { maxTokens: 500 });
343
+ }
344
+ if (opts.dryRun) {
345
+ const userPrompt = generateEnrichedUserPrompt(context, gitSummary);
346
+ displayDryRun(context, generateSystemPrompt(), userPrompt, gitContext, gitSummary);
347
+ return;
348
+ }
349
+ let suggestions = getSuggestions(context, opts.noLlm ?? false);
350
+ if (suggestions.length === 0) {
351
+ console.log(chalk.yellow('\nNo lane suggestions generated.'));
352
+ console.log(chalk.gray('Try providing more project structure (packages/, docs/, etc.)'));
353
+ return;
354
+ }
355
+ console.log(chalk.bold(`\nGenerated ${suggestions.length} lane suggestion(s):`));
356
+ if (opts.interactive) {
357
+ suggestions = await interactiveMode(suggestions);
358
+ if (suggestions.length === 0) {
359
+ console.log(chalk.yellow('\nNo suggestions accepted.'));
360
+ return;
361
+ }
362
+ console.log(chalk.bold(`\nAccepted ${suggestions.length} suggestion(s)`));
363
+ }
364
+ else {
365
+ displaySuggestions(suggestions);
366
+ }
367
+ if (opts.json) {
368
+ outputAsJson(suggestions, context);
369
+ return;
370
+ }
371
+ if (opts.output) {
372
+ writeToFile(suggestions, opts.output, projectRoot);
373
+ return;
374
+ }
375
+ showSaveInstructions();
376
+ }
377
+ // Entry point
378
+ if (import.meta.main) {
379
+ void runCLI(main);
380
+ }
381
+ // Export for testing
382
+ export { main, parseOptions, formatSuggestion, interactiveMode, generateLaneInferenceYAML };
@@ -10,8 +10,8 @@
10
10
  * Usage:
11
11
  * pnpm mem:checkpoint 'note' [--session <id>] [--wu <id>] [--progress <text>] [--next-steps <text>] [--trigger <type>] [--quiet]
12
12
  *
13
- * @see {@link tools/lib/mem-checkpoint-core.mjs} - Core logic
14
- * @see {@link tools/__tests__/mem-checkpoint.test.mjs} - Tests
13
+ * @see {@link packages/@lumenflow/cli/src/lib/mem-checkpoint-core.ts} - Core logic
14
+ * @see {@link packages/@lumenflow/cli/src/__tests__/mem-checkpoint.test.ts} - Tests
15
15
  */
16
16
  import fs from 'node:fs/promises';
17
17
  import path from 'node:path';
@@ -23,8 +23,8 @@
23
23
  * pnpm mem:cleanup --session-id <uuid> # Close specific session
24
24
  * pnpm mem:cleanup --json # Output as JSON
25
25
  *
26
- * @see {@link tools/lib/mem-cleanup-core.mjs} - Core logic
27
- * @see {@link tools/__tests__/mem-cleanup.test.mjs} - Tests
26
+ * @see {@link packages/@lumenflow/cli/src/lib/mem-cleanup-core.ts} - Core logic
27
+ * @see {@link packages/@lumenflow/cli/src/__tests__/mem-cleanup.test.ts} - Tests
28
28
  */
29
29
  import fs from 'node:fs/promises';
30
30
  import path from 'node:path';