lean-spec 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,90 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.4] - 2025-11-10
11
+
12
+ ### Fixed
13
+ - Version now read dynamically from package.json instead of hardcoded in CLI
14
+ - Ensures version consistency across the package
15
+
16
+ ## [0.1.3] - 2025-11-10
17
+
18
+ ### Added
19
+
20
+ **New Commands:**
21
+ - `lean-spec migrate` - Migrate from existing tools (ADRs, RFCs, design docs) with AI assistance
22
+ - `lean-spec archive` - Archive completed specs with automatic frontmatter updates
23
+ - `lean-spec backfill` - Backfill timestamps and metadata from git history
24
+
25
+ **Documentation Enhancements:**
26
+ - Complete documentation site overhaul with improved information architecture
27
+ - AI-assisted spec writing guide with philosophy and best practices
28
+ - Migration guides for teams coming from ADRs, RFCs, and other tools
29
+ - First principles documentation (Context Economy, Signal-to-Noise, etc.)
30
+ - Comprehensive core concepts guide with practical examples
31
+
32
+ **Quality & Validation:**
33
+ - Enhanced `lean-spec validate` with complexity analysis
34
+ - Spec relationship clarity with bidirectional `related` and directional `depends_on`
35
+ - Improved frontmatter handling and metadata management
36
+
37
+ ### Changed
38
+
39
+ **User Experience:**
40
+ - Unified dashboard combining board view with project health metrics
41
+ - Pattern-aware list grouping with visual icons and better organization
42
+ - Improved init flow with pattern selection
43
+ - Enhanced stats dashboard with actionable insights
44
+ - Better MCP error handling and stability
45
+
46
+ **Documentation:**
47
+ - Restructured docs with clearer navigation and information flow
48
+ - Updated README with AI-first positioning
49
+ - Comprehensive examples and use cases
50
+ - Improved CLI command documentation
51
+
52
+ ### Fixed
53
+ - MCP server stability issues with frontmatter parsing
54
+ - TypeScript type errors in migrate command
55
+ - Documentation accuracy issues across all guides
56
+ - Frontmatter handling edge cases
57
+
58
+ ### Philosophy
59
+
60
+ This UAT release operationalizes LeanSpec's five first principles:
61
+ 1. **Context Economy** - Specs fit in working memory (<400 lines)
62
+ 2. **Signal-to-Noise** - Every word informs decisions
63
+ 3. **Intent Over Implementation** - Capture why, not just how
64
+ 4. **Bridge the Gap** - Both human and AI understand
65
+ 5. **Progressive Disclosure** - Add complexity only when needed
66
+
67
+ **Notable Completed Specs in this Release:**
68
+ - 063: Migration from existing tools
69
+ - 062: Documentation information architecture v2
70
+ - 061: AI-assisted spec writing
71
+ - 060: Core concepts coherence
72
+ - 058: Docs overview polish
73
+ - 057: Docs validation comprehensive
74
+ - 056: Docs site accuracy audit
75
+ - 055: README redesign (AI-first)
76
+ - 054: Validate output (lint-style)
77
+ - 052: Branding assets
78
+ - 051: First principles documentation
79
+ - 049: LeanSpec first principles foundation
80
+ - 048: Spec complexity analysis
81
+ - 047: Git backfill timestamps
82
+ - 046: Stats dashboard refactor
83
+ - 045: Unified dashboard
84
+ - 044: Spec relationships clarity
85
+
86
+ **Testing:**
87
+ - All 261 tests passing (100% pass rate)
88
+ - Zero critical bugs
89
+ - MCP server stable
90
+ - Documentation site builds cleanly
91
+
92
+ **Ready for:** UAT testing before official 0.2.0 launch
93
+
10
94
  ## [0.1.2] - 2025-11-10
11
95
 
12
96
  ### Changed
@@ -127,6 +211,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
127
211
  - Gray-matter for frontmatter parsing
128
212
  - Dayjs for date handling
129
213
 
214
+ [0.1.4]: https://github.com/codervisor/lean-spec/releases/tag/v0.1.4
215
+ [0.1.3]: https://github.com/codervisor/lean-spec/releases/tag/v0.1.3
130
216
  [0.1.2]: https://github.com/codervisor/lean-spec/releases/tag/v0.1.2
