@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
package/dist/doctor.js ADDED
@@ -0,0 +1,368 @@
1
+ /* eslint-disable no-console -- CLI command uses console for status output */
2
+ /**
3
+ * @file doctor.ts
4
+ * LumenFlow health check command (WU-1177)
5
+ * WU-1191: Lane health check integration
6
+ * Verifies all safety components are installed and configured correctly
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import { execFileSync } from 'node:child_process';
11
+ import { createWUParser } from '@lumenflow/core';
12
+ import { loadLaneDefinitions, detectLaneOverlaps } from './lane-health.js';
13
+ /**
14
+ * CLI option definitions for doctor command
15
+ */
16
+ const DOCTOR_OPTIONS = {
17
+ verbose: {
18
+ name: 'verbose',
19
+ flags: '-v, --verbose',
20
+ description: 'Show detailed output including all checks',
21
+ },
22
+ json: {
23
+ name: 'json',
24
+ flags: '--json',
25
+ description: 'Output results as JSON',
26
+ },
27
+ };
28
+ /**
29
+ * Parse doctor command options
30
+ */
31
+ export function parseDoctorOptions() {
32
+ const opts = createWUParser({
33
+ name: 'lumenflow-doctor',
34
+ description: 'Check LumenFlow safety components and configuration',
35
+ options: Object.values(DOCTOR_OPTIONS),
36
+ });
37
+ return {
38
+ verbose: opts.verbose ?? false,
39
+ json: opts.json ?? false,
40
+ };
41
+ }
42
+ /**
43
+ * Check if Husky hooks are installed
44
+ */
45
+ function checkHusky(projectDir) {
46
+ const huskyDir = path.join(projectDir, '.husky');
47
+ const preCommit = path.join(huskyDir, 'pre-commit');
48
+ if (!fs.existsSync(huskyDir)) {
49
+ return {
50
+ passed: false,
51
+ message: 'Husky hooks not installed',
52
+ details: 'Run: pnpm install && pnpm prepare',
53
+ };
54
+ }
55
+ if (!fs.existsSync(preCommit)) {
56
+ return {
57
+ passed: false,
58
+ message: 'Husky pre-commit hook missing',
59
+ details: 'Run: pnpm prepare',
60
+ };
61
+ }
62
+ return {
63
+ passed: true,
64
+ message: 'Husky hooks installed (.husky/pre-commit)',
65
+ };
66
+ }
67
+ /**
68
+ * Check if safe-git wrapper is present
69
+ */
70
+ function checkSafeGit(projectDir) {
71
+ const safeGitPath = path.join(projectDir, 'scripts', 'safe-git');
72
+ if (!fs.existsSync(safeGitPath)) {
73
+ return {
74
+ passed: false,
75
+ message: 'Safe-git wrapper missing',
76
+ details: 'The scripts/safe-git file should exist to block destructive git commands',
77
+ };
78
+ }
79
+ return {
80
+ passed: true,
81
+ message: 'Safe-git wrapper present (scripts/safe-git)',
82
+ };
83
+ }
84
+ /**
85
+ * Check if AGENTS.md exists
86
+ */
87
+ function checkAgentsMd(projectDir) {
88
+ const agentsMdPath = path.join(projectDir, 'AGENTS.md');
89
+ if (!fs.existsSync(agentsMdPath)) {
90
+ return {
91
+ passed: false,
92
+ message: 'AGENTS.md missing',
93
+ details: 'Run: lumenflow init to create universal agent instructions',
94
+ };
95
+ }
96
+ return {
97
+ passed: true,
98
+ message: 'AGENTS.md exists',
99
+ };
100
+ }
101
+ /**
102
+ * Check if .lumenflow.config.yaml exists
103
+ */
104
+ function checkLumenflowConfig(projectDir) {
105
+ const configPath = path.join(projectDir, '.lumenflow.config.yaml');
106
+ if (!fs.existsSync(configPath)) {
107
+ return {
108
+ passed: false,
109
+ message: 'LumenFlow config missing',
110
+ details: 'Run: lumenflow init to create configuration',
111
+ };
112
+ }
113
+ return {
114
+ passed: true,
115
+ message: 'LumenFlow config present (.lumenflow.config.yaml)',
116
+ };
117
+ }
118
+ /**
119
+ * Check vendor-specific config files
120
+ */
121
+ function checkVendorConfigs(projectDir) {
122
+ const claudeMdPath = path.join(projectDir, 'CLAUDE.md');
123
+ const cursorRulesPath = path.join(projectDir, '.cursor', 'rules', 'lumenflow.md');
124
+ const windsurfRulesPath = path.join(projectDir, '.windsurf', 'rules', 'lumenflow.md');
125
+ const clineRulesPath = path.join(projectDir, '.clinerules');
126
+ const agentsMdPath = path.join(projectDir, 'AGENTS.md');
127
+ return {
128
+ claude: {
129
+ present: fs.existsSync(claudeMdPath),
130
+ path: 'CLAUDE.md',
131
+ },
132
+ cursor: {
133
+ present: fs.existsSync(cursorRulesPath),
134
+ path: '.cursor/rules/lumenflow.md',
135
+ },
136
+ windsurf: {
137
+ present: fs.existsSync(windsurfRulesPath),
138
+ path: '.windsurf/rules/lumenflow.md',
139
+ },
140
+ cline: {
141
+ present: fs.existsSync(clineRulesPath),
142
+ path: '.clinerules',
143
+ },
144
+ codex: {
145
+ // Codex reads AGENTS.md directly
146
+ present: fs.existsSync(agentsMdPath),
147
+ path: 'AGENTS.md',
148
+ },
149
+ };
150
+ }
151
+ /**
152
+ * Get command version safely using execFileSync (no shell injection risk)
153
+ */
154
+ function getCommandVersion(command, args) {
155
+ try {
156
+ const output = execFileSync(command, args, {
157
+ encoding: 'utf-8',
158
+ stdio: ['pipe', 'pipe', 'pipe'],
159
+ }).trim();
160
+ return output;
161
+ }
162
+ catch {
163
+ return 'not found';
164
+ }
165
+ }
166
+ /**
167
+ * Parse semver version string to compare
168
+ */
169
+ function parseVersion(versionStr) {
170
+ // eslint-disable-next-line sonarjs/slow-regex, sonarjs/prefer-regexp-exec -- Simple semver extraction, no backtracking risk
171
+ const match = versionStr.match(/(\d+)\.(\d+)\.?(\d+)?/);
172
+ if (!match) {
173
+ return [0, 0, 0];
174
+ }
175
+ return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3] || '0', 10)];
176
+ }
177
+ /**
178
+ * Compare versions: returns true if actual >= required
179
+ */
180
+ function compareVersions(actual, required) {
181
+ const actualParts = parseVersion(actual);
182
+ const requiredParts = parseVersion(required);
183
+ for (let i = 0; i < 3; i++) {
184
+ if (actualParts[i] > requiredParts[i]) {
185
+ return true;
186
+ }
187
+ if (actualParts[i] < requiredParts[i]) {
188
+ return false;
189
+ }
190
+ }
191
+ return true;
192
+ }
193
+ /**
194
+ * WU-1191: Check lane health configuration
195
+ * Integrates lane:health overlap detection into lumenflow doctor
196
+ */
197
+ function checkLaneHealth(projectDir) {
198
+ const lanes = loadLaneDefinitions(projectDir);
199
+ // No lanes configured - considered healthy (nothing to check)
200
+ if (lanes.length === 0) {
201
+ return {
202
+ passed: true,
203
+ message: 'No lane definitions found - skipping lane health check',
204
+ };
205
+ }
206
+ // Check for overlapping code_paths
207
+ const overlapResult = detectLaneOverlaps(lanes);
208
+ if (overlapResult.hasOverlaps) {
209
+ const overlapCount = overlapResult.overlaps.length;
210
+ const firstOverlap = overlapResult.overlaps[0];
211
+ const laneNames = firstOverlap.lanes.join(' <-> ');
212
+ return {
213
+ passed: false,
214
+ message: `Lane overlap detected: ${overlapCount} overlap(s) found`,
215
+ details: `First overlap: ${laneNames}. Run 'pnpm lane:health' for full report.`,
216
+ };
217
+ }
218
+ return {
219
+ passed: true,
220
+ message: `Lane configuration healthy (${lanes.length} lanes, no overlaps)`,
221
+ };
222
+ }
223
+ /**
224
+ * Check prerequisite versions
225
+ */
226
+ function checkPrerequisites() {
227
+ const nodeVersion = getCommandVersion('node', ['--version']);
228
+ const pnpmVersion = getCommandVersion('pnpm', ['--version']);
229
+ const gitVersion = getCommandVersion('git', ['--version']);
230
+ const requiredNode = '22.0.0';
231
+ const requiredPnpm = '9.0.0';
232
+ const requiredGit = '2.0.0';
233
+ const nodeOk = nodeVersion !== 'not found' && compareVersions(nodeVersion, requiredNode);
234
+ const pnpmOk = pnpmVersion !== 'not found' && compareVersions(pnpmVersion, requiredPnpm);
235
+ const gitOk = gitVersion !== 'not found' && compareVersions(gitVersion, requiredGit);
236
+ return {
237
+ node: {
238
+ passed: nodeOk,
239
+ version: nodeVersion,
240
+ required: `>=${requiredNode}`,
241
+ message: nodeOk ? undefined : `Node.js ${requiredNode}+ required`,
242
+ },
243
+ pnpm: {
244
+ passed: pnpmOk,
245
+ version: pnpmVersion,
246
+ required: `>=${requiredPnpm}`,
247
+ message: pnpmOk ? undefined : `pnpm ${requiredPnpm}+ required`,
248
+ },
249
+ git: {
250
+ passed: gitOk,
251
+ version: gitVersion,
252
+ required: `>=${requiredGit}`,
253
+ message: gitOk ? undefined : `Git ${requiredGit}+ required`,
254
+ },
255
+ };
256
+ }
257
+ /**
258
+ * Run all doctor checks
259
+ */
260
+ export async function runDoctor(projectDir) {
261
+ const checks = {
262
+ husky: checkHusky(projectDir),
263
+ safeGit: checkSafeGit(projectDir),
264
+ agentsMd: checkAgentsMd(projectDir),
265
+ lumenflowConfig: checkLumenflowConfig(projectDir),
266
+ // WU-1191: Lane health check
267
+ laneHealth: checkLaneHealth(projectDir),
268
+ };
269
+ const vendorConfigs = checkVendorConfigs(projectDir);
270
+ const prerequisites = checkPrerequisites();
271
+ // Determine overall status
272
+ // Note: laneHealth is advisory (not included in critical checks)
273
+ const criticalChecks = [checks.husky, checks.safeGit, checks.agentsMd];
274
+ const allCriticalPassed = criticalChecks.every((check) => check.passed);
275
+ return {
276
+ status: allCriticalPassed ? 'ACTIVE' : 'INCOMPLETE',
277
+ checks,
278
+ vendorConfigs,
279
+ prerequisites,
280
+ };
281
+ }
282
+ /**
283
+ * Format doctor output for terminal display
284
+ */
285
+ export function formatDoctorOutput(result) {
286
+ const lines = [];
287
+ lines.push('');
288
+ lines.push('LumenFlow Health Check');
289
+ lines.push('─'.repeat(45));
290
+ // Core safety checks
291
+ lines.push('');
292
+ lines.push('Core Safety Components:');
293
+ const formatCheck = (check) => {
294
+ const symbol = check.passed ? '✓' : '✗';
295
+ return ` ${symbol} ${check.message}`;
296
+ };
297
+ lines.push(formatCheck(result.checks.husky));
298
+ lines.push(formatCheck(result.checks.safeGit));
299
+ lines.push(formatCheck(result.checks.agentsMd));
300
+ lines.push(formatCheck(result.checks.lumenflowConfig));
301
+ // WU-1191: Lane Health section
302
+ lines.push('');
303
+ lines.push('Lane Health:');
304
+ lines.push(formatCheck(result.checks.laneHealth));
305
+ // Vendor configs
306
+ lines.push('');
307
+ lines.push('Vendor Configs:');
308
+ const vendors = ['claude', 'cursor', 'windsurf', 'cline', 'codex'];
309
+ for (const vendor of vendors) {
310
+ const config = result.vendorConfigs[vendor];
311
+ const symbol = config.present ? '✓' : '○';
312
+ const status = config.present ? 'present' : 'not configured';
313
+ lines.push(` ${symbol} ${vendor}: ${status} (${config.path})`);
314
+ }
315
+ // Prerequisites
316
+ lines.push('');
317
+ lines.push('Prerequisites:');
318
+ const prereqs = ['node', 'pnpm', 'git'];
319
+ for (const prereq of prereqs) {
320
+ const check = result.prerequisites[prereq];
321
+ const symbol = check.passed ? '✓' : '✗';
322
+ const versionDisplay = check.version === 'not found' ? 'not found' : check.version;
323
+ lines.push(` ${symbol} ${prereq}: ${versionDisplay} (required: ${check.required})`);
324
+ }
325
+ // Summary
326
+ lines.push('');
327
+ lines.push('─'.repeat(45));
328
+ lines.push(`LumenFlow safety: ${result.status}`);
329
+ if (result.status === 'INCOMPLETE') {
330
+ lines.push('');
331
+ lines.push('To fix missing components:');
332
+ lines.push(' pnpm install && pnpm prepare # Install Husky hooks');
333
+ lines.push(' lumenflow init # Create missing config files');
334
+ }
335
+ lines.push('');
336
+ return lines.join('\n');
337
+ }
338
+ /**
339
+ * Format doctor output as JSON
340
+ */
341
+ export function formatDoctorJson(result) {
342
+ return JSON.stringify(result, null, 2);
343
+ }
344
+ /**
345
+ * CLI entry point
346
+ */
347
+ export async function main() {
348
+ const opts = parseDoctorOptions();
349
+ const projectDir = process.cwd();
350
+ const result = await runDoctor(projectDir);
351
+ if (opts.json) {
352
+ console.log(formatDoctorJson(result));
353
+ }
354
+ else {
355
+ console.log(formatDoctorOutput(result));
356
+ }
357
+ // Exit with error code if incomplete
358
+ if (result.status === 'INCOMPLETE') {
359
+ process.exit(1);
360
+ }
361
+ }
362
+ // CLI invocation when run directly
363
+ if (import.meta.main) {
364
+ main().catch((error) => {
365
+ console.error('Doctor failed:', error);
366
+ process.exit(1);
367
+ });
368
+ }
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { Command } from 'commander';
17
17
  import { getBottleneckAnalysis, } from '@lumenflow/metrics';
