lean-spec 0.2.9-dev.20251205030455 → 0.2.10

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.
@@ -6,12 +6,12 @@ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mc
6
6
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
7
7
  import { readFileSync, existsSync } from 'fs';
8
8
  import { fileURLToPath } from 'url';
9
- import * as path12 from 'path';
9
+ import * as path13 from 'path';
10
10
  import { dirname, join, resolve } from 'path';
11
11
  import { z } from 'zod';
12
- import * as fs8 from 'fs/promises';
12
+ import * as fs9 from 'fs/promises';
13
13
  import { readFile, writeFile } from 'fs/promises';
14
- import chalk15 from 'chalk';
14
+ import chalk16 from 'chalk';
15
15
  import { Command } from 'commander';
16
16
  import { spawn, execSync } from 'child_process';
17
17
  import matter from 'gray-matter';
@@ -31,12 +31,12 @@ function checkCommand() {
31
31
  async function checkSpecs(options = {}) {
32
32
  const config = await loadConfig();
33
33
  const cwd = process.cwd();
34
- path12.join(cwd, config.specsDir);
34
+ path13.join(cwd, config.specsDir);
35
35
  const specs = await loadAllSpecs();
36
36
  const sequenceMap = /* @__PURE__ */ new Map();
37
37
  const specPattern = createSpecDirPattern();
38
38
  for (const spec of specs) {
39
- const specName = path12.basename(spec.path);
39
+ const specName = path13.basename(spec.path);
40
40
  const match = specName.match(specPattern);
41
41
  if (match) {
42
42
  const seq = parseInt(match[1], 10);
@@ -54,7 +54,7 @@ async function checkSpecs(options = {}) {
54
54
  if (options.json) {
55
55
  console.log(JSON.stringify({ conflicts: [], hasConflicts: false }, null, 2));
56
56
  } else {
57
- console.log(chalk15.green("\u2713 No sequence conflicts detected"));
57
+ console.log(chalk16.green("\u2713 No sequence conflicts detected"));
58
58
  }
59
59
  }
60
60
  return true;
@@ -73,23 +73,23 @@ async function checkSpecs(options = {}) {
73
73
  if (!options.silent) {
74
74
  if (!options.quiet) {
75
75
  console.log("");
76
- console.log(chalk15.yellow("\u26A0\uFE0F Sequence conflicts detected:\n"));
76
+ console.log(chalk16.yellow("\u26A0\uFE0F Sequence conflicts detected:\n"));
77
77
  for (const [seq, paths] of conflicts) {
78
- console.log(chalk15.red(` Sequence ${String(seq).padStart(config.structure.sequenceDigits, "0")}:`));
78
+ console.log(chalk16.red(` Sequence ${String(seq).padStart(config.structure.sequenceDigits, "0")}:`));
79
79
  for (const p of paths) {
80
- console.log(chalk15.gray(` - ${sanitizeUserInput(p)}`));
80
+ console.log(chalk16.gray(` - ${sanitizeUserInput(p)}`));
81
81
  }
82
82
  console.log("");
83
83
  }
84
- console.log(chalk15.cyan("Tip: Use date prefix to prevent conflicts:"));
85
- console.log(chalk15.gray(' Edit .lean-spec/config.json \u2192 structure.prefix: "{YYYYMMDD}-"'));
84
+ console.log(chalk16.cyan("Tip: Use date prefix to prevent conflicts:"));
85
+ console.log(chalk16.gray(' Edit .lean-spec/config.json \u2192 structure.prefix: "{YYYYMMDD}-"'));
86
86
  console.log("");
87
- console.log(chalk15.cyan("Or rename folders manually to resolve."));
87
+ console.log(chalk16.cyan("Or rename folders manually to resolve."));
88
88
  console.log("");
89
89
  } else {
90
90
  console.log("");
91
- console.log(chalk15.yellow(`\u26A0\uFE0F Conflict warning: ${conflicts.length} sequence conflict(s) detected`));
92
- console.log(chalk15.gray("Run: lean-spec check"));
91
+ console.log(chalk16.yellow(`\u26A0\uFE0F Conflict warning: ${conflicts.length} sequence conflict(s) detected`));
92
+ console.log(chalk16.gray("Run: lean-spec check"));
93
93
  console.log("");
94
94
  }
95
95
  }
@@ -149,7 +149,7 @@ async function updateSpec(specPath, updates, options = {}) {
149
149
  await autoCheckIfEnabled();
150
150
  const cwd = options.cwd ?? process.cwd();
151
151
  const config = await loadConfig(cwd);
152
- const specsDir = path12.join(cwd, config.specsDir);
152
+ const specsDir = path13.join(cwd, config.specsDir);
153
153
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
154
154
  if (!resolvedPath) {
155
155
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}. Tried: ${sanitizeUserInput(specPath)}, specs/${sanitizeUserInput(specPath)}, and searching in date directories`);
@@ -171,12 +171,12 @@ async function updateSpec(specPath, updates, options = {}) {
171
171
  });
172
172
  }
173
173
  await updateFrontmatter(specFile, allUpdates);
174
- console.log(chalk15.green(`\u2713 Updated: ${sanitizeUserInput(path12.relative(cwd, resolvedPath))}`));
174
+ console.log(chalk16.green(`\u2713 Updated: ${sanitizeUserInput(path13.relative(cwd, resolvedPath))}`));
175
175
  const updatedFields = Object.keys(updates).filter((k) => k !== "customFields");
176
176
  if (updates.customFields) {
177
177
  updatedFields.push(...Object.keys(updates.customFields));
178
178
  }
179
- console.log(chalk15.gray(` Fields: ${updatedFields.join(", ")}`));
179
+ console.log(chalk16.gray(` Fields: ${updatedFields.join(", ")}`));
180
180
  }
181
181
 
182
182
  // src/commands/agent.ts
@@ -251,10 +251,10 @@ async function isAgentAvailable(agentConfig) {
251
251
  }
252
252
  const command = agentConfig.command;
253
253
  if (!command) return false;
254
- return new Promise((resolve2) => {
254
+ return new Promise((resolve3) => {
255
255
  const child = spawn("which", [command], { stdio: "pipe" });
256
- child.on("close", (code) => resolve2(code === 0));
257
- child.on("error", () => resolve2(false));
256
+ child.on("close", (code) => resolve3(code === 0));
257
+ child.on("error", () => resolve3(false));
258
258
  });
259
259
  }
260
260
  async function loadSpecContent(specPath) {
@@ -265,11 +265,11 @@ async function loadSpecContent(specPath) {
265
265
  const specDir = spec.fullPath;
266
266
  let content = "";
267
267
  try {
268
- const files = await fs8.readdir(specDir);
268
+ const files = await fs9.readdir(specDir);
269
269
  const mdFiles = files.filter((f) => f.endsWith(".md"));
270
270
  for (const file of mdFiles) {
271
- const filePath = path12.join(specDir, file);
272
- const fileContent = await fs8.readFile(filePath, "utf-8");
271
+ const filePath = path13.join(specDir, file);
272
+ const fileContent = await fs9.readFile(filePath, "utf-8");
273
273
  content += `
274
274
 
275
275
  ### ${file}
@@ -277,15 +277,15 @@ async function loadSpecContent(specPath) {
277
277
  ${fileContent}`;
278
278
  }
279
279
  } catch {
280
- content = await fs8.readFile(spec.filePath, "utf-8");
280
+ content = await fs9.readFile(spec.filePath, "utf-8");
281
281
  }
282
282
  return content;
283
283
  }
284
284
  async function createWorktree(specPath, specName, cwd) {
285
- const worktreePath = path12.join(cwd, ".worktrees", `spec-${specName}`);
285
+ const worktreePath = path13.join(cwd, ".worktrees", `spec-${specName}`);
286
286
  const branchName = `feature/${specName}`;
287
- await fs8.mkdir(path12.join(cwd, ".worktrees"), { recursive: true });
288
- return new Promise((resolve2, reject) => {
287
+ await fs9.mkdir(path13.join(cwd, ".worktrees"), { recursive: true });
288
+ return new Promise((resolve3, reject) => {
289
289
  const child = spawn("git", ["worktree", "add", worktreePath, "-b", branchName], {
290
290
  cwd,
291
291
  stdio: "pipe"
@@ -296,7 +296,7 @@ async function createWorktree(specPath, specName, cwd) {
296
296
  });
297
297
  child.on("close", (code) => {
298
298
  if (code === 0) {
299
- resolve2(worktreePath);
299
+ resolve3(worktreePath);
300
300
  } else {
301
301
  if (stderr.includes("already exists")) {
302
302
  const child2 = spawn("git", ["worktree", "add", worktreePath, branchName], {
@@ -305,7 +305,7 @@ async function createWorktree(specPath, specName, cwd) {
305
305
  });
306
306
  child2.on("close", (code2) => {
307
307
  if (code2 === 0) {
308
- resolve2(worktreePath);
308
+ resolve3(worktreePath);
309
309
  } else {
310
310
  reject(new Error(`Failed to create worktree: ${stderr}`));
311
311
  }
@@ -333,17 +333,17 @@ async function runCliAgent(specPath, agentConfig, worktreePath) {
333
333
  return child;
334
334
  }
335
335
  async function runCloudAgent(specPath, _agentConfig) {
336
- console.log(chalk15.yellow("Cloud agent integration requires GitHub API configuration."));
337
- console.log(chalk15.gray("The spec content has been prepared for manual dispatch."));
336
+ console.log(chalk16.yellow("Cloud agent integration requires GitHub API configuration."));
337
+ console.log(chalk16.gray("The spec content has been prepared for manual dispatch."));
338
338
  const content = await loadSpecContent(specPath);
339
339
  console.log("");
340
- console.log(chalk15.cyan("=== Spec Content for Cloud Agent ==="));
340
+ console.log(chalk16.cyan("=== Spec Content for Cloud Agent ==="));
341
341
  console.log(content.substring(0, 500) + (content.length > 500 ? "..." : ""));
342
342
  console.log("");
343
- console.log(chalk15.gray("To use GitHub Coding Agent:"));
344
- console.log(chalk15.gray(" 1. Create a GitHub Issue with the spec content"));
345
- console.log(chalk15.gray(" 2. Assign to the GitHub Coding Agent"));
346
- console.log(chalk15.gray(" 3. The agent will create a PR automatically"));
343
+ console.log(chalk16.gray("To use GitHub Coding Agent:"));
344
+ console.log(chalk16.gray(" 1. Create a GitHub Issue with the spec content"));
345
+ console.log(chalk16.gray(" 2. Assign to the GitHub Coding Agent"));
346
+ console.log(chalk16.gray(" 3. The agent will create a PR automatically"));
347
347
  }
348
348
  function agentCommand() {
349
349
  const cmd = new Command("agent").description("Dispatch specs to AI coding agents for automated implementation");
@@ -367,50 +367,50 @@ function agentCommand() {
367
367
  async function runAgent(specs, options = {}) {
368
368
  const config = await loadConfig();
369
369
  const cwd = process.cwd();
370
- const specsDir = path12.join(cwd, config.specsDir);
370
+ const specsDir = path13.join(cwd, config.specsDir);
371
371
  const agentName = options.agent || await getDefaultAgent(config);
372
372
  const agentConfig = await getAgentConfig(agentName, config);
373
373
  if (!agentConfig) {
374
- console.error(chalk15.red(`Unknown agent: ${agentName}`));
375
- console.log(chalk15.gray("Available agents: claude, copilot, aider, gemini, gh-coding"));
374
+ console.error(chalk16.red(`Unknown agent: ${agentName}`));
375
+ console.log(chalk16.gray("Available agents: claude, copilot, aider, gemini, gh-coding"));
376
376
  process.exit(1);
377
377
  }
378
378
  const available = await isAgentAvailable(agentConfig);
379
379
  if (!available && agentConfig.type === "cli" && !options.dryRun) {
380
- console.error(chalk15.red(`Agent not found: ${agentConfig.command}`));
381
- console.log(chalk15.gray(`Make sure ${agentConfig.command} is installed and in your PATH.`));
380
+ console.error(chalk16.red(`Agent not found: ${agentConfig.command}`));
381
+ console.log(chalk16.gray(`Make sure ${agentConfig.command} is installed and in your PATH.`));
382
382
  process.exit(1);
383
383
  }
384
384
  console.log("");
385
- console.log(chalk15.green(`\u{1F916} Dispatching to ${chalk15.cyan(agentName)} agent`));
385
+ console.log(chalk16.green(`\u{1F916} Dispatching to ${chalk16.cyan(agentName)} agent`));
386
386
  console.log("");
387
387
  const resolvedSpecs = [];
388
388
  for (const spec of specs) {
389
389
  const resolved = await resolveSpecPath(spec, cwd, specsDir);
390
390
  if (!resolved) {
391
- console.error(chalk15.red(`Spec not found: ${sanitizeUserInput(spec)}`));
391
+ console.error(chalk16.red(`Spec not found: ${sanitizeUserInput(spec)}`));
392
392
  process.exit(1);
393
393
  }
394
394
  resolvedSpecs.push(resolved);
395
395
  }
396
- console.log(chalk15.bold("Specs to process:"));
396
+ console.log(chalk16.bold("Specs to process:"));
397
397
  for (const specPath of resolvedSpecs) {
398
398
  const spec = await getSpec(specPath);
399
399
  if (spec) {
400
400
  const status = getStatusIndicator(spec.frontmatter.status);
401
401
  console.log(` \u2022 ${sanitizeUserInput(spec.name)} ${status}`);
402
402
  } else {
403
- console.log(` \u2022 ${sanitizeUserInput(path12.basename(specPath))}`);
403
+ console.log(` \u2022 ${sanitizeUserInput(path13.basename(specPath))}`);
404
404
  }
405
405
  }
406
406
  console.log("");
407
407
  if (options.dryRun) {
408
- console.log(chalk15.yellow("Dry run mode - no actions will be taken"));
408
+ console.log(chalk16.yellow("Dry run mode - no actions will be taken"));
409
409
  console.log("");
410
- console.log(chalk15.cyan("Would execute:"));
410
+ console.log(chalk16.cyan("Would execute:"));
411
411
  for (const specPath of resolvedSpecs) {
412
412
  const spec = await getSpec(specPath);
413
- const specName = spec?.name || path12.basename(specPath);
413
+ const specName = spec?.name || path13.basename(specPath);
414
414
  console.log(` 1. Update ${specName} status to in-progress`);
415
415
  if (options.parallel) {
416
416
  console.log(` 2. Create worktree at .worktrees/spec-${specName}`);
@@ -422,23 +422,23 @@ async function runAgent(specs, options = {}) {
422
422
  }
423
423
  for (const specPath of resolvedSpecs) {
424
424
  const spec = await getSpec(specPath);
425
- const specName = spec?.name || path12.basename(specPath);
426
- console.log(chalk15.bold(`Processing: ${specName}`));
425
+ const specName = spec?.name || path13.basename(specPath);
426
+ console.log(chalk16.bold(`Processing: ${specName}`));
427
427
  if (options.statusUpdate !== false) {
428
428
  try {
429
429
  await updateSpec(specName, { status: "in-progress" });
430
- console.log(chalk15.green(` \u2713 Updated status to in-progress`));
430
+ console.log(chalk16.green(` \u2713 Updated status to in-progress`));
431
431
  } catch (error) {
432
- console.log(chalk15.yellow(` \u26A0 Could not update status: ${error.message}`));
432
+ console.log(chalk16.yellow(` \u26A0 Could not update status: ${error.message}`));
433
433
  }
434
434
  }
435
435
  let worktreePath;
436
436
  if (options.parallel) {
437
437
  try {
438
438
  worktreePath = await createWorktree(specPath, specName, cwd);
439
- console.log(chalk15.green(` \u2713 Created worktree at ${worktreePath}`));
439
+ console.log(chalk16.green(` \u2713 Created worktree at ${worktreePath}`));
440
440
  } catch (error) {
441
- console.log(chalk15.yellow(` \u26A0 Could not create worktree: ${error.message}`));
441
+ console.log(chalk16.yellow(` \u26A0 Could not create worktree: ${error.message}`));
442
442
  }
443
443
  }
444
444
  const session = {
@@ -449,7 +449,7 @@ async function runAgent(specs, options = {}) {
449
449
  worktree: worktreePath
450
450
  };
451
451
  if (agentConfig.type === "cli") {
452
- console.log(chalk15.cyan(` \u2192 Launching ${agentName}...`));
452
+ console.log(chalk16.cyan(` \u2192 Launching ${agentName}...`));
453
453
  try {
454
454
  const child = await runCliAgent(specPath, agentConfig, worktreePath);
455
455
  session.pid = child.pid;
@@ -468,12 +468,12 @@ async function runAgent(specs, options = {}) {
468
468
  sess.error = error.message;
469
469
  }
470
470
  });
471
- console.log(chalk15.green(` \u2713 Agent launched (PID: ${child.pid})`));
471
+ console.log(chalk16.green(` \u2713 Agent launched (PID: ${child.pid})`));
472
472
  } catch (error) {
473
473
  session.status = "failed";
474
474
  session.error = error.message;
475
475
  activeSessions.set(specName, session);
476
- console.error(chalk15.red(` \u2717 Failed to launch agent: ${error.message}`));
476
+ console.error(chalk16.red(` \u2717 Failed to launch agent: ${error.message}`));
477
477
  }
478
478
  } else {
479
479
  activeSessions.set(specName, session);
@@ -481,8 +481,8 @@ async function runAgent(specs, options = {}) {
481
481
  }
482
482
  console.log("");
483
483
  }
484
- console.log(chalk15.green("\u2728 Agent dispatch complete"));
485
- console.log(chalk15.gray("Use `lean-spec agent status` to check progress"));
484
+ console.log(chalk16.green("\u2728 Agent dispatch complete"));
485
+ console.log(chalk16.gray("Use `lean-spec agent status` to check progress"));
486
486
  }
487
487
  async function showAgentStatus(spec, options = {}) {
488
488
  if (spec) {
@@ -491,7 +491,7 @@ async function showAgentStatus(spec, options = {}) {
491
491
  if (options.json) {
492
492
  console.log(JSON.stringify({ error: `No active session for spec: ${spec}` }));
493
493
  } else {
494
- console.log(chalk15.yellow(`No active session for spec: ${spec}`));
494
+ console.log(chalk16.yellow(`No active session for spec: ${spec}`));
495
495
  }
496
496
  return;
497
497
  }
@@ -499,7 +499,7 @@ async function showAgentStatus(spec, options = {}) {
499
499
  console.log(JSON.stringify(session, null, 2));
500
500
  } else {
501
501
  console.log("");
502
- console.log(chalk15.cyan(`Agent Session: ${spec}`));
502
+ console.log(chalk16.cyan(`Agent Session: ${spec}`));
503
503
  console.log(` Agent: ${session.agent}`);
504
504
  console.log(` Status: ${getSessionStatusIndicator(session.status)}`);
505
505
  console.log(` Started: ${session.startedAt}`);
@@ -510,7 +510,7 @@ async function showAgentStatus(spec, options = {}) {
510
510
  console.log(` PID: ${session.pid}`);
511
511
  }
512
512
  if (session.error) {
513
- console.log(` Error: ${chalk15.red(session.error)}`);
513
+ console.log(` Error: ${chalk16.red(session.error)}`);
514
514
  }
515
515
  console.log("");
516
516
  }
@@ -523,17 +523,17 @@ async function showAgentStatus(spec, options = {}) {
523
523
  return;
524
524
  }
525
525
  if (sessions.length === 0) {
526
- console.log(chalk15.gray("No active agent sessions"));
526
+ console.log(chalk16.gray("No active agent sessions"));
527
527
  return;
528
528
  }
529
529
  console.log("");
530
- console.log(chalk15.green("=== Agent Sessions ==="));
530
+ console.log(chalk16.green("=== Agent Sessions ==="));
531
531
  console.log("");
532
532
  for (const [specName, session] of sessions) {
533
- console.log(`${chalk15.bold(specName)}`);
533
+ console.log(`${chalk16.bold(specName)}`);
534
534
  console.log(` Agent: ${session.agent} | Status: ${getSessionStatusIndicator(session.status)}`);
535
535
  if (session.worktree) {
536
- console.log(` Worktree: ${chalk15.dim(session.worktree)}`);
536
+ console.log(` Worktree: ${chalk16.dim(session.worktree)}`);
537
537
  }
538
538
  }
539
539
  console.log("");
@@ -541,13 +541,13 @@ async function showAgentStatus(spec, options = {}) {
541
541
  function getSessionStatusIndicator(status) {
542
542
  switch (status) {
543
543
  case "running":
544
- return chalk15.blue("\u{1F504} Running");
544
+ return chalk16.blue("\u{1F504} Running");
545
545
  case "completed":
546
- return chalk15.green("\u2705 Completed");
546
+ return chalk16.green("\u2705 Completed");
547
547
  case "failed":
548
- return chalk15.red("\u274C Failed");
548
+ return chalk16.red("\u274C Failed");
549
549
  case "pending":
550
- return chalk15.yellow("\u23F3 Pending");
550
+ return chalk16.yellow("\u23F3 Pending");
551
551
  default:
552
552
  return status;
553
553
  }
@@ -584,42 +584,42 @@ async function listAgents(options = {}) {
584
584
  return;
585
585
  }
586
586
  console.log("");
587
- console.log(chalk15.green("=== Available AI Agents ==="));
587
+ console.log(chalk16.green("=== Available AI Agents ==="));
588
588
  console.log("");
589
- console.log(chalk15.bold("CLI-based (local):"));
589
+ console.log(chalk16.bold("CLI-based (local):"));
590
590
  for (const [name, info] of Object.entries(agents)) {
591
591
  if (info.type === "cli") {
592
- const defaultMarker = info.isDefault ? chalk15.green(" (default)") : "";
593
- const availableMarker = info.available ? chalk15.green("\u2713") : chalk15.red("\u2717");
594
- console.log(` ${availableMarker} ${name}${defaultMarker} ${chalk15.dim(`(${info.command})`)}`);
592
+ const defaultMarker = info.isDefault ? chalk16.green(" (default)") : "";
593
+ const availableMarker = info.available ? chalk16.green("\u2713") : chalk16.red("\u2717");
594
+ console.log(` ${availableMarker} ${name}${defaultMarker} ${chalk16.dim(`(${info.command})`)}`);
595
595
  }
596
596
  }
597
597
  console.log("");
598
- console.log(chalk15.bold("Cloud-based:"));
598
+ console.log(chalk16.bold("Cloud-based:"));
599
599
  for (const [name, info] of Object.entries(agents)) {
600
600
  if (info.type === "cloud") {
601
- const defaultMarker = info.isDefault ? chalk15.green(" (default)") : "";
601
+ const defaultMarker = info.isDefault ? chalk16.green(" (default)") : "";
602
602
  console.log(` \u2022 ${name}${defaultMarker}`);
603
603
  }
604
604
  }
605
605
  console.log("");
606
- console.log(chalk15.gray("Set default: lean-spec agent config <agent>"));
607
- console.log(chalk15.gray("Run agent: lean-spec agent run <spec> --agent <agent>"));
606
+ console.log(chalk16.gray("Set default: lean-spec agent config <agent>"));
607
+ console.log(chalk16.gray("Run agent: lean-spec agent run <spec> --agent <agent>"));
608
608
  console.log("");
609
609
  }
610
610
  async function setDefaultAgent(agent) {
611
611
  const config = await loadConfig();
612
612
  const agentConfig = await getAgentConfig(agent, config);
613
613
  if (!agentConfig) {
614
- console.error(chalk15.red(`Unknown agent: ${agent}`));
615
- console.log(chalk15.gray("Available agents: claude, copilot, aider, gemini, gh-coding"));
614
+ console.error(chalk16.red(`Unknown agent: ${agent}`));
615
+ console.log(chalk16.gray("Available agents: claude, copilot, aider, gemini, gh-coding"));
616
616
  process.exit(1);
617
617
  }
618
618
  const configWithAgents = config;
619
619
  configWithAgents.agents = configWithAgents.agents || {};
620
620
  configWithAgents.agents.default = agent;
621
621
  await saveConfig(configWithAgents);
622
- console.log(chalk15.green(`\u2713 Default agent set to: ${agent}`));
622
+ console.log(chalk16.green(`\u2713 Default agent set to: ${agent}`));
623
623
  }
624
624
 
625
625
  // src/mcp/helpers.ts
@@ -912,8 +912,8 @@ async function getGitInfo() {
912
912
  }
913
913
  async function getProjectName(cwd = process.cwd()) {
914
914
  try {
915
- const packageJsonPath = path12.join(cwd, "package.json");
916
- const content = await fs8.readFile(packageJsonPath, "utf-8");
915
+ const packageJsonPath = path13.join(cwd, "package.json");
916
+ const content = await fs9.readFile(packageJsonPath, "utf-8");
917
917
  const packageJson2 = JSON.parse(content);
918
918
  return packageJson2.name || null;
919
919
  } catch {
@@ -1007,7 +1007,7 @@ async function linkSpec(specPath, options) {
1007
1007
  await autoCheckIfEnabled();
1008
1008
  const config = await loadConfig();
1009
1009
  const cwd = process.cwd();
1010
- const specsDir = path12.join(cwd, config.specsDir);
1010
+ const specsDir = path13.join(cwd, config.specsDir);
1011
1011
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
1012
1012
  if (!resolvedPath) {
1013
1013
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
@@ -1019,7 +1019,7 @@ async function linkSpec(specPath, options) {
1019
1019
  const allSpecs = await loadAllSpecs({ includeArchived: true });
1020
1020
  const specMap = new Map(allSpecs.map((s) => [s.path, s]));
1021
1021
  const dependsOnSpecs = options.dependsOn ? options.dependsOn.split(",").map((s) => s.trim()) : [];
1022
- const targetSpecName = path12.basename(resolvedPath);
1022
+ const targetSpecName = path13.basename(resolvedPath);
1023
1023
  const resolvedDependencies = /* @__PURE__ */ new Map();
1024
1024
  for (const depSpec of dependsOnSpecs) {
1025
1025
  if (depSpec === targetSpecName || depSpec === specPath) {
@@ -1032,7 +1032,7 @@ async function linkSpec(specPath, options) {
1032
1032
  if (depResolvedPath === resolvedPath) {
1033
1033
  throw new Error(`Cannot link spec to itself: ${sanitizeUserInput(depSpec)}`);
1034
1034
  }
1035
- const depSpecName = path12.basename(depResolvedPath);
1035
+ const depSpecName = path13.basename(depResolvedPath);
1036
1036
  resolvedDependencies.set(depSpec, depSpecName);
1037
1037
  }
1038
1038
  const { parseFrontmatter: parseFrontmatter2 } = await import('./frontmatter-6ZBAGOEU.js');
@@ -1048,31 +1048,31 @@ async function linkSpec(specPath, options) {
1048
1048
  }
1049
1049
  }
1050
1050
  if (added === 0) {
1051
- console.log(chalk15.gray(`\u2139 Dependencies already exist, no changes made`));
1051
+ console.log(chalk16.gray(`\u2139 Dependencies already exist, no changes made`));
1052
1052
  return;
1053
1053
  }
1054
1054
  const cycles = detectCycles(targetSpecName, newDependsOn, specMap);
1055
1055
  if (cycles.length > 0) {
1056
- console.log(chalk15.yellow(`\u26A0\uFE0F Dependency cycle detected: ${cycles.join(" \u2192 ")}`));
1056
+ console.log(chalk16.yellow(`\u26A0\uFE0F Dependency cycle detected: ${cycles.join(" \u2192 ")}`));
1057
1057
  }
1058
1058
  await updateFrontmatter(specFile, { depends_on: newDependsOn });
1059
- console.log(chalk15.green(`\u2713 Added dependencies: ${dependsOnSpecs.join(", ")}`));
1060
- console.log(chalk15.gray(` Updated: ${sanitizeUserInput(path12.relative(cwd, resolvedPath))}`));
1059
+ console.log(chalk16.green(`\u2713 Added dependencies: ${dependsOnSpecs.join(", ")}`));
1060
+ console.log(chalk16.gray(` Updated: ${sanitizeUserInput(path13.relative(cwd, resolvedPath))}`));
1061
1061
  }
1062
- function detectCycles(startSpec, dependsOn, specMap, visited = /* @__PURE__ */ new Set(), path25 = []) {
1062
+ function detectCycles(startSpec, dependsOn, specMap, visited = /* @__PURE__ */ new Set(), path26 = []) {
1063
1063
  if (visited.has(startSpec)) {
1064
- const cycleStart = path25.indexOf(startSpec);
1064
+ const cycleStart = path26.indexOf(startSpec);
1065
1065
  if (cycleStart !== -1) {
1066
- return [...path25.slice(cycleStart), startSpec];
1066
+ return [...path26.slice(cycleStart), startSpec];
1067
1067
  }
1068
1068
  return [];
1069
1069
  }
1070
1070
  visited.add(startSpec);
1071
- path25.push(startSpec);
1071
+ path26.push(startSpec);
1072
1072
  for (const dep of dependsOn) {
1073
1073
  const depSpec = specMap.get(dep);
1074
1074
  if (depSpec && depSpec.frontmatter.depends_on) {
1075
- const cycle = detectCycles(dep, depSpec.frontmatter.depends_on, specMap, new Set(visited), [...path25]);
1075
+ const cycle = detectCycles(dep, depSpec.frontmatter.depends_on, specMap, new Set(visited), [...path26]);
1076
1076
  if (cycle.length > 0) {
1077
1077
  return cycle;
1078
1078
  }
@@ -1102,8 +1102,8 @@ function createCommand() {
1102
1102
  async function createSpec(name, options = {}) {
1103
1103
  const config = await loadConfig();
1104
1104
  const cwd = process.cwd();
1105
- const specsDir = path12.join(cwd, config.specsDir);
1106
- await fs8.mkdir(specsDir, { recursive: true });
1105
+ const specsDir = path13.join(cwd, config.specsDir);
1106
+ await fs9.mkdir(specsDir, { recursive: true });
1107
1107
  const seq = await getGlobalNextSeq(specsDir, config.structure.sequenceDigits);
1108
1108
  let specRelativePath;
1109
1109
  if (config.structure.pattern === "flat") {
@@ -1123,18 +1123,18 @@ async function createSpec(name, options = {}) {
1123
1123
  } else {
1124
1124
  throw new Error(`Unknown pattern: ${config.structure.pattern}`);
1125
1125
  }
1126
- const specDir = path12.join(specsDir, specRelativePath);
1127
- const specFile = path12.join(specDir, config.structure.defaultFile);
1126
+ const specDir = path13.join(specsDir, specRelativePath);
1127
+ const specFile = path13.join(specDir, config.structure.defaultFile);
1128
1128
  try {
1129
- await fs8.access(specDir);
1129
+ await fs9.access(specDir);
1130
1130
  throw new Error(`Spec already exists: ${sanitizeUserInput(specDir)}`);
1131
1131
  } catch (error) {
1132
1132
  if (error.code === "ENOENT") ; else {
1133
1133
  throw error;
1134
1134
  }
1135
1135
  }
1136
- await fs8.mkdir(specDir, { recursive: true });
1137
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
1136
+ await fs9.mkdir(specDir, { recursive: true });
1137
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
1138
1138
  let templateName;
1139
1139
  let templateDir = null;
1140
1140
  if (options.template) {
@@ -1147,24 +1147,24 @@ async function createSpec(name, options = {}) {
1147
1147
  } else {
1148
1148
  templateName = config.template || "spec-template.md";
1149
1149
  }
1150
- let templatePath = path12.join(templatesDir, templateName);
1150
+ let templatePath = path13.join(templatesDir, templateName);
1151
1151
  try {
1152
- const stat5 = await fs8.stat(templatePath);
1153
- if (stat5.isDirectory()) {
1152
+ const stat6 = await fs9.stat(templatePath);
1153
+ if (stat6.isDirectory()) {
1154
1154
  templateDir = templatePath;
1155
- templatePath = path12.join(templateDir, "README.md");
1156
- await fs8.access(templatePath);
1155
+ templatePath = path13.join(templateDir, "README.md");
1156
+ await fs9.access(templatePath);
1157
1157
  }
1158
1158
  } catch {
1159
- const legacyPath = path12.join(templatesDir, "spec-template.md");
1159
+ const legacyPath = path13.join(templatesDir, "spec-template.md");
1160
1160
  try {
1161
- await fs8.access(legacyPath);
1161
+ await fs9.access(legacyPath);
1162
1162
  templatePath = legacyPath;
1163
1163
  templateName = "spec-template.md";
1164
1164
  } catch {
1165
- const readmePath = path12.join(templatesDir, "README.md");
1165
+ const readmePath = path13.join(templatesDir, "README.md");
1166
1166
  try {
1167
- await fs8.access(readmePath);
1167
+ await fs9.access(readmePath);
1168
1168
  templatePath = readmePath;
1169
1169
  templateName = "README.md";
1170
1170
  } catch {
@@ -1175,7 +1175,7 @@ async function createSpec(name, options = {}) {
1175
1175
  let content;
1176
1176
  let varContext;
1177
1177
  try {
1178
- const template = await fs8.readFile(templatePath, "utf-8");
1178
+ const template = await fs9.readFile(templatePath, "utf-8");
1179
1179
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1180
1180
  const title = options.title || name;
1181
1181
  varContext = await buildVariableContext(config, { name: title, date });
@@ -1219,41 +1219,41 @@ ${options.description}`
1219
1219
  } catch (error) {
1220
1220
  throw new Error(`Template not found: ${templatePath}. Run: lean-spec init`);
1221
1221
  }
1222
- await fs8.writeFile(specFile, content, "utf-8");
1222
+ await fs9.writeFile(specFile, content, "utf-8");
1223
1223
  try {
1224
1224
  let additionalFiles = [];
1225
1225
  if (templateDir) {
1226
- const templateFiles = await fs8.readdir(templateDir);
1226
+ const templateFiles = await fs9.readdir(templateDir);
1227
1227
  additionalFiles = templateFiles.filter(
1228
1228
  (f) => f.endsWith(".md") && f !== "README.md"
1229
1229
  );
1230
1230
  }
1231
1231
  if (additionalFiles.length > 0) {
1232
1232
  for (const file of additionalFiles) {
1233
- const srcPath = path12.join(templateDir, file);
1234
- const destPath = path12.join(specDir, file);
1235
- let fileContent = await fs8.readFile(srcPath, "utf-8");
1233
+ const srcPath = path13.join(templateDir, file);
1234
+ const destPath = path13.join(specDir, file);
1235
+ let fileContent = await fs9.readFile(srcPath, "utf-8");
1236
1236
  fileContent = resolveVariables(fileContent, varContext);
1237
- await fs8.writeFile(destPath, fileContent, "utf-8");
1237
+ await fs9.writeFile(destPath, fileContent, "utf-8");
1238
1238
  }
1239
- console.log(chalk15.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1240
- console.log(chalk15.gray(` Files: ${config.structure.defaultFile}, ${additionalFiles.join(", ")}`));
1239
+ console.log(chalk16.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1240
+ console.log(chalk16.gray(` Files: ${config.structure.defaultFile}, ${additionalFiles.join(", ")}`));
1241
1241
  } else {
1242
- console.log(chalk15.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1243
- console.log(chalk15.gray(` Edit: ${sanitizeUserInput(specFile)}`));
1242
+ console.log(chalk16.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1243
+ console.log(chalk16.gray(` Edit: ${sanitizeUserInput(specFile)}`));
1244
1244
  }
1245
1245
  } catch (error) {
1246
- console.log(chalk15.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1247
- console.log(chalk15.gray(` Edit: ${sanitizeUserInput(specFile)}`));
1246
+ console.log(chalk16.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
1247
+ console.log(chalk16.gray(` Edit: ${sanitizeUserInput(specFile)}`));
1248
1248
  }
1249
1249
  if (options.dependsOn && options.dependsOn.length > 0) {
1250
- const newSpecName = path12.basename(specDir);
1250
+ const newSpecName = path13.basename(specDir);
1251
1251
  try {
1252
1252
  await linkSpec(newSpecName, {
1253
1253
  dependsOn: options.dependsOn.join(",")
1254
1254
  });
1255
1255
  } catch (error) {
1256
- console.log(chalk15.yellow(`\u26A0\uFE0F Warning: Failed to add relationships: ${error.message}`));
1256
+ console.log(chalk16.yellow(`\u26A0\uFE0F Warning: Failed to add relationships: ${error.message}`));
1257
1257
  }
1258
1258
  }
1259
1259
  await autoCheckIfEnabled();
@@ -1267,7 +1267,7 @@ async function archiveSpec(specPath) {
1267
1267
  await autoCheckIfEnabled();
1268
1268
  const config = await loadConfig();
1269
1269
  const cwd = process.cwd();
1270
- const specsDir = path12.join(cwd, config.specsDir);
1270
+ const specsDir = path13.join(cwd, config.specsDir);
1271
1271
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
1272
1272
  if (!resolvedPath) {
1273
1273
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
@@ -1276,12 +1276,12 @@ async function archiveSpec(specPath) {
1276
1276
  if (specFile) {
1277
1277
  await updateFrontmatter(specFile, { status: "archived" });
1278
1278
  }
1279
- const archiveDir = path12.join(specsDir, "archived");
1280
- await fs8.mkdir(archiveDir, { recursive: true });
1281
- const specName = path12.basename(resolvedPath);
1282
- const archivePath = path12.join(archiveDir, specName);
1283
- await fs8.rename(resolvedPath, archivePath);
1284
- console.log(chalk15.green(`\u2713 Archived: ${sanitizeUserInput(archivePath)}`));
1279
+ const archiveDir = path13.join(specsDir, "archived");
1280
+ await fs9.mkdir(archiveDir, { recursive: true });
1281
+ const specName = path13.basename(resolvedPath);
1282
+ const archivePath = path13.join(archiveDir, specName);
1283
+ await fs9.rename(resolvedPath, archivePath);
1284
+ console.log(chalk16.green(`\u2713 Archived: ${sanitizeUserInput(archivePath)}`));
1285
1285
  }
1286
1286
 
1287
1287
  // src/utils/pattern-detection.ts
@@ -1330,9 +1330,9 @@ async function listSpecs(options = {}) {
1330
1330
  await autoCheckIfEnabled();
1331
1331
  const config = await loadConfig();
1332
1332
  const cwd = process.cwd();
1333
- const specsDir = path12.join(cwd, config.specsDir);
1333
+ const specsDir = path13.join(cwd, config.specsDir);
1334
1334
  try {
1335
- await fs8.access(specsDir);
1335
+ await fs9.access(specsDir);
1336
1336
  } catch {
1337
1337
  console.log("");
1338
1338
  console.log("No specs directory found. Initialize with: lean-spec init");
@@ -1360,7 +1360,7 @@ async function listSpecs(options = {}) {
1360
1360
  if (options.json) {
1361
1361
  console.log(JSON.stringify({ specs: [], total: 0 }, null, 2));
1362
1362
  } else {
1363
- console.log(chalk15.dim("No specs found."));
1363
+ console.log(chalk16.dim("No specs found."));
1364
1364
  }
1365
1365
  return;
1366
1366
  }
@@ -1383,7 +1383,7 @@ async function listSpecs(options = {}) {
1383
1383
  console.log(JSON.stringify(jsonOutput, null, 2));
1384
1384
  return;
1385
1385
  }
1386
- console.log(chalk15.bold.cyan("\u{1F4C4} Spec List"));
1386
+ console.log(chalk16.bold.cyan("\u{1F4C4} Spec List"));
1387
1387
  const filterParts = [];
1388
1388
  if (options.status) {
1389
1389
  const statusStr = Array.isArray(options.status) ? options.status.join(",") : options.status;
@@ -1396,7 +1396,7 @@ async function listSpecs(options = {}) {
1396
1396
  }
1397
1397
  if (options.assignee) filterParts.push(`assignee=${options.assignee}`);
1398
1398
  if (filterParts.length > 0) {
1399
- console.log(chalk15.dim(`Filtered by: ${filterParts.join(", ")}`));
1399
+ console.log(chalk16.dim(`Filtered by: ${filterParts.join(", ")}`));
1400
1400
  }
1401
1401
  console.log("");
1402
1402
  const patternInfo = detectPatternType(config);
@@ -1406,7 +1406,7 @@ async function listSpecs(options = {}) {
1406
1406
  renderFlatList(specs);
1407
1407
  }
1408
1408
  console.log("");
1409
- console.log(chalk15.bold(`Total: ${chalk15.green(specs.length)} spec${specs.length !== 1 ? "s" : ""}`));
1409
+ console.log(chalk16.bold(`Total: ${chalk16.green(specs.length)} spec${specs.length !== 1 ? "s" : ""}`));
1410
1410
  }
1411
1411
  function renderFlatList(specs) {
1412
1412
  for (const spec of specs) {
@@ -1414,25 +1414,25 @@ function renderFlatList(specs) {
1414
1414
  const priorityEmoji = getPriorityEmoji(spec.frontmatter.priority);
1415
1415
  let assigneeStr = "";
1416
1416
  if (spec.frontmatter.assignee) {
1417
- assigneeStr = " " + chalk15.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
1417
+ assigneeStr = " " + chalk16.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
1418
1418
  }
1419
1419
  let tagsStr = "";
1420
1420
  if (spec.frontmatter.tags?.length) {
1421
1421
  const tags = Array.isArray(spec.frontmatter.tags) ? spec.frontmatter.tags : [];
1422
1422
  if (tags.length > 0) {
1423
1423
  const tagStr = tags.map((tag) => `#${sanitizeUserInput(tag)}`).join(" ");
1424
- tagsStr = " " + chalk15.dim(chalk15.magenta(tagStr));
1424
+ tagsStr = " " + chalk16.dim(chalk16.magenta(tagStr));
1425
1425
  }
1426
1426
  }
1427
1427
  let subSpecStr = "";
1428
1428
  if (spec.subFiles) {
1429
1429
  const docCount = spec.subFiles.filter((f) => f.type === "document").length;
1430
1430
  if (docCount > 0) {
1431
- subSpecStr = " " + chalk15.dim(chalk15.yellow(`(+${docCount} sub-spec${docCount > 1 ? "s" : ""})`));
1431
+ subSpecStr = " " + chalk16.dim(chalk16.yellow(`(+${docCount} sub-spec${docCount > 1 ? "s" : ""})`));
1432
1432
  }
1433
1433
  }
1434
1434
  const priorityPrefix = priorityEmoji ? `${priorityEmoji} ` : "";
1435
- console.log(`${priorityPrefix}${statusEmoji} ${chalk15.cyan(sanitizeUserInput(spec.path))}${assigneeStr}${tagsStr}${subSpecStr}`);
1435
+ console.log(`${priorityPrefix}${statusEmoji} ${chalk16.cyan(sanitizeUserInput(spec.path))}${assigneeStr}${tagsStr}${subSpecStr}`);
1436
1436
  }
1437
1437
  }
1438
1438
  function renderGroupedList(specs, groupExtractor) {
@@ -1461,7 +1461,7 @@ function renderGroupedList(specs, groupExtractor) {
1461
1461
  const groupName = sortedGroups[i];
1462
1462
  const groupSpecs = groups.get(groupName);
1463
1463
  const groupEmoji = /^\d{8}$/.test(groupName) ? "\u{1F4C5}" : groupName.startsWith("milestone") ? "\u{1F3AF}" : "\u{1F4C1}";
1464
- console.log(`${chalk15.bold.cyan(`${groupEmoji} ${groupName}/`)} ${chalk15.dim(`(${groupSpecs.length})`)}`);
1464
+ console.log(`${chalk16.bold.cyan(`${groupEmoji} ${groupName}/`)} ${chalk16.dim(`(${groupSpecs.length})`)}`);
1465
1465
  console.log("");
1466
1466
  for (const spec of groupSpecs) {
1467
1467
  const statusEmoji = getStatusEmoji(spec.frontmatter.status);
@@ -1469,25 +1469,25 @@ function renderGroupedList(specs, groupExtractor) {
1469
1469
  const displayPath = spec.path.includes("/") ? spec.path.split("/").slice(1).join("/") : spec.path;
1470
1470
  let assigneeStr = "";
1471
1471
  if (spec.frontmatter.assignee) {
1472
- assigneeStr = " " + chalk15.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
1472
+ assigneeStr = " " + chalk16.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
1473
1473
  }
1474
1474
  let tagsStr = "";
1475
1475
  if (spec.frontmatter.tags?.length) {
1476
1476
  const tags = Array.isArray(spec.frontmatter.tags) ? spec.frontmatter.tags : [];
1477
1477
  if (tags.length > 0) {
1478
1478
  const tagStr = tags.map((tag) => `#${sanitizeUserInput(tag)}`).join(" ");
1479
- tagsStr = " " + chalk15.dim(chalk15.magenta(tagStr));
1479
+ tagsStr = " " + chalk16.dim(chalk16.magenta(tagStr));
1480
1480
  }
1481
1481
  }
1482
1482
  let subSpecStr = "";
1483
1483
  if (spec.subFiles) {
1484
1484
  const docCount = spec.subFiles.filter((f) => f.type === "document").length;
1485
1485
  if (docCount > 0) {
1486
- subSpecStr = " " + chalk15.dim(chalk15.yellow(`(+${docCount} sub-spec${docCount > 1 ? "s" : ""})`));
1486
+ subSpecStr = " " + chalk16.dim(chalk16.yellow(`(+${docCount} sub-spec${docCount > 1 ? "s" : ""})`));
1487
1487
  }
1488
1488
  }
1489
1489
  const priorityPrefix = priorityEmoji ? `${priorityEmoji} ` : "";
1490
- console.log(` ${priorityPrefix}${statusEmoji} ${chalk15.cyan(sanitizeUserInput(displayPath))}${assigneeStr}${tagsStr}${subSpecStr}`);
1490
+ console.log(` ${priorityPrefix}${statusEmoji} ${chalk16.cyan(sanitizeUserInput(displayPath))}${assigneeStr}${tagsStr}${subSpecStr}`);
1491
1491
  }
1492
1492
  if (i < sortedGroups.length - 1) {
1493
1493
  console.log("");
@@ -1507,7 +1507,7 @@ async function unlinkSpec(specPath, options) {
1507
1507
  await autoCheckIfEnabled();
1508
1508
  const config = await loadConfig();
1509
1509
  const cwd = process.cwd();
1510
- const specsDir = path12.join(cwd, config.specsDir);
1510
+ const specsDir = path13.join(cwd, config.specsDir);
1511
1511
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
1512
1512
  if (!resolvedPath) {
1513
1513
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
@@ -1530,7 +1530,7 @@ async function unlinkSpec(specPath, options) {
1530
1530
  for (const spec of toRemove) {
1531
1531
  const resolvedSpecPath = await resolveSpecPath(spec, cwd, specsDir);
1532
1532
  if (resolvedSpecPath) {
1533
- resolvedToRemove.add(path12.basename(resolvedSpecPath));
1533
+ resolvedToRemove.add(path13.basename(resolvedSpecPath));
1534
1534
  } else {
1535
1535
  resolvedToRemove.add(spec);
1536
1536
  }
@@ -1539,12 +1539,12 @@ async function unlinkSpec(specPath, options) {
1539
1539
  removedCount = currentDependsOn.length - newDependsOn.length;
1540
1540
  }
1541
1541
  if (removedCount === 0) {
1542
- console.log(chalk15.gray(`\u2139 No matching dependencies found to remove`));
1542
+ console.log(chalk16.gray(`\u2139 No matching dependencies found to remove`));
1543
1543
  return;
1544
1544
  }
1545
1545
  await updateFrontmatter(specFile, { depends_on: newDependsOn });
1546
- console.log(chalk15.green(`\u2713 Removed ${removedCount} dependencies`));
1547
- console.log(chalk15.gray(` Updated: ${sanitizeUserInput(path12.relative(cwd, resolvedPath))}`));
1546
+ console.log(chalk16.green(`\u2713 Removed ${removedCount} dependencies`));
1547
+ console.log(chalk16.gray(` Updated: ${sanitizeUserInput(path13.relative(cwd, resolvedPath))}`));
1548
1548
  }
1549
1549
  function templatesCommand() {
1550
1550
  const cmd = new Command("templates").description("Manage spec templates");
@@ -1570,131 +1570,131 @@ function templatesCommand() {
1570
1570
  }
1571
1571
  async function listTemplates(cwd = process.cwd()) {
1572
1572
  const config = await loadConfig(cwd);
1573
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
1573
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
1574
1574
  console.log("");
1575
- console.log(chalk15.green("=== Project Templates ==="));
1575
+ console.log(chalk16.green("=== Project Templates ==="));
1576
1576
  console.log("");
1577
1577
  try {
1578
- await fs8.access(templatesDir);
1578
+ await fs9.access(templatesDir);
1579
1579
  } catch {
1580
- console.log(chalk15.yellow("No templates directory found."));
1581
- console.log(chalk15.gray("Run: lean-spec init"));
1580
+ console.log(chalk16.yellow("No templates directory found."));
1581
+ console.log(chalk16.gray("Run: lean-spec init"));
1582
1582
  console.log("");
1583
1583
  return;
1584
1584
  }
1585
- const entries = await fs8.readdir(templatesDir, { withFileTypes: true });
1585
+ const entries = await fs9.readdir(templatesDir, { withFileTypes: true });
1586
1586
  const templateFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".md"));
1587
1587
  const templateDirs = entries.filter((e) => e.isDirectory());
1588
1588
  if (templateFiles.length === 0 && templateDirs.length === 0) {
1589
- console.log(chalk15.yellow("No templates found."));
1589
+ console.log(chalk16.yellow("No templates found."));
1590
1590
  console.log("");
1591
1591
  return;
1592
1592
  }
1593
1593
  if (config.templates && Object.keys(config.templates).length > 0) {
1594
- console.log(chalk15.cyan("Registered:"));
1594
+ console.log(chalk16.cyan("Registered:"));
1595
1595
  for (const [name, file] of Object.entries(config.templates)) {
1596
1596
  const isDefault = config.template === file;
1597
- const marker = isDefault ? chalk15.green("\u2713 (default)") : "";
1598
- const templatePath = path12.join(templatesDir, file);
1597
+ const marker = isDefault ? chalk16.green("\u2713 (default)") : "";
1598
+ const templatePath = path13.join(templatesDir, file);
1599
1599
  try {
1600
- const stat5 = await fs8.stat(templatePath);
1601
- if (stat5.isDirectory()) {
1602
- const dirFiles = await fs8.readdir(templatePath);
1600
+ const stat6 = await fs9.stat(templatePath);
1601
+ if (stat6.isDirectory()) {
1602
+ const dirFiles = await fs9.readdir(templatePath);
1603
1603
  const mdFiles = dirFiles.filter((f) => f.endsWith(".md"));
1604
- console.log(` ${chalk15.bold(name)}: ${file}/ ${marker}`);
1605
- console.log(chalk15.gray(` Files: ${mdFiles.join(", ")}`));
1604
+ console.log(` ${chalk16.bold(name)}: ${file}/ ${marker}`);
1605
+ console.log(chalk16.gray(` Files: ${mdFiles.join(", ")}`));
1606
1606
  } else {
1607
- console.log(` ${chalk15.bold(name)}: ${file} ${marker}`);
1607
+ console.log(` ${chalk16.bold(name)}: ${file} ${marker}`);
1608
1608
  }
1609
1609
  } catch {
1610
- console.log(` ${chalk15.bold(name)}: ${file} ${marker} ${chalk15.red("(missing)")}`);
1610
+ console.log(` ${chalk16.bold(name)}: ${file} ${marker} ${chalk16.red("(missing)")}`);
1611
1611
  }
1612
1612
  }
1613
1613
  console.log("");
1614
1614
  }
1615
1615
  if (templateFiles.length > 0) {
1616
- console.log(chalk15.cyan("Available files:"));
1616
+ console.log(chalk16.cyan("Available files:"));
1617
1617
  for (const entry of templateFiles) {
1618
- const filePath = path12.join(templatesDir, entry.name);
1619
- const stat5 = await fs8.stat(filePath);
1620
- const sizeKB = (stat5.size / 1024).toFixed(1);
1618
+ const filePath = path13.join(templatesDir, entry.name);
1619
+ const stat6 = await fs9.stat(filePath);
1620
+ const sizeKB = (stat6.size / 1024).toFixed(1);
1621
1621
  console.log(` ${entry.name} (${sizeKB} KB)`);
1622
1622
  }
1623
1623
  console.log("");
1624
1624
  }
1625
1625
  if (templateDirs.length > 0) {
1626
- console.log(chalk15.cyan("Available directories (multi-file templates):"));
1626
+ console.log(chalk16.cyan("Available directories (multi-file templates):"));
1627
1627
  for (const entry of templateDirs) {
1628
- const dirPath = path12.join(templatesDir, entry.name);
1629
- const dirFiles = await fs8.readdir(dirPath);
1628
+ const dirPath = path13.join(templatesDir, entry.name);
1629
+ const dirFiles = await fs9.readdir(dirPath);
1630
1630
  const mdFiles = dirFiles.filter((f) => f.endsWith(".md"));
1631
1631
  console.log(` ${entry.name}/ (${mdFiles.length} files: ${mdFiles.join(", ")})`);
1632
1632
  }
1633
1633
  console.log("");
1634
1634
  }
1635
- console.log(chalk15.gray("Use templates with: lean-spec create <name> --template=<template-name>"));
1635
+ console.log(chalk16.gray("Use templates with: lean-spec create <name> --template=<template-name>"));
1636
1636
  console.log("");
1637
1637
  }
1638
1638
  async function showTemplate(templateName, cwd = process.cwd()) {
1639
1639
  const config = await loadConfig(cwd);
1640
1640
  if (!config.templates?.[templateName]) {
1641
- console.error(chalk15.red(`Template not found: ${templateName}`));
1642
- console.error(chalk15.gray(`Available: ${Object.keys(config.templates || {}).join(", ")}`));
1641
+ console.error(chalk16.red(`Template not found: ${templateName}`));
1642
+ console.error(chalk16.gray(`Available: ${Object.keys(config.templates || {}).join(", ")}`));
1643
1643
  process.exit(1);
1644
1644
  }
1645
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
1645
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
1646
1646
  const templateFile = config.templates[templateName];
1647
- const templatePath = path12.join(templatesDir, templateFile);
1647
+ const templatePath = path13.join(templatesDir, templateFile);
1648
1648
  try {
1649
- const stat5 = await fs8.stat(templatePath);
1650
- if (stat5.isDirectory()) {
1649
+ const stat6 = await fs9.stat(templatePath);
1650
+ if (stat6.isDirectory()) {
1651
1651
  console.log("");
1652
- console.log(chalk15.cyan(`=== Template: ${templateName} (${templateFile}/) ===`));
1652
+ console.log(chalk16.cyan(`=== Template: ${templateName} (${templateFile}/) ===`));
1653
1653
  console.log("");
1654
- const files = await fs8.readdir(templatePath);
1654
+ const files = await fs9.readdir(templatePath);
1655
1655
  const mdFiles = files.filter((f) => f.endsWith(".md"));
1656
1656
  for (const file of mdFiles) {
1657
- const filePath = path12.join(templatePath, file);
1658
- const content = await fs8.readFile(filePath, "utf-8");
1659
- console.log(chalk15.yellow(`--- ${file} ---`));
1657
+ const filePath = path13.join(templatePath, file);
1658
+ const content = await fs9.readFile(filePath, "utf-8");
1659
+ console.log(chalk16.yellow(`--- ${file} ---`));
1660
1660
  console.log(content);
1661
1661
  console.log("");
1662
1662
  }
1663
1663
  } else {
1664
- const content = await fs8.readFile(templatePath, "utf-8");
1664
+ const content = await fs9.readFile(templatePath, "utf-8");
1665
1665
  console.log("");
1666
- console.log(chalk15.cyan(`=== Template: ${templateName} (${templateFile}) ===`));
1666
+ console.log(chalk16.cyan(`=== Template: ${templateName} (${templateFile}) ===`));
1667
1667
  console.log("");
1668
1668
  console.log(content);
1669
1669
  console.log("");
1670
1670
  }
1671
1671
  } catch (error) {
1672
- console.error(chalk15.red(`Error reading template: ${templateFile}`));
1672
+ console.error(chalk16.red(`Error reading template: ${templateFile}`));
1673
1673
  console.error(error);
1674
1674
  process.exit(1);
1675
1675
  }
1676
1676
  }
1677
1677
  async function addTemplate(name, file, cwd = process.cwd()) {
1678
1678
  const config = await loadConfig(cwd);
1679
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
1680
- const templatePath = path12.join(templatesDir, file);
1679
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
1680
+ const templatePath = path13.join(templatesDir, file);
1681
1681
  try {
1682
- const stat5 = await fs8.stat(templatePath);
1683
- if (stat5.isDirectory()) {
1684
- const mainFile = path12.join(templatePath, "README.md");
1682
+ const stat6 = await fs9.stat(templatePath);
1683
+ if (stat6.isDirectory()) {
1684
+ const mainFile = path13.join(templatePath, "README.md");
1685
1685
  try {
1686
- await fs8.access(mainFile);
1686
+ await fs9.access(mainFile);
1687
1687
  } catch {
1688
- console.error(chalk15.red(`Directory template must contain README.md: ${file}/`));
1689
- console.error(chalk15.gray(`Expected at: ${mainFile}`));
1688
+ console.error(chalk16.red(`Directory template must contain README.md: ${file}/`));
1689
+ console.error(chalk16.gray(`Expected at: ${mainFile}`));
1690
1690
  process.exit(1);
1691
1691
  }
1692
1692
  }
1693
1693
  } catch {
1694
- console.error(chalk15.red(`Template not found: ${file}`));
1695
- console.error(chalk15.gray(`Expected at: ${templatePath}`));
1694
+ console.error(chalk16.red(`Template not found: ${file}`));
1695
+ console.error(chalk16.gray(`Expected at: ${templatePath}`));
1696
1696
  console.error(
1697
- chalk15.yellow("Create the file/directory first or use: lean-spec templates copy <source> <target>")
1697
+ chalk16.yellow("Create the file/directory first or use: lean-spec templates copy <source> <target>")
1698
1698
  );
1699
1699
  process.exit(1);
1700
1700
  }
@@ -1702,60 +1702,60 @@ async function addTemplate(name, file, cwd = process.cwd()) {
1702
1702
  config.templates = {};
1703
1703
  }
1704
1704
  if (config.templates[name]) {
1705
- console.log(chalk15.yellow(`Warning: Template '${name}' already exists, updating...`));
1705
+ console.log(chalk16.yellow(`Warning: Template '${name}' already exists, updating...`));
1706
1706
  }
1707
1707
  config.templates[name] = file;
1708
1708
  await saveConfig(config, cwd);
1709
- console.log(chalk15.green(`\u2713 Added template: ${name} \u2192 ${file}`));
1710
- console.log(chalk15.gray(` Use with: lean-spec create <spec-name> --template=${name}`));
1709
+ console.log(chalk16.green(`\u2713 Added template: ${name} \u2192 ${file}`));
1710
+ console.log(chalk16.gray(` Use with: lean-spec create <spec-name> --template=${name}`));
1711
1711
  }
1712
1712
  async function removeTemplate(name, cwd = process.cwd()) {
1713
1713
  const config = await loadConfig(cwd);
1714
1714
  if (!config.templates?.[name]) {
1715
- console.error(chalk15.red(`Template not found: ${name}`));
1716
- console.error(chalk15.gray(`Available: ${Object.keys(config.templates || {}).join(", ")}`));
1715
+ console.error(chalk16.red(`Template not found: ${name}`));
1716
+ console.error(chalk16.gray(`Available: ${Object.keys(config.templates || {}).join(", ")}`));
1717
1717
  process.exit(1);
1718
1718
  }
1719
1719
  if (name === "default") {
1720
- console.error(chalk15.red("Cannot remove default template"));
1720
+ console.error(chalk16.red("Cannot remove default template"));
1721
1721
  process.exit(1);
1722
1722
  }
1723
1723
  const file = config.templates[name];
1724
1724
  delete config.templates[name];
1725
1725
  await saveConfig(config, cwd);
1726
- console.log(chalk15.green(`\u2713 Removed template: ${name}`));
1727
- console.log(chalk15.gray(` Note: Template file ${file} still exists in .lean-spec/templates/`));
1726
+ console.log(chalk16.green(`\u2713 Removed template: ${name}`));
1727
+ console.log(chalk16.gray(` Note: Template file ${file} still exists in .lean-spec/templates/`));
1728
1728
  }
1729
1729
  async function copyTemplate(source, target, cwd = process.cwd()) {
1730
1730
  const config = await loadConfig(cwd);
1731
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
1731
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
1732
1732
  let sourceFile;
1733
1733
  if (config.templates?.[source]) {
1734
1734
  sourceFile = config.templates[source];
1735
1735
  } else {
1736
1736
  sourceFile = source;
1737
1737
  }
1738
- const sourcePath = path12.join(templatesDir, sourceFile);
1738
+ const sourcePath = path13.join(templatesDir, sourceFile);
1739
1739
  try {
1740
- await fs8.access(sourcePath);
1740
+ await fs9.access(sourcePath);
1741
1741
  } catch {
1742
- console.error(chalk15.red(`Source template not found: ${source}`));
1743
- console.error(chalk15.gray(`Expected at: ${sourcePath}`));
1742
+ console.error(chalk16.red(`Source template not found: ${source}`));
1743
+ console.error(chalk16.gray(`Expected at: ${sourcePath}`));
1744
1744
  process.exit(1);
1745
1745
  }
1746
1746
  const targetFile = target.endsWith(".md") ? target : `${target}.md`;
1747
- const targetPath = path12.join(templatesDir, targetFile);
1748
- await fs8.copyFile(sourcePath, targetPath);
1749
- console.log(chalk15.green(`\u2713 Copied: ${sourceFile} \u2192 ${targetFile}`));
1747
+ const targetPath = path13.join(templatesDir, targetFile);
1748
+ await fs9.copyFile(sourcePath, targetPath);
1749
+ console.log(chalk16.green(`\u2713 Copied: ${sourceFile} \u2192 ${targetFile}`));
1750
1750
  if (!config.templates) {
1751
1751
  config.templates = {};
1752
1752
  }
1753
1753
  const templateName = target.replace(/\.md$/, "");
1754
1754
  config.templates[templateName] = targetFile;
1755
1755
  await saveConfig(config, cwd);
1756
- console.log(chalk15.green(`\u2713 Registered template: ${templateName}`));
1757
- console.log(chalk15.gray(` Edit: ${targetPath}`));
1758
- console.log(chalk15.gray(` Use with: lean-spec create <spec-name> --template=${templateName}`));
1756
+ console.log(chalk16.green(`\u2713 Registered template: ${templateName}`));
1757
+ console.log(chalk16.gray(` Edit: ${targetPath}`));
1758
+ console.log(chalk16.gray(` Use with: lean-spec create <spec-name> --template=${templateName}`));
1759
1759
  }
1760
1760
  var AI_TOOL_CONFIGS = {
1761
1761
  aider: {
@@ -1776,7 +1776,7 @@ var AI_TOOL_CONFIGS = {
1776
1776
  claude: {
1777
1777
  file: "CLAUDE.md",
1778
1778
  description: "Claude Code (CLAUDE.md)",
1779
- default: true,
1779
+ default: false,
1780
1780
  usesSymlink: true,
1781
1781
  detection: {
1782
1782
  commands: ["claude"],
@@ -1891,7 +1891,7 @@ async function configDirExists(dirName) {
1891
1891
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
1892
1892
  if (!homeDir) return false;
1893
1893
  try {
1894
- await fs8.access(path12.join(homeDir, dirName));
1894
+ await fs9.access(path13.join(homeDir, dirName));
1895
1895
  return true;
1896
1896
  } catch {
1897
1897
  return false;
@@ -1904,13 +1904,13 @@ async function extensionInstalled(extensionId) {
1904
1904
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
1905
1905
  if (!homeDir) return false;
1906
1906
  const extensionDirs = [
1907
- path12.join(homeDir, ".vscode", "extensions"),
1908
- path12.join(homeDir, ".vscode-server", "extensions"),
1909
- path12.join(homeDir, ".cursor", "extensions")
1907
+ path13.join(homeDir, ".vscode", "extensions"),
1908
+ path13.join(homeDir, ".vscode-server", "extensions"),
1909
+ path13.join(homeDir, ".cursor", "extensions")
1910
1910
  ];
1911
1911
  for (const extDir of extensionDirs) {
1912
1912
  try {
1913
- const entries = await fs8.readdir(extDir);
1913
+ const entries = await fs9.readdir(extDir);
1914
1914
  if (entries.some((e) => e.toLowerCase().startsWith(extensionId.toLowerCase()))) {
1915
1915
  return true;
1916
1916
  }
@@ -1990,10 +1990,10 @@ async function createAgentToolSymlinks(cwd, selectedTools) {
1990
1990
  }
1991
1991
  }
1992
1992
  for (const file of filesToCreate) {
1993
- const targetPath = path12.join(cwd, file);
1993
+ const targetPath = path13.join(cwd, file);
1994
1994
  try {
1995
1995
  try {
1996
- await fs8.access(targetPath);
1996
+ await fs9.access(targetPath);
1997
1997
  results.push({ file, skipped: true });
1998
1998
  continue;
1999
1999
  } catch {
@@ -2008,10 +2008,10 @@ async function createAgentToolSymlinks(cwd, selectedTools) {
2008
2008
 
2009
2009
  See AGENTS.md for the full LeanSpec AI agent instructions.
2010
2010
  `;
2011
- await fs8.writeFile(targetPath, windowsContent, "utf-8");
2011
+ await fs9.writeFile(targetPath, windowsContent, "utf-8");
2012
2012
  results.push({ file, created: true, error: "created as copy (Windows)" });
2013
2013
  } else {
2014
- await fs8.symlink("AGENTS.md", targetPath);
2014
+ await fs9.symlink("AGENTS.md", targetPath);
2015
2015
  results.push({ file, created: true });
2016
2016
  }
2017
2017
  } catch (error) {
@@ -2032,7 +2032,7 @@ async function detectExistingSystemPrompts(cwd) {
2032
2032
  const found = [];
2033
2033
  for (const file of commonFiles) {
2034
2034
  try {
2035
- await fs8.access(path12.join(cwd, file));
2035
+ await fs9.access(path13.join(cwd, file));
2036
2036
  found.push(file);
2037
2037
  } catch {
2038
2038
  }
@@ -2041,20 +2041,20 @@ async function detectExistingSystemPrompts(cwd) {
2041
2041
  }
2042
2042
  async function handleExistingFiles(action, existingFiles, templateDir, cwd, variables = {}) {
2043
2043
  for (const file of existingFiles) {
2044
- const filePath = path12.join(cwd, file);
2045
- const templateFilePath = path12.join(templateDir, file);
2044
+ const filePath = path13.join(cwd, file);
2045
+ const templateFilePath = path13.join(templateDir, file);
2046
2046
  try {
2047
- await fs8.access(templateFilePath);
2047
+ await fs9.access(templateFilePath);
2048
2048
  } catch {
2049
2049
  continue;
2050
2050
  }
2051
2051
  if (action === "merge-ai" && file === "AGENTS.md") {
2052
- const existing = await fs8.readFile(filePath, "utf-8");
2053
- let template = await fs8.readFile(templateFilePath, "utf-8");
2052
+ const existing = await fs9.readFile(filePath, "utf-8");
2053
+ let template = await fs9.readFile(templateFilePath, "utf-8");
2054
2054
  for (const [key, value] of Object.entries(variables)) {
2055
2055
  template = template.replace(new RegExp(`\\{${key}\\}`, "g"), value);
2056
2056
  }
2057
- const promptPath = path12.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
2057
+ const promptPath = path13.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
2058
2058
  const aiPrompt = `# AI Prompt: Consolidate AGENTS.md
2059
2059
 
2060
2060
  ## Task
@@ -2086,20 +2086,20 @@ Create a single consolidated AGENTS.md that:
2086
2086
  - Maintains clear structure and readability
2087
2087
  - Removes any duplicate or conflicting guidance
2088
2088
  `;
2089
- await fs8.mkdir(path12.dirname(promptPath), { recursive: true });
2090
- await fs8.writeFile(promptPath, aiPrompt, "utf-8");
2091
- console.log(chalk15.green(`\u2713 Created AI consolidation prompt`));
2092
- console.log(chalk15.cyan(` \u2192 ${promptPath}`));
2089
+ await fs9.mkdir(path13.dirname(promptPath), { recursive: true });
2090
+ await fs9.writeFile(promptPath, aiPrompt, "utf-8");
2091
+ console.log(chalk16.green(`\u2713 Created AI consolidation prompt`));
2092
+ console.log(chalk16.cyan(` \u2192 ${promptPath}`));
2093
2093
  console.log("");
2094
- console.log(chalk15.yellow("\u{1F4DD} Next steps:"));
2095
- console.log(chalk15.gray(" 1. Open .lean-spec/MERGE-AGENTS-PROMPT.md"));
2096
- console.log(chalk15.gray(" 2. Send it to your AI coding assistant (GitHub Copilot, Cursor, etc.)"));
2097
- console.log(chalk15.gray(" 3. Let AI create the consolidated AGENTS.md"));
2098
- console.log(chalk15.gray(" 4. Review and commit the result"));
2094
+ console.log(chalk16.yellow("\u{1F4DD} Next steps:"));
2095
+ console.log(chalk16.gray(" 1. Open .lean-spec/MERGE-AGENTS-PROMPT.md"));
2096
+ console.log(chalk16.gray(" 2. Send it to your AI coding assistant (GitHub Copilot, Cursor, etc.)"));
2097
+ console.log(chalk16.gray(" 3. Let AI create the consolidated AGENTS.md"));
2098
+ console.log(chalk16.gray(" 4. Review and commit the result"));
2099
2099
  console.log("");
2100
2100
  } else if (action === "merge-append" && file === "AGENTS.md") {
2101
- const existing = await fs8.readFile(filePath, "utf-8");
2102
- let template = await fs8.readFile(templateFilePath, "utf-8");
2101
+ const existing = await fs9.readFile(filePath, "utf-8");
2102
+ let template = await fs9.readFile(templateFilePath, "utf-8");
2103
2103
  for (const [key, value] of Object.entries(variables)) {
2104
2104
  template = template.replace(new RegExp(`\\{${key}\\}`, "g"), value);
2105
2105
  }
@@ -2110,29 +2110,29 @@ Create a single consolidated AGENTS.md that:
2110
2110
  ## LeanSpec Integration
2111
2111
 
2112
2112
  ${template.split("\n").slice(1).join("\n")}`;
2113
- await fs8.writeFile(filePath, merged, "utf-8");
2114
- console.log(chalk15.green(`\u2713 Appended LeanSpec section to ${file}`));
2115
- console.log(chalk15.yellow(" \u26A0 Note: May be verbose. Consider consolidating later."));
2113
+ await fs9.writeFile(filePath, merged, "utf-8");
2114
+ console.log(chalk16.green(`\u2713 Appended LeanSpec section to ${file}`));
2115
+ console.log(chalk16.yellow(" \u26A0 Note: May be verbose. Consider consolidating later."));
2116
2116
  } else if (action === "overwrite") {
2117
2117
  const backupPath = `${filePath}.backup`;
2118
- await fs8.rename(filePath, backupPath);
2119
- console.log(chalk15.yellow(`\u2713 Backed up ${file} \u2192 ${file}.backup`));
2120
- let content = await fs8.readFile(templateFilePath, "utf-8");
2118
+ await fs9.rename(filePath, backupPath);
2119
+ console.log(chalk16.yellow(`\u2713 Backed up ${file} \u2192 ${file}.backup`));
2120
+ let content = await fs9.readFile(templateFilePath, "utf-8");
2121
2121
  for (const [key, value] of Object.entries(variables)) {
2122
2122
  content = content.replace(new RegExp(`\\{${key}\\}`, "g"), value);
2123
2123
  }
2124
- await fs8.writeFile(filePath, content, "utf-8");
2125
- console.log(chalk15.green(`\u2713 Created new ${file}`));
2126
- console.log(chalk15.gray(` \u{1F4A1} Your original content is preserved in ${file}.backup`));
2124
+ await fs9.writeFile(filePath, content, "utf-8");
2125
+ console.log(chalk16.green(`\u2713 Created new ${file}`));
2126
+ console.log(chalk16.gray(` \u{1F4A1} Your original content is preserved in ${file}.backup`));
2127
2127
  }
2128
2128
  }
2129
2129
  }
2130
2130
  async function copyDirectory(src, dest, skipFiles = [], variables = {}) {
2131
- await fs8.mkdir(dest, { recursive: true });
2132
- const entries = await fs8.readdir(src, { withFileTypes: true });
2131
+ await fs9.mkdir(dest, { recursive: true });
2132
+ const entries = await fs9.readdir(src, { withFileTypes: true });
2133
2133
  for (const entry of entries) {
2134
- const srcPath = path12.join(src, entry.name);
2135
- const destPath = path12.join(dest, entry.name);
2134
+ const srcPath = path13.join(src, entry.name);
2135
+ const destPath = path13.join(dest, entry.name);
2136
2136
  if (skipFiles.includes(entry.name)) {
2137
2137
  continue;
2138
2138
  }
@@ -2140,28 +2140,28 @@ async function copyDirectory(src, dest, skipFiles = [], variables = {}) {
2140
2140
  await copyDirectory(srcPath, destPath, skipFiles, variables);
2141
2141
  } else {
2142
2142
  try {
2143
- await fs8.access(destPath);
2143
+ await fs9.access(destPath);
2144
2144
  } catch {
2145
- let content = await fs8.readFile(srcPath, "utf-8");
2145
+ let content = await fs9.readFile(srcPath, "utf-8");
2146
2146
  for (const [key, value] of Object.entries(variables)) {
2147
2147
  content = content.replace(new RegExp(`\\{${key}\\}`, "g"), value);
2148
2148
  }
2149
- await fs8.writeFile(destPath, content, "utf-8");
2149
+ await fs9.writeFile(destPath, content, "utf-8");
2150
2150
  }
2151
2151
  }
2152
2152
  }
2153
2153
  }
2154
2154
  async function getProjectName2(cwd) {
2155
2155
  try {
2156
- const packageJsonPath = path12.join(cwd, "package.json");
2157
- const content = await fs8.readFile(packageJsonPath, "utf-8");
2156
+ const packageJsonPath = path13.join(cwd, "package.json");
2157
+ const content = await fs9.readFile(packageJsonPath, "utf-8");
2158
2158
  const pkg = JSON.parse(content);
2159
2159
  if (pkg.name) {
2160
2160
  return pkg.name;
2161
2161
  }
2162
2162
  } catch {
2163
2163
  }
2164
- return path12.basename(cwd);
2164
+ return path13.basename(cwd);
2165
2165
  }
2166
2166
  function buildMergeCommand(cli, promptPath) {
2167
2167
  const prompt = `Follow the instructions in ${promptPath} to consolidate AGENTS.md. Read the prompt file, then edit AGENTS.md with the merged content.`;
@@ -2197,7 +2197,7 @@ async function executeMergeWithAI(cwd, promptPath, tool, timeoutMs = 12e4) {
2197
2197
  return arg;
2198
2198
  });
2199
2199
  const fullCommand = `${command} ${quotedArgs.join(" ")}`;
2200
- return new Promise((resolve2) => {
2200
+ return new Promise((resolve3) => {
2201
2201
  let output = "";
2202
2202
  let errorOutput = "";
2203
2203
  let timedOut = false;
@@ -2221,19 +2221,19 @@ async function executeMergeWithAI(cwd, promptPath, tool, timeoutMs = 12e4) {
2221
2221
  child.on("close", (code) => {
2222
2222
  clearTimeout(timeout);
2223
2223
  if (timedOut) {
2224
- resolve2({
2224
+ resolve3({
2225
2225
  success: false,
2226
2226
  output,
2227
2227
  error: "Command timed out",
2228
2228
  timedOut: true
2229
2229
  });
2230
2230
  } else if (code === 0) {
2231
- resolve2({
2231
+ resolve3({
2232
2232
  success: true,
2233
2233
  output
2234
2234
  });
2235
2235
  } else {
2236
- resolve2({
2236
+ resolve3({
2237
2237
  success: false,
2238
2238
  output,
2239
2239
  error: errorOutput || `Process exited with code ${code}`
@@ -2242,7 +2242,7 @@ async function executeMergeWithAI(cwd, promptPath, tool, timeoutMs = 12e4) {
2242
2242
  });
2243
2243
  child.on("error", (err) => {
2244
2244
  clearTimeout(timeout);
2245
- resolve2({
2245
+ resolve3({
2246
2246
  success: false,
2247
2247
  error: err.message
2248
2248
  });
@@ -2279,6 +2279,225 @@ function getDisplayCommand(tool, promptPath) {
2279
2279
  });
2280
2280
  return `${command} ${displayArgs.join(" ")}`;
2281
2281
  }
2282
+ var MCP_TOOL_CONFIGS = {
2283
+ "claude": {
2284
+ id: "claude",
2285
+ name: "Claude Code",
2286
+ description: "Claude Code (.mcp.json)",
2287
+ configPath: ".mcp.json",
2288
+ configLocation: "workspace",
2289
+ usesProjectVariable: true,
2290
+ detection: {
2291
+ directories: [".claude"],
2292
+ files: ["CLAUDE.md", ".claude.json"]
2293
+ }
2294
+ },
2295
+ vscode: {
2296
+ id: "vscode",
2297
+ name: "VS Code",
2298
+ description: "VS Code with GitHub Copilot (.vscode/mcp.json)",
2299
+ configPath: ".vscode/mcp.json",
2300
+ configLocation: "workspace",
2301
+ usesProjectVariable: false,
2302
+ detection: {
2303
+ directories: [".vscode"]
2304
+ }
2305
+ },
2306
+ cursor: {
2307
+ id: "cursor",
2308
+ name: "Cursor",
2309
+ description: "Cursor (.cursor/mcp.json)",
2310
+ configPath: ".cursor/mcp.json",
2311
+ configLocation: "workspace",
2312
+ usesProjectVariable: false,
2313
+ detection: {
2314
+ directories: [".cursor"],
2315
+ files: [".cursorrules"]
2316
+ }
2317
+ },
2318
+ windsurf: {
2319
+ id: "windsurf",
2320
+ name: "Windsurf",
2321
+ description: "Windsurf (.windsurf/mcp.json)",
2322
+ configPath: ".windsurf/mcp.json",
2323
+ configLocation: "workspace",
2324
+ usesProjectVariable: false,
2325
+ detection: {
2326
+ directories: [".windsurf"],
2327
+ files: [".windsurfrules"]
2328
+ }
2329
+ }
2330
+ };
2331
+ async function detectMcpTools(cwd) {
2332
+ const results = [];
2333
+ for (const [key, config] of Object.entries(MCP_TOOL_CONFIGS)) {
2334
+ const reasons = [];
2335
+ const detection = config.detection;
2336
+ if (!detection) {
2337
+ results.push({ tool: key, detected: false, reasons: [] });
2338
+ continue;
2339
+ }
2340
+ if (detection.directories) {
2341
+ for (const dir of detection.directories) {
2342
+ const dirPath = path13.join(cwd, dir);
2343
+ try {
2344
+ const stat6 = await fs9.stat(dirPath);
2345
+ if (stat6.isDirectory()) {
2346
+ reasons.push(`${dir}/ directory found`);
2347
+ }
2348
+ } catch {
2349
+ }
2350
+ }
2351
+ }
2352
+ if (detection.files) {
2353
+ for (const file of detection.files) {
2354
+ const filePath = path13.join(cwd, file);
2355
+ try {
2356
+ await fs9.access(filePath);
2357
+ reasons.push(`${file} found`);
2358
+ } catch {
2359
+ }
2360
+ }
2361
+ }
2362
+ results.push({
2363
+ tool: key,
2364
+ detected: reasons.length > 0,
2365
+ reasons
2366
+ });
2367
+ }
2368
+ return results;
2369
+ }
2370
+ function generateMcpConfig(projectPath, tool) {
2371
+ const config = MCP_TOOL_CONFIGS[tool];
2372
+ const projectArg = config.usesProjectVariable ? "${workspaceFolder}" : projectPath;
2373
+ return {
2374
+ command: "npx",
2375
+ args: ["-y", "@leanspec/mcp", "--project", projectArg]
2376
+ };
2377
+ }
2378
+ function generateMcpConfigFile(projectPath, tool) {
2379
+ return {
2380
+ mcpServers: {
2381
+ "lean-spec": generateMcpConfig(projectPath, tool)
2382
+ }
2383
+ };
2384
+ }
2385
+ async function readMcpConfig(configPath) {
2386
+ try {
2387
+ const content = await fs9.readFile(configPath, "utf-8");
2388
+ return JSON.parse(content);
2389
+ } catch {
2390
+ return null;
2391
+ }
2392
+ }
2393
+ async function writeMcpConfig(configPath, config) {
2394
+ const dir = path13.dirname(configPath);
2395
+ await fs9.mkdir(dir, { recursive: true });
2396
+ await fs9.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
2397
+ }
2398
+ async function createMcpConfig(cwd, tool) {
2399
+ const toolConfig = MCP_TOOL_CONFIGS[tool];
2400
+ const configPath = path13.join(cwd, toolConfig.configPath);
2401
+ const absoluteProjectPath = path13.resolve(cwd);
2402
+ try {
2403
+ const existingConfig = await readMcpConfig(configPath);
2404
+ if (existingConfig) {
2405
+ if (existingConfig.mcpServers?.["lean-spec"]) {
2406
+ return {
2407
+ tool,
2408
+ configPath: toolConfig.configPath,
2409
+ skipped: true
2410
+ };
2411
+ }
2412
+ const newServerConfig = generateMcpConfig(absoluteProjectPath, tool);
2413
+ existingConfig.mcpServers = existingConfig.mcpServers || {};
2414
+ existingConfig.mcpServers["lean-spec"] = newServerConfig;
2415
+ await writeMcpConfig(configPath, existingConfig);
2416
+ return {
2417
+ tool,
2418
+ configPath: toolConfig.configPath,
2419
+ merged: true
2420
+ };
2421
+ }
2422
+ const newConfig = generateMcpConfigFile(absoluteProjectPath, tool);
2423
+ await writeMcpConfig(configPath, newConfig);
2424
+ return {
2425
+ tool,
2426
+ configPath: toolConfig.configPath,
2427
+ created: true
2428
+ };
2429
+ } catch (error) {
2430
+ return {
2431
+ tool,
2432
+ configPath: toolConfig.configPath,
2433
+ error: error instanceof Error ? error.message : "Unknown error"
2434
+ };
2435
+ }
2436
+ }
2437
+ async function createMcpConfigs(cwd, tools) {
2438
+ const results = [];
2439
+ for (const tool of tools) {
2440
+ const result = await createMcpConfig(cwd, tool);
2441
+ results.push(result);
2442
+ }
2443
+ return results;
2444
+ }
2445
+ function printMcpConfigResults(results) {
2446
+ for (const result of results) {
2447
+ const config = MCP_TOOL_CONFIGS[result.tool];
2448
+ if (result.created) {
2449
+ console.log(chalk16.green(`\u2713 ${config.name}: Created ${result.configPath}`));
2450
+ } else if (result.merged) {
2451
+ console.log(chalk16.green(`\u2713 ${config.name}: Added lean-spec to ${result.configPath}`));
2452
+ } else if (result.skipped) {
2453
+ console.log(chalk16.yellow(`\u26A0 ${config.name}: Already configured in ${result.configPath}`));
2454
+ } else if (result.error) {
2455
+ console.log(chalk16.red(`\u2717 ${config.name}: ${result.error}`));
2456
+ }
2457
+ }
2458
+ }
2459
+ async function getDefaultMcpToolSelection(cwd) {
2460
+ const detectionResults = await detectMcpTools(cwd);
2461
+ const detectedTools = detectionResults.filter((r) => r.detected).map((r) => r.tool);
2462
+ if (detectedTools.length > 0) {
2463
+ return { defaults: detectedTools, detected: detectionResults };
2464
+ }
2465
+ return { defaults: [], detected: detectionResults };
2466
+ }
2467
+ function parseMcpConfigFlag(value) {
2468
+ if (value === "all") {
2469
+ return "all";
2470
+ }
2471
+ if (value === "none") {
2472
+ return "none";
2473
+ }
2474
+ const tools = value.split(",").map((t) => t.trim().toLowerCase());
2475
+ const validTools = [];
2476
+ for (const tool of tools) {
2477
+ const normalized = normalizeToolName(tool);
2478
+ if (normalized && isValidMcpTool(normalized)) {
2479
+ validTools.push(normalized);
2480
+ }
2481
+ }
2482
+ return validTools;
2483
+ }
2484
+ function normalizeToolName(tool) {
2485
+ const aliases = {
2486
+ "claude": "claude",
2487
+ "claude-code": "claude",
2488
+ "claudecode": "claude",
2489
+ "vscode": "vscode",
2490
+ "vs-code": "vscode",
2491
+ "code": "vscode",
2492
+ "copilot": "vscode",
2493
+ "cursor": "cursor",
2494
+ "windsurf": "windsurf"
2495
+ };
2496
+ return aliases[tool] || null;
2497
+ }
2498
+ function isValidMcpTool(tool) {
2499
+ return tool in MCP_TOOL_CONFIGS;
2500
+ }
2282
2501
 
2283
2502
  // src/utils/examples.ts
2284
2503
  var EXAMPLES = {
@@ -2327,9 +2546,9 @@ function exampleExists(name) {
2327
2546
  }
2328
2547
 
2329
2548
  // src/commands/init.ts
2330
- var __dirname = path12.dirname(fileURLToPath(import.meta.url));
2331
- var TEMPLATES_DIR = path12.join(__dirname, "..", "templates");
2332
- var EXAMPLES_DIR = path12.join(TEMPLATES_DIR, "examples");
2549
+ var __dirname = path13.dirname(fileURLToPath(import.meta.url));
2550
+ var TEMPLATES_DIR = path13.join(__dirname, "..", "templates");
2551
+ var EXAMPLES_DIR = path13.join(TEMPLATES_DIR, "examples");
2333
2552
  async function attemptAutoMerge(cwd, promptPath, autoExecute) {
2334
2553
  const cliTools = await getCliCapableDetectedTools();
2335
2554
  if (cliTools.length === 0) {
@@ -2338,12 +2557,12 @@ async function attemptAutoMerge(cwd, promptPath, autoExecute) {
2338
2557
  const tool = cliTools[0];
2339
2558
  const displayCmd = getDisplayCommand(tool.tool, promptPath);
2340
2559
  console.log("");
2341
- console.log(chalk15.cyan(`\u{1F50D} Detected AI CLI: ${tool.config.description}`));
2560
+ console.log(chalk16.cyan(`\u{1F50D} Detected AI CLI: ${tool.config.description}`));
2342
2561
  for (const reason of tool.reasons) {
2343
- console.log(chalk15.gray(` \u2514\u2500 ${reason}`));
2562
+ console.log(chalk16.gray(` \u2514\u2500 ${reason}`));
2344
2563
  }
2345
2564
  console.log("");
2346
- console.log(chalk15.gray(`Command: ${displayCmd}`));
2565
+ console.log(chalk16.gray(`Command: ${displayCmd}`));
2347
2566
  console.log("");
2348
2567
  let shouldExecute = autoExecute;
2349
2568
  if (!autoExecute) {
@@ -2353,52 +2572,52 @@ async function attemptAutoMerge(cwd, promptPath, autoExecute) {
2353
2572
  });
2354
2573
  }
2355
2574
  if (!shouldExecute) {
2356
- console.log(chalk15.gray("Skipping auto-merge. Run the command above manually to merge."));
2575
+ console.log(chalk16.gray("Skipping auto-merge. Run the command above manually to merge."));
2357
2576
  return false;
2358
2577
  }
2359
2578
  console.log("");
2360
- console.log(chalk15.cyan("\u{1F916} Running AI-assisted merge..."));
2361
- console.log(chalk15.gray(" (This may take a moment)"));
2579
+ console.log(chalk16.cyan("\u{1F916} Running AI-assisted merge..."));
2580
+ console.log(chalk16.gray(" (This may take a moment)"));
2362
2581
  console.log("");
2363
2582
  const result = await executeMergeWithAI(cwd, promptPath, tool.tool);
2364
2583
  if (result.success) {
2365
2584
  console.log("");
2366
- console.log(chalk15.green("\u2713 AGENTS.md merged successfully!"));
2367
- console.log(chalk15.gray(" Review changes: git diff AGENTS.md"));
2585
+ console.log(chalk16.green("\u2713 AGENTS.md merged successfully!"));
2586
+ console.log(chalk16.gray(" Review changes: git diff AGENTS.md"));
2368
2587
  return true;
2369
2588
  } else if (result.timedOut) {
2370
2589
  console.log("");
2371
- console.log(chalk15.yellow("\u26A0 Merge timed out. Try running the command manually:"));
2372
- console.log(chalk15.gray(` ${displayCmd}`));
2590
+ console.log(chalk16.yellow("\u26A0 Merge timed out. Try running the command manually:"));
2591
+ console.log(chalk16.gray(` ${displayCmd}`));
2373
2592
  return false;
2374
2593
  } else {
2375
2594
  console.log("");
2376
- console.log(chalk15.yellow(`\u26A0 Auto-merge encountered an issue: ${result.error}`));
2377
- console.log(chalk15.gray(" Try running the command manually:"));
2378
- console.log(chalk15.gray(` ${displayCmd}`));
2595
+ console.log(chalk16.yellow(`\u26A0 Auto-merge encountered an issue: ${result.error}`));
2596
+ console.log(chalk16.gray(" Try running the command manually:"));
2597
+ console.log(chalk16.gray(` ${displayCmd}`));
2379
2598
  return false;
2380
2599
  }
2381
2600
  }
2382
2601
  async function handleReinitialize(cwd, skipPrompts, forceReinit) {
2383
- const specsDir = path12.join(cwd, "specs");
2602
+ const specsDir = path13.join(cwd, "specs");
2384
2603
  let specCount = 0;
2385
2604
  try {
2386
- const entries = await fs8.readdir(specsDir, { withFileTypes: true });
2605
+ const entries = await fs9.readdir(specsDir, { withFileTypes: true });
2387
2606
  specCount = entries.filter((e) => e.isDirectory()).length;
2388
2607
  } catch {
2389
2608
  }
2390
2609
  console.log("");
2391
- console.log(chalk15.yellow("\u26A0 LeanSpec is already initialized in this directory."));
2610
+ console.log(chalk16.yellow("\u26A0 LeanSpec is already initialized in this directory."));
2392
2611
  if (specCount > 0) {
2393
- console.log(chalk15.cyan(` Found ${specCount} spec${specCount > 1 ? "s" : ""} in specs/`));
2612
+ console.log(chalk16.cyan(` Found ${specCount} spec${specCount > 1 ? "s" : ""} in specs/`));
2394
2613
  }
2395
2614
  console.log("");
2396
2615
  if (forceReinit) {
2397
- console.log(chalk15.gray("Force flag detected. Resetting configuration..."));
2616
+ console.log(chalk16.gray("Force flag detected. Resetting configuration..."));
2398
2617
  return "reset-config";
2399
2618
  }
2400
2619
  if (skipPrompts) {
2401
- console.log(chalk15.gray("Using safe upgrade (preserving all existing files)"));
2620
+ console.log(chalk16.gray("Using safe upgrade (preserving all existing files)"));
2402
2621
  return "upgrade";
2403
2622
  }
2404
2623
  const strategy = await select({
@@ -2432,15 +2651,15 @@ async function handleReinitialize(cwd, skipPrompts, forceReinit) {
2432
2651
  warnings.push(`${specCount} spec${specCount > 1 ? "s" : ""} in specs/`);
2433
2652
  }
2434
2653
  try {
2435
- await fs8.access(path12.join(cwd, "AGENTS.md"));
2654
+ await fs9.access(path13.join(cwd, "AGENTS.md"));
2436
2655
  warnings.push("AGENTS.md");
2437
2656
  } catch {
2438
2657
  }
2439
2658
  if (warnings.length > 0) {
2440
2659
  console.log("");
2441
- console.log(chalk15.red("\u26A0 This will permanently delete:"));
2660
+ console.log(chalk16.red("\u26A0 This will permanently delete:"));
2442
2661
  for (const warning of warnings) {
2443
- console.log(chalk15.red(` - ${warning}`));
2662
+ console.log(chalk16.red(` - ${warning}`));
2444
2663
  }
2445
2664
  console.log("");
2446
2665
  const confirmed = await confirm({
@@ -2448,22 +2667,22 @@ async function handleReinitialize(cwd, skipPrompts, forceReinit) {
2448
2667
  default: false
2449
2668
  });
2450
2669
  if (!confirmed) {
2451
- console.log(chalk15.gray("Cancelled."));
2670
+ console.log(chalk16.gray("Cancelled."));
2452
2671
  return "cancel";
2453
2672
  }
2454
2673
  }
2455
- console.log(chalk15.gray("Performing full reset..."));
2456
- await fs8.rm(path12.join(cwd, ".lean-spec"), { recursive: true, force: true });
2457
- console.log(chalk15.gray(" Removed .lean-spec/"));
2674
+ console.log(chalk16.gray("Performing full reset..."));
2675
+ await fs9.rm(path13.join(cwd, ".lean-spec"), { recursive: true, force: true });
2676
+ console.log(chalk16.gray(" Removed .lean-spec/"));
2458
2677
  try {
2459
- await fs8.rm(specsDir, { recursive: true, force: true });
2460
- console.log(chalk15.gray(" Removed specs/"));
2678
+ await fs9.rm(specsDir, { recursive: true, force: true });
2679
+ console.log(chalk16.gray(" Removed specs/"));
2461
2680
  } catch {
2462
2681
  }
2463
2682
  for (const file of ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]) {
2464
2683
  try {
2465
- await fs8.rm(path12.join(cwd, file), { force: true });
2466
- console.log(chalk15.gray(` Removed ${file}`));
2684
+ await fs9.rm(path13.join(cwd, file), { force: true });
2685
+ console.log(chalk16.gray(` Removed ${file}`));
2467
2686
  } catch {
2468
2687
  }
2469
2688
  }
@@ -2471,22 +2690,22 @@ async function handleReinitialize(cwd, skipPrompts, forceReinit) {
2471
2690
  return strategy;
2472
2691
  }
2473
2692
  async function upgradeConfig(cwd) {
2474
- const configPath = path12.join(cwd, ".lean-spec", "config.json");
2693
+ const configPath = path13.join(cwd, ".lean-spec", "config.json");
2475
2694
  let existingConfig;
2476
2695
  try {
2477
- const content = await fs8.readFile(configPath, "utf-8");
2696
+ const content = await fs9.readFile(configPath, "utf-8");
2478
2697
  existingConfig = JSON.parse(content);
2479
2698
  } catch {
2480
- console.error(chalk15.red("Error reading existing config"));
2699
+ console.error(chalk16.red("Error reading existing config"));
2481
2700
  process.exit(1);
2482
2701
  }
2483
- const templateConfigPath = path12.join(TEMPLATES_DIR, "standard", "config.json");
2702
+ const templateConfigPath = path13.join(TEMPLATES_DIR, "standard", "config.json");
2484
2703
  let templateConfig;
2485
2704
  try {
2486
- const content = await fs8.readFile(templateConfigPath, "utf-8");
2705
+ const content = await fs9.readFile(templateConfigPath, "utf-8");
2487
2706
  templateConfig = JSON.parse(content).config;
2488
2707
  } catch {
2489
- console.error(chalk15.red("Error reading template config"));
2708
+ console.error(chalk16.red("Error reading template config"));
2490
2709
  process.exit(1);
2491
2710
  }
2492
2711
  const upgradedConfig = {
@@ -2498,70 +2717,70 @@ async function upgradeConfig(cwd) {
2498
2717
  ...existingConfig.structure
2499
2718
  }
2500
2719
  };
2501
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
2720
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
2502
2721
  try {
2503
- await fs8.mkdir(templatesDir, { recursive: true });
2722
+ await fs9.mkdir(templatesDir, { recursive: true });
2504
2723
  } catch {
2505
2724
  }
2506
2725
  const templateFiles = ["spec-template.md"];
2507
2726
  let templatesUpdated = false;
2508
2727
  for (const file of templateFiles) {
2509
- const destPath = path12.join(templatesDir, file);
2728
+ const destPath = path13.join(templatesDir, file);
2510
2729
  try {
2511
- await fs8.access(destPath);
2730
+ await fs9.access(destPath);
2512
2731
  } catch {
2513
- const srcPath = path12.join(TEMPLATES_DIR, "standard", "files", "README.md");
2732
+ const srcPath = path13.join(TEMPLATES_DIR, "standard", "files", "README.md");
2514
2733
  try {
2515
- await fs8.copyFile(srcPath, destPath);
2734
+ await fs9.copyFile(srcPath, destPath);
2516
2735
  templatesUpdated = true;
2517
- console.log(chalk15.green(`\u2713 Added missing template: ${file}`));
2736
+ console.log(chalk16.green(`\u2713 Added missing template: ${file}`));
2518
2737
  } catch {
2519
2738
  }
2520
2739
  }
2521
2740
  }
2522
- const agentsPath = path12.join(cwd, "AGENTS.md");
2741
+ const agentsPath = path13.join(cwd, "AGENTS.md");
2523
2742
  let agentsCreated = false;
2524
2743
  let agentsPreserved = false;
2525
2744
  try {
2526
- await fs8.access(agentsPath);
2745
+ await fs9.access(agentsPath);
2527
2746
  agentsPreserved = true;
2528
2747
  } catch {
2529
- const templateDir = path12.join(TEMPLATES_DIR, "standard");
2530
- const agentsSourcePath = path12.join(templateDir, "AGENTS.md");
2748
+ const templateDir = path13.join(TEMPLATES_DIR, "standard");
2749
+ const agentsSourcePath = path13.join(templateDir, "AGENTS.md");
2531
2750
  try {
2532
2751
  const projectName = await getProjectName2(cwd);
2533
- let agentsContent = await fs8.readFile(agentsSourcePath, "utf-8");
2752
+ let agentsContent = await fs9.readFile(agentsSourcePath, "utf-8");
2534
2753
  agentsContent = agentsContent.replace(/\{project_name\}/g, projectName);
2535
- await fs8.writeFile(agentsPath, agentsContent, "utf-8");
2754
+ await fs9.writeFile(agentsPath, agentsContent, "utf-8");
2536
2755
  agentsCreated = true;
2537
- console.log(chalk15.green("\u2713 Created missing AGENTS.md"));
2756
+ console.log(chalk16.green("\u2713 Created missing AGENTS.md"));
2538
2757
  } catch (error) {
2539
- console.log(chalk15.yellow(`\u26A0 Could not create AGENTS.md: ${error}`));
2758
+ console.log(chalk16.yellow(`\u26A0 Could not create AGENTS.md: ${error}`));
2540
2759
  }
2541
2760
  }
2542
2761
  await saveConfig(upgradedConfig, cwd);
2543
2762
  console.log("");
2544
- console.log(chalk15.green("\u2713 Configuration upgraded!"));
2763
+ console.log(chalk16.green("\u2713 Configuration upgraded!"));
2545
2764
  console.log("");
2546
- console.log(chalk15.gray("What was updated:"));
2547
- console.log(chalk15.gray(" - Config merged with latest defaults"));
2765
+ console.log(chalk16.gray("What was updated:"));
2766
+ console.log(chalk16.gray(" - Config merged with latest defaults"));
2548
2767
  if (templatesUpdated) {
2549
- console.log(chalk15.gray(" - Missing templates added"));
2768
+ console.log(chalk16.gray(" - Missing templates added"));
2550
2769
  }
2551
2770
  if (agentsCreated) {
2552
- console.log(chalk15.gray(" - AGENTS.md created (was missing)"));
2771
+ console.log(chalk16.gray(" - AGENTS.md created (was missing)"));
2553
2772
  }
2554
2773
  console.log("");
2555
- console.log(chalk15.gray("What was preserved:"));
2556
- console.log(chalk15.gray(" - Your specs/ directory"));
2774
+ console.log(chalk16.gray("What was preserved:"));
2775
+ console.log(chalk16.gray(" - Your specs/ directory"));
2557
2776
  if (agentsPreserved) {
2558
- console.log(chalk15.gray(" - Your AGENTS.md"));
2777
+ console.log(chalk16.gray(" - Your AGENTS.md"));
2559
2778
  }
2560
- console.log(chalk15.gray(" - Your custom settings"));
2779
+ console.log(chalk16.gray(" - Your custom settings"));
2561
2780
  console.log("");
2562
2781
  }
2563
2782
  function initCommand() {
2564
- return new Command("init").description("Initialize LeanSpec in current directory").option("-y, --yes", "Skip prompts and use defaults (quick start with standard template)").option("-f, --force", "Force re-initialization (resets config, keeps specs)").option("--template <name>", "Use specific template (standard or detailed)").option("--example [name]", "Scaffold an example project for tutorials (interactive if no name provided)").option("--name <dirname>", "Custom directory name for example project").option("--list", "List available example projects").option("--agent-tools <tools>", 'AI tools to create symlinks for (comma-separated: claude,gemini,copilot or "all" or "none")').action(async (options) => {
2783
+ return new Command("init").description("Initialize LeanSpec in current directory").option("-y, --yes", "Skip prompts and use defaults (quick start with standard template)").option("-f, --force", "Force re-initialization (resets config, keeps specs)").option("--template <name>", "Use specific template (standard or detailed)").option("--example [name]", "Scaffold an example project for tutorials (interactive if no name provided)").option("--name <dirname>", "Custom directory name for example project").option("--list", "List available example projects").option("--agent-tools <tools>", 'AI tools to create symlinks for (comma-separated: claude,gemini,copilot or "all" or "none")').option("--mcp-config <tools>", 'Configure MCP server for AI tools (comma-separated: claude-code,vscode,cursor,windsurf or "all" or "none")').action(async (options) => {
2565
2784
  if (options.list) {
2566
2785
  await listExamples();
2567
2786
  return;
@@ -2570,15 +2789,15 @@ function initCommand() {
2570
2789
  await scaffoldExample(options.example, options.name);
2571
2790
  return;
2572
2791
  }
2573
- await initProject(options.yes, options.template, options.agentTools, options.force);
2792
+ await initProject(options.yes, options.template, options.agentTools, options.force, options.mcpConfig);
2574
2793
  });
2575
2794
  }
2576
- async function initProject(skipPrompts = false, templateOption, agentToolsOption, forceReinit = false) {
2795
+ async function initProject(skipPrompts = false, templateOption, agentToolsOption, forceReinit = false, mcpConfigOption) {
2577
2796
  const cwd = process.cwd();
2578
- const configPath = path12.join(cwd, ".lean-spec", "config.json");
2797
+ const configPath = path13.join(cwd, ".lean-spec", "config.json");
2579
2798
  let isAlreadyInitialized = false;
2580
2799
  try {
2581
- await fs8.access(configPath);
2800
+ await fs9.access(configPath);
2582
2801
  isAlreadyInitialized = true;
2583
2802
  } catch {
2584
2803
  }
@@ -2592,16 +2811,17 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2592
2811
  return;
2593
2812
  }
2594
2813
  if (strategy === "reset-config") {
2595
- await fs8.rm(path12.join(cwd, ".lean-spec"), { recursive: true, force: true });
2596
- console.log(chalk15.gray("Removed .lean-spec/ configuration"));
2814
+ await fs9.rm(path13.join(cwd, ".lean-spec"), { recursive: true, force: true });
2815
+ console.log(chalk16.gray("Removed .lean-spec/ configuration"));
2597
2816
  }
2598
2817
  }
2599
2818
  console.log("");
2600
- console.log(chalk15.green("Welcome to LeanSpec!"));
2819
+ console.log(chalk16.green("Welcome to LeanSpec!"));
2601
2820
  console.log("");
2602
2821
  let setupMode = "quick";
2603
2822
  let templateName = templateOption || "standard";
2604
2823
  let selectedAgentTools = [];
2824
+ let selectedMcpTools = [];
2605
2825
  if (agentToolsOption) {
2606
2826
  if (agentToolsOption === "all") {
2607
2827
  selectedAgentTools = Object.keys(AI_TOOL_CONFIGS);
@@ -2611,11 +2831,24 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2611
2831
  selectedAgentTools = agentToolsOption.split(",").map((t) => t.trim());
2612
2832
  }
2613
2833
  }
2834
+ if (mcpConfigOption) {
2835
+ const parsed = parseMcpConfigFlag(mcpConfigOption);
2836
+ if (parsed === "all") {
2837
+ selectedMcpTools = Object.keys(MCP_TOOL_CONFIGS);
2838
+ } else if (parsed === "none") {
2839
+ selectedMcpTools = [];
2840
+ } else {
2841
+ selectedMcpTools = parsed;
2842
+ }
2843
+ }
2614
2844
  if (skipPrompts) {
2615
- console.log(chalk15.gray("Using defaults: quick start with standard template"));
2845
+ console.log(chalk16.gray("Using defaults: quick start with standard template"));
2616
2846
  if (!agentToolsOption) {
2617
2847
  selectedAgentTools = ["copilot"];
2618
2848
  }
2849
+ if (!mcpConfigOption) {
2850
+ selectedMcpTools = ["claude"];
2851
+ }
2619
2852
  console.log("");
2620
2853
  } else if (!templateOption) {
2621
2854
  setupMode = await select({
@@ -2654,24 +2887,24 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2654
2887
  }
2655
2888
  }
2656
2889
  if (templateName === "minimal") {
2657
- console.log(chalk15.yellow('\u26A0 The "minimal" template has been removed.'));
2658
- console.log(chalk15.gray(' Using "standard" template instead (same lightweight approach).'));
2890
+ console.log(chalk16.yellow('\u26A0 The "minimal" template has been removed.'));
2891
+ console.log(chalk16.gray(' Using "standard" template instead (same lightweight approach).'));
2659
2892
  console.log("");
2660
2893
  templateName = "standard";
2661
2894
  } else if (templateName === "enterprise") {
2662
- console.log(chalk15.yellow('\u26A0 The "enterprise" template has been renamed to "detailed".'));
2663
- console.log(chalk15.gray(' Using "detailed" template (sub-spec structure for complex specs).'));
2895
+ console.log(chalk16.yellow('\u26A0 The "enterprise" template has been renamed to "detailed".'));
2896
+ console.log(chalk16.gray(' Using "detailed" template (sub-spec structure for complex specs).'));
2664
2897
  console.log("");
2665
2898
  templateName = "detailed";
2666
2899
  }
2667
- const templateDir = path12.join(TEMPLATES_DIR, templateName);
2668
- const templateConfigPath = path12.join(templateDir, "config.json");
2900
+ const templateDir = path13.join(TEMPLATES_DIR, templateName);
2901
+ const templateConfigPath = path13.join(templateDir, "config.json");
2669
2902
  let templateConfig;
2670
2903
  try {
2671
- const content = await fs8.readFile(templateConfigPath, "utf-8");
2904
+ const content = await fs9.readFile(templateConfigPath, "utf-8");
2672
2905
  templateConfig = JSON.parse(content).config;
2673
2906
  } catch {
2674
- console.error(chalk15.red(`Error: Template not found: ${templateName}`));
2907
+ console.error(chalk16.red(`Error: Template not found: ${templateName}`));
2675
2908
  process.exit(1);
2676
2909
  }
2677
2910
  let patternChoice = "simple";
@@ -2714,9 +2947,9 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2714
2947
  templateConfig.structure.prefix = "{YYYYMMDD}-";
2715
2948
  } else if (patternChoice === "custom") {
2716
2949
  console.log("");
2717
- console.log(chalk15.yellow("\u26A0 Custom pattern input is not yet implemented."));
2718
- console.log(chalk15.gray(" You can manually edit .lean-spec/config.json after initialization."));
2719
- console.log(chalk15.gray(" Using simple pattern for now."));
2950
+ console.log(chalk16.yellow("\u26A0 Custom pattern input is not yet implemented."));
2951
+ console.log(chalk16.gray(" You can manually edit .lean-spec/config.json after initialization."));
2952
+ console.log(chalk16.gray(" Using simple pattern for now."));
2720
2953
  console.log("");
2721
2954
  templateConfig.structure.pattern = "flat";
2722
2955
  templateConfig.structure.prefix = "";
@@ -2726,12 +2959,12 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2726
2959
  const anyDetected = detectionResults.some((r) => r.detected);
2727
2960
  if (anyDetected) {
2728
2961
  console.log("");
2729
- console.log(chalk15.cyan("\u{1F50D} Detected AI tools:"));
2962
+ console.log(chalk16.cyan("\u{1F50D} Detected AI tools:"));
2730
2963
  for (const result of detectionResults) {
2731
2964
  if (result.detected) {
2732
- console.log(chalk15.gray(` ${AI_TOOL_CONFIGS[result.tool].description}`));
2965
+ console.log(chalk16.gray(` ${AI_TOOL_CONFIGS[result.tool].description}`));
2733
2966
  for (const reason of result.reasons) {
2734
- console.log(chalk15.gray(` \u2514\u2500 ${reason}`));
2967
+ console.log(chalk16.gray(` \u2514\u2500 ${reason}`));
2735
2968
  }
2736
2969
  }
2737
2970
  }
@@ -2744,8 +2977,8 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2744
2977
  }));
2745
2978
  if (symlinkTools.length > 0) {
2746
2979
  console.log("");
2747
- console.log(chalk15.gray("AGENTS.md will be created as the primary instruction file."));
2748
- console.log(chalk15.gray("Some AI tools (Claude Code, Gemini CLI) use their own filenames."));
2980
+ console.log(chalk16.gray("AGENTS.md will be created as the primary instruction file."));
2981
+ console.log(chalk16.gray("Some AI tools (Claude Code, Gemini CLI) use their own filenames."));
2749
2982
  console.log("");
2750
2983
  const symlinkSelection = await checkbox({
2751
2984
  message: "Create symlinks for additional AI tools?",
@@ -2755,56 +2988,86 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2755
2988
  } else {
2756
2989
  selectedAgentTools = [];
2757
2990
  }
2991
+ if (!mcpConfigOption) {
2992
+ const { defaults: mcpDefaults, detected: mcpDetectionResults } = await getDefaultMcpToolSelection(cwd);
2993
+ const anyMcpDetected = mcpDetectionResults.some((r) => r.detected);
2994
+ if (anyMcpDetected) {
2995
+ console.log("");
2996
+ console.log(chalk16.cyan("\u{1F50D} Detected MCP-capable tools:"));
2997
+ for (const result of mcpDetectionResults) {
2998
+ if (result.detected) {
2999
+ console.log(chalk16.gray(` ${MCP_TOOL_CONFIGS[result.tool].description}`));
3000
+ for (const reason of result.reasons) {
3001
+ console.log(chalk16.gray(` \u2514\u2500 ${reason}`));
3002
+ }
3003
+ }
3004
+ }
3005
+ }
3006
+ console.log("");
3007
+ console.log(chalk16.gray("MCP (Model Context Protocol) provides richer AI integration than CLI alone."));
3008
+ console.log(chalk16.gray("Configure MCP server to enable structured data exchange with your AI tools."));
3009
+ console.log("");
3010
+ const mcpToolChoices = Object.entries(MCP_TOOL_CONFIGS).map(([key, config]) => ({
3011
+ name: config.description,
3012
+ value: key,
3013
+ checked: mcpDefaults.includes(key)
3014
+ }));
3015
+ const mcpSelection = await checkbox({
3016
+ message: "Configure MCP server for which tools?",
3017
+ choices: mcpToolChoices
3018
+ });
3019
+ selectedMcpTools = mcpSelection;
3020
+ }
2758
3021
  }
2759
- const templatesDir = path12.join(cwd, ".lean-spec", "templates");
3022
+ const templatesDir = path13.join(cwd, ".lean-spec", "templates");
2760
3023
  try {
2761
- await fs8.mkdir(templatesDir, { recursive: true });
3024
+ await fs9.mkdir(templatesDir, { recursive: true });
2762
3025
  } catch (error) {
2763
- console.error(chalk15.red("Error creating templates directory:"), error);
3026
+ console.error(chalk16.red("Error creating templates directory:"), error);
2764
3027
  process.exit(1);
2765
3028
  }
2766
- const templateFilesDir = path12.join(templateDir, "files");
3029
+ const templateFilesDir = path13.join(templateDir, "files");
2767
3030
  try {
2768
- const files = await fs8.readdir(templateFilesDir);
3031
+ const files = await fs9.readdir(templateFilesDir);
2769
3032
  if (templateName === "standard") {
2770
- const readmePath = path12.join(templateFilesDir, "README.md");
2771
- const targetSpecPath = path12.join(templatesDir, "spec-template.md");
2772
- await fs8.copyFile(readmePath, targetSpecPath);
2773
- console.log(chalk15.green("\u2713 Created .lean-spec/templates/spec-template.md"));
3033
+ const readmePath = path13.join(templateFilesDir, "README.md");
3034
+ const targetSpecPath = path13.join(templatesDir, "spec-template.md");
3035
+ await fs9.copyFile(readmePath, targetSpecPath);
3036
+ console.log(chalk16.green("\u2713 Created .lean-spec/templates/spec-template.md"));
2774
3037
  templateConfig.template = "spec-template.md";
2775
3038
  templateConfig.templates = {
2776
3039
  default: "spec-template.md"
2777
3040
  };
2778
3041
  } else if (templateName === "detailed") {
2779
3042
  for (const file of files) {
2780
- const srcPath = path12.join(templateFilesDir, file);
2781
- const destPath = path12.join(templatesDir, file);
2782
- await fs8.copyFile(srcPath, destPath);
3043
+ const srcPath = path13.join(templateFilesDir, file);
3044
+ const destPath = path13.join(templatesDir, file);
3045
+ await fs9.copyFile(srcPath, destPath);
2783
3046
  }
2784
- console.log(chalk15.green(`\u2713 Created .lean-spec/templates/ with ${files.length} files`));
2785
- console.log(chalk15.gray(` Files: ${files.join(", ")}`));
3047
+ console.log(chalk16.green(`\u2713 Created .lean-spec/templates/ with ${files.length} files`));
3048
+ console.log(chalk16.gray(` Files: ${files.join(", ")}`));
2786
3049
  templateConfig.template = "README.md";
2787
3050
  templateConfig.templates = {
2788
3051
  default: "README.md"
2789
3052
  };
2790
3053
  }
2791
3054
  } catch (error) {
2792
- console.error(chalk15.red("Error copying template files:"), error);
3055
+ console.error(chalk16.red("Error copying template files:"), error);
2793
3056
  process.exit(1);
2794
3057
  }
2795
3058
  await saveConfig(templateConfig, cwd);
2796
- console.log(chalk15.green("\u2713 Created .lean-spec/config.json"));
3059
+ console.log(chalk16.green("\u2713 Created .lean-spec/config.json"));
2797
3060
  const existingFiles = await detectExistingSystemPrompts(cwd);
2798
3061
  let skipFiles = [];
2799
3062
  let mergeCompleted = false;
2800
3063
  if (existingFiles.length > 0) {
2801
3064
  console.log("");
2802
- console.log(chalk15.yellow(`Found existing: ${existingFiles.join(", ")}`));
3065
+ console.log(chalk16.yellow(`Found existing: ${existingFiles.join(", ")}`));
2803
3066
  if (skipPrompts) {
2804
- console.log(chalk15.gray("Using AI-Assisted Merge for existing AGENTS.md"));
3067
+ console.log(chalk16.gray("Using AI-Assisted Merge for existing AGENTS.md"));
2805
3068
  const projectName2 = await getProjectName2(cwd);
2806
3069
  await handleExistingFiles("merge-ai", existingFiles, templateDir, cwd, { project_name: projectName2 });
2807
- const promptPath = path12.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
3070
+ const promptPath = path13.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
2808
3071
  mergeCompleted = await attemptAutoMerge(
2809
3072
  cwd,
2810
3073
  promptPath,
@@ -2842,7 +3105,7 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2842
3105
  if (action === "skip") {
2843
3106
  skipFiles = existingFiles;
2844
3107
  } else if (action === "merge-ai") {
2845
- const promptPath = path12.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
3108
+ const promptPath = path13.join(cwd, ".lean-spec", "MERGE-AGENTS-PROMPT.md");
2846
3109
  mergeCompleted = await attemptAutoMerge(
2847
3110
  cwd,
2848
3111
  promptPath,
@@ -2854,75 +3117,81 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
2854
3117
  }
2855
3118
  const projectName = await getProjectName2(cwd);
2856
3119
  if (!skipFiles.includes("AGENTS.md") && !mergeCompleted) {
2857
- const agentsSourcePath = path12.join(templateDir, "AGENTS.md");
2858
- const agentsTargetPath = path12.join(cwd, "AGENTS.md");
3120
+ const agentsSourcePath = path13.join(templateDir, "AGENTS.md");
3121
+ const agentsTargetPath = path13.join(cwd, "AGENTS.md");
2859
3122
  try {
2860
- let agentsContent = await fs8.readFile(agentsSourcePath, "utf-8");
3123
+ let agentsContent = await fs9.readFile(agentsSourcePath, "utf-8");
2861
3124
  agentsContent = agentsContent.replace(/\{project_name\}/g, projectName);
2862
- await fs8.writeFile(agentsTargetPath, agentsContent, "utf-8");
2863
- console.log(chalk15.green("\u2713 Created AGENTS.md"));
3125
+ await fs9.writeFile(agentsTargetPath, agentsContent, "utf-8");
3126
+ console.log(chalk16.green("\u2713 Created AGENTS.md"));
2864
3127
  } catch (error) {
2865
- console.error(chalk15.red("Error copying AGENTS.md:"), error);
3128
+ console.error(chalk16.red("Error copying AGENTS.md:"), error);
2866
3129
  process.exit(1);
2867
3130
  }
2868
3131
  if (selectedAgentTools.length > 0) {
2869
3132
  const symlinkResults = await createAgentToolSymlinks(cwd, selectedAgentTools);
2870
3133
  for (const result of symlinkResults) {
2871
3134
  if (result.created) {
2872
- console.log(chalk15.green(`\u2713 Created ${result.file} \u2192 AGENTS.md`));
3135
+ console.log(chalk16.green(`\u2713 Created ${result.file} \u2192 AGENTS.md`));
2873
3136
  } else if (result.skipped) {
2874
- console.log(chalk15.yellow(`\u26A0 Skipped ${result.file} (already exists)`));
3137
+ console.log(chalk16.yellow(`\u26A0 Skipped ${result.file} (already exists)`));
2875
3138
  } else if (result.error) {
2876
- console.log(chalk15.yellow(`\u26A0 Could not create ${result.file}: ${result.error}`));
3139
+ console.log(chalk16.yellow(`\u26A0 Could not create ${result.file}: ${result.error}`));
2877
3140
  }
2878
3141
  }
2879
3142
  }
2880
3143
  }
2881
- const filesDir = path12.join(templateDir, "files");
3144
+ const filesDir = path13.join(templateDir, "files");
2882
3145
  try {
2883
- const filesToCopy = await fs8.readdir(filesDir);
3146
+ const filesToCopy = await fs9.readdir(filesDir);
2884
3147
  const hasOtherFiles = filesToCopy.some((f) => !f.match(/\.(md)$/i) || !["README.md", "DESIGN.md", "PLAN.md", "TEST.md"].includes(f));
2885
3148
  if (hasOtherFiles) {
2886
3149
  await copyDirectory(filesDir, cwd, [...skipFiles, "README.md", "DESIGN.md", "PLAN.md", "TEST.md"], { project_name: projectName });
2887
3150
  }
2888
- console.log(chalk15.green("\u2713 Initialized project structure"));
3151
+ console.log(chalk16.green("\u2713 Initialized project structure"));
2889
3152
  } catch (error) {
2890
- console.error(chalk15.red("Error copying template files:"), error);
3153
+ console.error(chalk16.red("Error copying template files:"), error);
2891
3154
  process.exit(1);
2892
3155
  }
2893
- const specsDir = path12.join(cwd, "specs");
3156
+ const specsDir = path13.join(cwd, "specs");
2894
3157
  try {
2895
- await fs8.mkdir(specsDir, { recursive: true });
2896
- console.log(chalk15.green("\u2713 Created specs/ directory"));
3158
+ await fs9.mkdir(specsDir, { recursive: true });
3159
+ console.log(chalk16.green("\u2713 Created specs/ directory"));
2897
3160
  } catch (error) {
2898
- console.error(chalk15.red("Error creating specs directory:"), error);
3161
+ console.error(chalk16.red("Error creating specs directory:"), error);
2899
3162
  process.exit(1);
2900
3163
  }
3164
+ if (selectedMcpTools.length > 0) {
3165
+ console.log("");
3166
+ console.log(chalk16.cyan("Configuring MCP server..."));
3167
+ const mcpResults = await createMcpConfigs(cwd, selectedMcpTools);
3168
+ printMcpConfigResults(mcpResults);
3169
+ }
2901
3170
  console.log("");
2902
- console.log(chalk15.green("\u2713 LeanSpec initialized!"));
3171
+ console.log(chalk16.green("\u2713 LeanSpec initialized!"));
2903
3172
  console.log("");
2904
- console.log(chalk15.cyan("You're ready to go!") + chalk15.gray(" Ask your AI to create a spec for your next feature."));
3173
+ console.log(chalk16.cyan("You're ready to go!") + chalk16.gray(" Ask your AI to create a spec for your next feature."));
2905
3174
  console.log("");
2906
- console.log(chalk15.gray('Example: "Create a spec for user authentication"'));
2907
- console.log(chalk15.gray("Learn more: https://lean-spec.dev/docs/guide/getting-started"));
3175
+ console.log(chalk16.gray('Example: "Create a spec for user authentication"'));
3176
+ console.log(chalk16.gray("Learn more: https://lean-spec.dev/docs/guide/getting-started"));
2908
3177
  console.log("");
2909
3178
  }
2910
3179
  async function listExamples() {
2911
3180
  const examples = getExamplesList();
2912
3181
  console.log("");
2913
- console.log(chalk15.bold("Available Examples:"));
3182
+ console.log(chalk16.bold("Available Examples:"));
2914
3183
  console.log("");
2915
3184
  for (const example of examples) {
2916
- const difficultyColor = example.difficulty === "beginner" ? chalk15.green : example.difficulty === "intermediate" ? chalk15.yellow : chalk15.red;
2917
- console.log(chalk15.cyan(` ${example.name}`));
3185
+ const difficultyColor = example.difficulty === "beginner" ? chalk16.green : example.difficulty === "intermediate" ? chalk16.yellow : chalk16.red;
3186
+ console.log(chalk16.cyan(` ${example.name}`));
2918
3187
  console.log(` ${example.description}`);
2919
3188
  console.log(` ${difficultyColor(example.difficulty)} \u2022 ${example.tech.join(", ")} \u2022 ~${example.lines} lines`);
2920
- console.log(` Tutorial: ${chalk15.gray(example.tutorialUrl)}`);
3189
+ console.log(` Tutorial: ${chalk16.gray(example.tutorialUrl)}`);
2921
3190
  console.log("");
2922
3191
  }
2923
3192
  console.log("Usage:");
2924
- console.log(chalk15.gray(" lean-spec init --example <name>"));
2925
- console.log(chalk15.gray(" lean-spec init --example dark-theme"));
3193
+ console.log(chalk16.gray(" lean-spec init --example <name>"));
3194
+ console.log(chalk16.gray(" lean-spec init --example dark-theme"));
2926
3195
  console.log("");
2927
3196
  }
2928
3197
  async function scaffoldExample(exampleName, customName) {
@@ -2930,7 +3199,7 @@ async function scaffoldExample(exampleName, customName) {
2930
3199
  exampleName = await selectExample();
2931
3200
  }
2932
3201
  if (!exampleExists(exampleName)) {
2933
- console.error(chalk15.red(`Error: Example "${exampleName}" not found.`));
3202
+ console.error(chalk16.red(`Error: Example "${exampleName}" not found.`));
2934
3203
  console.log("");
2935
3204
  console.log("Available examples:");
2936
3205
  getExamplesList().forEach((ex) => {
@@ -2942,63 +3211,63 @@ async function scaffoldExample(exampleName, customName) {
2942
3211
  }
2943
3212
  const example = getExample(exampleName);
2944
3213
  const targetDirName = customName || exampleName;
2945
- const targetPath = path12.join(process.cwd(), targetDirName);
3214
+ const targetPath = path13.join(process.cwd(), targetDirName);
2946
3215
  try {
2947
- const files = await fs8.readdir(targetPath);
3216
+ const files = await fs9.readdir(targetPath);
2948
3217
  const nonGitFiles = files.filter((f) => f !== ".git");
2949
3218
  if (nonGitFiles.length > 0) {
2950
- console.error(chalk15.red(`Error: Directory "${targetDirName}" already exists and is not empty.`));
2951
- console.log(chalk15.gray("Choose a different name with --name option."));
3219
+ console.error(chalk16.red(`Error: Directory "${targetDirName}" already exists and is not empty.`));
3220
+ console.log(chalk16.gray("Choose a different name with --name option."));
2952
3221
  process.exit(1);
2953
3222
  }
2954
3223
  } catch {
2955
3224
  }
2956
3225
  console.log("");
2957
- console.log(chalk15.green(`Setting up example: ${example.title}`));
2958
- console.log(chalk15.gray(example.description));
3226
+ console.log(chalk16.green(`Setting up example: ${example.title}`));
3227
+ console.log(chalk16.gray(example.description));
2959
3228
  console.log("");
2960
- await fs8.mkdir(targetPath, { recursive: true });
2961
- console.log(chalk15.green(`\u2713 Created directory: ${targetDirName}/`));
2962
- const examplePath = path12.join(EXAMPLES_DIR, exampleName);
3229
+ await fs9.mkdir(targetPath, { recursive: true });
3230
+ console.log(chalk16.green(`\u2713 Created directory: ${targetDirName}/`));
3231
+ const examplePath = path13.join(EXAMPLES_DIR, exampleName);
2963
3232
  await copyDirectoryRecursive(examplePath, targetPath);
2964
- console.log(chalk15.green("\u2713 Copied example project"));
3233
+ console.log(chalk16.green("\u2713 Copied example project"));
2965
3234
  const originalCwd = process.cwd();
2966
3235
  try {
2967
3236
  process.chdir(targetPath);
2968
- console.log(chalk15.gray("Initializing LeanSpec..."));
3237
+ console.log(chalk16.gray("Initializing LeanSpec..."));
2969
3238
  await initProject(true);
2970
- console.log(chalk15.green("\u2713 Initialized LeanSpec"));
3239
+ console.log(chalk16.green("\u2713 Initialized LeanSpec"));
2971
3240
  } catch (error) {
2972
- console.error(chalk15.red("Error initializing LeanSpec:"), error);
3241
+ console.error(chalk16.red("Error initializing LeanSpec:"), error);
2973
3242
  process.exit(1);
2974
3243
  } finally {
2975
3244
  process.chdir(originalCwd);
2976
3245
  }
2977
3246
  const packageManager = await detectPackageManager();
2978
- console.log(chalk15.gray(`Installing dependencies with ${packageManager}...`));
3247
+ console.log(chalk16.gray(`Installing dependencies with ${packageManager}...`));
2979
3248
  try {
2980
3249
  const { execSync: execSync3 } = await import('child_process');
2981
3250
  execSync3(`${packageManager} install`, {
2982
3251
  cwd: targetPath,
2983
3252
  stdio: "inherit"
2984
3253
  });
2985
- console.log(chalk15.green("\u2713 Installed dependencies"));
3254
+ console.log(chalk16.green("\u2713 Installed dependencies"));
2986
3255
  } catch (error) {
2987
- console.log(chalk15.yellow("\u26A0 Failed to install dependencies automatically"));
2988
- console.log(chalk15.gray(` Run: cd ${targetDirName} && ${packageManager} install`));
3256
+ console.log(chalk16.yellow("\u26A0 Failed to install dependencies automatically"));
3257
+ console.log(chalk16.gray(` Run: cd ${targetDirName} && ${packageManager} install`));
2989
3258
  }
2990
3259
  console.log("");
2991
- console.log(chalk15.green("\u2713 Example project ready!"));
3260
+ console.log(chalk16.green("\u2713 Example project ready!"));
2992
3261
  console.log("");
2993
- console.log(chalk15.gray("Created:"));
2994
- console.log(chalk15.gray(` - Application code (${example.tech.join(", ")})`));
2995
- console.log(chalk15.gray(" - LeanSpec files (AGENTS.md, .lean-spec/, specs/)"));
3262
+ console.log(chalk16.gray("Created:"));
3263
+ console.log(chalk16.gray(` - Application code (${example.tech.join(", ")})`));
3264
+ console.log(chalk16.gray(" - LeanSpec files (AGENTS.md, .lean-spec/, specs/)"));
2996
3265
  console.log("");
2997
3266
  console.log("Next steps:");
2998
- console.log(chalk15.cyan(` 1. cd ${targetDirName}`));
2999
- console.log(chalk15.cyan(" 2. Open this project in your editor"));
3000
- console.log(chalk15.cyan(` 3. Follow the tutorial: ${example.tutorialUrl}`));
3001
- console.log(chalk15.cyan(` 4. Ask your AI: "Help me with this tutorial using LeanSpec"`));
3267
+ console.log(chalk16.cyan(` 1. cd ${targetDirName}`));
3268
+ console.log(chalk16.cyan(" 2. Open this project in your editor"));
3269
+ console.log(chalk16.cyan(` 3. Follow the tutorial: ${example.tutorialUrl}`));
3270
+ console.log(chalk16.cyan(` 4. Ask your AI: "Help me with this tutorial using LeanSpec"`));
3002
3271
  console.log("");
3003
3272
  }
3004
3273
  async function selectExample() {
@@ -3017,27 +3286,27 @@ async function selectExample() {
3017
3286
  return choice;
3018
3287
  }
3019
3288
  async function copyDirectoryRecursive(src, dest) {
3020
- const entries = await fs8.readdir(src, { withFileTypes: true });
3289
+ const entries = await fs9.readdir(src, { withFileTypes: true });
3021
3290
  for (const entry of entries) {
3022
- const srcPath = path12.join(src, entry.name);
3023
- const destPath = path12.join(dest, entry.name);
3291
+ const srcPath = path13.join(src, entry.name);
3292
+ const destPath = path13.join(dest, entry.name);
3024
3293
  if (entry.isDirectory()) {
3025
- await fs8.mkdir(destPath, { recursive: true });
3294
+ await fs9.mkdir(destPath, { recursive: true });
3026
3295
  await copyDirectoryRecursive(srcPath, destPath);
3027
3296
  } else {
3028
- await fs8.copyFile(srcPath, destPath);
3297
+ await fs9.copyFile(srcPath, destPath);
3029
3298
  }
3030
3299
  }
3031
3300
  }
3032
3301
  async function detectPackageManager() {
3033
3302
  const cwd = process.cwd();
3034
3303
  try {
3035
- await fs8.access(path12.join(cwd, "..", "pnpm-lock.yaml"));
3304
+ await fs9.access(path13.join(cwd, "..", "pnpm-lock.yaml"));
3036
3305
  return "pnpm";
3037
3306
  } catch {
3038
3307
  }
3039
3308
  try {
3040
- await fs8.access(path12.join(cwd, "..", "yarn.lock"));
3309
+ await fs9.access(path13.join(cwd, "..", "yarn.lock"));
3041
3310
  return "yarn";
3042
3311
  } catch {
3043
3312
  }
@@ -3055,7 +3324,7 @@ async function showFiles(specPath, options = {}) {
3055
3324
  await autoCheckIfEnabled();
3056
3325
  const config = await loadConfig();
3057
3326
  const cwd = process.cwd();
3058
- const specsDir = path12.join(cwd, config.specsDir);
3327
+ const specsDir = path13.join(cwd, config.specsDir);
3059
3328
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
3060
3329
  if (!resolvedPath) {
3061
3330
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}. Try using the full path or spec name (e.g., 001-my-spec)`);
@@ -3066,8 +3335,8 @@ async function showFiles(specPath, options = {}) {
3066
3335
  }
3067
3336
  const subFiles = await loadSubFiles(spec.fullPath);
3068
3337
  if (options.json) {
3069
- const readmeStat2 = await fs8.stat(spec.filePath);
3070
- const readmeContent2 = await fs8.readFile(spec.filePath, "utf-8");
3338
+ const readmeStat2 = await fs9.stat(spec.filePath);
3339
+ const readmeContent2 = await fs9.readFile(spec.filePath, "utf-8");
3071
3340
  const readmeTokens2 = await countTokens({ content: readmeContent2 });
3072
3341
  const jsonOutput = {
3073
3342
  spec: spec.name,
@@ -3091,14 +3360,14 @@ async function showFiles(specPath, options = {}) {
3091
3360
  return;
3092
3361
  }
3093
3362
  console.log("");
3094
- console.log(chalk15.cyan(`\u{1F4C4} Files in ${sanitizeUserInput(spec.name)}`));
3363
+ console.log(chalk16.cyan(`\u{1F4C4} Files in ${sanitizeUserInput(spec.name)}`));
3095
3364
  console.log("");
3096
- console.log(chalk15.green("Required:"));
3097
- const readmeStat = await fs8.stat(spec.filePath);
3365
+ console.log(chalk16.green("Required:"));
3366
+ const readmeStat = await fs9.stat(spec.filePath);
3098
3367
  const readmeSize = formatSize(readmeStat.size);
3099
- const readmeContent = await fs8.readFile(spec.filePath, "utf-8");
3368
+ const readmeContent = await fs9.readFile(spec.filePath, "utf-8");
3100
3369
  const readmeTokens = await countTokens({ content: readmeContent });
3101
- console.log(chalk15.green(` \u2713 README.md (${readmeSize}, ~${readmeTokens.total.toLocaleString()} tokens) Main spec`));
3370
+ console.log(chalk16.green(` \u2713 README.md (${readmeSize}, ~${readmeTokens.total.toLocaleString()} tokens) Main spec`));
3102
3371
  console.log("");
3103
3372
  let filteredFiles = subFiles;
3104
3373
  if (options.type === "docs") {
@@ -3107,27 +3376,27 @@ async function showFiles(specPath, options = {}) {
3107
3376
  filteredFiles = subFiles.filter((f) => f.type === "asset");
3108
3377
  }
3109
3378
  if (filteredFiles.length === 0) {
3110
- console.log(chalk15.gray("No additional files"));
3379
+ console.log(chalk16.gray("No additional files"));
3111
3380
  console.log("");
3112
3381
  return;
3113
3382
  }
3114
3383
  const documents = filteredFiles.filter((f) => f.type === "document");
3115
3384
  const assets = filteredFiles.filter((f) => f.type === "asset");
3116
3385
  if (documents.length > 0 && (!options.type || options.type === "docs")) {
3117
- console.log(chalk15.cyan("Documents:"));
3386
+ console.log(chalk16.cyan("Documents:"));
3118
3387
  for (const file of documents) {
3119
3388
  const size = formatSize(file.size);
3120
- const content = await fs8.readFile(file.path, "utf-8");
3389
+ const content = await fs9.readFile(file.path, "utf-8");
3121
3390
  const tokenCount = await countTokens({ content });
3122
- console.log(chalk15.cyan(` \u2713 ${sanitizeUserInput(file.name).padEnd(20)} (${size}, ~${tokenCount.total.toLocaleString()} tokens)`));
3391
+ console.log(chalk16.cyan(` \u2713 ${sanitizeUserInput(file.name).padEnd(20)} (${size}, ~${tokenCount.total.toLocaleString()} tokens)`));
3123
3392
  }
3124
3393
  console.log("");
3125
3394
  }
3126
3395
  if (assets.length > 0 && (!options.type || options.type === "assets")) {
3127
- console.log(chalk15.yellow("Assets:"));
3396
+ console.log(chalk16.yellow("Assets:"));
3128
3397
  for (const file of assets) {
3129
3398
  const size = formatSize(file.size);
3130
- console.log(chalk15.yellow(` \u2713 ${sanitizeUserInput(file.name).padEnd(20)} (${size})`));
3399
+ console.log(chalk16.yellow(` \u2713 ${sanitizeUserInput(file.name).padEnd(20)} (${size})`));
3131
3400
  }
3132
3401
  console.log("");
3133
3402
  }
@@ -3135,7 +3404,7 @@ async function showFiles(specPath, options = {}) {
3135
3404
  const totalSize = formatSize(
3136
3405
  readmeStat.size + filteredFiles.reduce((sum, f) => sum + f.size, 0)
3137
3406
  );
3138
- console.log(chalk15.gray(`Total: ${totalFiles} files, ${totalSize}`));
3407
+ console.log(chalk16.gray(`Total: ${totalFiles} files, ${totalSize}`));
3139
3408
  console.log("");
3140
3409
  }
3141
3410
  function formatSize(bytes) {
@@ -3155,31 +3424,31 @@ function examplesCommand() {
3155
3424
  async function listExamples2() {
3156
3425
  const examples = getExamplesList();
3157
3426
  console.log("");
3158
- console.log(chalk15.bold("LeanSpec Example Projects"));
3427
+ console.log(chalk16.bold("LeanSpec Example Projects"));
3159
3428
  console.log("");
3160
3429
  console.log("Scaffold complete example projects to follow tutorials:");
3161
3430
  console.log("");
3162
3431
  for (const example of examples) {
3163
- const difficultyColor = example.difficulty === "beginner" ? chalk15.green : example.difficulty === "intermediate" ? chalk15.yellow : chalk15.red;
3432
+ const difficultyColor = example.difficulty === "beginner" ? chalk16.green : example.difficulty === "intermediate" ? chalk16.yellow : chalk16.red;
3164
3433
  const difficultyStars = example.difficulty === "beginner" ? "\u2605\u2606\u2606" : example.difficulty === "intermediate" ? "\u2605\u2605\u2606" : "\u2605\u2605\u2605";
3165
- console.log(chalk15.cyan.bold(` ${example.title}`));
3166
- console.log(` ${chalk15.gray(example.name)}`);
3434
+ console.log(chalk16.cyan.bold(` ${example.title}`));
3435
+ console.log(` ${chalk16.gray(example.name)}`);
3167
3436
  console.log(` ${example.description}`);
3168
3437
  console.log(` ${difficultyColor(difficultyStars + " " + example.difficulty)} \u2022 ${example.tech.join(", ")} \u2022 ~${example.lines} lines`);
3169
- console.log(` ${chalk15.gray("Tutorial:")} ${example.tutorial}`);
3170
- console.log(` ${chalk15.gray(example.tutorialUrl)}`);
3438
+ console.log(` ${chalk16.gray("Tutorial:")} ${example.tutorial}`);
3439
+ console.log(` ${chalk16.gray(example.tutorialUrl)}`);
3171
3440
  console.log("");
3172
3441
  }
3173
- console.log(chalk15.bold("Usage:"));
3442
+ console.log(chalk16.bold("Usage:"));
3174
3443
  console.log("");
3175
3444
  console.log(" # Scaffold an example");
3176
- console.log(chalk15.cyan(" lean-spec init --example <name>"));
3445
+ console.log(chalk16.cyan(" lean-spec init --example <name>"));
3177
3446
  console.log("");
3178
3447
  console.log(" # Interactive selection");
3179
- console.log(chalk15.cyan(" lean-spec init --example"));
3448
+ console.log(chalk16.cyan(" lean-spec init --example"));
3180
3449
  console.log("");
3181
3450
  console.log(" # Custom directory name");
3182
- console.log(chalk15.cyan(" lean-spec init --example dark-theme --name my-demo"));
3451
+ console.log(chalk16.cyan(" lean-spec init --example dark-theme --name my-demo"));
3183
3452
  console.log("");
3184
3453
  }
3185
3454
  function migrateCommand(inputPath, options = {}) {
@@ -3204,7 +3473,7 @@ function migrateCommand(inputPath, options = {}) {
3204
3473
  async function migrateSpecs(inputPath, options = {}) {
3205
3474
  const config = await loadConfig();
3206
3475
  try {
3207
- const stats = await fs8.stat(inputPath);
3476
+ const stats = await fs9.stat(inputPath);
3208
3477
  if (!stats.isDirectory()) {
3209
3478
  console.error("\x1B[31m\u274C Error:\x1B[0m Input path must be a directory");
3210
3479
  process.exit(1);
@@ -3239,16 +3508,16 @@ async function migrateSpecs(inputPath, options = {}) {
3239
3508
  async function scanDocuments(dirPath) {
3240
3509
  const documents = [];
3241
3510
  async function scanRecursive(currentPath) {
3242
- const entries = await fs8.readdir(currentPath, { withFileTypes: true });
3511
+ const entries = await fs9.readdir(currentPath, { withFileTypes: true });
3243
3512
  for (const entry of entries) {
3244
- const fullPath = path12.join(currentPath, entry.name);
3513
+ const fullPath = path13.join(currentPath, entry.name);
3245
3514
  if (entry.isDirectory()) {
3246
3515
  if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
3247
3516
  await scanRecursive(fullPath);
3248
3517
  }
3249
3518
  } else if (entry.isFile()) {
3250
3519
  if (entry.name.endsWith(".md") || entry.name.endsWith(".markdown")) {
3251
- const stats = await fs8.stat(fullPath);
3520
+ const stats = await fs9.stat(fullPath);
3252
3521
  documents.push({
3253
3522
  path: fullPath,
3254
3523
  name: entry.name,
@@ -3275,7 +3544,7 @@ async function detectSourceFormat(inputPath, documents) {
3275
3544
  return "generic";
3276
3545
  }
3277
3546
  async function migrateAuto(inputPath, documents, format, config, options) {
3278
- const specsDir = path12.join(process.cwd(), config.specsDir || "specs");
3547
+ const specsDir = path13.join(process.cwd(), config.specsDir || "specs");
3279
3548
  const startTime = Date.now();
3280
3549
  console.log("\u2550".repeat(70));
3281
3550
  console.log("\x1B[1m\x1B[36m\u{1F680} Auto Migration\x1B[0m");
@@ -3285,13 +3554,13 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3285
3554
  console.log("\x1B[33m\u26A0\uFE0F DRY RUN - No changes will be made\x1B[0m\n");
3286
3555
  }
3287
3556
  if (!options.dryRun) {
3288
- await fs8.mkdir(specsDir, { recursive: true });
3557
+ await fs9.mkdir(specsDir, { recursive: true });
3289
3558
  }
3290
3559
  let migratedCount = 0;
3291
3560
  let skippedCount = 0;
3292
3561
  let nextSeq = 1;
3293
3562
  try {
3294
- const existingSpecs = await fs8.readdir(specsDir);
3563
+ const existingSpecs = await fs9.readdir(specsDir);
3295
3564
  const seqNumbers = existingSpecs.map((name) => {
3296
3565
  const match = name.match(/^(\d+)-/);
3297
3566
  return match ? parseInt(match[1], 10) : 0;
@@ -3305,17 +3574,17 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3305
3574
  console.log("\x1B[36mMigrating spec-kit format...\x1B[0m\n");
3306
3575
  const specMdFiles = documents.filter((d) => d.name === "spec.md");
3307
3576
  for (const doc of specMdFiles) {
3308
- const sourceDir = path12.dirname(doc.path);
3309
- const dirName = path12.basename(sourceDir);
3577
+ const sourceDir = path13.dirname(doc.path);
3578
+ const dirName = path13.basename(sourceDir);
3310
3579
  const hasSeq = /^\d{3}-/.test(dirName);
3311
3580
  const targetDirName = hasSeq ? dirName : `${String(nextSeq).padStart(3, "0")}-${dirName}`;
3312
- const targetDir = path12.join(specsDir, targetDirName);
3581
+ const targetDir = path13.join(specsDir, targetDirName);
3313
3582
  if (!options.dryRun) {
3314
3583
  await copyDirectory2(sourceDir, targetDir);
3315
- const oldPath = path12.join(targetDir, "spec.md");
3316
- const newPath = path12.join(targetDir, "README.md");
3584
+ const oldPath = path13.join(targetDir, "spec.md");
3585
+ const newPath = path13.join(targetDir, "README.md");
3317
3586
  try {
3318
- await fs8.rename(oldPath, newPath);
3587
+ await fs9.rename(oldPath, newPath);
3319
3588
  } catch {
3320
3589
  }
3321
3590
  }
@@ -3327,8 +3596,8 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3327
3596
  console.log("\x1B[36mMigrating OpenSpec format...\x1B[0m\n");
3328
3597
  const folders = /* @__PURE__ */ new Map();
3329
3598
  for (const doc of documents) {
3330
- const parentDir = path12.dirname(doc.path);
3331
- const folderName = path12.basename(parentDir);
3599
+ const parentDir = path13.dirname(doc.path);
3600
+ const folderName = path13.basename(parentDir);
3332
3601
  if (!folders.has(folderName)) {
3333
3602
  folders.set(folderName, []);
3334
3603
  }
@@ -3339,13 +3608,13 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3339
3608
  continue;
3340
3609
  }
3341
3610
  const targetDirName = `${String(nextSeq).padStart(3, "0")}-${folderName}`;
3342
- const targetDir = path12.join(specsDir, targetDirName);
3611
+ const targetDir = path13.join(specsDir, targetDirName);
3343
3612
  if (!options.dryRun) {
3344
- await fs8.mkdir(targetDir, { recursive: true });
3613
+ await fs9.mkdir(targetDir, { recursive: true });
3345
3614
  for (const doc of docs) {
3346
3615
  const targetName = doc.name === "spec.md" ? "README.md" : doc.name;
3347
- const targetPath = path12.join(targetDir, targetName);
3348
- await fs8.copyFile(doc.path, targetPath);
3616
+ const targetPath = path13.join(targetDir, targetName);
3617
+ await fs9.copyFile(doc.path, targetPath);
3349
3618
  }
3350
3619
  }
3351
3620
  console.log(` \x1B[32m\u2713\x1B[0m ${folderName} \u2192 ${targetDirName}/`);
@@ -3355,18 +3624,18 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3355
3624
  } else {
3356
3625
  console.log("\x1B[36mMigrating generic markdown files...\x1B[0m\n");
3357
3626
  for (const doc of documents) {
3358
- const baseName = path12.basename(doc.name, path12.extname(doc.name)).replace(/^\d+-/, "").replace(/^[_-]+/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+$/, "");
3627
+ const baseName = path13.basename(doc.name, path13.extname(doc.name)).replace(/^\d+-/, "").replace(/^[_-]+/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+$/, "");
3359
3628
  if (!baseName) {
3360
3629
  console.log(` \x1B[33m\u26A0\x1B[0m Skipped: ${doc.name} (invalid name)`);
3361
3630
  skippedCount++;
3362
3631
  continue;
3363
3632
  }
3364
3633
  const targetDirName = `${String(nextSeq).padStart(3, "0")}-${baseName}`;
3365
- const targetDir = path12.join(specsDir, targetDirName);
3366
- const targetPath = path12.join(targetDir, "README.md");
3634
+ const targetDir = path13.join(specsDir, targetDirName);
3635
+ const targetPath = path13.join(targetDir, "README.md");
3367
3636
  if (!options.dryRun) {
3368
- await fs8.mkdir(targetDir, { recursive: true });
3369
- await fs8.copyFile(doc.path, targetPath);
3637
+ await fs9.mkdir(targetDir, { recursive: true });
3638
+ await fs9.copyFile(doc.path, targetPath);
3370
3639
  }
3371
3640
  console.log(` \x1B[32m\u2713\x1B[0m ${doc.name} \u2192 ${targetDirName}/README.md`);
3372
3641
  migratedCount++;
@@ -3410,15 +3679,15 @@ async function migrateAuto(inputPath, documents, format, config, options) {
3410
3679
  console.log(" lean-spec validate # Check for issues");
3411
3680
  }
3412
3681
  async function copyDirectory2(src, dest) {
3413
- await fs8.mkdir(dest, { recursive: true });
3414
- const entries = await fs8.readdir(src, { withFileTypes: true });
3682
+ await fs9.mkdir(dest, { recursive: true });
3683
+ const entries = await fs9.readdir(src, { withFileTypes: true });
3415
3684
  for (const entry of entries) {
3416
- const srcPath = path12.join(src, entry.name);
3417
- const destPath = path12.join(dest, entry.name);
3685
+ const srcPath = path13.join(src, entry.name);
3686
+ const destPath = path13.join(dest, entry.name);
3418
3687
  if (entry.isDirectory()) {
3419
3688
  await copyDirectory2(srcPath, destPath);
3420
3689
  } else {
3421
- await fs8.copyFile(srcPath, destPath);
3690
+ await fs9.copyFile(srcPath, destPath);
3422
3691
  }
3423
3692
  }
3424
3693
  }
@@ -3776,7 +4045,7 @@ async function showBoard(options) {
3776
4045
  if (options.json) {
3777
4046
  console.log(JSON.stringify({ columns: {}, total: 0 }, null, 2));
3778
4047
  } else {
3779
- console.log(chalk15.dim("No specs found."));
4048
+ console.log(chalk16.dim("No specs found."));
3780
4049
  }
3781
4050
  return;
3782
4051
  }
@@ -3815,12 +4084,12 @@ async function showBoard(options) {
3815
4084
  console.log(JSON.stringify(jsonOutput, null, 2));
3816
4085
  return;
3817
4086
  }
3818
- console.log(chalk15.bold.cyan("\u{1F4CB} Spec Kanban Board"));
4087
+ console.log(chalk16.bold.cyan("\u{1F4CB} Spec Kanban Board"));
3819
4088
  if (options.tag || options.assignee) {
3820
4089
  const filterParts = [];
3821
4090
  if (options.tag) filterParts.push(`tag=${options.tag}`);
3822
4091
  if (options.assignee) filterParts.push(`assignee=${options.assignee}`);
3823
- console.log(chalk15.dim(`Filtered by: ${filterParts.join(", ")}`));
4092
+ console.log(chalk16.dim(`Filtered by: ${filterParts.join(", ")}`));
3824
4093
  }
3825
4094
  console.log("");
3826
4095
  if (!options.simple) {
@@ -3835,12 +4104,12 @@ async function showBoard(options) {
3835
4104
  const padding = boxWidth - 2 - visibleLength;
3836
4105
  return content + " ".repeat(Math.max(0, padding));
3837
4106
  };
3838
- console.log(chalk15.dim(topBorder));
3839
- const headerLine = chalk15.bold(" Project Overview");
3840
- console.log(chalk15.dim("\u2551") + padLine(headerLine) + chalk15.dim("\u2551"));
3841
- const percentageColor = completionMetrics.score >= 70 ? chalk15.green : completionMetrics.score >= 40 ? chalk15.yellow : chalk15.red;
4107
+ console.log(chalk16.dim(topBorder));
4108
+ const headerLine = chalk16.bold(" Project Overview");
4109
+ console.log(chalk16.dim("\u2551") + padLine(headerLine) + chalk16.dim("\u2551"));
4110
+ const percentageColor = completionMetrics.score >= 70 ? chalk16.green : completionMetrics.score >= 40 ? chalk16.yellow : chalk16.red;
3842
4111
  const line1 = ` ${completionMetrics.totalSpecs} total \xB7 ${completionMetrics.activeSpecs} active \xB7 ${completionMetrics.completeSpecs} complete ${percentageColor("(" + completionMetrics.score + "%)")}`;
3843
- console.log(chalk15.dim("\u2551") + padLine(line1) + chalk15.dim("\u2551"));
4112
+ console.log(chalk16.dim("\u2551") + padLine(line1) + chalk16.dim("\u2551"));
3844
4113
  if (completionMetrics.criticalIssues.length > 0 || completionMetrics.warnings.length > 0) {
3845
4114
  const alerts = [];
3846
4115
  if (completionMetrics.criticalIssues.length > 0) {
@@ -3849,27 +4118,27 @@ async function showBoard(options) {
3849
4118
  if (completionMetrics.warnings.length > 0) {
3850
4119
  alerts.push(`${completionMetrics.warnings.length} specs WIP > 7 days`);
3851
4120
  }
3852
- const alertLine = ` ${chalk15.yellow("\u26A0\uFE0F " + alerts.join(" \xB7 "))}`;
3853
- console.log(chalk15.dim("\u2551") + padLine(alertLine) + chalk15.dim("\u2551"));
4121
+ const alertLine = ` ${chalk16.yellow("\u26A0\uFE0F " + alerts.join(" \xB7 "))}`;
4122
+ console.log(chalk16.dim("\u2551") + padLine(alertLine) + chalk16.dim("\u2551"));
3854
4123
  }
3855
- const velocityLine = ` ${chalk15.cyan("\u{1F680} Velocity:")} ${velocityMetrics.cycleTime.average.toFixed(1)}d avg cycle \xB7 ${(velocityMetrics.throughput.perWeek / 7 * 7).toFixed(1)}/wk throughput`;
3856
- console.log(chalk15.dim("\u2551") + padLine(velocityLine) + chalk15.dim("\u2551"));
3857
- console.log(chalk15.dim(bottomBorder));
4124
+ const velocityLine = ` ${chalk16.cyan("\u{1F680} Velocity:")} ${velocityMetrics.cycleTime.average.toFixed(1)}d avg cycle \xB7 ${(velocityMetrics.throughput.perWeek / 7 * 7).toFixed(1)}/wk throughput`;
4125
+ console.log(chalk16.dim("\u2551") + padLine(velocityLine) + chalk16.dim("\u2551"));
4126
+ console.log(chalk16.dim(bottomBorder));
3858
4127
  console.log("");
3859
4128
  if (options.completionOnly) {
3860
4129
  return;
3861
4130
  }
3862
4131
  }
3863
4132
  renderColumn(STATUS_CONFIG.planned.label, STATUS_CONFIG.planned.emoji, columns.planned, true, STATUS_CONFIG.planned.colorFn);
3864
- console.log(chalk15.dim("\u2501".repeat(70)));
4133
+ console.log(chalk16.dim("\u2501".repeat(70)));
3865
4134
  console.log("");
3866
4135
  renderColumn(STATUS_CONFIG["in-progress"].label, STATUS_CONFIG["in-progress"].emoji, columns["in-progress"], true, STATUS_CONFIG["in-progress"].colorFn);
3867
- console.log(chalk15.dim("\u2501".repeat(70)));
4136
+ console.log(chalk16.dim("\u2501".repeat(70)));
3868
4137
  console.log("");
3869
4138
  renderColumn(STATUS_CONFIG.complete.label, STATUS_CONFIG.complete.emoji, columns.complete, options.complete || false, STATUS_CONFIG.complete.colorFn);
3870
4139
  }
3871
4140
  function renderColumn(title, emoji, specs, expanded, colorFn) {
3872
- console.log(`${emoji} ${colorFn(chalk15.bold(`${title} (${specs.length})`))}`);
4141
+ console.log(`${emoji} ${colorFn(chalk16.bold(`${title} (${specs.length})`))}`);
3873
4142
  console.log("");
3874
4143
  if (expanded && specs.length > 0) {
3875
4144
  const priorityGroups = {
@@ -3894,30 +4163,30 @@ function renderColumn(title, emoji, specs, expanded, colorFn) {
3894
4163
  firstGroup = false;
3895
4164
  const priorityLabel = priority === "none" ? "No Priority" : priority.charAt(0).toUpperCase() + priority.slice(1);
3896
4165
  const priorityEmoji = priority === "none" ? "\u26AA" : PRIORITY_CONFIG[priority].emoji;
3897
- const priorityColor = priority === "none" ? chalk15.dim : PRIORITY_CONFIG[priority].colorFn;
3898
- console.log(` ${priorityColor(`${priorityEmoji} ${chalk15.bold(priorityLabel)} ${chalk15.dim(`(${groupSpecs.length})`)}`)}`);
4166
+ const priorityColor = priority === "none" ? chalk16.dim : PRIORITY_CONFIG[priority].colorFn;
4167
+ console.log(` ${priorityColor(`${priorityEmoji} ${chalk16.bold(priorityLabel)} ${chalk16.dim(`(${groupSpecs.length})`)}`)}`);
3899
4168
  for (const spec of groupSpecs) {
3900
4169
  let assigneeStr = "";
3901
4170
  if (spec.frontmatter.assignee) {
3902
- assigneeStr = " " + chalk15.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
4171
+ assigneeStr = " " + chalk16.cyan(`@${sanitizeUserInput(spec.frontmatter.assignee)}`);
3903
4172
  }
3904
4173
  let tagsStr = "";
3905
4174
  if (spec.frontmatter.tags?.length) {
3906
4175
  const tags = Array.isArray(spec.frontmatter.tags) ? spec.frontmatter.tags : [];
3907
4176
  if (tags.length > 0) {
3908
4177
  const tagStr = tags.map((tag) => `#${sanitizeUserInput(tag)}`).join(" ");
3909
- tagsStr = " " + chalk15.dim(chalk15.magenta(tagStr));
4178
+ tagsStr = " " + chalk16.dim(chalk16.magenta(tagStr));
3910
4179
  }
3911
4180
  }
3912
- console.log(` ${chalk15.cyan(sanitizeUserInput(spec.path))}${assigneeStr}${tagsStr}`);
4181
+ console.log(` ${chalk16.cyan(sanitizeUserInput(spec.path))}${assigneeStr}${tagsStr}`);
3913
4182
  }
3914
4183
  }
3915
4184
  console.log("");
3916
4185
  } else if (!expanded && specs.length > 0) {
3917
- console.log(` ${chalk15.dim("(collapsed, use --complete to expand)")}`);
4186
+ console.log(` ${chalk16.dim("(collapsed, use --complete to expand)")}`);
3918
4187
  console.log("");
3919
4188
  } else {
3920
- console.log(` ${chalk15.dim("(empty)")}`);
4189
+ console.log(` ${chalk16.dim("(empty)")}`);
3921
4190
  console.log("");
3922
4191
  }
3923
4192
  }
@@ -4086,26 +4355,26 @@ async function showStats(options) {
4086
4355
  console.log(JSON.stringify(data, null, 2));
4087
4356
  return;
4088
4357
  }
4089
- console.log(chalk15.bold.cyan("\u{1F4CA} Spec Stats"));
4358
+ console.log(chalk16.bold.cyan("\u{1F4CA} Spec Stats"));
4090
4359
  console.log("");
4091
4360
  if (options.tag || options.assignee) {
4092
4361
  const filterParts = [];
4093
4362
  if (options.tag) filterParts.push(`tag=${options.tag}`);
4094
4363
  if (options.assignee) filterParts.push(`assignee=${options.assignee}`);
4095
- console.log(chalk15.dim(`Filtered by: ${filterParts.join(", ")}`));
4364
+ console.log(chalk16.dim(`Filtered by: ${filterParts.join(", ")}`));
4096
4365
  console.log("");
4097
4366
  }
4098
4367
  if (showSimplified) {
4099
- console.log(chalk15.bold("\u{1F4C8} Overview"));
4368
+ console.log(chalk16.bold("\u{1F4C8} Overview"));
4100
4369
  console.log("");
4101
4370
  const completionStatus = getCompletionStatus(completionMetrics.score);
4102
- const completionColor = completionStatus.color === "green" ? chalk15.green : completionStatus.color === "yellow" ? chalk15.yellow : chalk15.red;
4103
- console.log(` Total Specs ${chalk15.cyan(completionMetrics.totalSpecs)}`);
4104
- console.log(` Active (Planned+WIP) ${chalk15.yellow(completionMetrics.activeSpecs)}`);
4105
- console.log(` Complete ${chalk15.green(completionMetrics.completeSpecs)}`);
4371
+ const completionColor = completionStatus.color === "green" ? chalk16.green : completionStatus.color === "yellow" ? chalk16.yellow : chalk16.red;
4372
+ console.log(` Total Specs ${chalk16.cyan(completionMetrics.totalSpecs)}`);
4373
+ console.log(` Active (Planned+WIP) ${chalk16.yellow(completionMetrics.activeSpecs)}`);
4374
+ console.log(` Complete ${chalk16.green(completionMetrics.completeSpecs)}`);
4106
4375
  console.log(` Completion Rate ${completionColor(`${completionMetrics.score}% ${completionStatus.emoji}`)}`);
4107
4376
  console.log("");
4108
- console.log(chalk15.bold("\u{1F4CA} Status"));
4377
+ console.log(chalk16.bold("\u{1F4CA} Status"));
4109
4378
  console.log("");
4110
4379
  const labelWidth2 = 15;
4111
4380
  const barWidth2 = 20;
@@ -4114,19 +4383,19 @@ async function showStats(options) {
4114
4383
  const width = Math.round(count / maxCount * barWidth2);
4115
4384
  const filledWidth = Math.min(width, barWidth2);
4116
4385
  const emptyWidth = barWidth2 - filledWidth;
4117
- return char.repeat(filledWidth) + chalk15.dim("\u2591").repeat(emptyWidth);
4386
+ return char.repeat(filledWidth) + chalk16.dim("\u2591").repeat(emptyWidth);
4118
4387
  };
4119
- console.log(` \u{1F4C5} ${"Planned".padEnd(labelWidth2)} ${chalk15.cyan(createBar2(statusCounts.planned, maxStatusCount))} ${chalk15.cyan(statusCounts.planned)}`);
4120
- console.log(` \u23F3 ${"In Progress".padEnd(labelWidth2)} ${chalk15.yellow(createBar2(statusCounts["in-progress"], maxStatusCount))} ${chalk15.yellow(statusCounts["in-progress"])}`);
4121
- console.log(` \u2705 ${"Complete".padEnd(labelWidth2)} ${chalk15.green(createBar2(statusCounts.complete, maxStatusCount))} ${chalk15.green(statusCounts.complete)}`);
4388
+ console.log(` \u{1F4C5} ${"Planned".padEnd(labelWidth2)} ${chalk16.cyan(createBar2(statusCounts.planned, maxStatusCount))} ${chalk16.cyan(statusCounts.planned)}`);
4389
+ console.log(` \u23F3 ${"In Progress".padEnd(labelWidth2)} ${chalk16.yellow(createBar2(statusCounts["in-progress"], maxStatusCount))} ${chalk16.yellow(statusCounts["in-progress"])}`);
4390
+ console.log(` \u2705 ${"Complete".padEnd(labelWidth2)} ${chalk16.green(createBar2(statusCounts.complete, maxStatusCount))} ${chalk16.green(statusCounts.complete)}`);
4122
4391
  if (statusCounts.archived > 0) {
4123
- console.log(` \u{1F4E6} ${"Archived".padEnd(labelWidth2)} ${chalk15.dim(createBar2(statusCounts.archived, maxStatusCount))} ${chalk15.dim(statusCounts.archived)}`);
4392
+ console.log(` \u{1F4E6} ${"Archived".padEnd(labelWidth2)} ${chalk16.dim(createBar2(statusCounts.archived, maxStatusCount))} ${chalk16.dim(statusCounts.archived)}`);
4124
4393
  }
4125
4394
  console.log("");
4126
4395
  const criticalCount = priorityCounts.critical || 0;
4127
4396
  const highCount = priorityCounts.high || 0;
4128
4397
  if (criticalCount > 0 || highCount > 0) {
4129
- console.log(chalk15.bold("\u{1F3AF} Priority Focus"));
4398
+ console.log(chalk16.bold("\u{1F3AF} Priority Focus"));
4130
4399
  console.log("");
4131
4400
  if (criticalCount > 0) {
4132
4401
  const criticalPlanned = specs.filter((s) => s.frontmatter.priority === "critical" && s.frontmatter.status === "planned").length;
@@ -4136,11 +4405,11 @@ async function showStats(options) {
4136
4405
  (s) => s.frontmatter.priority === "critical" && s.frontmatter.due && dayjs2(s.frontmatter.due).isBefore(dayjs2(), "day") && s.frontmatter.status !== "complete"
4137
4406
  ).length;
4138
4407
  const parts = [];
4139
- if (criticalPlanned > 0) parts.push(chalk15.dim(`${criticalPlanned} planned`));
4408
+ if (criticalPlanned > 0) parts.push(chalk16.dim(`${criticalPlanned} planned`));
4140
4409
  if (criticalInProgress > 0) parts.push(`${criticalInProgress} in-progress`);
4141
- if (criticalComplete > 0) parts.push(chalk15.green(`${criticalComplete} complete`));
4142
- if (criticalOverdue > 0) parts.push(chalk15.red(`${criticalOverdue} overdue!`));
4143
- console.log(` \u{1F534} Critical ${chalk15.red(criticalCount)} specs${parts.length > 0 ? ` (${parts.join(", ")})` : ""}`);
4410
+ if (criticalComplete > 0) parts.push(chalk16.green(`${criticalComplete} complete`));
4411
+ if (criticalOverdue > 0) parts.push(chalk16.red(`${criticalOverdue} overdue!`));
4412
+ console.log(` \u{1F534} Critical ${chalk16.red(criticalCount)} specs${parts.length > 0 ? ` (${parts.join(", ")})` : ""}`);
4144
4413
  }
4145
4414
  if (highCount > 0) {
4146
4415
  const highPlanned = specs.filter((s) => s.frontmatter.priority === "high" && s.frontmatter.status === "planned").length;
@@ -4150,52 +4419,52 @@ async function showStats(options) {
4150
4419
  (s) => s.frontmatter.priority === "high" && s.frontmatter.due && dayjs2(s.frontmatter.due).isBefore(dayjs2(), "day") && s.frontmatter.status !== "complete"
4151
4420
  ).length;
4152
4421
  const parts = [];
4153
- if (highPlanned > 0) parts.push(chalk15.dim(`${highPlanned} planned`));
4422
+ if (highPlanned > 0) parts.push(chalk16.dim(`${highPlanned} planned`));
4154
4423
  if (highInProgress > 0) parts.push(`${highInProgress} in-progress`);
4155
- if (highComplete > 0) parts.push(chalk15.green(`${highComplete} complete`));
4156
- if (highOverdue > 0) parts.push(chalk15.yellow(`${highOverdue} overdue`));
4157
- console.log(` \u{1F7E0} High ${chalk15.hex("#FFA500")(highCount)} specs${parts.length > 0 ? ` (${parts.join(", ")})` : ""}`);
4424
+ if (highComplete > 0) parts.push(chalk16.green(`${highComplete} complete`));
4425
+ if (highOverdue > 0) parts.push(chalk16.yellow(`${highOverdue} overdue`));
4426
+ console.log(` \u{1F7E0} High ${chalk16.hex("#FFA500")(highCount)} specs${parts.length > 0 ? ` (${parts.join(", ")})` : ""}`);
4158
4427
  }
4159
4428
  console.log("");
4160
4429
  }
4161
4430
  if (insights.length > 0) {
4162
- console.log(chalk15.bold.yellow("\u26A0\uFE0F Needs Attention"));
4431
+ console.log(chalk16.bold.yellow("\u26A0\uFE0F Needs Attention"));
4163
4432
  console.log("");
4164
4433
  for (const insight of insights) {
4165
- const color = insight.severity === "critical" ? chalk15.red : insight.severity === "warning" ? chalk15.yellow : chalk15.cyan;
4434
+ const color = insight.severity === "critical" ? chalk16.red : insight.severity === "warning" ? chalk16.yellow : chalk16.cyan;
4166
4435
  console.log(` ${color("\u2022")} ${insight.message}`);
4167
4436
  for (const specPath of insight.specs.slice(0, 3)) {
4168
4437
  const spec = specs.find((s) => s.path === specPath);
4169
4438
  const details = spec ? getSpecInsightDetails(spec) : null;
4170
- console.log(` ${chalk15.dim(specPath)}${details ? chalk15.dim(` (${details})`) : ""}`);
4439
+ console.log(` ${chalk16.dim(specPath)}${details ? chalk16.dim(` (${details})`) : ""}`);
4171
4440
  }
4172
4441
  if (insight.specs.length > 3) {
4173
- console.log(` ${chalk15.dim(`...and ${insight.specs.length - 3} more`)}`);
4442
+ console.log(` ${chalk16.dim(`...and ${insight.specs.length - 3} more`)}`);
4174
4443
  }
4175
4444
  }
4176
4445
  console.log("");
4177
4446
  } else if (completionMetrics.activeSpecs === 0 && completionMetrics.completeSpecs > 0) {
4178
- console.log(chalk15.bold.green("\u{1F389} All Specs Complete!"));
4447
+ console.log(chalk16.bold.green("\u{1F389} All Specs Complete!"));
4179
4448
  console.log("");
4180
- console.log(` ${chalk15.dim("Great work! All active specs are complete.")}`);
4449
+ console.log(` ${chalk16.dim("Great work! All active specs are complete.")}`);
4181
4450
  console.log("");
4182
4451
  } else if (completionMetrics.activeSpecs > 0) {
4183
- console.log(chalk15.bold.green("\u2728 All Clear!"));
4452
+ console.log(chalk16.bold.green("\u2728 All Clear!"));
4184
4453
  console.log("");
4185
- console.log(` ${chalk15.dim("No critical issues detected. Keep up the good work!")}`);
4454
+ console.log(` ${chalk16.dim("No critical issues detected. Keep up the good work!")}`);
4186
4455
  console.log("");
4187
4456
  }
4188
- console.log(chalk15.bold("\u{1F680} Velocity Summary"));
4457
+ console.log(chalk16.bold("\u{1F680} Velocity Summary"));
4189
4458
  console.log("");
4190
- const cycleTimeStatus = velocityMetrics.cycleTime.average <= 7 ? chalk15.green("\u2713") : chalk15.yellow("\u26A0");
4191
- const throughputTrend = velocityMetrics.throughput.trend === "up" ? chalk15.green("\u2191") : velocityMetrics.throughput.trend === "down" ? chalk15.red("\u2193") : chalk15.yellow("\u2192");
4192
- console.log(` Avg Cycle Time ${chalk15.cyan(velocityMetrics.cycleTime.average.toFixed(1))} days ${cycleTimeStatus}${velocityMetrics.cycleTime.average <= 7 ? chalk15.dim(" (target: 7d)") : ""}`);
4193
- console.log(` Throughput ${chalk15.cyan((velocityMetrics.throughput.perWeek / 7 * 7).toFixed(1))}/week ${throughputTrend}`);
4194
- console.log(` WIP ${chalk15.yellow(velocityMetrics.wip.current)} specs`);
4459
+ const cycleTimeStatus = velocityMetrics.cycleTime.average <= 7 ? chalk16.green("\u2713") : chalk16.yellow("\u26A0");
4460
+ const throughputTrend = velocityMetrics.throughput.trend === "up" ? chalk16.green("\u2191") : velocityMetrics.throughput.trend === "down" ? chalk16.red("\u2193") : chalk16.yellow("\u2192");
4461
+ console.log(` Avg Cycle Time ${chalk16.cyan(velocityMetrics.cycleTime.average.toFixed(1))} days ${cycleTimeStatus}${velocityMetrics.cycleTime.average <= 7 ? chalk16.dim(" (target: 7d)") : ""}`);
4462
+ console.log(` Throughput ${chalk16.cyan((velocityMetrics.throughput.perWeek / 7 * 7).toFixed(1))}/week ${throughputTrend}`);
4463
+ console.log(` WIP ${chalk16.yellow(velocityMetrics.wip.current)} specs`);
4195
4464
  console.log("");
4196
- console.log(chalk15.dim("\u{1F4A1} Use `lean-spec stats --full` for detailed analytics"));
4197
- console.log(chalk15.dim(" Use `lean-spec stats --velocity` for velocity breakdown"));
4198
- console.log(chalk15.dim(" Use `lean-spec stats --timeline` for activity timeline"));
4465
+ console.log(chalk16.dim("\u{1F4A1} Use `lean-spec stats --full` for detailed analytics"));
4466
+ console.log(chalk16.dim(" Use `lean-spec stats --velocity` for velocity breakdown"));
4467
+ console.log(chalk16.dim(" Use `lean-spec stats --timeline` for activity timeline"));
4199
4468
  console.log("");
4200
4469
  return;
4201
4470
  }
@@ -4211,97 +4480,97 @@ async function showStats(options) {
4211
4480
  (sum, count) => sum + count,
4212
4481
  0
4213
4482
  );
4214
- console.log(chalk15.bold("\u{1F4C8} Overview"));
4483
+ console.log(chalk16.bold("\u{1F4C8} Overview"));
4215
4484
  console.log("");
4216
4485
  console.log(
4217
4486
  ` ${"Metric".padEnd(labelWidth)} ${"Value".padStart(valueWidth)}`
4218
4487
  );
4219
4488
  console.log(
4220
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`
4489
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`
4221
4490
  );
4222
4491
  console.log(
4223
- ` ${"Total Specs".padEnd(labelWidth)} ${chalk15.green(specs.length.toString().padStart(valueWidth))}`
4492
+ ` ${"Total Specs".padEnd(labelWidth)} ${chalk16.green(specs.length.toString().padStart(valueWidth))}`
4224
4493
  );
4225
4494
  console.log(
4226
- ` ${"With Priority".padEnd(labelWidth)} ${chalk15.cyan(totalWithPriority.toString().padStart(valueWidth))}`
4495
+ ` ${"With Priority".padEnd(labelWidth)} ${chalk16.cyan(totalWithPriority.toString().padStart(valueWidth))}`
4227
4496
  );
4228
4497
  console.log(
4229
- ` ${"Unique Tags".padEnd(labelWidth)} ${chalk15.magenta(Object.keys(tagCounts).length.toString().padStart(valueWidth))}`
4498
+ ` ${"Unique Tags".padEnd(labelWidth)} ${chalk16.magenta(Object.keys(tagCounts).length.toString().padStart(valueWidth))}`
4230
4499
  );
4231
4500
  console.log("");
4232
- console.log(chalk15.bold("\u{1F4CA} Status Distribution"));
4501
+ console.log(chalk16.bold("\u{1F4CA} Status Distribution"));
4233
4502
  console.log("");
4234
4503
  const maxStatusCount = Math.max(...Object.values(statusCounts));
4235
4504
  const colWidth = barWidth + 3;
4236
4505
  console.log(
4237
- ` ${"Status".padEnd(labelWidth)} ${chalk15.cyan("Count".padEnd(colWidth))}`
4506
+ ` ${"Status".padEnd(labelWidth)} ${chalk16.cyan("Count".padEnd(colWidth))}`
4238
4507
  );
4239
4508
  console.log(
4240
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(colWidth))}`
4509
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(colWidth))}`
4241
4510
  );
4242
4511
  console.log(
4243
- ` \u{1F4CB} ${"Planned".padEnd(labelWidth - 3)} ${chalk15.cyan(createBar(statusCounts.planned, maxStatusCount).padEnd(barWidth))}${chalk15.cyan(statusCounts.planned.toString().padStart(3))}`
4512
+ ` \u{1F4CB} ${"Planned".padEnd(labelWidth - 3)} ${chalk16.cyan(createBar(statusCounts.planned, maxStatusCount).padEnd(barWidth))}${chalk16.cyan(statusCounts.planned.toString().padStart(3))}`
4244
4513
  );
4245
4514
  console.log(
4246
- ` \u23F3 ${"In Progress".padEnd(labelWidth - 3)} ${chalk15.yellow(createBar(statusCounts["in-progress"], maxStatusCount).padEnd(barWidth))}${chalk15.yellow(statusCounts["in-progress"].toString().padStart(3))}`
4515
+ ` \u23F3 ${"In Progress".padEnd(labelWidth - 3)} ${chalk16.yellow(createBar(statusCounts["in-progress"], maxStatusCount).padEnd(barWidth))}${chalk16.yellow(statusCounts["in-progress"].toString().padStart(3))}`
4247
4516
  );
4248
4517
  console.log(
4249
- ` \u2705 ${"Complete".padEnd(labelWidth - 3)} ${chalk15.green(createBar(statusCounts.complete, maxStatusCount).padEnd(barWidth))}${chalk15.green(statusCounts.complete.toString().padStart(3))}`
4518
+ ` \u2705 ${"Complete".padEnd(labelWidth - 3)} ${chalk16.green(createBar(statusCounts.complete, maxStatusCount).padEnd(barWidth))}${chalk16.green(statusCounts.complete.toString().padStart(3))}`
4250
4519
  );
4251
4520
  console.log(
4252
- ` \u{1F4E6} ${"Archived".padEnd(labelWidth - 3)} ${chalk15.dim(createBar(statusCounts.archived, maxStatusCount).padEnd(barWidth))}${chalk15.dim(statusCounts.archived.toString().padStart(3))}`
4521
+ ` \u{1F4E6} ${"Archived".padEnd(labelWidth - 3)} ${chalk16.dim(createBar(statusCounts.archived, maxStatusCount).padEnd(barWidth))}${chalk16.dim(statusCounts.archived.toString().padStart(3))}`
4253
4522
  );
4254
4523
  console.log("");
4255
4524
  if (totalWithPriority > 0) {
4256
- console.log(chalk15.bold("\u{1F3AF} Priority Breakdown"));
4525
+ console.log(chalk16.bold("\u{1F3AF} Priority Breakdown"));
4257
4526
  console.log("");
4258
4527
  const maxPriorityCount = Math.max(
4259
4528
  ...Object.values(priorityCounts).filter((c) => c > 0)
4260
4529
  );
4261
4530
  console.log(
4262
- ` ${"Priority".padEnd(labelWidth)} ${chalk15.cyan("Count".padEnd(colWidth))}`
4531
+ ` ${"Priority".padEnd(labelWidth)} ${chalk16.cyan("Count".padEnd(colWidth))}`
4263
4532
  );
4264
4533
  console.log(
4265
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(colWidth))}`
4534
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(colWidth))}`
4266
4535
  );
4267
4536
  if (priorityCounts.critical > 0) {
4268
4537
  console.log(
4269
- ` \u{1F534} ${"Critical".padEnd(labelWidth - 3)} ${chalk15.red(createBar(priorityCounts.critical, maxPriorityCount).padEnd(barWidth))}${chalk15.red(priorityCounts.critical.toString().padStart(3))}`
4538
+ ` \u{1F534} ${"Critical".padEnd(labelWidth - 3)} ${chalk16.red(createBar(priorityCounts.critical, maxPriorityCount).padEnd(barWidth))}${chalk16.red(priorityCounts.critical.toString().padStart(3))}`
4270
4539
  );
4271
4540
  }
4272
4541
  if (priorityCounts.high > 0) {
4273
4542
  console.log(
4274
- ` \u{1F7E0} ${"High".padEnd(labelWidth - 3)} ${chalk15.hex("#FFA500")(createBar(priorityCounts.high, maxPriorityCount).padEnd(barWidth))}${chalk15.hex("#FFA500")(priorityCounts.high.toString().padStart(3))}`
4543
+ ` \u{1F7E0} ${"High".padEnd(labelWidth - 3)} ${chalk16.hex("#FFA500")(createBar(priorityCounts.high, maxPriorityCount).padEnd(barWidth))}${chalk16.hex("#FFA500")(priorityCounts.high.toString().padStart(3))}`
4275
4544
  );
4276
4545
  }
4277
4546
  if (priorityCounts.medium > 0) {
4278
4547
  console.log(
4279
- ` \u{1F7E1} ${"Medium".padEnd(labelWidth - 3)} ${chalk15.yellow(createBar(priorityCounts.medium, maxPriorityCount).padEnd(barWidth))}${chalk15.yellow(priorityCounts.medium.toString().padStart(3))}`
4548
+ ` \u{1F7E1} ${"Medium".padEnd(labelWidth - 3)} ${chalk16.yellow(createBar(priorityCounts.medium, maxPriorityCount).padEnd(barWidth))}${chalk16.yellow(priorityCounts.medium.toString().padStart(3))}`
4280
4549
  );
4281
4550
  }
4282
4551
  if (priorityCounts.low > 0) {
4283
4552
  console.log(
4284
- ` \u{1F7E2} ${"Low".padEnd(labelWidth - 3)} ${chalk15.green(createBar(priorityCounts.low, maxPriorityCount).padEnd(barWidth))}${chalk15.green(priorityCounts.low.toString().padStart(3))}`
4553
+ ` \u{1F7E2} ${"Low".padEnd(labelWidth - 3)} ${chalk16.green(createBar(priorityCounts.low, maxPriorityCount).padEnd(barWidth))}${chalk16.green(priorityCounts.low.toString().padStart(3))}`
4285
4554
  );
4286
4555
  }
4287
4556
  console.log("");
4288
4557
  }
4289
4558
  const topTags = Object.entries(tagCounts).sort((a, b) => b[1] - a[1]).slice(0, 5);
4290
4559
  if (topTags.length > 0) {
4291
- console.log(chalk15.bold("\u{1F3F7}\uFE0F Popular Tags"));
4560
+ console.log(chalk16.bold("\u{1F3F7}\uFE0F Popular Tags"));
4292
4561
  console.log("");
4293
4562
  const maxTagCount = Math.max(...topTags.map(([, count]) => count));
4294
4563
  console.log(
4295
- ` ${"Tag".padEnd(labelWidth)} ${chalk15.magenta("Count".padEnd(colWidth))}`
4564
+ ` ${"Tag".padEnd(labelWidth)} ${chalk16.magenta("Count".padEnd(colWidth))}`
4296
4565
  );
4297
4566
  console.log(
4298
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(colWidth))}`
4567
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(colWidth))}`
4299
4568
  );
4300
4569
  for (const [tag, count] of topTags) {
4301
4570
  const truncatedTag = tag.length > labelWidth ? tag.substring(0, labelWidth - 1) + "\u2026" : tag;
4302
4571
  const bar = createBar(count, maxTagCount);
4303
4572
  console.log(
4304
- ` ${truncatedTag.padEnd(labelWidth)} ${chalk15.magenta(bar.padEnd(barWidth))}${chalk15.magenta(count.toString().padStart(3))}`
4573
+ ` ${truncatedTag.padEnd(labelWidth)} ${chalk16.magenta(bar.padEnd(barWidth))}${chalk16.magenta(count.toString().padStart(3))}`
4305
4574
  );
4306
4575
  }
4307
4576
  console.log("");
@@ -4333,14 +4602,14 @@ async function showStats(options) {
4333
4602
  ]);
4334
4603
  const sortedDates = Array.from(allDates).sort();
4335
4604
  if (sortedDates.length > 0) {
4336
- console.log(chalk15.bold(`\u{1F4C5} Activity (Last ${days} Days)`));
4605
+ console.log(chalk16.bold(`\u{1F4C5} Activity (Last ${days} Days)`));
4337
4606
  console.log("");
4338
4607
  const colWidth = barWidth + 3;
4339
4608
  console.log(
4340
- ` ${"Date".padEnd(15)} ${chalk15.cyan("Created".padEnd(colWidth))} ${chalk15.green("Completed".padEnd(colWidth))}`
4609
+ ` ${"Date".padEnd(15)} ${chalk16.cyan("Created".padEnd(colWidth))} ${chalk16.green("Completed".padEnd(colWidth))}`
4341
4610
  );
4342
4611
  console.log(
4343
- ` ${chalk15.dim("\u2500".repeat(15))} ${chalk15.dim("\u2500".repeat(colWidth))} ${chalk15.dim("\u2500".repeat(colWidth))}`
4612
+ ` ${chalk16.dim("\u2500".repeat(15))} ${chalk16.dim("\u2500".repeat(colWidth))} ${chalk16.dim("\u2500".repeat(colWidth))}`
4344
4613
  );
4345
4614
  const maxCount = Math.max(
4346
4615
  ...Object.values(createdByDate),
@@ -4354,85 +4623,85 @@ async function showStats(options) {
4354
4623
  const createdCol = `${createdBar.padEnd(barWidth)}${created.toString().padStart(3)}`;
4355
4624
  const completedCol = `${completedBar.padEnd(barWidth)}${completed.toString().padStart(3)}`;
4356
4625
  console.log(
4357
- ` ${chalk15.dim(date.padEnd(15))} ${chalk15.cyan(createdCol)} ${chalk15.green(completedCol)}`
4626
+ ` ${chalk16.dim(date.padEnd(15))} ${chalk16.cyan(createdCol)} ${chalk16.green(completedCol)}`
4358
4627
  );
4359
4628
  }
4360
4629
  console.log("");
4361
4630
  }
4362
4631
  }
4363
4632
  if (showVelocity) {
4364
- console.log(chalk15.bold("\u{1F680} Velocity Metrics"));
4633
+ console.log(chalk16.bold("\u{1F680} Velocity Metrics"));
4365
4634
  console.log("");
4366
- console.log(chalk15.bold("\u23F1\uFE0F Cycle Time (Created \u2192 Completed)"));
4635
+ console.log(chalk16.bold("\u23F1\uFE0F Cycle Time (Created \u2192 Completed)"));
4367
4636
  console.log("");
4368
4637
  console.log(
4369
4638
  ` ${"Metric".padEnd(labelWidth)} ${"Days".padStart(valueWidth)}`
4370
4639
  );
4371
4640
  console.log(
4372
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`
4641
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`
4373
4642
  );
4374
4643
  console.log(
4375
- ` ${"Average".padEnd(labelWidth)} ${chalk15.cyan(velocityMetrics.cycleTime.average.toFixed(1).padStart(valueWidth))}`
4644
+ ` ${"Average".padEnd(labelWidth)} ${chalk16.cyan(velocityMetrics.cycleTime.average.toFixed(1).padStart(valueWidth))}`
4376
4645
  );
4377
4646
  console.log(
4378
- ` ${"Median".padEnd(labelWidth)} ${chalk15.cyan(velocityMetrics.cycleTime.median.toFixed(1).padStart(valueWidth))}`
4647
+ ` ${"Median".padEnd(labelWidth)} ${chalk16.cyan(velocityMetrics.cycleTime.median.toFixed(1).padStart(valueWidth))}`
4379
4648
  );
4380
4649
  console.log(
4381
- ` ${"90th Percentile".padEnd(labelWidth)} ${chalk15.yellow(velocityMetrics.cycleTime.p90.toFixed(1).padStart(valueWidth))}`
4650
+ ` ${"90th Percentile".padEnd(labelWidth)} ${chalk16.yellow(velocityMetrics.cycleTime.p90.toFixed(1).padStart(valueWidth))}`
4382
4651
  );
4383
4652
  console.log("");
4384
- console.log(chalk15.bold("\u{1F4E6} Throughput"));
4653
+ console.log(chalk16.bold("\u{1F4E6} Throughput"));
4385
4654
  console.log("");
4386
4655
  console.log(
4387
4656
  ` ${"Period".padEnd(labelWidth)} ${"Specs".padStart(valueWidth)}`
4388
4657
  );
4389
4658
  console.log(
4390
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`
4659
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`
4391
4660
  );
4392
4661
  console.log(
4393
- ` ${"Last 7 days".padEnd(labelWidth)} ${chalk15.green(velocityMetrics.throughput.perWeek.toString().padStart(valueWidth))}`
4662
+ ` ${"Last 7 days".padEnd(labelWidth)} ${chalk16.green(velocityMetrics.throughput.perWeek.toString().padStart(valueWidth))}`
4394
4663
  );
4395
4664
  console.log(
4396
- ` ${"Last 30 days".padEnd(labelWidth)} ${chalk15.green(velocityMetrics.throughput.perMonth.toString().padStart(valueWidth))}`
4665
+ ` ${"Last 30 days".padEnd(labelWidth)} ${chalk16.green(velocityMetrics.throughput.perMonth.toString().padStart(valueWidth))}`
4397
4666
  );
4398
- const trendColor = velocityMetrics.throughput.trend === "up" ? chalk15.green : velocityMetrics.throughput.trend === "down" ? chalk15.red : chalk15.yellow;
4667
+ const trendColor = velocityMetrics.throughput.trend === "up" ? chalk16.green : velocityMetrics.throughput.trend === "down" ? chalk16.red : chalk16.yellow;
4399
4668
  const trendSymbol = velocityMetrics.throughput.trend === "up" ? "\u2191" : velocityMetrics.throughput.trend === "down" ? "\u2193" : "\u2192";
4400
4669
  console.log(
4401
4670
  ` ${"Trend".padEnd(labelWidth)} ${trendColor(trendSymbol + " " + velocityMetrics.throughput.trend.padStart(valueWidth - 2))}`
4402
4671
  );
4403
4672
  console.log("");
4404
- console.log(chalk15.bold("\u{1F504} Work In Progress"));
4673
+ console.log(chalk16.bold("\u{1F504} Work In Progress"));
4405
4674
  console.log("");
4406
4675
  console.log(
4407
4676
  ` ${"Metric".padEnd(labelWidth)} ${"Specs".padStart(valueWidth)}`
4408
4677
  );
4409
4678
  console.log(
4410
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`
4679
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`
4411
4680
  );
4412
4681
  console.log(
4413
- ` ${"Current".padEnd(labelWidth)} ${chalk15.yellow(velocityMetrics.wip.current.toString().padStart(valueWidth))}`
4682
+ ` ${"Current".padEnd(labelWidth)} ${chalk16.yellow(velocityMetrics.wip.current.toString().padStart(valueWidth))}`
4414
4683
  );
4415
4684
  console.log(
4416
- ` ${"30-day Average".padEnd(labelWidth)} ${chalk15.cyan(velocityMetrics.wip.average.toFixed(1).padStart(valueWidth))}`
4685
+ ` ${"30-day Average".padEnd(labelWidth)} ${chalk16.cyan(velocityMetrics.wip.average.toFixed(1).padStart(valueWidth))}`
4417
4686
  );
4418
4687
  console.log("");
4419
4688
  if (velocityMetrics.leadTime.plannedToInProgress > 0 || velocityMetrics.leadTime.inProgressToComplete > 0) {
4420
- console.log(chalk15.bold("\u{1F500} Lead Time by Stage"));
4689
+ console.log(chalk16.bold("\u{1F500} Lead Time by Stage"));
4421
4690
  console.log("");
4422
4691
  console.log(
4423
4692
  ` ${"Stage".padEnd(labelWidth)} ${"Days".padStart(valueWidth)}`
4424
4693
  );
4425
4694
  console.log(
4426
- ` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`
4695
+ ` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`
4427
4696
  );
4428
4697
  if (velocityMetrics.leadTime.plannedToInProgress > 0) {
4429
4698
  console.log(
4430
- ` ${"Planned \u2192 In Progress".padEnd(labelWidth)} ${chalk15.cyan(velocityMetrics.leadTime.plannedToInProgress.toFixed(1).padStart(valueWidth))}`
4699
+ ` ${"Planned \u2192 In Progress".padEnd(labelWidth)} ${chalk16.cyan(velocityMetrics.leadTime.plannedToInProgress.toFixed(1).padStart(valueWidth))}`
4431
4700
  );
4432
4701
  }
4433
4702
  if (velocityMetrics.leadTime.inProgressToComplete > 0) {
4434
4703
  console.log(
4435
- ` ${"In Progress \u2192 Complete".padEnd(labelWidth)} ${chalk15.green(velocityMetrics.leadTime.inProgressToComplete.toFixed(1).padStart(valueWidth))}`
4704
+ ` ${"In Progress \u2192 Complete".padEnd(labelWidth)} ${chalk16.green(velocityMetrics.leadTime.inProgressToComplete.toFixed(1).padStart(valueWidth))}`
4436
4705
  );
4437
4706
  }
4438
4707
  console.log("");
@@ -4443,16 +4712,16 @@ function searchCommand() {
4443
4712
  return new Command("search").description("Full-text search with advanced query syntax").argument("[query]", "Search query (supports AND, OR, NOT, field:value, fuzzy~)").option("--status <status>", "Filter by status").option("--tag <tag>", "Filter by tag").option("--priority <priority>", "Filter by priority").option("--assignee <name>", "Filter by assignee").option("--field <name=value...>", "Filter by custom field (can specify multiple)").option("--json", "Output as JSON").option("--help-syntax", "Show advanced query syntax help").action(async (query, options) => {
4444
4713
  if (options.helpSyntax) {
4445
4714
  console.log("");
4446
- console.log(chalk15.cyan("Advanced Search Syntax"));
4447
- console.log(chalk15.gray("\u2500".repeat(60)));
4715
+ console.log(chalk16.cyan("Advanced Search Syntax"));
4716
+ console.log(chalk16.gray("\u2500".repeat(60)));
4448
4717
  console.log("");
4449
4718
  console.log(getSearchSyntaxHelp());
4450
4719
  console.log("");
4451
4720
  return;
4452
4721
  }
4453
4722
  if (!query) {
4454
- console.log(chalk15.yellow("Usage: lean-spec search <query>"));
4455
- console.log(chalk15.gray("Use --help-syntax for advanced query syntax"));
4723
+ console.log(chalk16.yellow("Usage: lean-spec search <query>"));
4724
+ console.log(chalk16.gray("Use --help-syntax for advanced query syntax"));
4456
4725
  return;
4457
4726
  }
4458
4727
  const customFields = parseCustomFieldOptions(options.field);
@@ -4525,34 +4794,34 @@ async function performSearch(query, options) {
4525
4794
  }
4526
4795
  if (results.length === 0) {
4527
4796
  console.log("");
4528
- console.log(chalk15.yellow(`\u{1F50D} No specs found matching "${sanitizeUserInput(query)}"`));
4797
+ console.log(chalk16.yellow(`\u{1F50D} No specs found matching "${sanitizeUserInput(query)}"`));
4529
4798
  if (Object.keys(filter).length > 0) {
4530
4799
  const filters = [];
4531
4800
  if (options.status) filters.push(`status=${sanitizeUserInput(options.status)}`);
4532
4801
  if (options.tag) filters.push(`tag=${sanitizeUserInput(options.tag)}`);
4533
4802
  if (options.priority) filters.push(`priority=${sanitizeUserInput(options.priority)}`);
4534
4803
  if (options.assignee) filters.push(`assignee=${sanitizeUserInput(options.assignee)}`);
4535
- console.log(chalk15.gray(`With filters: ${filters.join(", ")}`));
4804
+ console.log(chalk16.gray(`With filters: ${filters.join(", ")}`));
4536
4805
  }
4537
4806
  console.log("");
4538
4807
  return;
4539
4808
  }
4540
4809
  console.log("");
4541
- console.log(chalk15.green(`\u{1F50D} Found ${results.length} spec${results.length === 1 ? "" : "s"} matching "${sanitizeUserInput(query)}"`));
4542
- console.log(chalk15.gray(` Searched ${metadata.specsSearched} specs in ${metadata.searchTime}ms`));
4810
+ console.log(chalk16.green(`\u{1F50D} Found ${results.length} spec${results.length === 1 ? "" : "s"} matching "${sanitizeUserInput(query)}"`));
4811
+ console.log(chalk16.gray(` Searched ${metadata.specsSearched} specs in ${metadata.searchTime}ms`));
4543
4812
  if (Object.keys(filter).length > 0) {
4544
4813
  const filters = [];
4545
4814
  if (options.status) filters.push(`status=${sanitizeUserInput(options.status)}`);
4546
4815
  if (options.tag) filters.push(`tag=${sanitizeUserInput(options.tag)}`);
4547
4816
  if (options.priority) filters.push(`priority=${sanitizeUserInput(options.priority)}`);
4548
4817
  if (options.assignee) filters.push(`assignee=${sanitizeUserInput(options.assignee)}`);
4549
- console.log(chalk15.gray(` With filters: ${filters.join(", ")}`));
4818
+ console.log(chalk16.gray(` With filters: ${filters.join(", ")}`));
4550
4819
  }
4551
4820
  console.log("");
4552
4821
  for (const result of results) {
4553
4822
  const { spec, matches, score, totalMatches } = result;
4554
4823
  const statusEmoji = spec.status === "in-progress" ? "\u{1F528}" : spec.status === "complete" ? "\u2705" : "\u{1F4C5}";
4555
- console.log(chalk15.cyan(`${statusEmoji} ${sanitizeUserInput(spec.path)} ${chalk15.gray(`(${score}% match)`)}`));
4824
+ console.log(chalk16.cyan(`${statusEmoji} ${sanitizeUserInput(spec.path)} ${chalk16.gray(`(${score}% match)`)}`));
4556
4825
  const meta = [];
4557
4826
  if (spec.priority) {
4558
4827
  const priorityEmoji = spec.priority === "critical" ? "\u{1F534}" : spec.priority === "high" ? "\u{1F7E1}" : spec.priority === "medium" ? "\u{1F7E0}" : "\u{1F7E2}";
@@ -4562,30 +4831,30 @@ async function performSearch(query, options) {
4562
4831
  meta.push(`[${spec.tags.map((tag) => sanitizeUserInput(tag)).join(", ")}]`);
4563
4832
  }
4564
4833
  if (meta.length > 0) {
4565
- console.log(chalk15.gray(` ${meta.join(" \u2022 ")}`));
4834
+ console.log(chalk16.gray(` ${meta.join(" \u2022 ")}`));
4566
4835
  }
4567
4836
  const titleMatch = matches.find((m) => m.field === "title");
4568
4837
  if (titleMatch) {
4569
- console.log(` ${chalk15.bold("Title:")} ${highlightMatches(titleMatch.text, titleMatch.highlights)}`);
4838
+ console.log(` ${chalk16.bold("Title:")} ${highlightMatches(titleMatch.text, titleMatch.highlights)}`);
4570
4839
  }
4571
4840
  const descMatch = matches.find((m) => m.field === "description");
4572
4841
  if (descMatch) {
4573
- console.log(` ${chalk15.bold("Description:")} ${highlightMatches(descMatch.text, descMatch.highlights)}`);
4842
+ console.log(` ${chalk16.bold("Description:")} ${highlightMatches(descMatch.text, descMatch.highlights)}`);
4574
4843
  }
4575
4844
  const tagMatches = matches.filter((m) => m.field === "tags");
4576
4845
  if (tagMatches.length > 0) {
4577
- console.log(` ${chalk15.bold("Tags:")} ${tagMatches.map((m) => highlightMatches(m.text, m.highlights)).join(", ")}`);
4846
+ console.log(` ${chalk16.bold("Tags:")} ${tagMatches.map((m) => highlightMatches(m.text, m.highlights)).join(", ")}`);
4578
4847
  }
4579
4848
  const contentMatches = matches.filter((m) => m.field === "content");
4580
4849
  if (contentMatches.length > 0) {
4581
- console.log(` ${chalk15.bold("Content matches:")}`);
4850
+ console.log(` ${chalk16.bold("Content matches:")}`);
4582
4851
  for (const match of contentMatches) {
4583
- const lineInfo = match.lineNumber ? chalk15.gray(`[L${match.lineNumber}]`) : "";
4852
+ const lineInfo = match.lineNumber ? chalk16.gray(`[L${match.lineNumber}]`) : "";
4584
4853
  console.log(` ${lineInfo} ${highlightMatches(match.text, match.highlights)}`);
4585
4854
  }
4586
4855
  }
4587
4856
  if (totalMatches > matches.length) {
4588
- console.log(chalk15.gray(` ... and ${totalMatches - matches.length} more match${totalMatches - matches.length === 1 ? "" : "es"}`));
4857
+ console.log(chalk16.gray(` ... and ${totalMatches - matches.length} more match${totalMatches - matches.length === 1 ? "" : "es"}`));
4589
4858
  }
4590
4859
  console.log("");
4591
4860
  }
@@ -4596,7 +4865,7 @@ function highlightMatches(text, highlights) {
4596
4865
  let lastEnd = 0;
4597
4866
  for (const [start, end] of highlights) {
4598
4867
  result += text.substring(lastEnd, start);
4599
- result += chalk15.yellow(text.substring(start, end));
4868
+ result += chalk16.yellow(text.substring(start, end));
4600
4869
  lastEnd = end;
4601
4870
  }
4602
4871
  result += text.substring(lastEnd);
@@ -4614,7 +4883,7 @@ async function showDeps(specPath, options = {}) {
4614
4883
  await autoCheckIfEnabled();
4615
4884
  const config = await loadConfig();
4616
4885
  const cwd = process.cwd();
4617
- const specsDir = path12.join(cwd, config.specsDir);
4886
+ const specsDir = path13.join(cwd, config.specsDir);
4618
4887
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
4619
4888
  if (!resolvedPath) {
4620
4889
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
@@ -4672,17 +4941,17 @@ async function showDeps(specPath, options = {}) {
4672
4941
  return;
4673
4942
  }
4674
4943
  console.log("");
4675
- console.log(chalk15.green(`\u{1F4E6} Dependencies for ${chalk15.cyan(sanitizeUserInput(spec.path))}`));
4944
+ console.log(chalk16.green(`\u{1F4E6} Dependencies for ${chalk16.cyan(sanitizeUserInput(spec.path))}`));
4676
4945
  console.log("");
4677
4946
  const hasAnyDependencies = dependsOn.length > 0 || requiredBy.length > 0;
4678
4947
  if (!hasAnyDependencies) {
4679
- console.log(chalk15.gray(" No dependencies"));
4948
+ console.log(chalk16.gray(" No dependencies"));
4680
4949
  console.log("");
4681
4950
  return;
4682
4951
  }
4683
4952
  if ((mode === "complete" || mode === "upstream" || mode === "impact") && dependsOn.length > 0) {
4684
4953
  const label = mode === "complete" ? "Depends On" : mode === "upstream" ? "Upstream Dependencies" : "Upstream (Impact)";
4685
- console.log(chalk15.bold(`${label}:`));
4954
+ console.log(chalk16.bold(`${label}:`));
4686
4955
  for (const dep of dependsOn) {
4687
4956
  const status = getStatusIndicator(dep.frontmatter.status);
4688
4957
  console.log(` \u2192 ${sanitizeUserInput(dep.path)} ${status}`);
@@ -4691,7 +4960,7 @@ async function showDeps(specPath, options = {}) {
4691
4960
  }
4692
4961
  if ((mode === "complete" || mode === "downstream" || mode === "impact") && requiredBy.length > 0) {
4693
4962
  const label = mode === "complete" ? "Required By" : mode === "downstream" ? "Downstream Dependents" : "Downstream (Impact)";
4694
- console.log(chalk15.bold(`${label}:`));
4963
+ console.log(chalk16.bold(`${label}:`));
4695
4964
  for (const blocked of requiredBy) {
4696
4965
  const status = getStatusIndicator(blocked.frontmatter.status);
4697
4966
  console.log(` \u2190 ${sanitizeUserInput(blocked.path)} ${status}`);
@@ -4699,15 +4968,15 @@ async function showDeps(specPath, options = {}) {
4699
4968
  console.log("");
4700
4969
  }
4701
4970
  if (mode === "complete" && (options.graph || dependsOn.length > 0)) {
4702
- console.log(chalk15.bold("Dependency Chain:"));
4971
+ console.log(chalk16.bold("Dependency Chain:"));
4703
4972
  const chain = buildDependencyChain(spec, specMap, options.depth || 3);
4704
4973
  displayChain(chain, 0);
4705
4974
  console.log("");
4706
4975
  }
4707
4976
  if (mode === "impact") {
4708
4977
  const total = dependsOn.length + requiredBy.length;
4709
- console.log(chalk15.bold(`Impact Summary:`));
4710
- console.log(` Changing this spec affects ${chalk15.yellow(total)} specs total`);
4978
+ console.log(chalk16.bold(`Impact Summary:`));
4979
+ console.log(` Changing this spec affects ${chalk16.yellow(total)} specs total`);
4711
4980
  console.log(` Upstream: ${dependsOn.length} | Downstream: ${requiredBy.length}`);
4712
4981
  console.log("");
4713
4982
  }
@@ -4737,7 +5006,7 @@ function buildDependencyChain(spec, specMap, maxDepth, currentDepth = 0, visited
4737
5006
  function displayChain(node, level) {
4738
5007
  const indent = " ".repeat(level);
4739
5008
  const status = getStatusIndicator(node.spec.frontmatter.status);
4740
- const name = level === 0 ? chalk15.cyan(node.spec.path) : node.spec.path;
5009
+ const name = level === 0 ? chalk16.cyan(node.spec.path) : node.spec.path;
4741
5010
  console.log(`${indent}${name} ${status}`);
4742
5011
  for (const dep of node.dependencies) {
4743
5012
  const prefix = " ".repeat(level) + "\u2514\u2500 ";
@@ -4798,19 +5067,19 @@ async function showTimeline(options) {
4798
5067
  console.log(JSON.stringify(jsonOutput, null, 2));
4799
5068
  return;
4800
5069
  }
4801
- console.log(chalk15.bold.cyan("\u{1F4C8} Spec Timeline"));
5070
+ console.log(chalk16.bold.cyan("\u{1F4C8} Spec Timeline"));
4802
5071
  console.log("");
4803
5072
  const allDates = /* @__PURE__ */ new Set([...Object.keys(createdByDate), ...Object.keys(completedByDate)]);
4804
5073
  const sortedDates = Array.from(allDates).sort();
4805
5074
  if (sortedDates.length > 0) {
4806
- console.log(chalk15.bold(`\u{1F4C5} Activity (Last ${days} Days)`));
5075
+ console.log(chalk16.bold(`\u{1F4C5} Activity (Last ${days} Days)`));
4807
5076
  console.log("");
4808
5077
  const labelWidth2 = 15;
4809
5078
  const barWidth = 20;
4810
5079
  const specsWidth = 3;
4811
5080
  const colWidth = barWidth + specsWidth;
4812
- console.log(` ${"Date".padEnd(labelWidth2)} ${chalk15.cyan("Created".padEnd(colWidth))} ${chalk15.green("Completed".padEnd(colWidth))}`);
4813
- console.log(` ${chalk15.dim("\u2500".repeat(labelWidth2))} ${chalk15.dim("\u2500".repeat(colWidth))} ${chalk15.dim("\u2500".repeat(colWidth))}`);
5081
+ console.log(` ${"Date".padEnd(labelWidth2)} ${chalk16.cyan("Created".padEnd(colWidth))} ${chalk16.green("Completed".padEnd(colWidth))}`);
5082
+ console.log(` ${chalk16.dim("\u2500".repeat(labelWidth2))} ${chalk16.dim("\u2500".repeat(colWidth))} ${chalk16.dim("\u2500".repeat(colWidth))}`);
4814
5083
  const maxCount = Math.max(...Object.values(createdByDate), ...Object.values(completedByDate));
4815
5084
  for (const date of sortedDates) {
4816
5085
  const created = createdByDate[date] || 0;
@@ -4819,7 +5088,7 @@ async function showTimeline(options) {
4819
5088
  const completedBar = createBar(completed, maxCount, barWidth);
4820
5089
  const createdCol = `${createdBar.padEnd(barWidth)}${created.toString().padStart(specsWidth)}`;
4821
5090
  const completedCol = `${completedBar.padEnd(barWidth)}${completed.toString().padStart(specsWidth)}`;
4822
- console.log(` ${chalk15.dim(date.padEnd(labelWidth2))} ${chalk15.cyan(createdCol)} ${chalk15.green(completedCol)}`);
5091
+ console.log(` ${chalk16.dim(date.padEnd(labelWidth2))} ${chalk16.cyan(createdCol)} ${chalk16.green(completedCol)}`);
4823
5092
  }
4824
5093
  console.log("");
4825
5094
  }
@@ -4829,18 +5098,18 @@ async function showTimeline(options) {
4829
5098
  return dateB.diff(dateA);
4830
5099
  }).slice(0, 6);
4831
5100
  if (sortedMonths.length > 0) {
4832
- console.log(chalk15.bold("\u{1F4CA} Monthly Overview"));
5101
+ console.log(chalk16.bold("\u{1F4CA} Monthly Overview"));
4833
5102
  console.log("");
4834
5103
  const labelWidth2 = 15;
4835
5104
  const barWidth = 20;
4836
5105
  const specsWidth = 3;
4837
5106
  const colWidth = barWidth + specsWidth;
4838
- console.log(` ${"Month".padEnd(labelWidth2)} ${chalk15.magenta("Specs".padEnd(colWidth))}`);
4839
- console.log(` ${chalk15.dim("\u2500".repeat(labelWidth2))} ${chalk15.dim("\u2500".repeat(colWidth))}`);
5107
+ console.log(` ${"Month".padEnd(labelWidth2)} ${chalk16.magenta("Specs".padEnd(colWidth))}`);
5108
+ console.log(` ${chalk16.dim("\u2500".repeat(labelWidth2))} ${chalk16.dim("\u2500".repeat(colWidth))}`);
4840
5109
  const maxCount = Math.max(...sortedMonths.map(([, count]) => count));
4841
5110
  for (const [month, count] of sortedMonths) {
4842
5111
  const bar = createBar(count, maxCount, barWidth);
4843
- console.log(` ${month.padEnd(labelWidth2)} ${chalk15.magenta(bar.padEnd(barWidth))}${chalk15.magenta(count.toString().padStart(specsWidth))}`);
5112
+ console.log(` ${month.padEnd(labelWidth2)} ${chalk16.magenta(bar.padEnd(barWidth))}${chalk16.magenta(count.toString().padStart(specsWidth))}`);
4844
5113
  }
4845
5114
  console.log("");
4846
5115
  }
@@ -4854,14 +5123,14 @@ async function showTimeline(options) {
4854
5123
  const completed = dayjs2(s.frontmatter.completed);
4855
5124
  return completed.isAfter(today.subtract(30, "day"));
4856
5125
  }).length;
4857
- console.log(chalk15.bold("\u2705 Completion Rate"));
5126
+ console.log(chalk16.bold("\u2705 Completion Rate"));
4858
5127
  console.log("");
4859
5128
  const labelWidth = 15;
4860
5129
  const valueWidth = 5;
4861
5130
  console.log(` ${"Period".padEnd(labelWidth)} ${"Specs".padStart(valueWidth)}`);
4862
- console.log(` ${chalk15.dim("\u2500".repeat(labelWidth))} ${chalk15.dim("\u2500".repeat(valueWidth))}`);
4863
- console.log(` ${"Last 7 days".padEnd(labelWidth)} ${chalk15.green(last7Days.toString().padStart(valueWidth))}`);
4864
- console.log(` ${"Last 30 days".padEnd(labelWidth)} ${chalk15.green(last30Days.toString().padStart(valueWidth))}`);
5131
+ console.log(` ${chalk16.dim("\u2500".repeat(labelWidth))} ${chalk16.dim("\u2500".repeat(valueWidth))}`);
5132
+ console.log(` ${"Last 7 days".padEnd(labelWidth)} ${chalk16.green(last7Days.toString().padStart(valueWidth))}`);
5133
+ console.log(` ${"Last 30 days".padEnd(labelWidth)} ${chalk16.green(last30Days.toString().padStart(valueWidth))}`);
4865
5134
  console.log("");
4866
5135
  if (options.byTag) {
4867
5136
  const tagStats = {};
@@ -4883,9 +5152,9 @@ async function showTimeline(options) {
4883
5152
  }
4884
5153
  const sortedTags = Object.entries(tagStats).sort((a, b) => b[1].created - a[1].created).slice(0, 10);
4885
5154
  if (sortedTags.length > 0) {
4886
- console.log(chalk15.bold("\u{1F3F7}\uFE0F By Tag"));
5155
+ console.log(chalk16.bold("\u{1F3F7}\uFE0F By Tag"));
4887
5156
  for (const [tag, stats] of sortedTags) {
4888
- console.log(` ${chalk15.dim("#")}${tag.padEnd(20)} ${chalk15.cyan(stats.created)} created \xB7 ${chalk15.green(stats.completed)} completed`);
5157
+ console.log(` ${chalk16.dim("#")}${tag.padEnd(20)} ${chalk16.cyan(stats.created)} created \xB7 ${chalk16.green(stats.completed)} completed`);
4889
5158
  }
4890
5159
  console.log("");
4891
5160
  }
@@ -4910,9 +5179,9 @@ async function showTimeline(options) {
4910
5179
  }
4911
5180
  const sortedAssignees = Object.entries(assigneeStats).sort((a, b) => b[1].created - a[1].created);
4912
5181
  if (sortedAssignees.length > 0) {
4913
- console.log(chalk15.bold("\u{1F464} By Assignee"));
5182
+ console.log(chalk16.bold("\u{1F464} By Assignee"));
4914
5183
  for (const [assignee, stats] of sortedAssignees) {
4915
- console.log(` ${chalk15.dim("@")}${assignee.padEnd(20)} ${chalk15.cyan(stats.created)} created \xB7 ${chalk15.green(stats.completed)} completed`);
5184
+ console.log(` ${chalk16.dim("@")}${assignee.padEnd(20)} ${chalk16.cyan(stats.created)} created \xB7 ${chalk16.green(stats.completed)} completed`);
4916
5185
  }
4917
5186
  console.log("");
4918
5187
  }
@@ -4930,10 +5199,10 @@ var STATUS_CONFIG2 = {
4930
5199
  archived: { emoji: "\u{1F4E6}", color: "gray" }
4931
5200
  };
4932
5201
  var PRIORITY_CONFIG3 = {
4933
- critical: { emoji: "\u{1F534}", label: "CRITICAL", colorFn: chalk15.red },
4934
- high: { emoji: "\u{1F7E0}", label: "HIGH", colorFn: chalk15.hex("#FFA500") },
4935
- medium: { emoji: "\u{1F7E1}", label: "MEDIUM", colorFn: chalk15.yellow },
4936
- low: { emoji: "\u{1F7E2}", label: "LOW", colorFn: chalk15.green }
5202
+ critical: { emoji: "\u{1F534}", label: "CRITICAL", colorFn: chalk16.red },
5203
+ high: { emoji: "\u{1F7E0}", label: "HIGH", colorFn: chalk16.hex("#FFA500") },
5204
+ medium: { emoji: "\u{1F7E1}", label: "MEDIUM", colorFn: chalk16.yellow },
5205
+ low: { emoji: "\u{1F7E2}", label: "LOW", colorFn: chalk16.green }
4937
5206
  };
4938
5207
  function ganttCommand() {
4939
5208
  return new Command("gantt").description("Show timeline with dependencies").option("--weeks <n>", "Show N weeks (default: 4)", parseInt).option("--show-complete", "Include completed specs").option("--critical-path", "Highlight critical path").option("--json", "Output as JSON").action(async (options) => {
@@ -4964,8 +5233,8 @@ async function showGantt(options) {
4964
5233
  if (options.json) {
4965
5234
  console.log(JSON.stringify({ specs: [], weeks }, null, 2));
4966
5235
  } else {
4967
- console.log(chalk15.dim("No active specs found."));
4968
- console.log(chalk15.dim("Tip: Use --show-complete to include completed specs."));
5236
+ console.log(chalk16.dim("No active specs found."));
5237
+ console.log(chalk16.dim("Tip: Use --show-complete to include completed specs."));
4969
5238
  }
4970
5239
  return;
4971
5240
  }
@@ -5018,7 +5287,7 @@ async function showGantt(options) {
5018
5287
  const overdue = relevantSpecs.filter(
5019
5288
  (s) => s.frontmatter.due && dayjs2(s.frontmatter.due).isBefore(today) && s.frontmatter.status !== "complete"
5020
5289
  ).length;
5021
- console.log(chalk15.bold.cyan(`\u{1F4C5} Gantt Chart (${weeks} weeks from ${startDate.format("MMM D, YYYY")})`));
5290
+ console.log(chalk16.bold.cyan(`\u{1F4C5} Gantt Chart (${weeks} weeks from ${startDate.format("MMM D, YYYY")})`));
5022
5291
  console.log("");
5023
5292
  const specHeader = "Spec".padEnd(SPEC_COLUMN_WIDTH);
5024
5293
  const timelineHeader = "Timeline";
@@ -5030,17 +5299,17 @@ async function showGantt(options) {
5030
5299
  calendarDates.push(dateStr);
5031
5300
  }
5032
5301
  const dateRow = " ".repeat(SPEC_COLUMN_WIDTH) + COLUMN_SEPARATOR + calendarDates.join("");
5033
- console.log(chalk15.dim(dateRow));
5302
+ console.log(chalk16.dim(dateRow));
5034
5303
  const specSeparator = "\u2500".repeat(SPEC_COLUMN_WIDTH);
5035
5304
  const timelineSeparator = "\u2500".repeat(timelineColumnWidth);
5036
- console.log(chalk15.dim(specSeparator + COLUMN_SEPARATOR + timelineSeparator));
5305
+ console.log(chalk16.dim(specSeparator + COLUMN_SEPARATOR + timelineSeparator));
5037
5306
  const todayWeekOffset = today.diff(startDate, "week");
5038
5307
  const todayMarkerPos = todayWeekOffset * 8;
5039
5308
  let todayMarker = " ".repeat(SPEC_COLUMN_WIDTH) + COLUMN_SEPARATOR;
5040
5309
  if (todayMarkerPos >= 0 && todayMarkerPos < timelineColumnWidth) {
5041
5310
  todayMarker += " ".repeat(todayMarkerPos) + "\u2502 Today";
5042
5311
  }
5043
- console.log(chalk15.dim(todayMarker));
5312
+ console.log(chalk16.dim(todayMarker));
5044
5313
  console.log("");
5045
5314
  const priorities = ["critical", "high", "medium", "low"];
5046
5315
  for (const priority of priorities) {
@@ -5058,9 +5327,9 @@ async function showGantt(options) {
5058
5327
  const summaryParts = [];
5059
5328
  if (inProgress > 0) summaryParts.push(`${inProgress} in-progress`);
5060
5329
  if (planned > 0) summaryParts.push(`${planned} planned`);
5061
- if (overdue > 0) summaryParts.push(chalk15.red(`${overdue} overdue`));
5062
- console.log(chalk15.bold("Summary: ") + summaryParts.join(" \xB7 "));
5063
- console.log(chalk15.dim('\u{1F4A1} Tip: Add "due: YYYY-MM-DD" to frontmatter for timeline planning'));
5330
+ if (overdue > 0) summaryParts.push(chalk16.red(`${overdue} overdue`));
5331
+ console.log(chalk16.bold("Summary: ") + summaryParts.join(" \xB7 "));
5332
+ console.log(chalk16.dim('\u{1F4A1} Tip: Add "due: YYYY-MM-DD" to frontmatter for timeline planning'));
5064
5333
  }
5065
5334
  function renderSpecRow(spec, startDate, endDate, weeks, today) {
5066
5335
  const statusConfig = STATUS_CONFIG2[spec.frontmatter.status];
@@ -5073,7 +5342,7 @@ function renderSpecRow(spec, startDate, endDate, weeks, today) {
5073
5342
  const specColumn = `${SPEC_INDENT}${emoji} ${specName}`.padEnd(SPEC_COLUMN_WIDTH);
5074
5343
  let timelineColumn;
5075
5344
  if (!spec.frontmatter.due) {
5076
- timelineColumn = chalk15.dim("(no due date set)");
5345
+ timelineColumn = chalk16.dim("(no due date set)");
5077
5346
  } else {
5078
5347
  timelineColumn = renderTimelineBar(spec, startDate, endDate, weeks, today);
5079
5348
  }
@@ -5096,13 +5365,13 @@ function renderTimelineBar(spec, startDate, endDate, weeks, today) {
5096
5365
  result += " ".repeat(barStart);
5097
5366
  }
5098
5367
  if (spec.frontmatter.status === "complete") {
5099
- result += chalk15.green(FILLED_BAR_CHAR.repeat(barLength));
5368
+ result += chalk16.green(FILLED_BAR_CHAR.repeat(barLength));
5100
5369
  } else if (spec.frontmatter.status === "in-progress") {
5101
5370
  const halfLength = Math.floor(barLength / 2);
5102
- result += chalk15.yellow(FILLED_BAR_CHAR.repeat(halfLength));
5103
- result += chalk15.dim(EMPTY_BAR_CHAR.repeat(barLength - halfLength));
5371
+ result += chalk16.yellow(FILLED_BAR_CHAR.repeat(halfLength));
5372
+ result += chalk16.dim(EMPTY_BAR_CHAR.repeat(barLength - halfLength));
5104
5373
  } else {
5105
- result += chalk15.dim(EMPTY_BAR_CHAR.repeat(barLength));
5374
+ result += chalk16.dim(EMPTY_BAR_CHAR.repeat(barLength));
5106
5375
  }
5107
5376
  const trailingSpace = totalChars - barEnd;
5108
5377
  if (trailingSpace > 0) {
@@ -5128,12 +5397,12 @@ async function countSpecTokens(specPath, options = {}) {
5128
5397
  try {
5129
5398
  const config = await loadConfig();
5130
5399
  const cwd = process.cwd();
5131
- const specsDir = path12.join(cwd, config.specsDir);
5400
+ const specsDir = path13.join(cwd, config.specsDir);
5132
5401
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
5133
5402
  if (!resolvedPath) {
5134
5403
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
5135
5404
  }
5136
- const specName = path12.basename(resolvedPath);
5405
+ const specName = path13.basename(resolvedPath);
5137
5406
  const result = await counter.countSpec(resolvedPath, {
5138
5407
  detailed: options.detailed,
5139
5408
  includeSubSpecs: options.includeSubSpecs
@@ -5146,42 +5415,42 @@ async function countSpecTokens(specPath, options = {}) {
5146
5415
  }, null, 2));
5147
5416
  return;
5148
5417
  }
5149
- console.log(chalk15.bold.cyan(`\u{1F4CA} Token Count: ${specName}`));
5418
+ console.log(chalk16.bold.cyan(`\u{1F4CA} Token Count: ${specName}`));
5150
5419
  console.log("");
5151
5420
  const indicators = counter.getPerformanceIndicators(result.total);
5152
5421
  const levelEmoji = indicators.level === "excellent" ? "\u2705" : indicators.level === "good" ? "\u{1F44D}" : indicators.level === "warning" ? "\u26A0\uFE0F" : "\u{1F534}";
5153
- console.log(` Total: ${chalk15.cyan(result.total.toLocaleString())} tokens ${levelEmoji}`);
5422
+ console.log(` Total: ${chalk16.cyan(result.total.toLocaleString())} tokens ${levelEmoji}`);
5154
5423
  console.log("");
5155
5424
  if (result.files.length > 1 || options.detailed) {
5156
- console.log(chalk15.bold("Files:"));
5425
+ console.log(chalk16.bold("Files:"));
5157
5426
  console.log("");
5158
5427
  for (const file of result.files) {
5159
- const lineInfo = file.lines ? chalk15.dim(` (${file.lines} lines)`) : "";
5160
- console.log(` ${file.path.padEnd(25)} ${chalk15.cyan(file.tokens.toLocaleString().padStart(6))} tokens${lineInfo}`);
5428
+ const lineInfo = file.lines ? chalk16.dim(` (${file.lines} lines)`) : "";
5429
+ console.log(` ${file.path.padEnd(25)} ${chalk16.cyan(file.tokens.toLocaleString().padStart(6))} tokens${lineInfo}`);
5161
5430
  }
5162
5431
  console.log("");
5163
5432
  }
5164
5433
  if (options.detailed && result.breakdown) {
5165
5434
  const b = result.breakdown;
5166
5435
  const total = b.code + b.prose + b.tables + b.frontmatter;
5167
- console.log(chalk15.bold("Content Breakdown:"));
5436
+ console.log(chalk16.bold("Content Breakdown:"));
5168
5437
  console.log("");
5169
- console.log(` Prose ${chalk15.cyan(b.prose.toLocaleString().padStart(6))} tokens ${chalk15.dim(`(${Math.round(b.prose / total * 100)}%)`)}`);
5170
- console.log(` Code ${chalk15.cyan(b.code.toLocaleString().padStart(6))} tokens ${chalk15.dim(`(${Math.round(b.code / total * 100)}%)`)}`);
5171
- console.log(` Tables ${chalk15.cyan(b.tables.toLocaleString().padStart(6))} tokens ${chalk15.dim(`(${Math.round(b.tables / total * 100)}%)`)}`);
5172
- console.log(` Frontmatter ${chalk15.cyan(b.frontmatter.toLocaleString().padStart(6))} tokens ${chalk15.dim(`(${Math.round(b.frontmatter / total * 100)}%)`)}`);
5438
+ console.log(` Prose ${chalk16.cyan(b.prose.toLocaleString().padStart(6))} tokens ${chalk16.dim(`(${Math.round(b.prose / total * 100)}%)`)}`);
5439
+ console.log(` Code ${chalk16.cyan(b.code.toLocaleString().padStart(6))} tokens ${chalk16.dim(`(${Math.round(b.code / total * 100)}%)`)}`);
5440
+ console.log(` Tables ${chalk16.cyan(b.tables.toLocaleString().padStart(6))} tokens ${chalk16.dim(`(${Math.round(b.tables / total * 100)}%)`)}`);
5441
+ console.log(` Frontmatter ${chalk16.cyan(b.frontmatter.toLocaleString().padStart(6))} tokens ${chalk16.dim(`(${Math.round(b.frontmatter / total * 100)}%)`)}`);
5173
5442
  console.log("");
5174
5443
  }
5175
- console.log(chalk15.bold("Performance Indicators:"));
5444
+ console.log(chalk16.bold("Performance Indicators:"));
5176
5445
  console.log("");
5177
- const costColor = indicators.costMultiplier < 2 ? chalk15.green : indicators.costMultiplier < 4 ? chalk15.yellow : chalk15.red;
5178
- const effectivenessColor = indicators.effectiveness >= 95 ? chalk15.green : indicators.effectiveness >= 85 ? chalk15.yellow : chalk15.red;
5179
- console.log(` Cost multiplier: ${costColor(`${indicators.costMultiplier}x`)} ${chalk15.dim("vs 1,200 token baseline")}`);
5180
- console.log(` AI effectiveness: ${effectivenessColor(`~${indicators.effectiveness}%`)} ${chalk15.dim("(hypothesis)")}`);
5446
+ const costColor = indicators.costMultiplier < 2 ? chalk16.green : indicators.costMultiplier < 4 ? chalk16.yellow : chalk16.red;
5447
+ const effectivenessColor = indicators.effectiveness >= 95 ? chalk16.green : indicators.effectiveness >= 85 ? chalk16.yellow : chalk16.red;
5448
+ console.log(` Cost multiplier: ${costColor(`${indicators.costMultiplier}x`)} ${chalk16.dim("vs 1,200 token baseline")}`);
5449
+ console.log(` AI effectiveness: ${effectivenessColor(`~${indicators.effectiveness}%`)} ${chalk16.dim("(hypothesis)")}`);
5181
5450
  console.log(` Context Economy: ${levelEmoji} ${indicators.recommendation}`);
5182
5451
  console.log("");
5183
5452
  if (!options.includeSubSpecs && result.files.length === 1) {
5184
- console.log(chalk15.dim("\u{1F4A1} Use `--include-sub-specs` to count all sub-spec files"));
5453
+ console.log(chalk16.dim("\u{1F4A1} Use `--include-sub-specs` to count all sub-spec files"));
5185
5454
  }
5186
5455
  } finally {
5187
5456
  counter.dispose();
@@ -5227,46 +5496,46 @@ async function tokensAllCommand(options = {}) {
5227
5496
  console.log(JSON.stringify(results, null, 2));
5228
5497
  return;
5229
5498
  }
5230
- console.log(chalk15.bold.cyan("\u{1F4CA} Token Counts"));
5499
+ console.log(chalk16.bold.cyan("\u{1F4CA} Token Counts"));
5231
5500
  console.log("");
5232
- console.log(chalk15.dim(`Sorted by: ${sortBy}`));
5501
+ console.log(chalk16.dim(`Sorted by: ${sortBy}`));
5233
5502
  console.log("");
5234
5503
  const totalTokens = results.reduce((sum, r) => sum + r.tokens, 0);
5235
5504
  const avgTokens = Math.round(totalTokens / results.length);
5236
5505
  const warningCount = results.filter((r) => r.level === "warning" || r.level === "problem").length;
5237
- console.log(chalk15.bold("Summary:"));
5506
+ console.log(chalk16.bold("Summary:"));
5238
5507
  console.log("");
5239
- console.log(` Total specs: ${chalk15.cyan(results.length)}`);
5240
- console.log(` Total tokens: ${chalk15.cyan(totalTokens.toLocaleString())}`);
5241
- console.log(` Average tokens: ${chalk15.cyan(avgTokens.toLocaleString())}`);
5508
+ console.log(` Total specs: ${chalk16.cyan(results.length)}`);
5509
+ console.log(` Total tokens: ${chalk16.cyan(totalTokens.toLocaleString())}`);
5510
+ console.log(` Average tokens: ${chalk16.cyan(avgTokens.toLocaleString())}`);
5242
5511
  if (warningCount > 0) {
5243
- console.log(` Needs review: ${chalk15.yellow(warningCount)} specs ${chalk15.dim("(\u26A0\uFE0F or \u{1F534})")}`);
5512
+ console.log(` Needs review: ${chalk16.yellow(warningCount)} specs ${chalk16.dim("(\u26A0\uFE0F or \u{1F534})")}`);
5244
5513
  }
5245
5514
  console.log("");
5246
5515
  const nameCol = 35;
5247
5516
  const tokensCol = 10;
5248
5517
  const linesCol = 8;
5249
- console.log(chalk15.bold(
5518
+ console.log(chalk16.bold(
5250
5519
  "Spec".padEnd(nameCol) + "Tokens".padStart(tokensCol) + "Lines".padStart(linesCol) + " Status"
5251
5520
  ));
5252
- console.log(chalk15.dim("\u2500".repeat(nameCol + tokensCol + linesCol + 10)));
5521
+ console.log(chalk16.dim("\u2500".repeat(nameCol + tokensCol + linesCol + 10)));
5253
5522
  const displayCount = options.all ? results.length : Math.min(20, results.length);
5254
5523
  for (let i = 0; i < displayCount; i++) {
5255
5524
  const r = results[i];
5256
5525
  const emoji = r.level === "excellent" ? "\u2705" : r.level === "good" ? "\u{1F44D}" : r.level === "warning" ? "\u26A0\uFE0F" : "\u{1F534}";
5257
- const tokensColor = r.level === "excellent" || r.level === "good" ? chalk15.cyan : r.level === "warning" ? chalk15.yellow : chalk15.red;
5526
+ const tokensColor = r.level === "excellent" || r.level === "good" ? chalk16.cyan : r.level === "warning" ? chalk16.yellow : chalk16.red;
5258
5527
  const name = r.name.length > nameCol - 2 ? r.name.substring(0, nameCol - 3) + "\u2026" : r.name;
5259
5528
  console.log(
5260
- name.padEnd(nameCol) + tokensColor(r.tokens.toLocaleString().padStart(tokensCol)) + chalk15.dim(r.lines.toString().padStart(linesCol)) + ` ${emoji}`
5529
+ name.padEnd(nameCol) + tokensColor(r.tokens.toLocaleString().padStart(tokensCol)) + chalk16.dim(r.lines.toString().padStart(linesCol)) + ` ${emoji}`
5261
5530
  );
5262
5531
  }
5263
5532
  if (results.length > displayCount) {
5264
5533
  console.log("");
5265
- console.log(chalk15.dim(`... and ${results.length - displayCount} more specs`));
5266
- console.log(chalk15.dim(`Use --all to show all specs`));
5534
+ console.log(chalk16.dim(`... and ${results.length - displayCount} more specs`));
5535
+ console.log(chalk16.dim(`Use --all to show all specs`));
5267
5536
  }
5268
5537
  console.log("");
5269
- console.log(chalk15.dim("Legend: \u2705 excellent (<2K) | \u{1F44D} good (<3.5K) | \u26A0\uFE0F warning (<5K) | \u{1F534} problem (>5K)"));
5538
+ console.log(chalk16.dim("Legend: \u2705 excellent (<2K) | \u{1F44D} good (<3.5K) | \u26A0\uFE0F warning (<5K) | \u{1F534} problem (>5K)"));
5270
5539
  console.log("");
5271
5540
  }
5272
5541
  function analyzeCommand() {
@@ -5280,13 +5549,13 @@ async function analyzeSpec(specPath, options = {}) {
5280
5549
  try {
5281
5550
  const config = await loadConfig();
5282
5551
  const cwd = process.cwd();
5283
- const specsDir = path12.join(cwd, config.specsDir);
5552
+ const specsDir = path13.join(cwd, config.specsDir);
5284
5553
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
5285
5554
  if (!resolvedPath) {
5286
5555
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
5287
5556
  }
5288
- const specName = path12.basename(resolvedPath);
5289
- const readmePath = path12.join(resolvedPath, "README.md");
5557
+ const specName = path13.basename(resolvedPath);
5558
+ const readmePath = path13.join(resolvedPath, "README.md");
5290
5559
  const content = await readFile(readmePath, "utf-8");
5291
5560
  const structure = analyzeMarkdownStructure(content);
5292
5561
  const tokenResult = await counter.countSpec(resolvedPath, {
@@ -5389,44 +5658,44 @@ function getThresholdLimit(level) {
5389
5658
  }
5390
5659
  }
5391
5660
  function displayAnalysis(result, verbose) {
5392
- console.log(chalk15.bold.cyan(`\u{1F4CA} Spec Analysis: ${result.spec}`));
5661
+ console.log(chalk16.bold.cyan(`\u{1F4CA} Spec Analysis: ${result.spec}`));
5393
5662
  console.log("");
5394
5663
  const statusEmoji = result.threshold.status === "excellent" ? "\u2705" : result.threshold.status === "good" ? "\u{1F44D}" : result.threshold.status === "warning" ? "\u26A0\uFE0F" : "\u{1F534}";
5395
- const tokenColor = result.threshold.status === "excellent" || result.threshold.status === "good" ? chalk15.cyan : result.threshold.status === "warning" ? chalk15.yellow : chalk15.red;
5396
- console.log(chalk15.bold("Token Count:"), tokenColor(result.metrics.tokens.toLocaleString()), "tokens", statusEmoji);
5397
- console.log(chalk15.dim(` Threshold: ${result.threshold.limit.toLocaleString()} tokens`));
5398
- console.log(chalk15.dim(` Status: ${result.threshold.message}`));
5664
+ const tokenColor = result.threshold.status === "excellent" || result.threshold.status === "good" ? chalk16.cyan : result.threshold.status === "warning" ? chalk16.yellow : chalk16.red;
5665
+ console.log(chalk16.bold("Token Count:"), tokenColor(result.metrics.tokens.toLocaleString()), "tokens", statusEmoji);
5666
+ console.log(chalk16.dim(` Threshold: ${result.threshold.limit.toLocaleString()} tokens`));
5667
+ console.log(chalk16.dim(` Status: ${result.threshold.message}`));
5399
5668
  console.log("");
5400
- console.log(chalk15.bold("Structure:"));
5401
- console.log(` Lines: ${chalk15.cyan(result.metrics.lines.toLocaleString())}`);
5402
- console.log(` Sections: ${chalk15.cyan(result.metrics.sections.total)} (H1:${result.metrics.sections.h1}, H2:${result.metrics.sections.h2}, H3:${result.metrics.sections.h3}, H4:${result.metrics.sections.h4})`);
5403
- console.log(` Code blocks: ${chalk15.cyan(result.metrics.codeBlocks)}`);
5404
- console.log(` Max nesting: ${chalk15.cyan(result.metrics.maxNesting)} levels`);
5669
+ console.log(chalk16.bold("Structure:"));
5670
+ console.log(` Lines: ${chalk16.cyan(result.metrics.lines.toLocaleString())}`);
5671
+ console.log(` Sections: ${chalk16.cyan(result.metrics.sections.total)} (H1:${result.metrics.sections.h1}, H2:${result.metrics.sections.h2}, H3:${result.metrics.sections.h3}, H4:${result.metrics.sections.h4})`);
5672
+ console.log(` Code blocks: ${chalk16.cyan(result.metrics.codeBlocks)}`);
5673
+ console.log(` Max nesting: ${chalk16.cyan(result.metrics.maxNesting)} levels`);
5405
5674
  console.log("");
5406
5675
  if (verbose && result.structure.length > 0) {
5407
5676
  const topSections = result.structure.filter((s) => s.level <= 2).sort((a, b) => b.tokens - a.tokens).slice(0, 5);
5408
- console.log(chalk15.bold("Top Sections by Size:"));
5677
+ console.log(chalk16.bold("Top Sections by Size:"));
5409
5678
  console.log("");
5410
5679
  for (let i = 0; i < topSections.length; i++) {
5411
5680
  const s = topSections[i];
5412
5681
  const percentage = Math.round(s.tokens / result.metrics.tokens * 100);
5413
5682
  const indent = " ".repeat(s.level - 1);
5414
5683
  console.log(` ${i + 1}. ${indent}${s.section}`);
5415
- console.log(` ${chalk15.cyan(s.tokens.toLocaleString())} tokens / ${s.lineRange[1] - s.lineRange[0] + 1} lines ${chalk15.dim(`(${percentage}%)`)}`);
5416
- console.log(chalk15.dim(` Lines ${s.lineRange[0]}-${s.lineRange[1]}`));
5684
+ console.log(` ${chalk16.cyan(s.tokens.toLocaleString())} tokens / ${s.lineRange[1] - s.lineRange[0] + 1} lines ${chalk16.dim(`(${percentage}%)`)}`);
5685
+ console.log(chalk16.dim(` Lines ${s.lineRange[0]}-${s.lineRange[1]}`));
5417
5686
  }
5418
5687
  console.log("");
5419
5688
  }
5420
- const actionColor = result.recommendation.action === "none" ? chalk15.green : result.recommendation.action === "compact" ? chalk15.yellow : result.recommendation.action === "split" ? chalk15.red : chalk15.blue;
5421
- console.log(chalk15.bold("Recommendation:"), actionColor(result.recommendation.action.toUpperCase()));
5422
- console.log(chalk15.dim(` ${result.recommendation.reason}`));
5423
- console.log(chalk15.dim(` Confidence: ${result.recommendation.confidence}`));
5689
+ const actionColor = result.recommendation.action === "none" ? chalk16.green : result.recommendation.action === "compact" ? chalk16.yellow : result.recommendation.action === "split" ? chalk16.red : chalk16.blue;
5690
+ console.log(chalk16.bold("Recommendation:"), actionColor(result.recommendation.action.toUpperCase()));
5691
+ console.log(chalk16.dim(` ${result.recommendation.reason}`));
5692
+ console.log(chalk16.dim(` Confidence: ${result.recommendation.confidence}`));
5424
5693
  console.log("");
5425
5694
  if (result.recommendation.action === "split") {
5426
- console.log(chalk15.dim("\u{1F4A1} Use `lean-spec split` to partition into sub-specs"));
5427
- console.log(chalk15.dim("\u{1F4A1} Consider splitting by H2 sections (concerns)"));
5695
+ console.log(chalk16.dim("\u{1F4A1} Use `lean-spec split` to partition into sub-specs"));
5696
+ console.log(chalk16.dim("\u{1F4A1} Consider splitting by H2 sections (concerns)"));
5428
5697
  } else if (result.recommendation.action === "compact") {
5429
- console.log(chalk15.dim("\u{1F4A1} Use `lean-spec compact` to remove redundancy"));
5698
+ console.log(chalk16.dim("\u{1F4A1} Use `lean-spec compact` to remove redundancy"));
5430
5699
  }
5431
5700
  console.log("");
5432
5701
  }
@@ -5458,13 +5727,13 @@ async function splitSpec(specPath, options) {
5458
5727
  }
5459
5728
  const config = await loadConfig();
5460
5729
  const cwd = process.cwd();
5461
- const specsDir = path12.join(cwd, config.specsDir);
5730
+ const specsDir = path13.join(cwd, config.specsDir);
5462
5731
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
5463
5732
  if (!resolvedPath) {
5464
5733
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
5465
5734
  }
5466
- const specName = path12.basename(resolvedPath);
5467
- const readmePath = path12.join(resolvedPath, "README.md");
5735
+ const specName = path13.basename(resolvedPath);
5736
+ const readmePath = path13.join(resolvedPath, "README.md");
5468
5737
  const content = await readFile(readmePath, "utf-8");
5469
5738
  const parsedOutputs = parseOutputSpecs(options.outputs);
5470
5739
  validateNoOverlaps(parsedOutputs);
@@ -5487,7 +5756,7 @@ async function splitSpec(specPath, options) {
5487
5756
  await executeSplit(resolvedPath, specName, content, extractions, options);
5488
5757
  } catch (error) {
5489
5758
  if (error instanceof Error) {
5490
- console.error(chalk15.red(`Error: ${error.message}`));
5759
+ console.error(chalk16.red(`Error: ${error.message}`));
5491
5760
  }
5492
5761
  throw error;
5493
5762
  }
@@ -5525,30 +5794,30 @@ function validateNoOverlaps(outputs) {
5525
5794
  }
5526
5795
  }
5527
5796
  async function displayDryRun(specName, extractions) {
5528
- console.log(chalk15.bold.cyan(`\u{1F4CB} Split Preview: ${specName}`));
5797
+ console.log(chalk16.bold.cyan(`\u{1F4CB} Split Preview: ${specName}`));
5529
5798
  console.log("");
5530
- console.log(chalk15.bold("Would create:"));
5799
+ console.log(chalk16.bold("Would create:"));
5531
5800
  console.log("");
5532
5801
  for (const ext of extractions) {
5533
- console.log(` ${chalk15.cyan(ext.file)}`);
5802
+ console.log(` ${chalk16.cyan(ext.file)}`);
5534
5803
  console.log(` Lines: ${ext.lines}`);
5535
5804
  const previewLines = ext.content.split("\n").slice(0, 3);
5536
- console.log(chalk15.dim(" Preview:"));
5805
+ console.log(chalk16.dim(" Preview:"));
5537
5806
  for (const line of previewLines) {
5538
- console.log(chalk15.dim(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
5807
+ console.log(chalk16.dim(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
5539
5808
  }
5540
5809
  console.log("");
5541
5810
  }
5542
- console.log(chalk15.dim("No files modified (dry run)"));
5543
- console.log(chalk15.dim("Run without --dry-run to apply changes"));
5811
+ console.log(chalk16.dim("No files modified (dry run)"));
5812
+ console.log(chalk16.dim("Run without --dry-run to apply changes"));
5544
5813
  console.log("");
5545
5814
  }
5546
5815
  async function executeSplit(specPath, specName, originalContent, extractions, options) {
5547
- console.log(chalk15.bold.cyan(`\u2702\uFE0F Splitting: ${specName}`));
5816
+ console.log(chalk16.bold.cyan(`\u2702\uFE0F Splitting: ${specName}`));
5548
5817
  console.log("");
5549
5818
  const frontmatter = parseFrontmatterFromString(originalContent);
5550
5819
  for (const ext of extractions) {
5551
- const outputPath = path12.join(specPath, ext.file);
5820
+ const outputPath = path13.join(specPath, ext.file);
5552
5821
  let finalContent = ext.content;
5553
5822
  if (ext.file === "README.md" && frontmatter) {
5554
5823
  const { content: contentWithFrontmatter } = createUpdatedFrontmatter(
@@ -5558,21 +5827,21 @@ async function executeSplit(specPath, specName, originalContent, extractions, op
5558
5827
  finalContent = contentWithFrontmatter;
5559
5828
  }
5560
5829
  await writeFile(outputPath, finalContent, "utf-8");
5561
- console.log(chalk15.green(`\u2713 Created ${ext.file} (${ext.lines} lines)`));
5830
+ console.log(chalk16.green(`\u2713 Created ${ext.file} (${ext.lines} lines)`));
5562
5831
  }
5563
5832
  if (options.updateRefs) {
5564
- const readmePath = path12.join(specPath, "README.md");
5833
+ const readmePath = path13.join(specPath, "README.md");
5565
5834
  const readmeContent = await readFile(readmePath, "utf-8");
5566
5835
  const updatedReadme = await addSubSpecLinks(
5567
5836
  readmeContent,
5568
5837
  extractions.map((e) => e.file).filter((f) => f !== "README.md")
5569
5838
  );
5570
5839
  await writeFile(readmePath, updatedReadme, "utf-8");
5571
- console.log(chalk15.green(`\u2713 Updated README.md with sub-spec links`));
5840
+ console.log(chalk16.green(`\u2713 Updated README.md with sub-spec links`));
5572
5841
  }
5573
5842
  console.log("");
5574
- console.log(chalk15.bold.green("Split complete!"));
5575
- console.log(chalk15.dim(`Created ${extractions.length} files in ${specName}`));
5843
+ console.log(chalk16.bold.green("Split complete!"));
5844
+ console.log(chalk16.dim(`Created ${extractions.length} files in ${specName}`));
5576
5845
  console.log("");
5577
5846
  }
5578
5847
  async function addSubSpecLinks(content, subSpecs) {
@@ -5640,13 +5909,13 @@ async function compactSpec(specPath, options) {
5640
5909
  }
5641
5910
  const config = await loadConfig();
5642
5911
  const cwd = process.cwd();
5643
- const specsDir = path12.join(cwd, config.specsDir);
5912
+ const specsDir = path13.join(cwd, config.specsDir);
5644
5913
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
5645
5914
  if (!resolvedPath) {
5646
5915
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
5647
5916
  }
5648
- const specName = path12.basename(resolvedPath);
5649
- const readmePath = path12.join(resolvedPath, "README.md");
5917
+ const specName = path13.basename(resolvedPath);
5918
+ const readmePath = path13.join(resolvedPath, "README.md");
5650
5919
  const content = await readFile(readmePath, "utf-8");
5651
5920
  const parsedRemoves = parseRemoveSpecs(options.removes);
5652
5921
  validateNoOverlaps2(parsedRemoves);
@@ -5657,7 +5926,7 @@ async function compactSpec(specPath, options) {
5657
5926
  await executeCompact(readmePath, specName, content, parsedRemoves);
5658
5927
  } catch (error) {
5659
5928
  if (error instanceof Error) {
5660
- console.error(chalk15.red(`Error: ${error.message}`));
5929
+ console.error(chalk16.red(`Error: ${error.message}`));
5661
5930
  }
5662
5931
  throw error;
5663
5932
  }
@@ -5696,9 +5965,9 @@ function validateNoOverlaps2(removes) {
5696
5965
  }
5697
5966
  }
5698
5967
  async function displayDryRun2(specName, content, removes) {
5699
- console.log(chalk15.bold.cyan(`\u{1F4CB} Compact Preview: ${specName}`));
5968
+ console.log(chalk16.bold.cyan(`\u{1F4CB} Compact Preview: ${specName}`));
5700
5969
  console.log("");
5701
- console.log(chalk15.bold("Would remove:"));
5970
+ console.log(chalk16.bold("Would remove:"));
5702
5971
  console.log("");
5703
5972
  let totalLines = 0;
5704
5973
  for (const remove of removes) {
@@ -5707,29 +5976,29 @@ async function displayDryRun2(specName, content, removes) {
5707
5976
  const removedContent = extractLines(content, remove.startLine, remove.endLine);
5708
5977
  const previewLines = removedContent.split("\n").slice(0, 3);
5709
5978
  console.log(` Lines ${remove.startLine}-${remove.endLine} (${lineCount} lines)`);
5710
- console.log(chalk15.dim(" Preview:"));
5979
+ console.log(chalk16.dim(" Preview:"));
5711
5980
  for (const line of previewLines) {
5712
- console.log(chalk15.dim(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
5981
+ console.log(chalk16.dim(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
5713
5982
  }
5714
5983
  if (removedContent.split("\n").length > 3) {
5715
- console.log(chalk15.dim(` ... (${removedContent.split("\n").length - 3} more lines)`));
5984
+ console.log(chalk16.dim(` ... (${removedContent.split("\n").length - 3} more lines)`));
5716
5985
  }
5717
5986
  console.log("");
5718
5987
  }
5719
5988
  const originalLines = countLines(content);
5720
5989
  const remainingLines = originalLines - totalLines;
5721
5990
  const percentage = Math.round(totalLines / originalLines * 100);
5722
- console.log(chalk15.bold("Summary:"));
5723
- console.log(` Original lines: ${chalk15.cyan(originalLines)}`);
5724
- console.log(` Removing: ${chalk15.yellow(totalLines)} lines (${percentage}%)`);
5725
- console.log(` Remaining lines: ${chalk15.cyan(remainingLines)}`);
5991
+ console.log(chalk16.bold("Summary:"));
5992
+ console.log(` Original lines: ${chalk16.cyan(originalLines)}`);
5993
+ console.log(` Removing: ${chalk16.yellow(totalLines)} lines (${percentage}%)`);
5994
+ console.log(` Remaining lines: ${chalk16.cyan(remainingLines)}`);
5726
5995
  console.log("");
5727
- console.log(chalk15.dim("No files modified (dry run)"));
5728
- console.log(chalk15.dim("Run without --dry-run to apply changes"));
5996
+ console.log(chalk16.dim("No files modified (dry run)"));
5997
+ console.log(chalk16.dim("Run without --dry-run to apply changes"));
5729
5998
  console.log("");
5730
5999
  }
5731
6000
  async function executeCompact(readmePath, specName, content, removes) {
5732
- console.log(chalk15.bold.cyan(`\u{1F5DC}\uFE0F Compacting: ${specName}`));
6001
+ console.log(chalk16.bold.cyan(`\u{1F5DC}\uFE0F Compacting: ${specName}`));
5733
6002
  console.log("");
5734
6003
  const sorted = [...removes].sort((a, b) => b.startLine - a.startLine);
5735
6004
  let updatedContent = content;
@@ -5738,22 +6007,22 @@ async function executeCompact(readmePath, specName, content, removes) {
5738
6007
  const lineCount = remove.endLine - remove.startLine + 1;
5739
6008
  updatedContent = removeLines(updatedContent, remove.startLine, remove.endLine);
5740
6009
  totalRemoved += lineCount;
5741
- console.log(chalk15.green(`\u2713 Removed lines ${remove.startLine}-${remove.endLine} (${lineCount} lines)`));
6010
+ console.log(chalk16.green(`\u2713 Removed lines ${remove.startLine}-${remove.endLine} (${lineCount} lines)`));
5742
6011
  }
5743
6012
  await writeFile(readmePath, updatedContent, "utf-8");
5744
6013
  const originalLines = countLines(content);
5745
6014
  const finalLines = countLines(updatedContent);
5746
6015
  const percentage = Math.round(totalRemoved / originalLines * 100);
5747
6016
  console.log("");
5748
- console.log(chalk15.bold.green("Compaction complete!"));
5749
- console.log(chalk15.dim(`Removed ${totalRemoved} lines (${percentage}%)`));
5750
- console.log(chalk15.dim(`${originalLines} \u2192 ${finalLines} lines`));
6017
+ console.log(chalk16.bold.green("Compaction complete!"));
6018
+ console.log(chalk16.dim(`Removed ${totalRemoved} lines (${percentage}%)`));
6019
+ console.log(chalk16.dim(`${originalLines} \u2192 ${finalLines} lines`));
5751
6020
  console.log("");
5752
6021
  }
5753
6022
  marked.use(markedTerminal());
5754
6023
  async function readSpecContent(specPath, cwd = process.cwd()) {
5755
6024
  const config = await loadConfig(cwd);
5756
- const specsDir = path12.join(cwd, config.specsDir);
6025
+ const specsDir = path13.join(cwd, config.specsDir);
5757
6026
  let resolvedPath = null;
5758
6027
  let targetFile = null;
5759
6028
  const pathParts = specPath.split("/").filter((p) => p);
@@ -5762,9 +6031,9 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
5762
6031
  const filePart = pathParts[pathParts.length - 1];
5763
6032
  resolvedPath = await resolveSpecPath(specPart, cwd, specsDir);
5764
6033
  if (resolvedPath) {
5765
- targetFile = path12.join(resolvedPath, filePart);
6034
+ targetFile = path13.join(resolvedPath, filePart);
5766
6035
  try {
5767
- await fs8.access(targetFile);
6036
+ await fs9.access(targetFile);
5768
6037
  } catch {
5769
6038
  return null;
5770
6039
  }
@@ -5783,8 +6052,8 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
5783
6052
  if (!targetFile) {
5784
6053
  return null;
5785
6054
  }
5786
- const rawContent = await fs8.readFile(targetFile, "utf-8");
5787
- const fileName = path12.basename(targetFile);
6055
+ const rawContent = await fs9.readFile(targetFile, "utf-8");
6056
+ const fileName = path13.basename(targetFile);
5788
6057
  const isSubSpec = fileName !== config.structure.defaultFile;
5789
6058
  let frontmatter = null;
5790
6059
  if (!isSubSpec) {
@@ -5813,7 +6082,7 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
5813
6082
  }
5814
6083
  }
5815
6084
  const content = lines.slice(contentStartIndex).join("\n").trim();
5816
- const specName = path12.basename(resolvedPath);
6085
+ const specName = path13.basename(resolvedPath);
5817
6086
  const displayName = isSubSpec ? `${specName}/${fileName}` : specName;
5818
6087
  return {
5819
6088
  frontmatter,
@@ -5836,7 +6105,7 @@ function formatFrontmatter(frontmatter) {
5836
6105
  archived: "\u{1F4E6}"
5837
6106
  };
5838
6107
  const statusEmoji = statusEmojis[frontmatter.status] || "\u{1F4C4}";
5839
- lines.push(chalk15.bold(`${statusEmoji} Status: `) + chalk15.cyan(frontmatter.status));
6108
+ lines.push(chalk16.bold(`${statusEmoji} Status: `) + chalk16.cyan(frontmatter.status));
5840
6109
  if (frontmatter.priority) {
5841
6110
  const priorityEmojis = {
5842
6111
  low: "\u{1F7E2}",
@@ -5845,25 +6114,25 @@ function formatFrontmatter(frontmatter) {
5845
6114
  critical: "\u{1F534}"
5846
6115
  };
5847
6116
  const priorityEmoji = priorityEmojis[frontmatter.priority] || "";
5848
- lines.push(chalk15.bold(`${priorityEmoji} Priority: `) + chalk15.yellow(frontmatter.priority));
6117
+ lines.push(chalk16.bold(`${priorityEmoji} Priority: `) + chalk16.yellow(frontmatter.priority));
5849
6118
  }
5850
6119
  if (frontmatter.created) {
5851
- lines.push(chalk15.bold("\u{1F4C6} Created: ") + chalk15.gray(String(frontmatter.created)));
6120
+ lines.push(chalk16.bold("\u{1F4C6} Created: ") + chalk16.gray(String(frontmatter.created)));
5852
6121
  }
5853
6122
  if (frontmatter.tags && frontmatter.tags.length > 0) {
5854
- const tagStr = frontmatter.tags.map((tag) => chalk15.blue(`#${tag}`)).join(" ");
5855
- lines.push(chalk15.bold("\u{1F3F7}\uFE0F Tags: ") + tagStr);
6123
+ const tagStr = frontmatter.tags.map((tag) => chalk16.blue(`#${tag}`)).join(" ");
6124
+ lines.push(chalk16.bold("\u{1F3F7}\uFE0F Tags: ") + tagStr);
5856
6125
  }
5857
6126
  if (frontmatter.assignee) {
5858
- lines.push(chalk15.bold("\u{1F464} Assignee: ") + chalk15.green(frontmatter.assignee));
6127
+ lines.push(chalk16.bold("\u{1F464} Assignee: ") + chalk16.green(frontmatter.assignee));
5859
6128
  }
5860
6129
  const standardFields = ["status", "priority", "created", "tags", "assignee"];
5861
6130
  const customFields = Object.entries(frontmatter).filter(([key]) => !standardFields.includes(key)).filter(([_, value]) => value !== void 0 && value !== null);
5862
6131
  if (customFields.length > 0) {
5863
6132
  lines.push("");
5864
- lines.push(chalk15.bold("Custom Fields:"));
6133
+ lines.push(chalk16.bold("Custom Fields:"));
5865
6134
  for (const [key, value] of customFields) {
5866
- lines.push(` ${chalk15.gray(key)}: ${chalk15.white(String(value))}`);
6135
+ lines.push(` ${chalk16.gray(key)}: ${chalk16.white(String(value))}`);
5867
6136
  }
5868
6137
  }
5869
6138
  return lines.join("\n");
@@ -5871,11 +6140,11 @@ function formatFrontmatter(frontmatter) {
5871
6140
  function displayFormattedSpec(spec) {
5872
6141
  const output = [];
5873
6142
  output.push("");
5874
- output.push(chalk15.bold.cyan(`\u2501\u2501\u2501 ${spec.name} \u2501\u2501\u2501`));
6143
+ output.push(chalk16.bold.cyan(`\u2501\u2501\u2501 ${spec.name} \u2501\u2501\u2501`));
5875
6144
  output.push("");
5876
6145
  output.push(formatFrontmatter(spec.frontmatter));
5877
6146
  output.push("");
5878
- output.push(chalk15.gray("\u2500".repeat(60)));
6147
+ output.push(chalk16.gray("\u2500".repeat(60)));
5879
6148
  output.push("");
5880
6149
  return output.join("\n");
5881
6150
  }
@@ -5937,7 +6206,7 @@ function openCommand(specPath, options = {}) {
5937
6206
  async function openSpec(specPath, options = {}) {
5938
6207
  const cwd = process.cwd();
5939
6208
  const config = await loadConfig(cwd);
5940
- const specsDir = path12.join(cwd, config.specsDir);
6209
+ const specsDir = path13.join(cwd, config.specsDir);
5941
6210
  let resolvedPath = null;
5942
6211
  let targetFile = null;
5943
6212
  const pathParts = specPath.split("/").filter((p) => p);
@@ -5946,9 +6215,9 @@ async function openSpec(specPath, options = {}) {
5946
6215
  const filePart = pathParts[pathParts.length - 1];
5947
6216
  resolvedPath = await resolveSpecPath(specPart, cwd, specsDir);
5948
6217
  if (resolvedPath) {
5949
- targetFile = path12.join(resolvedPath, filePart);
6218
+ targetFile = path13.join(resolvedPath, filePart);
5950
6219
  try {
5951
- await fs8.access(targetFile);
6220
+ await fs9.access(targetFile);
5952
6221
  } catch {
5953
6222
  targetFile = null;
5954
6223
  }
@@ -5980,7 +6249,7 @@ async function openSpec(specPath, options = {}) {
5980
6249
  editor = "xdg-open";
5981
6250
  }
5982
6251
  }
5983
- console.log(chalk15.gray(`Opening ${targetFile} with ${editor}...`));
6252
+ console.log(chalk16.gray(`Opening ${targetFile} with ${editor}...`));
5984
6253
  const child = spawn(editor, [targetFile], {
5985
6254
  stdio: "inherit",
5986
6255
  shell: true
@@ -5988,21 +6257,21 @@ async function openSpec(specPath, options = {}) {
5988
6257
  const guiEditors = ["open", "start", "xdg-open", "code", "atom", "subl"];
5989
6258
  const editorCommand = editor.trim().split(" ")[0];
5990
6259
  if (editorCommand && guiEditors.includes(editorCommand)) {
5991
- return new Promise((resolve2, reject) => {
6260
+ return new Promise((resolve3, reject) => {
5992
6261
  child.on("error", (error) => {
5993
6262
  reject(new Error(`Error opening editor: ${error.message}`));
5994
6263
  });
5995
6264
  child.unref();
5996
- resolve2();
6265
+ resolve3();
5997
6266
  });
5998
6267
  } else {
5999
- return new Promise((resolve2, reject) => {
6268
+ return new Promise((resolve3, reject) => {
6000
6269
  child.on("error", (error) => {
6001
6270
  reject(new Error(`Error opening editor: ${error.message}`));
6002
6271
  });
6003
6272
  child.on("close", (code) => {
6004
6273
  if (code === 0) {
6005
- resolve2();
6274
+ resolve3();
6006
6275
  } else {
6007
6276
  reject(new Error(`Editor exited with code ${code}`));
6008
6277
  }
@@ -6062,8 +6331,8 @@ function uiCommand() {
6062
6331
  async function startUi(options) {
6063
6332
  const portNum = parseInt(options.port, 10);
6064
6333
  if (isNaN(portNum) || portNum < 1 || portNum > 65535) {
6065
- console.error(chalk15.red(`\u2717 Invalid port number: ${options.port}`));
6066
- console.log(chalk15.dim("Port must be between 1 and 65535"));
6334
+ console.error(chalk16.red(`\u2717 Invalid port number: ${options.port}`));
6335
+ console.log(chalk16.dim("Port must be between 1 and 65535"));
6067
6336
  throw new Error(`Invalid port: ${options.port}`);
6068
6337
  }
6069
6338
  const cwd = process.cwd();
@@ -6077,24 +6346,24 @@ async function startUi(options) {
6077
6346
  specsDir = join(cwd, config.specsDir);
6078
6347
  }
6079
6348
  if (!existsSync(specsDir)) {
6080
- console.error(chalk15.red(`\u2717 Specs directory not found: ${specsDir}`));
6081
- console.log(chalk15.dim("\nRun `lean-spec init` to initialize LeanSpec in this directory."));
6349
+ console.error(chalk16.red(`\u2717 Specs directory not found: ${specsDir}`));
6350
+ console.log(chalk16.dim("\nRun `lean-spec init` to initialize LeanSpec in this directory."));
6082
6351
  throw new Error(`Specs directory not found: ${specsDir}`);
6083
6352
  }
6084
6353
  } else {
6085
- console.log(chalk15.cyan("\u2192 Multi-project mode enabled"));
6354
+ console.log(chalk16.cyan("\u2192 Multi-project mode enabled"));
6086
6355
  if (options.addProject) {
6087
- console.log(chalk15.dim(` Adding project: ${options.addProject}`));
6356
+ console.log(chalk16.dim(` Adding project: ${options.addProject}`));
6088
6357
  }
6089
6358
  if (options.discover) {
6090
- console.log(chalk15.dim(` Will discover projects in: ${options.discover}`));
6359
+ console.log(chalk16.dim(` Will discover projects in: ${options.discover}`));
6091
6360
  }
6092
6361
  }
6093
6362
  if (options.dev) {
6094
6363
  const isLeanSpecMonorepo = checkIsLeanSpecMonorepo(cwd);
6095
6364
  if (!isLeanSpecMonorepo) {
6096
- console.error(chalk15.red(`\u2717 Development mode only works in the LeanSpec monorepo`));
6097
- console.log(chalk15.dim("Remove --dev flag to use production mode"));
6365
+ console.error(chalk16.red(`\u2717 Development mode only works in the LeanSpec monorepo`));
6366
+ console.log(chalk16.dim("Remove --dev flag to use production mode"));
6098
6367
  throw new Error("Not in LeanSpec monorepo");
6099
6368
  }
6100
6369
  const localUiDir = join(cwd, "packages/ui");
@@ -6116,15 +6385,15 @@ function checkIsLeanSpecMonorepo(cwd) {
6116
6385
  }
6117
6386
  }
6118
6387
  async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6119
- console.log(chalk15.dim("\u2192 Detected LeanSpec monorepo, using local ui package\n"));
6388
+ console.log(chalk16.dim("\u2192 Detected LeanSpec monorepo, using local ui package\n"));
6120
6389
  const repoRoot = resolve(uiDir, "..", "..");
6121
6390
  const packageManager = detectPackageManager2(repoRoot);
6122
6391
  if (options.dryRun) {
6123
- console.log(chalk15.cyan("Would run:"));
6124
- console.log(chalk15.dim(` cd ${uiDir}`));
6125
- console.log(chalk15.dim(` SPECS_MODE=${specsMode} SPECS_DIR=${specsDir} PORT=${options.port} ${packageManager} run dev`));
6392
+ console.log(chalk16.cyan("Would run:"));
6393
+ console.log(chalk16.dim(` cd ${uiDir}`));
6394
+ console.log(chalk16.dim(` SPECS_MODE=${specsMode} SPECS_DIR=${specsDir} PORT=${options.port} ${packageManager} run dev`));
6126
6395
  if (options.open) {
6127
- console.log(chalk15.dim(` open http://localhost:${options.port}`));
6396
+ console.log(chalk16.dim(` open http://localhost:${options.port}`));
6128
6397
  }
6129
6398
  return;
6130
6399
  }
@@ -6143,11 +6412,11 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6143
6412
  });
6144
6413
  const readyTimeout = setTimeout(async () => {
6145
6414
  spinner.succeed("Web UI running");
6146
- console.log(chalk15.green(`
6415
+ console.log(chalk16.green(`
6147
6416
  \u2728 LeanSpec UI: http://localhost:${options.port}
6148
6417
  `));
6149
6418
  if (options.multiProject) {
6150
- console.log(chalk15.cyan("Multi-project mode is active"));
6419
+ console.log(chalk16.cyan("Multi-project mode is active"));
6151
6420
  if (options.addProject) {
6152
6421
  try {
6153
6422
  const res = await fetch(`http://localhost:${options.port}/api/projects`, {
@@ -6156,16 +6425,16 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6156
6425
  body: JSON.stringify({ path: options.addProject })
6157
6426
  });
6158
6427
  if (res.ok) {
6159
- console.log(chalk15.green(` \u2713 Added project: ${options.addProject}`));
6428
+ console.log(chalk16.green(` \u2713 Added project: ${options.addProject}`));
6160
6429
  } else {
6161
- console.error(chalk15.red(` \u2717 Failed to add project: ${options.addProject}`));
6430
+ console.error(chalk16.red(` \u2717 Failed to add project: ${options.addProject}`));
6162
6431
  }
6163
6432
  } catch (e) {
6164
- console.error(chalk15.red(` \u2717 Failed to connect to server for adding project`));
6433
+ console.error(chalk16.red(` \u2717 Failed to connect to server for adding project`));
6165
6434
  }
6166
6435
  }
6167
6436
  if (options.discover) {
6168
- console.log(chalk15.dim(` Discovering projects in: ${options.discover}...`));
6437
+ console.log(chalk16.dim(` Discovering projects in: ${options.discover}...`));
6169
6438
  try {
6170
6439
  const res = await fetch(`http://localhost:${options.port}/api/local-projects/discover`, {
6171
6440
  method: "POST",
@@ -6175,7 +6444,7 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6175
6444
  if (res.ok) {
6176
6445
  const data = await res.json();
6177
6446
  const discovered = data.discovered || [];
6178
- console.log(chalk15.green(` \u2713 Found ${discovered.length} projects`));
6447
+ console.log(chalk16.green(` \u2713 Found ${discovered.length} projects`));
6179
6448
  for (const p of discovered) {
6180
6449
  const addRes = await fetch(`http://localhost:${options.port}/api/projects`, {
6181
6450
  method: "POST",
@@ -6183,27 +6452,27 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6183
6452
  body: JSON.stringify({ path: p.path })
6184
6453
  });
6185
6454
  if (addRes.ok) {
6186
- console.log(chalk15.dim(` + Added: ${p.name} (${p.path})`));
6455
+ console.log(chalk16.dim(` + Added: ${p.name} (${p.path})`));
6187
6456
  }
6188
6457
  }
6189
6458
  } else {
6190
- console.error(chalk15.red(` \u2717 Failed to discover projects`));
6459
+ console.error(chalk16.red(` \u2717 Failed to discover projects`));
6191
6460
  }
6192
6461
  } catch (e) {
6193
- console.error(chalk15.red(` \u2717 Failed to connect to server for discovery`));
6462
+ console.error(chalk16.red(` \u2717 Failed to connect to server for discovery`));
6194
6463
  }
6195
6464
  }
6196
6465
  }
6197
- console.log(chalk15.dim("\nPress Ctrl+C to stop\n"));
6466
+ console.log(chalk16.dim("\nPress Ctrl+C to stop\n"));
6198
6467
  if (options.open) {
6199
6468
  try {
6200
6469
  const openModule = await import('open');
6201
6470
  const open = openModule.default;
6202
6471
  await open(`http://localhost:${options.port}`);
6203
6472
  } catch (error) {
6204
- console.log(chalk15.yellow("\u26A0 Could not open browser automatically"));
6205
- console.log(chalk15.dim("Please visit the URL above manually\n"));
6206
- console.error(chalk15.dim(`Debug: ${error instanceof Error ? error.message : String(error)}`));
6473
+ console.log(chalk16.yellow("\u26A0 Could not open browser automatically"));
6474
+ console.log(chalk16.dim("Please visit the URL above manually\n"));
6475
+ console.error(chalk16.dim(`Debug: ${error instanceof Error ? error.message : String(error)}`));
6207
6476
  }
6208
6477
  }
6209
6478
  }, 3e3);
@@ -6220,7 +6489,7 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6220
6489
  }
6221
6490
  } catch (err) {
6222
6491
  }
6223
- console.log(chalk15.dim("\n\u2713 Web UI stopped"));
6492
+ console.log(chalk16.dim("\n\u2713 Web UI stopped"));
6224
6493
  process.exit(0);
6225
6494
  };
6226
6495
  process.once("SIGINT", () => shutdown("SIGINT"));
@@ -6234,7 +6503,7 @@ async function runLocalWeb(uiDir, specsDir, specsMode, options) {
6234
6503
  spinner.stop();
6235
6504
  if (code !== 0 && code !== null) {
6236
6505
  spinner.fail("Web UI failed to start");
6237
- console.error(chalk15.red(`
6506
+ console.error(chalk16.red(`
6238
6507
  Process exited with code ${code}`));
6239
6508
  process.exit(code);
6240
6509
  }
@@ -6242,12 +6511,12 @@ Process exited with code ${code}`));
6242
6511
  });
6243
6512
  }
6244
6513
  async function runPublishedUI(cwd, specsDir, specsMode, options) {
6245
- console.log(chalk15.dim("\u2192 Using published @leanspec/ui package\n"));
6514
+ console.log(chalk16.dim("\u2192 Using published @leanspec/ui package\n"));
6246
6515
  const packageManager = detectPackageManager2(cwd);
6247
6516
  const { command, args, preview } = buildUiRunner(packageManager, specsDir, specsMode, options.port, options.open, options.multiProject);
6248
6517
  if (options.dryRun) {
6249
- console.log(chalk15.cyan("Would run:"));
6250
- console.log(chalk15.dim(` ${preview}`));
6518
+ console.log(chalk16.cyan("Would run:"));
6519
+ console.log(chalk16.dim(` ${preview}`));
6251
6520
  return;
6252
6521
  }
6253
6522
  const child = spawn(command, args, {
@@ -6266,7 +6535,7 @@ async function runPublishedUI(cwd, specsDir, specsMode, options) {
6266
6535
  }
6267
6536
  } catch (err) {
6268
6537
  }
6269
- console.log(chalk15.dim("\n\u2713 Web UI stopped"));
6538
+ console.log(chalk16.dim("\n\u2713 Web UI stopped"));
6270
6539
  process.exit(0);
6271
6540
  };
6272
6541
  process.once("SIGINT", () => shutdownPublished("SIGINT"));
@@ -6280,14 +6549,14 @@ async function runPublishedUI(cwd, specsDir, specsMode, options) {
6280
6549
  process.exit(0);
6281
6550
  return;
6282
6551
  }
6283
- console.error(chalk15.red(`
6552
+ console.error(chalk16.red(`
6284
6553
  @leanspec/ui exited with code ${code}`));
6285
- console.log(chalk15.dim("Make sure npm can download @leanspec/ui (https://www.npmjs.com/package/@leanspec/ui)."));
6554
+ console.log(chalk16.dim("Make sure npm can download @leanspec/ui (https://www.npmjs.com/package/@leanspec/ui)."));
6286
6555
  process.exit(code);
6287
6556
  });
6288
6557
  child.on("error", (error) => {
6289
- console.error(chalk15.red(`Failed to launch @leanspec/ui: ${error instanceof Error ? error.message : String(error)}`));
6290
- console.log(chalk15.dim("You can also run it manually with `npx @leanspec/ui --specs <dir>`"));
6558
+ console.error(chalk16.red(`Failed to launch @leanspec/ui: ${error instanceof Error ? error.message : String(error)}`));
6559
+ console.log(chalk16.dim("You can also run it manually with `npx @leanspec/ui --specs <dir>`"));
6291
6560
  process.exit(1);
6292
6561
  });
6293
6562
  }
@@ -6590,7 +6859,7 @@ function createTool() {
6590
6859
  async function getDepsData(specPath, mode = "complete") {
6591
6860
  const config = await loadConfig();
6592
6861
  const cwd = process.cwd();
6593
- const specsDir = path12.join(cwd, config.specsDir);
6862
+ const specsDir = path13.join(cwd, config.specsDir);
6594
6863
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
6595
6864
  if (!resolvedPath) {
6596
6865
  throw new Error(`Spec not found: ${specPath}`);
@@ -7139,7 +7408,7 @@ function tokensTool() {
7139
7408
  try {
7140
7409
  const config = await loadConfig();
7141
7410
  const cwd = process.cwd();
7142
- const specsDir = path12.join(cwd, config.specsDir);
7411
+ const specsDir = path13.join(cwd, config.specsDir);
7143
7412
  const resolvedPath = await resolveSpecPath(input.specPath, cwd, specsDir);
7144
7413
  if (!resolvedPath) {
7145
7414
  return {
@@ -7150,7 +7419,7 @@ function tokensTool() {
7150
7419
  isError: true
7151
7420
  };
7152
7421
  }
7153
- const specName = path12.basename(resolvedPath);
7422
+ const specName = path13.basename(resolvedPath);
7154
7423
  const result = await counter.countSpec(resolvedPath, {
7155
7424
  detailed: input.detailed,
7156
7425
  includeSubSpecs: input.includeSubSpecs
@@ -7941,5 +8210,5 @@ if (import.meta.url === `file://${process.argv[1]}`) {
7941
8210
  }
7942
8211
 
7943
8212
  export { agentCommand, analyzeCommand, archiveCommand, boardCommand, checkCommand, compactCommand, createCommand, createMcpServer, depsCommand, examplesCommand, filesCommand, ganttCommand, initCommand, linkCommand, listCommand, mcpCommand, migrateCommand, openCommand, searchCommand, splitCommand, statsCommand, templatesCommand, timelineCommand, tokensCommand, uiCommand, unlinkCommand, updateCommand, viewCommand };
7944
- //# sourceMappingURL=chunk-BJHJ6IUO.js.map
7945
- //# sourceMappingURL=chunk-BJHJ6IUO.js.map
8213
+ //# sourceMappingURL=chunk-KTNU4LUR.js.map
8214
+ //# sourceMappingURL=chunk-KTNU4LUR.js.map