131
217
  [0.1.1]: https://github.com/codervisor/lean-spec/releases/tag/v0.1.1
132
218
  [0.1.0]: https://github.com/codervisor/lean-spec/releases/tag/v0.1.0
@@ -141,13 +141,13 @@ async function loadSubFiles(specDir, options = {}) {
141
141
  if (entry.name === "README.md") continue;
142
142
  if (entry.isDirectory()) continue;
143
143
  const filePath = path2.join(specDir, entry.name);
144
- const stat4 = await fs2.stat(filePath);
144
+ const stat5 = await fs2.stat(filePath);
145
145
  const ext = path2.extname(entry.name).toLowerCase();
146
146
  const isDocument = ext === ".md";
147
147
  const subFile = {
148
148
  name: entry.name,
149
149
  path: filePath,
150
- size: stat4.size,
150
+ size: stat5.size,
151
151
  type: isDocument ? "document" : "asset"
152
152
  };
153
153
  if (isDocument && options.includeContent) {
@@ -734,7 +734,7 @@ ${options.description}`
734
734
  );
735
735
  }
736
736
  } catch (error) {
737
- throw new Error(`Template not found: ${templatePath}. Run: lspec init`);
737
+ throw new Error(`Template not found: ${templatePath}. Run: lean-spec init`);
738
738
  }
739
739
  await fs5.writeFile(specFile, content, "utf-8");
740
740
  console.log(chalk4.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
@@ -755,6 +755,10 @@ async function archiveSpec(specPath) {
755
755
  if (!resolvedPath) {
756
756
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
757
757
  }
758
+ const specFile = await getSpecFile(resolvedPath, config.structure.defaultFile);
759
+ if (specFile) {
760
+ await updateFrontmatter(specFile, { status: "archived" });
761
+ }
758
762
  const archiveDir = path7.join(specsDir, "archived");
759
763
  await fs6.mkdir(archiveDir, { recursive: true });
760
764
  const specName = path7.basename(resolvedPath);
@@ -870,7 +874,7 @@ async function listSpecs(options = {}) {
870
874
  await fs7.access(specsDir);
871
875
  } catch {
872
876
  console.log("");
873
- console.log("No specs directory found. Initialize with: lspec init");
877
+ console.log("No specs directory found. Initialize with: lean-spec init");
874
878
  console.log("");
875
879
  return;
876
880
  }
@@ -1359,7 +1363,7 @@ async function listTemplates(cwd = process.cwd()) {
1359
1363
  await fs8.access(templatesDir);
1360
1364
  } catch {
1361
1365
  console.log(chalk9.yellow("No templates directory found."));
1362
- console.log(chalk9.gray("Run: lspec init"));
1366
+ console.log(chalk9.gray("Run: lean-spec init"));
1363
1367
  console.log("");
1364
1368
  return;
1365
1369
  }
@@ -1382,12 +1386,12 @@ async function listTemplates(cwd = process.cwd()) {
1382
1386
  console.log(chalk9.cyan("Available files:"));
1383
1387
  for (const file of templateFiles) {
1384
1388
  const filePath = path11.join(templatesDir, file);
1385
- const stat4 = await fs8.stat(filePath);
1386
- const sizeKB = (stat4.size / 1024).toFixed(1);
1389
+ const stat5 = await fs8.stat(filePath);
1390
+ const sizeKB = (stat5.size / 1024).toFixed(1);
1387
1391
  console.log(` ${file} (${sizeKB} KB)`);
1388
1392
  }
1389
1393
  console.log("");
1390
- console.log(chalk9.gray("Use templates with: lspec create <name> --template=<template-name>"));
1394
+ console.log(chalk9.gray("Use templates with: lean-spec create <name> --template=<template-name>"));
1391
1395
  console.log("");
1392
1396
  }
1393
1397
  async function showTemplate(templateName, cwd = process.cwd()) {
@@ -1423,7 +1427,7 @@ async function addTemplate(name, file, cwd = process.cwd()) {
1423
1427
  console.error(chalk9.red(`Template file not found: ${file}`));
1424
1428
  console.error(chalk9.gray(`Expected at: ${templatePath}`));
1425
1429
  console.error(
1426
- chalk9.yellow("Create the file first or use: lspec templates copy <source> <target>")
1430
+ chalk9.yellow("Create the file first or use: lean-spec templates copy <source> <target>")
1427
1431
  );
1428
1432
  process.exit(1);
1429
1433
  }
@@ -1436,7 +1440,7 @@ async function addTemplate(name, file, cwd = process.cwd()) {
1436
1440
  config.templates[name] = file;
1437
1441
  await saveConfig(config, cwd);
1438
1442
  console.log(chalk9.green(`\u2713 Added template: ${name} \u2192 ${file}`));
1439
- console.log(chalk9.gray(` Use with: lspec create <spec-name> --template=${name}`));
1443
+ console.log(chalk9.gray(` Use with: lean-spec create <spec-name> --template=${name}`));
1440
1444
  }
1441
1445
  async function removeTemplate(name, cwd = process.cwd()) {
1442
1446
  const config = await loadConfig(cwd);
@@ -1484,7 +1488,7 @@ async function copyTemplate(source, target, cwd = process.cwd()) {
1484
1488
  await saveConfig(config, cwd);
1485
1489
  console.log(chalk9.green(`\u2713 Registered template: ${templateName}`));
1486
1490
  console.log(chalk9.gray(` Edit: ${targetPath}`));
1487
- console.log(chalk9.gray(` Use with: lspec create <spec-name> --template=${templateName}`));
1491
+ console.log(chalk9.gray(` Use with: lean-spec create <spec-name> --template=${templateName}`));
1488
1492
  }
1489
1493
 
1490
1494
  // src/commands/init.ts
@@ -1820,7 +1824,7 @@ async function initProject() {
1820
1824
  console.log("Next steps:");
1821
1825
  console.log(chalk11.gray(" - Review and customize AGENTS.md"));
1822
1826
  console.log(chalk11.gray(" - Check out example spec in specs/"));
1823
- console.log(chalk11.gray(" - Create your first spec: lspec create my-feature"));
1827
+ console.log(chalk11.gray(" - Create your first spec: lean-spec create my-feature"));
1824
1828
  console.log("");
1825
1829
  }
1826
1830
 
@@ -2786,6 +2790,220 @@ async function validateCommand(options = {}) {
2786
2790
  return !hasErrors;
2787
2791
  }
2788
2792
 
2793
+ // src/commands/migrate.ts
2794
+ import * as fs13 from "fs/promises";
2795
+ import * as path17 from "path";
2796
+ async function migrateCommand(inputPath, options = {}) {
2797
+ const config = await loadConfig();
2798
+ try {
2799
+ const stats = await fs13.stat(inputPath);
2800
+ if (!stats.isDirectory()) {
2801
+ console.error("\x1B[31m\u274C Error:\x1B[0m Input path must be a directory");
2802
+ process.exit(1);
2803
+ }
2804
+ } catch (error) {
2805
+ console.error(`\x1B[31m\u274C Error:\x1B[0m Path not found: ${inputPath}`);
2806
+ process.exit(1);
2807
+ }
2808
+ console.log(`\x1B[36mScanning:\x1B[0m ${inputPath}
2809
+ `);
2810
+ const documents = await scanDocuments(inputPath);
2811
+ if (documents.length === 0) {
2812
+ console.error(`\x1B[31m\u274C Error:\x1B[0m No documents found in ${inputPath}`);
2813
+ console.error(" Check path and try again");
2814
+ process.exit(1);
2815
+ }
2816
+ console.log(`\x1B[32m\u2713\x1B[0m Found ${documents.length} document${documents.length === 1 ? "" : "s"}
2817
+ `);
2818
+ if (options.aiProvider) {
2819
+ await migrateWithAI(inputPath, documents, options);
2820
+ } else {
2821
+ await outputManualInstructions(inputPath, documents, config);
2822
+ }
2823
+ }
2824
+ async function scanDocuments(dirPath) {
2825
+ const documents = [];
2826
+ async function scanRecursive(currentPath) {
2827
+ const entries = await fs13.readdir(currentPath, { withFileTypes: true });
2828
+ for (const entry of entries) {
2829
+ const fullPath = path17.join(currentPath, entry.name);
2830
+ if (entry.isDirectory()) {
2831
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
2832
+ await scanRecursive(fullPath);
2833
+ }
2834
+ } else if (entry.isFile()) {
2835
+ if (entry.name.endsWith(".md") || entry.name.endsWith(".markdown")) {
2836
+ const stats = await fs13.stat(fullPath);
2837
+ documents.push({
2838
+ path: fullPath,
2839
+ name: entry.name,
2840
+ size: stats.size
2841
+ });
2842
+ }
2843
+ }
2844
+ }
2845
+ }
2846
+ await scanRecursive(dirPath);
2847
+ return documents;
2848
+ }
2849
+ async function outputManualInstructions(inputPath, documents, config) {
2850
+ const specsDir = config.specsDir || "specs";
2851
+ console.log("\u2550".repeat(70));
2852
+ console.log("\x1B[1m\x1B[36m\u{1F4CB} LeanSpec Migration Instructions\x1B[0m");
2853
+ console.log("\u2550".repeat(70));
2854
+ console.log();
2855
+ console.log("\x1B[1mSource Location:\x1B[0m");
2856
+ console.log(` ${inputPath} (${documents.length} documents found)`);
2857
+ console.log();
2858
+ console.log("\x1B[1mMigration Prompt:\x1B[0m");
2859
+ console.log(" Copy this prompt to your AI assistant (Copilot, Claude, ChatGPT, etc.):");
2860
+ console.log();
2861
+ console.log("\u2500".repeat(70));
2862
+ console.log();
2863
+ console.log("You are helping migrate specification documents to LeanSpec format.");
2864
+ console.log();
2865
+ console.log(`\x1B[1mSource:\x1B[0m ${inputPath}`);
2866
+ console.log();
2867
+ console.log("\x1B[1mYour Task:\x1B[0m");
2868
+ console.log("1. Analyze the source documents to understand their format and structure");
2869
+ console.log("2. For each document, extract:");
2870
+ console.log(" - Title/name");
2871
+ console.log(" - Status (map to: planned, in-progress, complete, archived)");
2872
+ console.log(" - Creation date");
2873
+ console.log(" - Priority (if present)");
2874
+ console.log(" - Main content sections");
2875
+ console.log(" - Relationships to other documents");
2876
+ console.log();
2877
+ console.log("3. Migrate each document by running these commands:");
2878
+ console.log();
2879
+ console.log(" # Create spec");
2880
+ console.log(" lean-spec create <name>");
2881
+ console.log();
2882
+ console.log(" # Set metadata (NEVER edit frontmatter manually)");
2883
+ console.log(" lean-spec update <name> --status <status>");
2884
+ console.log(" lean-spec update <name> --priority <priority>");
2885
+ console.log(" lean-spec update <name> --tags <tag1,tag2>");
2886
+ console.log();
2887
+ console.log(" # Edit content with your preferred tool");
2888
+ console.log(" # Map original sections to LeanSpec structure:");
2889
+ console.log(" # - Overview: Problem statement and context");
2890
+ console.log(" # - Design: Technical approach and decisions");
2891
+ console.log(" # - Plan: Implementation steps (if applicable)");
2892
+ console.log(" # - Test: Validation criteria (if applicable)");
2893
+ console.log(" # - Notes: Additional context, trade-offs, alternatives");
2894
+ console.log();
2895
+ console.log("4. After migration, run:");
2896
+ console.log();
2897
+ console.log(" lean-spec validate # Check for issues");
2898
+ console.log(" lean-spec board # Verify migration");
2899
+ console.log();
2900
+ console.log("\x1B[1mImportant Rules:\x1B[0m");
2901
+ console.log("- Preserve decision rationale and context");
2902
+ console.log("- Map status appropriately to LeanSpec states");
2903
+ console.log("- Link related specs using `related` field (manual frontmatter edit)");
2904
+ console.log("- Follow LeanSpec first principles: clarity over completeness");
2905
+ console.log("- Keep specs under 400 lines (split if needed)");
2906
+ console.log();
2907
+ console.log("\u2500".repeat(70));
2908
+ console.log();
2909
+ console.log("\x1B[36m\u2139\x1B[0m \x1B[1mTip:\x1B[0m For AI-assisted migration, use:");
2910
+ console.log(" \x1B[90mlean-spec migrate <path> --with copilot\x1B[0m");
2911
+ console.log();
2912
+ }
2913
+ async function migrateWithAI(inputPath, documents, options) {
2914
+ const provider = options.aiProvider;
2915
+ console.log(`\x1B[36m\u{1F916} AI-Assisted Migration:\x1B[0m ${provider}
2916
+ `);
2917
+ const tool = await verifyAITool(provider);
2918
+ if (!tool.installed) {
2919
+ console.error(`\x1B[31m\u274C ${tool.name} CLI not found\x1B[0m`);
2920
+ console.error(` Install: ${tool.installCmd}`);
2921
+ console.error(" Or run without --with flag for manual instructions");
2922
+ process.exit(1);
2923
+ }
2924
+ if (!tool.compatible) {
2925
+ console.error(`\x1B[31m\u274C ${tool.name} version ${tool.version} too old\x1B[0m`);
2926
+ console.error(` Required: >=${tool.minVersion}`);
2927
+ console.error(` Update: ${tool.updateCmd}`);
2928
+ process.exit(1);
2929
+ }
2930
+ console.log(`\x1B[32m\u2713\x1B[0m ${tool.name} CLI verified (v${tool.version})
2931
+ `);
2932
+ console.log("\x1B[33m\u26A0 AI-assisted migration is not yet fully implemented\x1B[0m");
2933
+ console.log(" This feature will automatically execute migration via AI CLI tools.");
2934
+ console.log();
2935
+ console.log(" For now, use manual mode (without --with flag) to get migration instructions.");
2936
+ console.log();
2937
+ }
2938
+ async function verifyAITool(provider) {
2939
+ const tools = {
2940
+ copilot: {
2941
+ name: "GitHub Copilot CLI",
2942
+ cliCommand: "github-copilot-cli",
2943
+ installCmd: "npm install -g @githubnext/github-copilot-cli",
2944
+ updateCmd: "npm update -g @githubnext/github-copilot-cli",
2945
+ versionCmd: "github-copilot-cli --version",
2946
+ minVersion: "0.1.0"
2947
+ },
2948
+ claude: {
2949
+ name: "Claude CLI",
2950
+ cliCommand: "claude",
2951
+ installCmd: "pip install claude-cli",
2952
+ updateCmd: "pip install --upgrade claude-cli",
2953
+ versionCmd: "claude --version",
2954
+ minVersion: "1.0.0"
2955
+ },
2956
+ gemini: {
2957
+ name: "Gemini CLI",
2958
+ cliCommand: "gemini-cli",
2959
+ installCmd: "npm install -g @google/gemini-cli",
2960
+ updateCmd: "npm update -g @google/gemini-cli",
2961
+ versionCmd: "gemini-cli --version",
2962
+ minVersion: "1.0.0"
2963
+ }
2964
+ };
2965
+ const toolDef = tools[provider];
2966
+ let installed = false;
2967
+ let version;
2968
+ try {
2969
+ const { execSync: execSync3 } = await import("child_process");
2970
+ execSync3(`which ${toolDef.cliCommand}`, { stdio: "ignore" });
2971
+ installed = true;
2972
+ try {
2973
+ const versionOutput = execSync3(toolDef.versionCmd, {
2974
+ encoding: "utf-8",
2975
+ stdio: ["ignore", "pipe", "ignore"]
2976
+ });
2977
+ const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
2978
+ if (versionMatch) {
2979
+ version = versionMatch[1];
2980
+ }
2981
+ } catch {
2982
+ version = "unknown";
2983
+ }
2984
+ } catch {
2985
+ installed = false;
2986
+ }
2987
+ const compatible = installed && (version === "unknown" || version !== void 0 && satisfiesVersion(version, toolDef.minVersion));
2988
+ return {
2989
+ ...toolDef,
2990
+ installed,
2991
+ version,
2992
+ compatible
2993
+ };
2994
+ }
2995
+ function satisfiesVersion(version, minVersion) {
2996
+ const vParts = version.split(".").map(Number);
2997
+ const minParts = minVersion.split(".").map(Number);
2998
+ for (let i = 0; i < 3; i++) {
2999
+ const v = vParts[i] || 0;
3000
+ const min = minParts[i] || 0;
3001
+ if (v > min) return true;
3002
+ if (v < min) return false;
3003
+ }
3004
+ return true;
3005
+ }
3006
+
2789
3007
  // src/commands/board.ts
2790
3008
  import chalk15 from "chalk";
2791
3009
 
@@ -3374,9 +3592,9 @@ async function statsCommand(options) {
3374
3592
  console.log(` Throughput ${chalk16.cyan((velocityMetrics.throughput.perWeek / 7 * 7).toFixed(1))}/week ${throughputTrend}`);
3375
3593
  console.log(` WIP ${chalk16.yellow(velocityMetrics.wip.current)} specs`);
3376
3594
  console.log("");
3377
- console.log(chalk16.dim("\u{1F4A1} Use `lspec stats --full` for detailed analytics"));
3378
- console.log(chalk16.dim(" Use `lspec stats --velocity` for velocity breakdown"));
3379
- console.log(chalk16.dim(" Use `lspec stats --timeline` for activity timeline"));
3595
+ console.log(chalk16.dim("\u{1F4A1} Use `lean-spec stats --full` for detailed analytics"));
3596
+ console.log(chalk16.dim(" Use `lean-spec stats --velocity` for velocity breakdown"));
3597
+ console.log(chalk16.dim(" Use `lean-spec stats --timeline` for activity timeline"));
3380
3598
  console.log("");
3381
3599
  return;
3382
3600
  }
@@ -3723,12 +3941,12 @@ function escapeRegex(str) {
3723
3941
 
3724
3942
  // src/commands/deps.ts
3725
3943
  import chalk18 from "chalk";
3726
- import * as path17 from "path";
3944
+ import * as path18 from "path";
3727
3945
  async function depsCommand(specPath, options) {
3728
3946
  await autoCheckIfEnabled();
3729
3947
  const config = await loadConfig();
3730
3948
  const cwd = process.cwd();
3731
- const specsDir = path17.join(cwd, config.specsDir);
3949
+ const specsDir = path18.join(cwd, config.specsDir);
3732
3950
  const resolvedPath = await resolveSpecPath(specPath, cwd, specsDir);
3733
3951
  if (!resolvedPath) {
3734
3952
  throw new Error(`Spec not found: ${sanitizeUserInput(specPath)}`);
@@ -3804,8 +4022,8 @@ function findDependencies(spec, specMap) {
3804
4022
  if (dep) {
3805
4023
  deps.push(dep);
3806
4024
  } else {
3807
- for (const [path19, s] of specMap.entries()) {
3808
- if (path19.includes(depPath)) {
4025
+ for (const [path20, s] of specMap.entries()) {
4026
+ if (path20.includes(depPath)) {
3809
4027
  deps.push(s);
3810
4028
  break;
3811
4029
  }
@@ -3837,8 +4055,8 @@ function findRelated(spec, specMap) {
3837
4055
  if (rel) {
3838
4056
  related.push(rel);
3839
4057
  } else {
3840
- for (const [path19, s] of specMap.entries()) {
3841
- if (path19.includes(relPath)) {
4058
+ for (const [path20, s] of specMap.entries()) {
4059
+ if (path20.includes(relPath)) {
3842
4060
  related.push(s);
3843
4061
  break;
3844
4062
  }
@@ -4243,8 +4461,8 @@ function renderTimelineBar(spec, startDate, endDate, weeks, today) {
4243
4461
  }
4244
4462
 
4245
4463
  // src/commands/viewer.ts
4246
- import * as fs13 from "fs/promises";
4247
- import * as path18 from "path";
4464
+ import * as fs14 from "fs/promises";
4465
+ import * as path19 from "path";
4248
4466
  import chalk21 from "chalk";
4249
4467
  import { marked } from "marked";
4250
4468
  import { markedTerminal } from "marked-terminal";
@@ -4252,7 +4470,7 @@ import { spawn } from "child_process";
4252
4470
  marked.use(markedTerminal());
4253
4471
  async function readSpecContent(specPath, cwd = process.cwd()) {
4254
4472
  const config = await loadConfig(cwd);
4255
- const specsDir = path18.join(cwd, config.specsDir);
4473
+ const specsDir = path19.join(cwd, config.specsDir);
4256
4474
  let resolvedPath = null;
4257
4475
  let targetFile = null;
4258
4476
  const pathParts = specPath.split("/").filter((p) => p);
@@ -4261,9 +4479,9 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
4261
4479
  const filePart = pathParts[pathParts.length - 1];
4262
4480
  resolvedPath = await resolveSpecPath(specPart, cwd, specsDir);
4263
4481
  if (resolvedPath) {
4264
- targetFile = path18.join(resolvedPath, filePart);
4482
+ targetFile = path19.join(resolvedPath, filePart);
4265
4483
  try {
4266
- await fs13.access(targetFile);
4484
+ await fs14.access(targetFile);
4267
4485
  } catch {
4268
4486
  return null;
4269
4487
  }
@@ -4282,8 +4500,8 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
4282
4500
  if (!targetFile) {
4283
4501
  return null;
4284
4502
  }
4285
- const rawContent = await fs13.readFile(targetFile, "utf-8");
4286
- const fileName = path18.basename(targetFile);
4503
+ const rawContent = await fs14.readFile(targetFile, "utf-8");
4504
+ const fileName = path19.basename(targetFile);
4287
4505
  const isSubSpec = fileName !== config.structure.defaultFile;
4288
4506
  let frontmatter = null;
4289
4507
  if (!isSubSpec) {
@@ -4312,7 +4530,7 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
4312
4530
  }
4313
4531
  }
4314
4532
  const content = lines.slice(contentStartIndex).join("\n").trim();
4315
- const specName = path18.basename(resolvedPath);
4533
+ const specName = path19.basename(resolvedPath);
4316
4534
  const displayName = isSubSpec ? `${specName}/${fileName}` : specName;
4317
4535
  return {
4318
4536
  frontmatter,
@@ -4379,7 +4597,7 @@ function displayFormattedSpec(spec) {
4379
4597
  async function viewCommand(specPath, options = {}) {
4380
4598
  const spec = await readSpecContent(specPath, process.cwd());
4381
4599
  if (!spec) {
4382
- throw new Error(`Spec not found: ${specPath}. Try: lspec list`);
4600
+ throw new Error(`Spec not found: ${specPath}. Try: lean-spec list`);
4383
4601
  }
4384
4602
  if (options.json) {
4385
4603
  const jsonOutput = {
@@ -4402,7 +4620,7 @@ async function viewCommand(specPath, options = {}) {
4402
4620
  async function openCommand(specPath, options = {}) {
4403
4621
  const cwd = process.cwd();
4404
4622
  const config = await loadConfig(cwd);
4405
- const specsDir = path18.join(cwd, config.specsDir);
4623
+ const specsDir = path19.join(cwd, config.specsDir);
4406
4624
  let resolvedPath = null;
4407
4625
  let targetFile = null;
4408
4626
  const pathParts = specPath.split("/").filter((p) => p);
@@ -4411,9 +4629,9 @@ async function openCommand(specPath, options = {}) {
4411
4629
  const filePart = pathParts[pathParts.length - 1];
4412
4630
  resolvedPath = await resolveSpecPath(specPart, cwd, specsDir);
4413
4631
  if (resolvedPath) {
4414
- targetFile = path18.join(resolvedPath, filePart);
4632
+ targetFile = path19.join(resolvedPath, filePart);
4415
4633
  try {
4416
- await fs13.access(targetFile);
4634
+ await fs14.access(targetFile);
4417
4635
  } catch {
4418
4636
  targetFile = null;
4419
4637
  }
@@ -5415,6 +5633,7 @@ export {
5415
5633
  initProject,
5416
5634
  filesCommand,
5417
5635
  validateCommand,
5636
+ migrateCommand,
5418
5637
  boardCommand,
5419
5638
  statsCommand,
5420
5639
  searchCommand,
@@ -5426,4 +5645,4 @@ export {
5426
5645
  createMcpServer,
5427
5646
  mcpCommand
5428
5647
  };
5429
- //# sourceMappingURL=chunk-OXTU3PN4.js.map
5648
+ //# sourceMappingURL=chunk-S6TGAL75.js.map