18
- import { buildDependencyGraph, renderMermaid } from '@lumenflow/core/dist/dependency-graph.js';
18
+ import { buildDependencyGraphAsync, renderMermaid, } from '@lumenflow/core/dist/dependency-graph.js';
19
19
  import { die } from '@lumenflow/core/dist/error-handler.js';
20
20
  /** Log prefix for console output */
21
21
  const LOG_PREFIX = '[flow:bottlenecks]';
@@ -144,7 +144,7 @@ async function main() {
144
144
  const limit = parseInt(opts.limit, 10);
145
145
  console.log(`${LOG_PREFIX} Building dependency graph...`);
146
146
  // Build dependency graph from WU YAML files
147
- const coreGraph = buildDependencyGraph();
147
+ const coreGraph = await buildDependencyGraphAsync();
148
148
  if (coreGraph.size === 0) {
149
149
  console.log(`${LOG_PREFIX} No WUs found in dependency graph.`);
150
150
  console.log(`${LOG_PREFIX} Ensure WU YAML files exist in docs/04-operations/tasks/wu/ with blocked_by/blocks fields.`);
@@ -174,9 +174,10 @@ async function main() {
174
174
  console.log(JSON.stringify(analysis, null, 2));
175
175
  }
176
176
  }
177
- // Guard main() for testability (WU-1366)
178
- import { fileURLToPath } from 'node:url';
179
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
177
+ // WU-1181: Use import.meta.main instead of process.argv[1] comparison
178
+ // The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
179
+ // path but import.meta.url resolves to the real path - they never match
180
+ if (import.meta.main) {
180
181
  main().catch((err) => {
181
182
  die(`Bottleneck analysis failed: ${err.message}`);
182
183
  });
@@ -302,9 +302,10 @@ async function main() {
302
302
  console.log(JSON.stringify(report, null, 2));
303
303
  }
304
304
  }
305
- // Guard main() for testability (WU-1366)
306
- import { fileURLToPath } from 'node:url';
307
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
305
+ // WU-1181: Use import.meta.main instead of process.argv[1] comparison
306
+ // The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
307
+ // path but import.meta.url resolves to the real path - they never match
308
+ if (import.meta.main) {
308
309
  main().catch((err) => {
309
310
  die(`Flow report failed: ${err.message}`);
310
311
  });