lean-spec 0.2.7-dev.20251127055844 → 0.2.7-dev.20251127073145

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,7 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import * as path17 from 'path';
7
7
  import { dirname, join, resolve } from 'path';
8
8
  import { z } from 'zod';
9
- import * as fs11 from 'fs/promises';
9
+ import * as fs12 from 'fs/promises';
10
10
  import { readFile, writeFile } from 'fs/promises';
11
11
  import chalk20 from 'chalk';
12
12
  import { Command } from 'commander';
@@ -43,7 +43,7 @@ var DEFAULT_CONFIG = {
43
43
  async function loadConfig(cwd = process.cwd()) {
44
44
  const configPath = path17.join(cwd, ".lean-spec", "config.json");
45
45
  try {
46
- const content = await fs11.readFile(configPath, "utf-8");
46
+ const content = await fs12.readFile(configPath, "utf-8");
47
47
  const userConfig = JSON.parse(content);
48
48
  const merged = { ...DEFAULT_CONFIG, ...userConfig };
49
49
  normalizeLegacyPattern(merged);
@@ -55,8 +55,8 @@ async function loadConfig(cwd = process.cwd()) {
55
55
  async function saveConfig(config, cwd = process.cwd()) {
56
56
  const configDir = path17.join(cwd, ".lean-spec");
57
57
  const configPath = path17.join(configDir, "config.json");
58
- await fs11.mkdir(configDir, { recursive: true });
59
- await fs11.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
58
+ await fs12.mkdir(configDir, { recursive: true });
59
+ await fs12.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
60
60
  }
61
61
  function getToday(format = "YYYYMMDD") {
62
62
  const now = /* @__PURE__ */ new Date();
@@ -136,12 +136,12 @@ function extractGroup(extractor, dateFormat = "YYYYMMDD", fields, fallback) {
136
136
  async function loadSubFiles(specDir, options = {}) {
137
137
  const subFiles = [];
138
138
  try {
139
- const entries = await fs11.readdir(specDir, { withFileTypes: true });
139
+ const entries = await fs12.readdir(specDir, { withFileTypes: true });
140
140
  for (const entry of entries) {
141
141
  if (entry.name === "README.md") continue;
142
142
  if (entry.isDirectory()) continue;
143
143
  const filePath = path17.join(specDir, entry.name);
144
- const stat6 = await fs11.stat(filePath);
144
+ const stat6 = await fs12.stat(filePath);
145
145
  const ext = path17.extname(entry.name).toLowerCase();
146
146
  const isDocument = ext === ".md";
147
147
  const subFile = {
@@ -151,7 +151,7 @@ async function loadSubFiles(specDir, options = {}) {
151
151
  type: isDocument ? "document" : "asset"
152
152
  };
153
153
  if (isDocument && options.includeContent) {
154
- subFile.content = await fs11.readFile(filePath, "utf-8");
154
+ subFile.content = await fs12.readFile(filePath, "utf-8");
155
155
  }
156
156
  subFiles.push(subFile);
157
157
  }
@@ -171,14 +171,14 @@ async function loadAllSpecs(options = {}) {
171
171
  const specsDir = path17.join(cwd, config.specsDir);
172
172
  const specs = [];
173
173
  try {
174
- await fs11.access(specsDir);
174
+ await fs12.access(specsDir);
175
175
  } catch {
176
176
  return [];
177
177
  }
178
178
  const specPattern = /^(\d{2,})-/;
179
179
  async function loadSpecsFromDir(dir, relativePath = "") {
180
180
  try {
181
- const entries = await fs11.readdir(dir, { withFileTypes: true });
181
+ const entries = await fs12.readdir(dir, { withFileTypes: true });
182
182
  for (const entry of entries) {
183
183
  if (!entry.isDirectory()) continue;
184
184
  if (entry.name === "archived" && relativePath === "") continue;
@@ -212,7 +212,7 @@ async function loadAllSpecs(options = {}) {
212
212
  frontmatter
213
213
  };
214
214
  if (options.includeContent) {
215
- specInfo.content = await fs11.readFile(specFile, "utf-8");
215
+ specInfo.content = await fs12.readFile(specFile, "utf-8");
216
216
  }
217
217
  if (options.includeSubFiles) {
218
218
  specInfo.subFiles = await loadSubFiles(entryPath, {
@@ -287,7 +287,7 @@ async function getSpec(specPath) {
287
287
  fullPath = path17.join(specsDir, specPath);
288
288
  }
289
289
  try {
290
- await fs11.access(fullPath);
290
+ await fs12.access(fullPath);
291
291
  } catch {
292
292
  return null;
293
293
  }
@@ -295,7 +295,7 @@ async function getSpec(specPath) {
295
295
  if (!specFile) return null;
296
296
  const frontmatter = await parseFrontmatter(specFile, config);
297
297
  if (!frontmatter) return null;
298
- const content = await fs11.readFile(specFile, "utf-8");
298
+ const content = await fs12.readFile(specFile, "utf-8");
299
299
  const relativePath = path17.relative(specsDir, fullPath);
300
300
  const parts = relativePath.split(path17.sep);
301
301
  const date = parts[0] === "archived" ? parts[1] : parts[0];
@@ -319,7 +319,7 @@ async function getGlobalNextSeq(specsDir, digits) {
319
319
  const specPattern = createSpecDirPattern();
320
320
  async function scanDirectory(dir) {
321
321
  try {
322
- const entries = await fs11.readdir(dir, { withFileTypes: true });
322
+ const entries = await fs12.readdir(dir, { withFileTypes: true });
323
323
  for (const entry of entries) {
324
324
  if (!entry.isDirectory()) continue;
325
325
  const match = entry.name.match(specPattern);
@@ -349,7 +349,7 @@ async function getGlobalNextSeq(specsDir, digits) {
349
349
  async function resolveSpecPath(specPath, cwd, specsDir) {
350
350
  if (path17.isAbsolute(specPath)) {
351
351
  try {
352
- await fs11.access(specPath);
352
+ await fs12.access(specPath);
353
353
  return specPath;
354
354
  } catch {
355
355
  return null;
@@ -357,13 +357,13 @@ async function resolveSpecPath(specPath, cwd, specsDir) {
357
357
  }
358
358
  const cwdPath = path17.resolve(cwd, specPath);
359
359
  try {
360
- await fs11.access(cwdPath);
360
+ await fs12.access(cwdPath);
361
361
  return cwdPath;
362
362
  } catch {
363
363
  }
364
364
  const specsPath = path17.join(specsDir, specPath);
365
365
  try {
366
- await fs11.access(specsPath);
366
+ await fs12.access(specsPath);
367
367
  return specsPath;
368
368
  } catch {
369
369
  }
@@ -381,7 +381,7 @@ async function searchBySequence(specsDir, seqNum) {
381
381
  const specPattern = createSpecDirPattern();
382
382
  async function scanDirectory(dir) {
383
383
  try {
384
- const entries = await fs11.readdir(dir, { withFileTypes: true });
384
+ const entries = await fs12.readdir(dir, { withFileTypes: true });
385
385
  for (const entry of entries) {
386
386
  if (!entry.isDirectory()) continue;
387
387
  const match = entry.name.match(specPattern);
@@ -404,7 +404,7 @@ async function searchBySequence(specsDir, seqNum) {
404
404
  async function searchInAllDirectories(specsDir, specName) {
405
405
  async function scanDirectory(dir) {
406
406
  try {
407
- const entries = await fs11.readdir(dir, { withFileTypes: true });
407
+ const entries = await fs12.readdir(dir, { withFileTypes: true });
408
408
  for (const entry of entries) {
409
409
  if (!entry.isDirectory()) continue;
410
410
  if (entry.name === specName) {
@@ -754,11 +754,11 @@ async function loadSpecContent(specPath) {
754
754
  const specDir = spec.fullPath;
755
755
  let content = "";
756
756
  try {
757
- const files = await fs11.readdir(specDir);
757
+ const files = await fs12.readdir(specDir);
758
758
  const mdFiles = files.filter((f) => f.endsWith(".md"));
759
759
  for (const file of mdFiles) {
760
760
  const filePath = path17.join(specDir, file);
761
- const fileContent = await fs11.readFile(filePath, "utf-8");
761
+ const fileContent = await fs12.readFile(filePath, "utf-8");
762
762
  content += `
763
763
 
764
764
  ### ${file}
@@ -766,14 +766,14 @@ async function loadSpecContent(specPath) {
766
766
  ${fileContent}`;
767
767
  }
768
768
  } catch {
769
- content = await fs11.readFile(spec.filePath, "utf-8");
769
+ content = await fs12.readFile(spec.filePath, "utf-8");
770
770
  }
771
771
  return content;
772
772
  }
773
773
  async function createWorktree(specPath, specName, cwd) {
774
774
  const worktreePath = path17.join(cwd, ".worktrees", `spec-${specName}`);
775
775
  const branchName = `feature/${specName}`;
776
- await fs11.mkdir(path17.join(cwd, ".worktrees"), { recursive: true });
776
+ await fs12.mkdir(path17.join(cwd, ".worktrees"), { recursive: true });
777
777
  return new Promise((resolve3, reject) => {
778
778
  const child = spawn("git", ["worktree", "add", worktreePath, "-b", branchName], {
779
779
  cwd,
@@ -1452,7 +1452,7 @@ var TokenCounter = class {
1452
1452
  * Count tokens in a single file
1453
1453
  */
1454
1454
  async countFile(filePath, options = {}) {
1455
- const content = await fs11.readFile(filePath, "utf-8");
1455
+ const content = await fs12.readFile(filePath, "utf-8");
1456
1456
  const tokens = await this.countString(content);
1457
1457
  const lines = content.split("\n").length;
1458
1458
  const result = {
@@ -1472,11 +1472,11 @@ var TokenCounter = class {
1472
1472
  * Count tokens in a spec (including sub-specs if requested)
1473
1473
  */
1474
1474
  async countSpec(specPath, options = {}) {
1475
- const stats = await fs11.stat(specPath);
1475
+ const stats = await fs12.stat(specPath);
1476
1476
  if (stats.isFile()) {
1477
1477
  return this.countFile(specPath, options);
1478
1478
  }
1479
- const files = await fs11.readdir(specPath);
1479
+ const files = await fs12.readdir(specPath);
1480
1480
  const mdFiles = files.filter((f) => f.endsWith(".md"));
1481
1481
  const filesToCount = [];
1482
1482
  if (mdFiles.includes("README.md")) {
@@ -1502,7 +1502,7 @@ var TokenCounter = class {
1502
1502
  }
1503
1503
  for (const file of filesToCount) {
1504
1504
  const filePath = path17.join(specPath, file);
1505
- const content = await fs11.readFile(filePath, "utf-8");
1505
+ const content = await fs12.readFile(filePath, "utf-8");
1506
1506
  const tokens = await this.countString(content);
1507
1507
  const lines = content.split("\n").length;
1508
1508
  fileCounts.push({
@@ -1838,7 +1838,7 @@ var ComplexityValidator = class {
1838
1838
  let subSpecCount = 0;
1839
1839
  try {
1840
1840
  const specDir = path17.dirname(spec.filePath);
1841
- const files = await fs11.readdir(specDir);
1841
+ const files = await fs12.readdir(specDir);
1842
1842
  const mdFiles = files.filter(
1843
1843
  (f) => f.endsWith(".md") && f !== "README.md"
1844
1844
  );
@@ -3266,7 +3266,7 @@ async function getGitInfo() {
3266
3266
  async function getProjectName(cwd = process.cwd()) {
3267
3267
  try {
3268
3268
  const packageJsonPath = path17.join(cwd, "package.json");
3269
- const content = await fs11.readFile(packageJsonPath, "utf-8");
3269
+ const content = await fs12.readFile(packageJsonPath, "utf-8");
3270
3270
  const packageJson2 = JSON.parse(content);
3271
3271
  return packageJson2.name || null;
3272
3272
  } catch {
@@ -3505,7 +3505,7 @@ async function createSpec(name, options = {}) {
3505
3505
  const config = await loadConfig();
3506
3506
  const cwd = process.cwd();
3507
3507
  const specsDir = path17.join(cwd, config.specsDir);
3508
- await fs11.mkdir(specsDir, { recursive: true });
3508
+ await fs12.mkdir(specsDir, { recursive: true });
3509
3509
  const seq = await getGlobalNextSeq(specsDir, config.structure.sequenceDigits);
3510
3510
  let specRelativePath;
3511
3511
  if (config.structure.pattern === "flat") {
@@ -3528,14 +3528,14 @@ async function createSpec(name, options = {}) {
3528
3528
  const specDir = path17.join(specsDir, specRelativePath);
3529
3529
  const specFile = path17.join(specDir, config.structure.defaultFile);
3530
3530
  try {
3531
- await fs11.access(specDir);
3531
+ await fs12.access(specDir);
3532
3532
  throw new Error(`Spec already exists: ${sanitizeUserInput(specDir)}`);
3533
3533
  } catch (error) {
3534
3534
  if (error.code === "ENOENT") ; else {
3535
3535
  throw error;
3536
3536
  }
3537
3537
  }
3538
- await fs11.mkdir(specDir, { recursive: true });
3538
+ await fs12.mkdir(specDir, { recursive: true });
3539
3539
  const templatesDir = path17.join(cwd, ".lean-spec", "templates");
3540
3540
  let templateName;
3541
3541
  if (options.template) {
@@ -3550,17 +3550,17 @@ async function createSpec(name, options = {}) {
3550
3550
  }
3551
3551
  let templatePath = path17.join(templatesDir, templateName);
3552
3552
  try {
3553
- await fs11.access(templatePath);
3553
+ await fs12.access(templatePath);
3554
3554
  } catch {
3555
3555
  const legacyPath = path17.join(templatesDir, "spec-template.md");
3556
3556
  try {
3557
- await fs11.access(legacyPath);
3557
+ await fs12.access(legacyPath);
3558
3558
  templatePath = legacyPath;
3559
3559
  templateName = "spec-template.md";
3560
3560
  } catch {
3561
3561
  const readmePath = path17.join(templatesDir, "README.md");
3562
3562
  try {
3563
- await fs11.access(readmePath);
3563
+ await fs12.access(readmePath);
3564
3564
  templatePath = readmePath;
3565
3565
  templateName = "README.md";
3566
3566
  } catch {
@@ -3571,7 +3571,7 @@ async function createSpec(name, options = {}) {
3571
3571
  let content;
3572
3572
  let varContext;
3573
3573
  try {
3574
- const template = await fs11.readFile(templatePath, "utf-8");
3574
+ const template = await fs12.readFile(templatePath, "utf-8");
3575
3575
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3576
3576
  const title = options.title || name;
3577
3577
  varContext = await buildVariableContext(config, { name: title, date });
@@ -3615,9 +3615,9 @@ ${options.description}`
3615
3615
  } catch (error) {
3616
3616
  throw new Error(`Template not found: ${templatePath}. Run: lean-spec init`);
3617
3617
  }
3618
- await fs11.writeFile(specFile, content, "utf-8");
3618
+ await fs12.writeFile(specFile, content, "utf-8");
3619
3619
  try {
3620
- const templateFiles = await fs11.readdir(templatesDir);
3620
+ const templateFiles = await fs12.readdir(templatesDir);
3621
3621
  const additionalFiles = templateFiles.filter(
3622
3622
  (f) => f.endsWith(".md") && f !== templateName && f !== "spec-template.md" && f !== config.structure.defaultFile
3623
3623
  );
@@ -3625,9 +3625,9 @@ ${options.description}`
3625
3625
  for (const file of additionalFiles) {
3626
3626
  const srcPath = path17.join(templatesDir, file);
3627
3627
  const destPath = path17.join(specDir, file);
3628
- let fileContent = await fs11.readFile(srcPath, "utf-8");
3628
+ let fileContent = await fs12.readFile(srcPath, "utf-8");
3629
3629
  fileContent = resolveVariables(fileContent, varContext);
3630
- await fs11.writeFile(destPath, fileContent, "utf-8");
3630
+ await fs12.writeFile(destPath, fileContent, "utf-8");
3631
3631
  }
3632
3632
  console.log(chalk20.green(`\u2713 Created: ${sanitizeUserInput(specDir)}/`));
3633
3633
  console.log(chalk20.gray(` Files: ${config.structure.defaultFile}, ${additionalFiles.join(", ")}`));
@@ -3672,10 +3672,10 @@ async function archiveSpec(specPath) {
3672
3672
  await updateFrontmatter(specFile, { status: "archived" });
3673
3673
  }
3674
3674
  const archiveDir = path17.join(specsDir, "archived");
3675
- await fs11.mkdir(archiveDir, { recursive: true });
3675
+ await fs12.mkdir(archiveDir, { recursive: true });
3676
3676
  const specName = path17.basename(resolvedPath);
3677
3677
  const archivePath = path17.join(archiveDir, specName);
3678
- await fs11.rename(resolvedPath, archivePath);
3678
+ await fs12.rename(resolvedPath, archivePath);
3679
3679
  console.log(chalk20.green(`\u2713 Archived: ${sanitizeUserInput(archivePath)}`));
3680
3680
  }
3681
3681
 
@@ -3727,7 +3727,7 @@ async function listSpecs(options = {}) {
3727
3727
  const cwd = process.cwd();
3728
3728
  const specsDir = path17.join(cwd, config.specsDir);
3729
3729
  try {
3730
- await fs11.access(specsDir);
3730
+ await fs12.access(specsDir);
3731
3731
  } catch {
3732
3732
  console.log("");
3733
3733
  console.log("No specs directory found. Initialize with: lean-spec init");
@@ -4355,14 +4355,14 @@ async function listTemplates(cwd = process.cwd()) {
4355
4355
  console.log(chalk20.green("=== Project Templates ==="));
4356
4356
  console.log("");
4357
4357
  try {
4358
- await fs11.access(templatesDir);
4358
+ await fs12.access(templatesDir);
4359
4359
  } catch {
4360
4360
  console.log(chalk20.yellow("No templates directory found."));
4361
4361
  console.log(chalk20.gray("Run: lean-spec init"));
4362
4362
  console.log("");
4363
4363
  return;
4364
4364
  }
4365
- const files = await fs11.readdir(templatesDir);
4365
+ const files = await fs12.readdir(templatesDir);
4366
4366
  const templateFiles = files.filter((f) => f.endsWith(".md"));
4367
4367
  if (templateFiles.length === 0) {
4368
4368
  console.log(chalk20.yellow("No templates found."));
@@ -4381,7 +4381,7 @@ async function listTemplates(cwd = process.cwd()) {
4381
4381
  console.log(chalk20.cyan("Available files:"));
4382
4382
  for (const file of templateFiles) {
4383
4383
  const filePath = path17.join(templatesDir, file);
4384
- const stat6 = await fs11.stat(filePath);
4384
+ const stat6 = await fs12.stat(filePath);
4385
4385
  const sizeKB = (stat6.size / 1024).toFixed(1);
4386
4386
  console.log(` ${file} (${sizeKB} KB)`);
4387
4387
  }
@@ -4400,7 +4400,7 @@ async function showTemplate(templateName, cwd = process.cwd()) {
4400
4400
  const templateFile = config.templates[templateName];
4401
4401
  const templatePath = path17.join(templatesDir, templateFile);
4402
4402
  try {
4403
- const content = await fs11.readFile(templatePath, "utf-8");
4403
+ const content = await fs12.readFile(templatePath, "utf-8");
4404
4404
  console.log("");
4405
4405
  console.log(chalk20.cyan(`=== Template: ${templateName} (${templateFile}) ===`));
4406
4406
  console.log("");
@@ -4417,7 +4417,7 @@ async function addTemplate(name, file, cwd = process.cwd()) {
4417
4417
  const templatesDir = path17.join(cwd, ".lean-spec", "templates");
4418
4418
  const templatePath = path17.join(templatesDir, file);
4419
4419
  try {
4420
- await fs11.access(templatePath);
4420
+ await fs12.access(templatePath);
4421
4421
  } catch {
4422
4422
  console.error(chalk20.red(`Template file not found: ${file}`));
4423
4423
  console.error(chalk20.gray(`Expected at: ${templatePath}`));
@@ -4465,7 +4465,7 @@ async function copyTemplate(source, target, cwd = process.cwd()) {
4465
4465
  }
4466
4466
  const sourcePath = path17.join(templatesDir, sourceFile);
4467
4467
  try {
4468
- await fs11.access(sourcePath);
4468
+ await fs12.access(sourcePath);
4469
4469
  } catch {
4470
4470
  console.error(chalk20.red(`Source template not found: ${source}`));
4471
4471
  console.error(chalk20.gray(`Expected at: ${sourcePath}`));
@@ -4473,7 +4473,7 @@ async function copyTemplate(source, target, cwd = process.cwd()) {
4473
4473
  }
4474
4474
  const targetFile = target.endsWith(".md") ? target : `${target}.md`;
4475
4475
  const targetPath = path17.join(templatesDir, targetFile);
4476
- await fs11.copyFile(sourcePath, targetPath);
4476
+ await fs12.copyFile(sourcePath, targetPath);
4477
4477
  console.log(chalk20.green(`\u2713 Copied: ${sourceFile} \u2192 ${targetFile}`));
4478
4478
  if (!config.templates) {
4479
4479
  config.templates = {};
@@ -4619,7 +4619,7 @@ async function configDirExists(dirName) {
4619
4619
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
4620
4620
  if (!homeDir) return false;
4621
4621
  try {
4622
- await fs11.access(path17.join(homeDir, dirName));
4622
+ await fs12.access(path17.join(homeDir, dirName));
4623
4623
  return true;
4624
4624
  } catch {
4625
4625
  return false;
@@ -4638,7 +4638,7 @@ async function extensionInstalled(extensionId) {
4638
4638
  ];
4639
4639
  for (const extDir of extensionDirs) {
4640
4640
  try {
4641
- const entries = await fs11.readdir(extDir);
4641
+ const entries = await fs12.readdir(extDir);
4642
4642
  if (entries.some((e) => e.toLowerCase().startsWith(extensionId.toLowerCase()))) {
4643
4643
  return true;
4644
4644
  }
@@ -4721,7 +4721,7 @@ async function createAgentToolSymlinks(cwd, selectedTools) {
4721
4721
  const targetPath = path17.join(cwd, file);
4722
4722
  try {
4723
4723
  try {
4724
- await fs11.access(targetPath);
4724
+ await fs12.access(targetPath);
4725
4725
  results.push({ file, skipped: true });
4726
4726
  continue;
4727
4727
  } catch {
@@ -4736,10 +4736,10 @@ async function createAgentToolSymlinks(cwd, selectedTools) {
4736
4736
 
4737
4737
  See AGENTS.md for the full LeanSpec AI agent instructions.
4738
4738
  `;
4739
- await fs11.writeFile(targetPath, windowsContent, "utf-8");
4739
+ await fs12.writeFile(targetPath, windowsContent, "utf-8");
4740
4740
  results.push({ file, created: true, error: "created as copy (Windows)" });
4741
4741
  } else {
4742
- await fs11.symlink("AGENTS.md", targetPath);
4742
+ await fs12.symlink("AGENTS.md", targetPath);
4743
4743
  results.push({ file, created: true });
4744
4744
  }
4745
4745
  } catch (error) {
@@ -4760,7 +4760,7 @@ async function detectExistingSystemPrompts(cwd) {
4760
4760
  const found = [];
4761
4761
  for (const file of commonFiles) {
4762
4762
  try {
4763
- await fs11.access(path17.join(cwd, file));
4763
+ await fs12.access(path17.join(cwd, file));
4764
4764
  found.push(file);
4765
4765
  } catch {
4766
4766
  }
@@ -4772,13 +4772,13 @@ async function handleExistingFiles(action, existingFiles, templateDir, cwd, vari
4772
4772
  const filePath = path17.join(cwd, file);
4773
4773
  const templateFilePath = path17.join(templateDir, file);
4774
4774
  try {
4775
- await fs11.access(templateFilePath);
4775
+ await fs12.access(templateFilePath);
4776
4776
  } catch {
4777
4777
  continue;
4778
4778
  }
4779
4779
  if (action === "merge-ai" && file === "AGENTS.md") {
4780
- const existing = await fs11.readFile(filePath, "utf-8");
4781
- let template = await fs11.readFile(templateFilePath, "utf-8");
4780
+ const existing = await fs12.readFile(filePath, "utf-8");
4781
+ let template = await fs12.readFile(templateFilePath, "utf-8");
4782
4782
  for (const [key, value] of Object.entries(variables)) {
4783
4783
  template = template.replace(new RegExp(`\\{${key}\\}`, "g"), value);
4784
4784
  }
@@ -4814,8 +4814,8 @@ Create a single consolidated AGENTS.md that:
4814
4814
  - Maintains clear structure and readability
4815
4815
  - Removes any duplicate or conflicting guidance
4816
4816
  `;
4817
- await fs11.mkdir(path17.dirname(promptPath), { recursive: true });
4818
- await fs11.writeFile(promptPath, aiPrompt, "utf-8");
4817
+ await fs12.mkdir(path17.dirname(promptPath), { recursive: true });
4818
+ await fs12.writeFile(promptPath, aiPrompt, "utf-8");
4819
4819
  console.log(chalk20.green(`\u2713 Created AI consolidation prompt`));
4820
4820
  console.log(chalk20.cyan(` \u2192 ${promptPath}`));
4821
4821
  console.log("");
@@ -4826,8 +4826,8 @@ Create a single consolidated AGENTS.md that:
4826
4826
  console.log(chalk20.gray(" 4. Review and commit the result"));
4827
4827
  console.log("");
4828
4828
  } else if (action === "merge-append" && file === "AGENTS.md") {
4829
- const existing = await fs11.readFile(filePath, "utf-8");
4830
- let template = await fs11.readFile(templateFilePath, "utf-8");
4829
+ const existing = await fs12.readFile(filePath, "utf-8");
4830
+ let template = await fs12.readFile(templateFilePath, "utf-8");
4831
4831
  for (const [key, value] of Object.entries(variables)) {
4832
4832
  template = template.replace(new RegExp(`\\{${key}\\}`, "g"), value);
4833
4833
  }
@@ -4838,26 +4838,26 @@ Create a single consolidated AGENTS.md that:
4838
4838
  ## LeanSpec Integration
4839
4839
 
4840
4840
  ${template.split("\n").slice(1).join("\n")}`;
4841
- await fs11.writeFile(filePath, merged, "utf-8");
4841
+ await fs12.writeFile(filePath, merged, "utf-8");
4842
4842
  console.log(chalk20.green(`\u2713 Appended LeanSpec section to ${file}`));
4843
4843
  console.log(chalk20.yellow(" \u26A0 Note: May be verbose. Consider consolidating later."));
4844
4844
  } else if (action === "overwrite") {
4845
4845
  const backupPath = `${filePath}.backup`;
4846
- await fs11.rename(filePath, backupPath);
4846
+ await fs12.rename(filePath, backupPath);
4847
4847
  console.log(chalk20.yellow(`\u2713 Backed up ${file} \u2192 ${file}.backup`));
4848
- let content = await fs11.readFile(templateFilePath, "utf-8");
4848
+ let content = await fs12.readFile(templateFilePath, "utf-8");
4849
4849
  for (const [key, value] of Object.entries(variables)) {
4850
4850
  content = content.replace(new RegExp(`\\{${key}\\}`, "g"), value);
4851
4851
  }
4852
- await fs11.writeFile(filePath, content, "utf-8");
4852
+ await fs12.writeFile(filePath, content, "utf-8");
4853
4853
  console.log(chalk20.green(`\u2713 Created new ${file}`));
4854
4854
  console.log(chalk20.gray(` \u{1F4A1} Your original content is preserved in ${file}.backup`));
4855
4855
  }
4856
4856
  }
4857
4857
  }
4858
4858
  async function copyDirectory(src, dest, skipFiles = [], variables = {}) {
4859
- await fs11.mkdir(dest, { recursive: true });
4860
- const entries = await fs11.readdir(src, { withFileTypes: true });
4859
+ await fs12.mkdir(dest, { recursive: true });
4860
+ const entries = await fs12.readdir(src, { withFileTypes: true });
4861
4861
  for (const entry of entries) {
4862
4862
  const srcPath = path17.join(src, entry.name);
4863
4863
  const destPath = path17.join(dest, entry.name);
@@ -4868,13 +4868,13 @@ async function copyDirectory(src, dest, skipFiles = [], variables = {}) {
4868
4868
  await copyDirectory(srcPath, destPath, skipFiles, variables);
4869
4869
  } else {
4870
4870
  try {
4871
- await fs11.access(destPath);
4871
+ await fs12.access(destPath);
4872
4872
  } catch {
4873
- let content = await fs11.readFile(srcPath, "utf-8");
4873
+ let content = await fs12.readFile(srcPath, "utf-8");
4874
4874
  for (const [key, value] of Object.entries(variables)) {
4875
4875
  content = content.replace(new RegExp(`\\{${key}\\}`, "g"), value);
4876
4876
  }
4877
- await fs11.writeFile(destPath, content, "utf-8");
4877
+ await fs12.writeFile(destPath, content, "utf-8");
4878
4878
  }
4879
4879
  }
4880
4880
  }
@@ -4882,7 +4882,7 @@ async function copyDirectory(src, dest, skipFiles = [], variables = {}) {
4882
4882
  async function getProjectName2(cwd) {
4883
4883
  try {
4884
4884
  const packageJsonPath = path17.join(cwd, "package.json");
4885
- const content = await fs11.readFile(packageJsonPath, "utf-8");
4885
+ const content = await fs12.readFile(packageJsonPath, "utf-8");
4886
4886
  const pkg = JSON.parse(content);
4887
4887
  if (pkg.name) {
4888
4888
  return pkg.name;
@@ -5107,8 +5107,164 @@ async function attemptAutoMerge(cwd, promptPath, autoExecute) {
5107
5107
  return false;
5108
5108
  }
5109
5109
  }
5110
+ async function handleReinitialize(cwd, skipPrompts, forceReinit) {
5111
+ const specsDir = path17.join(cwd, "specs");
5112
+ let specCount = 0;
5113
+ try {
5114
+ const entries = await fs12.readdir(specsDir, { withFileTypes: true });
5115
+ specCount = entries.filter((e) => e.isDirectory()).length;
5116
+ } catch {
5117
+ }
5118
+ console.log("");
5119
+ console.log(chalk20.yellow("\u26A0 LeanSpec is already initialized in this directory."));
5120
+ if (specCount > 0) {
5121
+ console.log(chalk20.cyan(` Found ${specCount} spec${specCount > 1 ? "s" : ""} in specs/`));
5122
+ }
5123
+ console.log("");
5124
+ if (forceReinit) {
5125
+ console.log(chalk20.gray("Force flag detected. Resetting configuration..."));
5126
+ return "reset-config";
5127
+ }
5128
+ if (skipPrompts) {
5129
+ console.log(chalk20.gray("Using safe upgrade (preserving all existing files)"));
5130
+ return "upgrade";
5131
+ }
5132
+ const strategy = await select({
5133
+ message: "What would you like to do?",
5134
+ choices: [
5135
+ {
5136
+ name: "Upgrade configuration (recommended)",
5137
+ value: "upgrade",
5138
+ description: "Update config to latest version. Keeps specs and AGENTS.md untouched."
5139
+ },
5140
+ {
5141
+ name: "Reset configuration",
5142
+ value: "reset-config",
5143
+ description: "Fresh config from template. Keeps specs/ directory."
5144
+ },
5145
+ {
5146
+ name: "Full reset",
5147
+ value: "full-reset",
5148
+ description: "Remove .lean-spec/, specs/, and AGENTS.md. Start completely fresh."
5149
+ },
5150
+ {
5151
+ name: "Cancel",
5152
+ value: "cancel",
5153
+ description: "Exit without changes."
5154
+ }
5155
+ ]
5156
+ });
5157
+ if (strategy === "full-reset") {
5158
+ const warnings = [];
5159
+ if (specCount > 0) {
5160
+ warnings.push(`${specCount} spec${specCount > 1 ? "s" : ""} in specs/`);
5161
+ }
5162
+ try {
5163
+ await fs12.access(path17.join(cwd, "AGENTS.md"));
5164
+ warnings.push("AGENTS.md");
5165
+ } catch {
5166
+ }
5167
+ if (warnings.length > 0) {
5168
+ console.log("");
5169
+ console.log(chalk20.red("\u26A0 This will permanently delete:"));
5170
+ for (const warning of warnings) {
5171
+ console.log(chalk20.red(` - ${warning}`));
5172
+ }
5173
+ console.log("");
5174
+ const confirmed = await confirm({
5175
+ message: "Are you sure you want to continue?",
5176
+ default: false
5177
+ });
5178
+ if (!confirmed) {
5179
+ console.log(chalk20.gray("Cancelled."));
5180
+ return "cancel";
5181
+ }
5182
+ }
5183
+ console.log(chalk20.gray("Performing full reset..."));
5184
+ await fs12.rm(path17.join(cwd, ".lean-spec"), { recursive: true, force: true });
5185
+ console.log(chalk20.gray(" Removed .lean-spec/"));
5186
+ try {
5187
+ await fs12.rm(specsDir, { recursive: true, force: true });
5188
+ console.log(chalk20.gray(" Removed specs/"));
5189
+ } catch {
5190
+ }
5191
+ for (const file of ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]) {
5192
+ try {
5193
+ await fs12.rm(path17.join(cwd, file), { force: true });
5194
+ console.log(chalk20.gray(` Removed ${file}`));
5195
+ } catch {
5196
+ }
5197
+ }
5198
+ }
5199
+ return strategy;
5200
+ }
5201
+ async function upgradeConfig(cwd) {
5202
+ const configPath = path17.join(cwd, ".lean-spec", "config.json");
5203
+ let existingConfig;
5204
+ try {
5205
+ const content = await fs12.readFile(configPath, "utf-8");
5206
+ existingConfig = JSON.parse(content);
5207
+ } catch {
5208
+ console.error(chalk20.red("Error reading existing config"));
5209
+ process.exit(1);
5210
+ }
5211
+ const templateConfigPath = path17.join(TEMPLATES_DIR, "standard", "config.json");
5212
+ let templateConfig;
5213
+ try {
5214
+ const content = await fs12.readFile(templateConfigPath, "utf-8");
5215
+ templateConfig = JSON.parse(content).config;
5216
+ } catch {
5217
+ console.error(chalk20.red("Error reading template config"));
5218
+ process.exit(1);
5219
+ }
5220
+ const upgradedConfig = {
5221
+ ...templateConfig,
5222
+ ...existingConfig,
5223
+ // Deep merge structure
5224
+ structure: {
5225
+ ...templateConfig.structure,
5226
+ ...existingConfig.structure
5227
+ }
5228
+ };
5229
+ const templatesDir = path17.join(cwd, ".lean-spec", "templates");
5230
+ try {
5231
+ await fs12.mkdir(templatesDir, { recursive: true });
5232
+ } catch {
5233
+ }
5234
+ const templateFiles = ["spec-template.md"];
5235
+ let templatesUpdated = false;
5236
+ for (const file of templateFiles) {
5237
+ const destPath = path17.join(templatesDir, file);
5238
+ try {
5239
+ await fs12.access(destPath);
5240
+ } catch {
5241
+ const srcPath = path17.join(TEMPLATES_DIR, "standard", "files", "README.md");
5242
+ try {
5243
+ await fs12.copyFile(srcPath, destPath);
5244
+ templatesUpdated = true;
5245
+ console.log(chalk20.green(`\u2713 Added missing template: ${file}`));
5246
+ } catch {
5247
+ }
5248
+ }
5249
+ }
5250
+ await saveConfig(upgradedConfig, cwd);
5251
+ console.log("");
5252
+ console.log(chalk20.green("\u2713 Configuration upgraded!"));
5253
+ console.log("");
5254
+ console.log(chalk20.gray("What was updated:"));
5255
+ console.log(chalk20.gray(" - Config merged with latest defaults"));
5256
+ if (templatesUpdated) {
5257
+ console.log(chalk20.gray(" - Missing templates added"));
5258
+ }
5259
+ console.log("");
5260
+ console.log(chalk20.gray("What was preserved:"));
5261
+ console.log(chalk20.gray(" - Your specs/ directory"));
5262
+ console.log(chalk20.gray(" - Your AGENTS.md"));
5263
+ console.log(chalk20.gray(" - Your custom settings"));
5264
+ console.log("");
5265
+ }
5110
5266
  function initCommand() {
5111
- return new Command("init").description("Initialize LeanSpec in current directory").option("-y, --yes", "Skip prompts and use defaults (quick start with standard template)").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) => {
5267
+ 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) => {
5112
5268
  if (options.list) {
5113
5269
  await listExamples();
5114
5270
  return;
@@ -5117,18 +5273,32 @@ function initCommand() {
5117
5273
  await scaffoldExample(options.example, options.name);
5118
5274
  return;
5119
5275
  }
5120
- await initProject(options.yes, options.template, options.agentTools);
5276
+ await initProject(options.yes, options.template, options.agentTools, options.force);
5121
5277
  });
5122
5278
  }
5123
- async function initProject(skipPrompts = false, templateOption, agentToolsOption) {
5279
+ async function initProject(skipPrompts = false, templateOption, agentToolsOption, forceReinit = false) {
5124
5280
  const cwd = process.cwd();
5281
+ const configPath = path17.join(cwd, ".lean-spec", "config.json");
5282
+ let isAlreadyInitialized = false;
5125
5283
  try {
5126
- await fs11.access(path17.join(cwd, ".lean-spec", "config.json"));
5127
- console.log(chalk20.yellow("\u26A0 LeanSpec already initialized in this directory."));
5128
- console.log(chalk20.gray("To reinitialize, delete .lean-spec/ directory first."));
5129
- return;
5284
+ await fs12.access(configPath);
5285
+ isAlreadyInitialized = true;
5130
5286
  } catch {
5131
5287
  }
5288
+ if (isAlreadyInitialized) {
5289
+ const strategy = await handleReinitialize(cwd, skipPrompts, forceReinit);
5290
+ if (strategy === "cancel") {
5291
+ return;
5292
+ }
5293
+ if (strategy === "upgrade") {
5294
+ await upgradeConfig(cwd);
5295
+ return;
5296
+ }
5297
+ if (strategy === "reset-config") {
5298
+ await fs12.rm(path17.join(cwd, ".lean-spec"), { recursive: true, force: true });
5299
+ console.log(chalk20.gray("Removed .lean-spec/ configuration"));
5300
+ }
5301
+ }
5132
5302
  console.log("");
5133
5303
  console.log(chalk20.green("Welcome to LeanSpec!"));
5134
5304
  console.log("");
@@ -5201,7 +5371,7 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5201
5371
  const templateConfigPath = path17.join(templateDir, "config.json");
5202
5372
  let templateConfig;
5203
5373
  try {
5204
- const content = await fs11.readFile(templateConfigPath, "utf-8");
5374
+ const content = await fs12.readFile(templateConfigPath, "utf-8");
5205
5375
  templateConfig = JSON.parse(content).config;
5206
5376
  } catch {
5207
5377
  console.error(chalk20.red(`Error: Template not found: ${templateName}`));
@@ -5270,30 +5440,39 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5270
5440
  }
5271
5441
  console.log("");
5272
5442
  }
5273
- const toolChoices = Object.entries(AI_TOOL_CONFIGS).map(([key, config]) => ({
5443
+ const symlinkTools = Object.entries(AI_TOOL_CONFIGS).filter(([, config]) => config.usesSymlink).map(([key, config]) => ({
5274
5444
  name: config.description,
5275
5445
  value: key,
5276
5446
  checked: detectedDefaults.includes(key)
5277
5447
  }));
5278
- selectedAgentTools = await checkbox({
5279
- message: "Which AI tools do you use? (creates symlinks for tool-specific instruction files)",
5280
- choices: toolChoices
5281
- });
5448
+ if (symlinkTools.length > 0) {
5449
+ console.log("");
5450
+ console.log(chalk20.gray("AGENTS.md will be created as the primary instruction file."));
5451
+ console.log(chalk20.gray("Some AI tools (Claude Code, Gemini CLI) use their own filenames."));
5452
+ console.log("");
5453
+ const symlinkSelection = await checkbox({
5454
+ message: "Create symlinks for additional AI tools?",
5455
+ choices: symlinkTools
5456
+ });
5457
+ selectedAgentTools = symlinkSelection;
5458
+ } else {
5459
+ selectedAgentTools = [];
5460
+ }
5282
5461
  }
5283
5462
  const templatesDir = path17.join(cwd, ".lean-spec", "templates");
5284
5463
  try {
5285
- await fs11.mkdir(templatesDir, { recursive: true });
5464
+ await fs12.mkdir(templatesDir, { recursive: true });
5286
5465
  } catch (error) {
5287
5466
  console.error(chalk20.red("Error creating templates directory:"), error);
5288
5467
  process.exit(1);
5289
5468
  }
5290
5469
  const templateFilesDir = path17.join(templateDir, "files");
5291
5470
  try {
5292
- const files = await fs11.readdir(templateFilesDir);
5471
+ const files = await fs12.readdir(templateFilesDir);
5293
5472
  if (templateName === "standard") {
5294
5473
  const readmePath = path17.join(templateFilesDir, "README.md");
5295
5474
  const targetSpecPath = path17.join(templatesDir, "spec-template.md");
5296
- await fs11.copyFile(readmePath, targetSpecPath);
5475
+ await fs12.copyFile(readmePath, targetSpecPath);
5297
5476
  console.log(chalk20.green("\u2713 Created .lean-spec/templates/spec-template.md"));
5298
5477
  templateConfig.template = "spec-template.md";
5299
5478
  templateConfig.templates = {
@@ -5303,7 +5482,7 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5303
5482
  for (const file of files) {
5304
5483
  const srcPath = path17.join(templateFilesDir, file);
5305
5484
  const destPath = path17.join(templatesDir, file);
5306
- await fs11.copyFile(srcPath, destPath);
5485
+ await fs12.copyFile(srcPath, destPath);
5307
5486
  }
5308
5487
  console.log(chalk20.green(`\u2713 Created .lean-spec/templates/ with ${files.length} files`));
5309
5488
  console.log(chalk20.gray(` Files: ${files.join(", ")}`));
@@ -5381,9 +5560,9 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5381
5560
  const agentsSourcePath = path17.join(templateDir, "AGENTS.md");
5382
5561
  const agentsTargetPath = path17.join(cwd, "AGENTS.md");
5383
5562
  try {
5384
- let agentsContent = await fs11.readFile(agentsSourcePath, "utf-8");
5563
+ let agentsContent = await fs12.readFile(agentsSourcePath, "utf-8");
5385
5564
  agentsContent = agentsContent.replace(/\{project_name\}/g, projectName);
5386
- await fs11.writeFile(agentsTargetPath, agentsContent, "utf-8");
5565
+ await fs12.writeFile(agentsTargetPath, agentsContent, "utf-8");
5387
5566
  console.log(chalk20.green("\u2713 Created AGENTS.md"));
5388
5567
  } catch (error) {
5389
5568
  console.error(chalk20.red("Error copying AGENTS.md:"), error);
@@ -5404,7 +5583,7 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5404
5583
  }
5405
5584
  const filesDir = path17.join(templateDir, "files");
5406
5585
  try {
5407
- const filesToCopy = await fs11.readdir(filesDir);
5586
+ const filesToCopy = await fs12.readdir(filesDir);
5408
5587
  const hasOtherFiles = filesToCopy.some((f) => !f.match(/\.(md)$/i) || !["README.md", "DESIGN.md", "PLAN.md", "TEST.md"].includes(f));
5409
5588
  if (hasOtherFiles) {
5410
5589
  await copyDirectory(filesDir, cwd, [...skipFiles, "README.md", "DESIGN.md", "PLAN.md", "TEST.md"], { project_name: projectName });
@@ -5416,7 +5595,7 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5416
5595
  }
5417
5596
  const specsDir = path17.join(cwd, "specs");
5418
5597
  try {
5419
- await fs11.mkdir(specsDir, { recursive: true });
5598
+ await fs12.mkdir(specsDir, { recursive: true });
5420
5599
  console.log(chalk20.green("\u2713 Created specs/ directory"));
5421
5600
  } catch (error) {
5422
5601
  console.error(chalk20.red("Error creating specs directory:"), error);
@@ -5425,9 +5604,10 @@ async function initProject(skipPrompts = false, templateOption, agentToolsOption
5425
5604
  console.log("");
5426
5605
  console.log(chalk20.green("\u2713 LeanSpec initialized!"));
5427
5606
  console.log("");
5428
- console.log("Next steps:");
5429
- console.log(chalk20.cyan(" 1. Edit AGENTS.md") + chalk20.gray(' \u2192 Fill in the "\u{1F4CB} Project Context" section'));
5430
- console.log(chalk20.cyan(" 2. Create your first spec:") + chalk20.gray(" lean-spec create my-feature"));
5607
+ console.log(chalk20.cyan("You're ready to go!") + chalk20.gray(" Ask your AI to create a spec for your next feature."));
5608
+ console.log("");
5609
+ console.log(chalk20.gray('Example: "Create a spec for user authentication"'));
5610
+ console.log(chalk20.gray("Learn more: https://lean-spec.dev/docs/guide/getting-started"));
5431
5611
  console.log("");
5432
5612
  }
5433
5613
  async function listExamples() {
@@ -5467,7 +5647,7 @@ async function scaffoldExample(exampleName, customName) {
5467
5647
  const targetDirName = customName || exampleName;
5468
5648
  const targetPath = path17.join(process.cwd(), targetDirName);
5469
5649
  try {
5470
- const files = await fs11.readdir(targetPath);
5650
+ const files = await fs12.readdir(targetPath);
5471
5651
  const nonGitFiles = files.filter((f) => f !== ".git");
5472
5652
  if (nonGitFiles.length > 0) {
5473
5653
  console.error(chalk20.red(`Error: Directory "${targetDirName}" already exists and is not empty.`));
@@ -5480,7 +5660,7 @@ async function scaffoldExample(exampleName, customName) {
5480
5660
  console.log(chalk20.green(`Setting up example: ${example.title}`));
5481
5661
  console.log(chalk20.gray(example.description));
5482
5662
  console.log("");
5483
- await fs11.mkdir(targetPath, { recursive: true });
5663
+ await fs12.mkdir(targetPath, { recursive: true });
5484
5664
  console.log(chalk20.green(`\u2713 Created directory: ${targetDirName}/`));
5485
5665
  const examplePath = path17.join(EXAMPLES_DIR, exampleName);
5486
5666
  await copyDirectoryRecursive(examplePath, targetPath);
@@ -5540,27 +5720,27 @@ async function selectExample() {
5540
5720
  return choice;
5541
5721
  }
5542
5722
  async function copyDirectoryRecursive(src, dest) {
5543
- const entries = await fs11.readdir(src, { withFileTypes: true });
5723
+ const entries = await fs12.readdir(src, { withFileTypes: true });
5544
5724
  for (const entry of entries) {
5545
5725
  const srcPath = path17.join(src, entry.name);
5546
5726
  const destPath = path17.join(dest, entry.name);
5547
5727
  if (entry.isDirectory()) {
5548
- await fs11.mkdir(destPath, { recursive: true });
5728
+ await fs12.mkdir(destPath, { recursive: true });
5549
5729
  await copyDirectoryRecursive(srcPath, destPath);
5550
5730
  } else {
5551
- await fs11.copyFile(srcPath, destPath);
5731
+ await fs12.copyFile(srcPath, destPath);
5552
5732
  }
5553
5733
  }
5554
5734
  }
5555
5735
  async function detectPackageManager() {
5556
5736
  const cwd = process.cwd();
5557
5737
  try {
5558
- await fs11.access(path17.join(cwd, "..", "pnpm-lock.yaml"));
5738
+ await fs12.access(path17.join(cwd, "..", "pnpm-lock.yaml"));
5559
5739
  return "pnpm";
5560
5740
  } catch {
5561
5741
  }
5562
5742
  try {
5563
- await fs11.access(path17.join(cwd, "..", "yarn.lock"));
5743
+ await fs12.access(path17.join(cwd, "..", "yarn.lock"));
5564
5744
  return "yarn";
5565
5745
  } catch {
5566
5746
  }
@@ -5589,8 +5769,8 @@ async function showFiles(specPath, options = {}) {
5589
5769
  }
5590
5770
  const subFiles = await loadSubFiles(spec.fullPath);
5591
5771
  if (options.json) {
5592
- const readmeStat2 = await fs11.stat(spec.filePath);
5593
- const readmeContent2 = await fs11.readFile(spec.filePath, "utf-8");
5772
+ const readmeStat2 = await fs12.stat(spec.filePath);
5773
+ const readmeContent2 = await fs12.readFile(spec.filePath, "utf-8");
5594
5774
  const readmeTokens2 = await countTokens({ content: readmeContent2 });
5595
5775
  const jsonOutput = {
5596
5776
  spec: spec.name,
@@ -5617,9 +5797,9 @@ async function showFiles(specPath, options = {}) {
5617
5797
  console.log(chalk20.cyan(`\u{1F4C4} Files in ${sanitizeUserInput(spec.name)}`));
5618
5798
  console.log("");
5619
5799
  console.log(chalk20.green("Required:"));
5620
- const readmeStat = await fs11.stat(spec.filePath);
5800
+ const readmeStat = await fs12.stat(spec.filePath);
5621
5801
  const readmeSize = formatSize(readmeStat.size);
5622
- const readmeContent = await fs11.readFile(spec.filePath, "utf-8");
5802
+ const readmeContent = await fs12.readFile(spec.filePath, "utf-8");
5623
5803
  const readmeTokens = await countTokens({ content: readmeContent });
5624
5804
  console.log(chalk20.green(` \u2713 README.md (${readmeSize}, ~${readmeTokens.total.toLocaleString()} tokens) Main spec`));
5625
5805
  console.log("");
@@ -5640,7 +5820,7 @@ async function showFiles(specPath, options = {}) {
5640
5820
  console.log(chalk20.cyan("Documents:"));
5641
5821
  for (const file of documents) {
5642
5822
  const size = formatSize(file.size);
5643
- const content = await fs11.readFile(file.path, "utf-8");
5823
+ const content = await fs12.readFile(file.path, "utf-8");
5644
5824
  const tokenCount = await countTokens({ content });
5645
5825
  console.log(chalk20.cyan(` \u2713 ${sanitizeUserInput(file.name).padEnd(20)} (${size}, ~${tokenCount.total.toLocaleString()} tokens)`));
5646
5826
  }
@@ -6709,7 +6889,7 @@ async function validateSpecs(options = {}) {
6709
6889
  for (const spec of specs) {
6710
6890
  let content;
6711
6891
  try {
6712
- content = await fs11.readFile(spec.filePath, "utf-8");
6892
+ content = await fs12.readFile(spec.filePath, "utf-8");
6713
6893
  } catch (error) {
6714
6894
  console.error(chalk20.red(`Error reading ${spec.filePath}:`), error);
6715
6895
  continue;
@@ -6763,7 +6943,7 @@ function migrateCommand(inputPath, options = {}) {
6763
6943
  async function migrateSpecs(inputPath, options = {}) {
6764
6944
  const config = await loadConfig();
6765
6945
  try {
6766
- const stats = await fs11.stat(inputPath);
6946
+ const stats = await fs12.stat(inputPath);
6767
6947
  if (!stats.isDirectory()) {
6768
6948
  console.error("\x1B[31m\u274C Error:\x1B[0m Input path must be a directory");
6769
6949
  process.exit(1);
@@ -6791,7 +6971,7 @@ async function migrateSpecs(inputPath, options = {}) {
6791
6971
  async function scanDocuments(dirPath) {
6792
6972
  const documents = [];
6793
6973
  async function scanRecursive(currentPath) {
6794
- const entries = await fs11.readdir(currentPath, { withFileTypes: true });
6974
+ const entries = await fs12.readdir(currentPath, { withFileTypes: true });
6795
6975
  for (const entry of entries) {
6796
6976
  const fullPath = path17.join(currentPath, entry.name);
6797
6977
  if (entry.isDirectory()) {
@@ -6800,7 +6980,7 @@ async function scanDocuments(dirPath) {
6800
6980
  }
6801
6981
  } else if (entry.isFile()) {
6802
6982
  if (entry.name.endsWith(".md") || entry.name.endsWith(".markdown")) {
6803
- const stats = await fs11.stat(fullPath);
6983
+ const stats = await fs12.stat(fullPath);
6804
6984
  documents.push({
6805
6985
  path: fullPath,
6806
6986
  name: entry.name,
@@ -9164,7 +9344,7 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
9164
9344
  if (resolvedPath) {
9165
9345
  targetFile = path17.join(resolvedPath, filePart);
9166
9346
  try {
9167
- await fs11.access(targetFile);
9347
+ await fs12.access(targetFile);
9168
9348
  } catch {
9169
9349
  return null;
9170
9350
  }
@@ -9183,7 +9363,7 @@ async function readSpecContent(specPath, cwd = process.cwd()) {
9183
9363
  if (!targetFile) {
9184
9364
  return null;
9185
9365
  }
9186
- const rawContent = await fs11.readFile(targetFile, "utf-8");
9366
+ const rawContent = await fs12.readFile(targetFile, "utf-8");
9187
9367
  const fileName = path17.basename(targetFile);
9188
9368
  const isSubSpec = fileName !== config.structure.defaultFile;
9189
9369
  let frontmatter = null;
@@ -9348,7 +9528,7 @@ async function openSpec(specPath, options = {}) {
9348
9528
  if (resolvedPath) {
9349
9529
  targetFile = path17.join(resolvedPath, filePart);
9350
9530
  try {
9351
- await fs11.access(targetFile);
9531
+ await fs12.access(targetFile);
9352
9532
  } catch {
9353
9533
  targetFile = null;
9354
9534
  }
@@ -11204,5 +11384,5 @@ if (import.meta.url === `file://${process.argv[1]}`) {
11204
11384
  }
11205
11385
 
11206
11386
  export { agentCommand, analyzeCommand, archiveCommand, backfillCommand, boardCommand, checkCommand, compactCommand, createCommand, createMcpServer, depsCommand, examplesCommand, filesCommand, ganttCommand, initCommand, linkCommand, listCommand, mcpCommand, migrateCommand, openCommand, searchCommand, splitCommand, statsCommand, templatesCommand, timelineCommand, tokensCommand, uiCommand, unlinkCommand, updateCommand, validateCommand, viewCommand };
11207
- //# sourceMappingURL=chunk-FTKNRIOE.js.map
11208
- //# sourceMappingURL=chunk-FTKNRIOE.js.map
11387
+ //# sourceMappingURL=chunk-2DAPKDV5.js.map
11388
+ //# sourceMappingURL=chunk-2DAPKDV5.js.map