lynxprompt 0.4.0 → 0.4.3

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/dist/index.js CHANGED
@@ -264,15 +264,18 @@ function displayWelcome(user) {
264
264
  TEAMS: { color: chalk.yellow, emoji: "\u{1F465}", badge: "Teams" }
265
265
  };
266
266
  const config2 = planConfig[plan] || planConfig.FREE;
267
+ const W = 45;
268
+ const b = chalk.bold;
269
+ const pad = (s, len) => s + " ".repeat(Math.max(0, len - s.length));
267
270
  console.log();
268
- console.log(chalk.bold("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
269
- console.log(chalk.bold("\u2502") + " " + chalk.bold("\u2502"));
270
- console.log(chalk.bold("\u2502") + chalk.green.bold(` ${config2.emoji} Welcome to LynxPrompt CLI!`) + " " + chalk.bold("\u2502"));
271
- console.log(chalk.bold("\u2502") + " " + chalk.bold("\u2502"));
272
- console.log(chalk.bold("\u2502") + ` ${chalk.white("User:")} ${chalk.bold(name.padEnd(38))}` + chalk.bold("\u2502"));
273
- console.log(chalk.bold("\u2502") + ` ${chalk.white("Plan:")} ${config2.color(config2.badge.padEnd(38))}` + chalk.bold("\u2502"));
274
- console.log(chalk.bold("\u2502") + " " + chalk.bold("\u2502"));
275
- console.log(chalk.bold("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
271
+ console.log(b("\u250C" + "\u2500".repeat(W) + "\u2510"));
272
+ console.log(b("\u2502") + " ".repeat(W) + b("\u2502"));
273
+ console.log(b("\u2502") + pad(` ${config2.emoji} Welcome to LynxPrompt CLI!`, W - 1) + b("\u2502"));
274
+ console.log(b("\u2502") + " ".repeat(W) + b("\u2502"));
275
+ console.log(b("\u2502") + pad(` User: ${name}`, W) + b("\u2502"));
276
+ console.log(b("\u2502") + pad(` Plan: ${config2.badge}`, W) + b("\u2502"));
277
+ console.log(b("\u2502") + " ".repeat(W) + b("\u2502"));
278
+ console.log(b("\u2514" + "\u2500".repeat(W) + "\u2518"));
276
279
  console.log();
277
280
  console.log(chalk.bold("\u{1F4CB} Your CLI Capabilities:"));
278
281
  console.log();
@@ -1630,6 +1633,108 @@ async function detectProject(cwd) {
1630
1633
  if (await fileExists(join4(cwd, "Dockerfile")) || await fileExists(join4(cwd, "docker-compose.yml"))) {
1631
1634
  detected.stack.push("docker");
1632
1635
  detected.type = "application";
1636
+ detected.hasDocker = true;
1637
+ }
1638
+ const licensePath = join4(cwd, "LICENSE");
1639
+ if (await fileExists(licensePath)) {
1640
+ try {
1641
+ const licenseContent = await readFile3(licensePath, "utf-8");
1642
+ const lowerContent = licenseContent.toLowerCase();
1643
+ if (lowerContent.includes("mit license") || lowerContent.includes("permission is hereby granted, free of charge")) {
1644
+ detected.license = "mit";
1645
+ } else if (lowerContent.includes("apache license") && lowerContent.includes("version 2.0")) {
1646
+ detected.license = "apache-2.0";
1647
+ } else if (lowerContent.includes("gnu general public license") && lowerContent.includes("version 3")) {
1648
+ detected.license = "gpl-3.0";
1649
+ } else if (lowerContent.includes("gnu lesser general public license")) {
1650
+ detected.license = "lgpl-3.0";
1651
+ } else if (lowerContent.includes("gnu affero general public license")) {
1652
+ detected.license = "agpl-3.0";
1653
+ } else if (lowerContent.includes("bsd 3-clause") || lowerContent.includes("redistribution and use in source and binary forms")) {
1654
+ detected.license = "bsd-3";
1655
+ } else if (lowerContent.includes("mozilla public license") && lowerContent.includes("2.0")) {
1656
+ detected.license = "mpl-2.0";
1657
+ } else if (lowerContent.includes("unlicense") || lowerContent.includes("this is free and unencumbered software")) {
1658
+ detected.license = "unlicense";
1659
+ }
1660
+ } catch {
1661
+ }
1662
+ }
1663
+ const gitConfigPath = join4(cwd, ".git", "config");
1664
+ if (await fileExists(gitConfigPath)) {
1665
+ try {
1666
+ const gitConfig = await readFile3(gitConfigPath, "utf-8");
1667
+ const urlMatch = gitConfig.match(/url\s*=\s*(.+)/);
1668
+ if (urlMatch) {
1669
+ const repoUrl = urlMatch[1].trim();
1670
+ detected.repoUrl = repoUrl;
1671
+ if (repoUrl.includes("github.com")) {
1672
+ detected.repoHost = "github";
1673
+ } else if (repoUrl.includes("gitlab.com") || repoUrl.includes("gitlab")) {
1674
+ detected.repoHost = "gitlab";
1675
+ } else if (repoUrl.includes("bitbucket")) {
1676
+ detected.repoHost = "bitbucket";
1677
+ } else if (repoUrl.includes("gitea") || repoUrl.includes("codeberg")) {
1678
+ detected.repoHost = "gitea";
1679
+ } else if (repoUrl.includes("azure")) {
1680
+ detected.repoHost = "azure";
1681
+ }
1682
+ }
1683
+ } catch {
1684
+ }
1685
+ }
1686
+ if (await fileExists(join4(cwd, ".github", "workflows"))) {
1687
+ detected.cicd = "github_actions";
1688
+ } else if (await fileExists(join4(cwd, ".gitlab-ci.yml"))) {
1689
+ detected.cicd = "gitlab_ci";
1690
+ } else if (await fileExists(join4(cwd, "Jenkinsfile"))) {
1691
+ detected.cicd = "jenkins";
1692
+ } else if (await fileExists(join4(cwd, ".circleci"))) {
1693
+ detected.cicd = "circleci";
1694
+ } else if (await fileExists(join4(cwd, ".travis.yml"))) {
1695
+ detected.cicd = "travis";
1696
+ } else if (await fileExists(join4(cwd, "azure-pipelines.yml"))) {
1697
+ detected.cicd = "azure_devops";
1698
+ } else if (await fileExists(join4(cwd, "bitbucket-pipelines.yml"))) {
1699
+ detected.cicd = "bitbucket";
1700
+ } else if (await fileExists(join4(cwd, ".drone.yml"))) {
1701
+ detected.cicd = "drone";
1702
+ }
1703
+ detected.existingFiles = [];
1704
+ const staticFiles = [
1705
+ ".editorconfig",
1706
+ "CONTRIBUTING.md",
1707
+ "CODE_OF_CONDUCT.md",
1708
+ "SECURITY.md",
1709
+ "ROADMAP.md",
1710
+ ".gitignore",
1711
+ ".github/FUNDING.yml",
1712
+ "LICENSE",
1713
+ "README.md",
1714
+ "ARCHITECTURE.md",
1715
+ "CHANGELOG.md"
1716
+ ];
1717
+ for (const file of staticFiles) {
1718
+ if (await fileExists(join4(cwd, file))) {
1719
+ detected.existingFiles.push(file);
1720
+ }
1721
+ }
1722
+ if (!detected.description) {
1723
+ const readmePath = join4(cwd, "README.md");
1724
+ if (await fileExists(readmePath)) {
1725
+ try {
1726
+ const readme = await readFile3(readmePath, "utf-8");
1727
+ const lines = readme.split("\n");
1728
+ for (const line of lines) {
1729
+ const trimmed = line.trim();
1730
+ if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!") && !trimmed.startsWith("[") && trimmed.length > 20) {
1731
+ detected.description = trimmed.substring(0, 200);
1732
+ break;
1733
+ }
1734
+ }
1735
+ } catch {
1736
+ }
1737
+ }
1633
1738
  }
1634
1739
  return detected.stack.length > 0 || detected.name ? detected : null;
1635
1740
  }
@@ -2006,7 +2111,8 @@ async function initCommand(options) {
2006
2111
  import chalk8 from "chalk";
2007
2112
  import prompts4 from "prompts";
2008
2113
  import ora7 from "ora";
2009
- import { writeFile as writeFile4, mkdir as mkdir4, access as access3 } from "fs/promises";
2114
+ import * as readline from "readline";
2115
+ import { writeFile as writeFile4, mkdir as mkdir4, access as access3, readFile as readFile5 } from "fs/promises";
2010
2116
  import { join as join6, dirname as dirname4 } from "path";
2011
2117
 
2012
2118
  // src/utils/generator.ts
@@ -2163,6 +2269,259 @@ var TEST_LEVEL_DESCRIPTIONS = {
2163
2269
  integration: "Integration tests for component interactions",
2164
2270
  e2e: "End-to-end tests for full user flows"
2165
2271
  };
2272
+ var STATIC_FILE_TEMPLATES = {
2273
+ editorconfig: () => `# EditorConfig is awesome: https://EditorConfig.org
2274
+
2275
+ root = true
2276
+
2277
+ [*]
2278
+ indent_style = space
2279
+ indent_size = 2
2280
+ end_of_line = lf
2281
+ charset = utf-8
2282
+ trim_trailing_whitespace = true
2283
+ insert_final_newline = true
2284
+
2285
+ [*.md]
2286
+ trim_trailing_whitespace = false
2287
+
2288
+ [Makefile]
2289
+ indent_style = tab
2290
+ `,
2291
+ contributing: (opts) => `# Contributing to ${opts.name}
2292
+
2293
+ Thank you for your interest in contributing!
2294
+
2295
+ ## How to Contribute
2296
+
2297
+ 1. Fork the repository
2298
+ 2. Create a feature branch (\`git checkout -b feature/amazing-feature\`)
2299
+ 3. Commit your changes${opts.conventionalCommits ? " using Conventional Commits format" : ""}
2300
+ 4. Push to the branch (\`git push origin feature/amazing-feature\`)
2301
+ 5. Open a Pull Request
2302
+
2303
+ ## Development Setup
2304
+
2305
+ \`\`\`bash
2306
+ # Clone your fork
2307
+ git clone https://github.com/YOUR_USERNAME/${opts.name}.git
2308
+ cd ${opts.name}
2309
+
2310
+ # Install dependencies
2311
+ npm install
2312
+
2313
+ # Run development server
2314
+ npm run dev
2315
+ \`\`\`
2316
+
2317
+ ## Code Style
2318
+
2319
+ Please follow the existing code style and conventions in this project.
2320
+ `,
2321
+ codeOfConduct: (opts) => `# Code of Conduct
2322
+
2323
+ ## Our Pledge
2324
+
2325
+ We pledge to make participation in the ${opts.name} project a harassment-free experience for everyone.
2326
+
2327
+ ## Our Standards
2328
+
2329
+ Examples of behavior that contributes to a positive environment:
2330
+ - Using welcoming and inclusive language
2331
+ - Being respectful of differing viewpoints
2332
+ - Gracefully accepting constructive criticism
2333
+ - Focusing on what is best for the community
2334
+
2335
+ ## Enforcement
2336
+
2337
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project team.
2338
+
2339
+ ## Attribution
2340
+
2341
+ This Code of Conduct is adapted from the Contributor Covenant, version 2.1.
2342
+ `,
2343
+ security: (opts) => `# Security Policy
2344
+
2345
+ ## Supported Versions
2346
+
2347
+ | Version | Supported |
2348
+ | ------- | ------------------ |
2349
+ | latest | :white_check_mark: |
2350
+
2351
+ ## Reporting a Vulnerability
2352
+
2353
+ If you discover a security vulnerability in ${opts.name}, please report it by emailing the maintainers.
2354
+
2355
+ **Please do not open a public issue for security vulnerabilities.**
2356
+
2357
+ We will acknowledge receipt within 48 hours and provide a detailed response within 7 days.
2358
+ `,
2359
+ roadmap: (opts) => `# Roadmap
2360
+
2361
+ ## ${opts.name} Development Roadmap
2362
+
2363
+ ### Current Version
2364
+
2365
+ - Core functionality
2366
+
2367
+ ### Planned Features
2368
+
2369
+ - [ ] Feature 1
2370
+ - [ ] Feature 2
2371
+ - [ ] Feature 3
2372
+
2373
+ ### Long-term Goals
2374
+
2375
+ - Goal 1
2376
+ - Goal 2
2377
+
2378
+ ---
2379
+ *This roadmap is subject to change based on community feedback and priorities.*
2380
+ `,
2381
+ gitignore: (opts) => {
2382
+ const patterns = ["# Dependencies", "node_modules/", ".pnpm-store/", ""];
2383
+ if (opts.stack.includes("python")) {
2384
+ patterns.push("# Python", "__pycache__/", "*.py[cod]", ".venv/", "venv/", "");
2385
+ }
2386
+ patterns.push("# Environment", ".env", ".env.local", ".env*.local", "");
2387
+ patterns.push("# Build outputs", "dist/", "build/", ".next/", "out/", "");
2388
+ patterns.push("# IDE", ".idea/", ".vscode/", "*.swp", "*.swo", "");
2389
+ patterns.push("# OS", ".DS_Store", "Thumbs.db", "");
2390
+ patterns.push("# Logs", "*.log", "npm-debug.log*", "");
2391
+ return patterns.join("\n");
2392
+ },
2393
+ funding: () => `# These are supported funding model platforms
2394
+
2395
+ github: [] # Replace with your GitHub username
2396
+ patreon: # Replace with your Patreon username
2397
+ open_collective: # Replace with your Open Collective username
2398
+ ko_fi: # Replace with your Ko-fi username
2399
+ custom: [] # Add custom funding links
2400
+ `,
2401
+ license: (opts) => {
2402
+ if (opts.license === "mit") {
2403
+ return `MIT License
2404
+
2405
+ Copyright (c) ${(/* @__PURE__ */ new Date()).getFullYear()} ${opts.name}
2406
+
2407
+ Permission is hereby granted, free of charge, to any person obtaining a copy
2408
+ of this software and associated documentation files (the "Software"), to deal
2409
+ in the Software without restriction, including without limitation the rights
2410
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2411
+ copies of the Software, and to permit persons to whom the Software is
2412
+ furnished to do so, subject to the following conditions:
2413
+
2414
+ The above copyright notice and this permission notice shall be included in all
2415
+ copies or substantial portions of the Software.
2416
+
2417
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2418
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2419
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2420
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2421
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2422
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2423
+ SOFTWARE.
2424
+ `;
2425
+ }
2426
+ return `# License
2427
+
2428
+ This project is licensed under the ${opts.license?.toUpperCase() || "Proprietary"} license.
2429
+ `;
2430
+ },
2431
+ readme: (opts) => {
2432
+ const stackBadges = opts.stack.slice(0, 5).map((s) => STACK_NAMES[s] || s).join(" \u2022 ");
2433
+ return `# ${opts.name}
2434
+
2435
+ ${opts.description || "A project generated with LynxPrompt."}
2436
+
2437
+ ${stackBadges ? `## Tech Stack
2438
+
2439
+ ${stackBadges}
2440
+ ` : ""}
2441
+ ## Getting Started
2442
+
2443
+ \`\`\`bash
2444
+ # Clone the repository
2445
+ git clone <repository-url>
2446
+ cd ${opts.name}
2447
+
2448
+ # Install dependencies
2449
+ npm install
2450
+
2451
+ # Run development server
2452
+ npm run dev
2453
+ \`\`\`
2454
+
2455
+ ## License
2456
+
2457
+ ${opts.license && opts.license !== "none" ? `This project is licensed under the ${opts.license.toUpperCase()} License.` : "See LICENSE file for details."}
2458
+ `;
2459
+ },
2460
+ architecture: (opts) => `# Architecture
2461
+
2462
+ ## ${opts.name} Architecture Overview
2463
+
2464
+ ${opts.architecture ? `### Pattern: ${opts.architecture}
2465
+ ` : ""}
2466
+ ### Directory Structure
2467
+
2468
+ \`\`\`
2469
+ ${opts.name}/
2470
+ \u251C\u2500\u2500 src/ # Source code
2471
+ \u251C\u2500\u2500 tests/ # Test files
2472
+ \u251C\u2500\u2500 docs/ # Documentation
2473
+ \u2514\u2500\u2500 ...
2474
+ \`\`\`
2475
+
2476
+ ### Key Components
2477
+
2478
+ 1. **Component A** - Description
2479
+ 2. **Component B** - Description
2480
+ 3. **Component C** - Description
2481
+
2482
+ ### Data Flow
2483
+
2484
+ Describe how data flows through the application.
2485
+
2486
+ ---
2487
+ *Generated by LynxPrompt*
2488
+ `,
2489
+ changelog: (opts) => `# Changelog
2490
+
2491
+ All notable changes to ${opts.name} will be documented in this file.
2492
+
2493
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2494
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2495
+
2496
+ ## [Unreleased]
2497
+
2498
+ ### Added
2499
+ - Initial project setup
2500
+
2501
+ ### Changed
2502
+
2503
+ ### Deprecated
2504
+
2505
+ ### Removed
2506
+
2507
+ ### Fixed
2508
+
2509
+ ### Security
2510
+ `
2511
+ };
2512
+ var STATIC_FILE_PATHS = {
2513
+ editorconfig: ".editorconfig",
2514
+ contributing: "CONTRIBUTING.md",
2515
+ codeOfConduct: "CODE_OF_CONDUCT.md",
2516
+ security: "SECURITY.md",
2517
+ roadmap: "ROADMAP.md",
2518
+ gitignore: ".gitignore",
2519
+ funding: ".github/FUNDING.yml",
2520
+ license: "LICENSE",
2521
+ readme: "README.md",
2522
+ architecture: "ARCHITECTURE.md",
2523
+ changelog: "CHANGELOG.md"
2524
+ };
2166
2525
  function generateConfig(options) {
2167
2526
  const files = {};
2168
2527
  for (const platform of options.platforms) {
@@ -2171,6 +2530,23 @@ function generateConfig(options) {
2171
2530
  files[filename] = generateFileContent(options, platform);
2172
2531
  }
2173
2532
  }
2533
+ if (options.staticFiles && options.staticFiles.length > 0) {
2534
+ for (const fileKey of options.staticFiles) {
2535
+ const filePath = STATIC_FILE_PATHS[fileKey];
2536
+ if (!filePath) continue;
2537
+ if (options.staticFileContents?.[fileKey]) {
2538
+ files[filePath] = options.staticFileContents[fileKey];
2539
+ } else {
2540
+ const templateFn = STATIC_FILE_TEMPLATES[fileKey];
2541
+ if (templateFn) {
2542
+ files[filePath] = templateFn(options);
2543
+ }
2544
+ }
2545
+ }
2546
+ }
2547
+ if (options.includeFunding && !options.staticFiles?.includes("funding")) {
2548
+ files[".github/FUNDING.yml"] = STATIC_FILE_TEMPLATES.funding(options);
2549
+ }
2174
2550
  return files;
2175
2551
  }
2176
2552
  function generateFileContent(options, platform) {
@@ -2243,9 +2619,15 @@ function generateFileContent(options, platform) {
2243
2619
  }
2244
2620
  sections.push("");
2245
2621
  }
2246
- if (options.repoHost || options.license || options.conventionalCommits) {
2622
+ if (options.letAiDecide) {
2247
2623
  if (isMarkdown || isMdc) {
2248
- sections.push("## Repository");
2624
+ sections.push("> **AI Assistance:** Let AI analyze the codebase and suggest additional technologies and approaches as needed.");
2625
+ sections.push("");
2626
+ }
2627
+ }
2628
+ if (options.repoHost || options.license || options.conventionalCommits || options.semver || options.cicd || options.deploymentTargets?.length || options.buildContainer || options.exampleRepoUrl || options.documentationUrl) {
2629
+ if (isMarkdown || isMdc) {
2630
+ sections.push("## Repository & Infrastructure");
2249
2631
  sections.push("");
2250
2632
  if (options.repoHost) {
2251
2633
  sections.push(`- **Host:** ${options.repoHost.charAt(0).toUpperCase() + options.repoHost.slice(1)}`);
@@ -2256,6 +2638,68 @@ function generateFileContent(options, platform) {
2256
2638
  if (options.conventionalCommits) {
2257
2639
  sections.push("- **Commits:** Follow [Conventional Commits](https://conventionalcommits.org) format");
2258
2640
  }
2641
+ if (options.semver) {
2642
+ sections.push("- **Versioning:** Follow [Semantic Versioning](https://semver.org) (semver)");
2643
+ }
2644
+ if (options.dependabot) {
2645
+ sections.push("- **Dependencies:** Dependabot/automated dependency updates enabled");
2646
+ }
2647
+ if (options.cicd) {
2648
+ const cicdNames = {
2649
+ github_actions: "GitHub Actions",
2650
+ gitlab_ci: "GitLab CI",
2651
+ jenkins: "Jenkins",
2652
+ circleci: "CircleCI",
2653
+ travis: "Travis CI",
2654
+ azure_devops: "Azure DevOps",
2655
+ bitbucket: "Bitbucket Pipelines",
2656
+ teamcity: "TeamCity",
2657
+ drone: "Drone",
2658
+ buildkite: "Buildkite"
2659
+ };
2660
+ sections.push(`- **CI/CD:** ${cicdNames[options.cicd] || options.cicd}`);
2661
+ }
2662
+ if (options.deploymentTargets && options.deploymentTargets.length > 0) {
2663
+ const targetNames = {
2664
+ vercel: "Vercel",
2665
+ netlify: "Netlify",
2666
+ aws: "AWS",
2667
+ gcp: "Google Cloud",
2668
+ azure: "Azure",
2669
+ docker: "Docker",
2670
+ kubernetes: "Kubernetes",
2671
+ heroku: "Heroku",
2672
+ digitalocean: "DigitalOcean",
2673
+ railway: "Railway",
2674
+ fly: "Fly.io",
2675
+ cloudflare: "Cloudflare"
2676
+ };
2677
+ const targets = options.deploymentTargets.map((t) => targetNames[t] || t).join(", ");
2678
+ sections.push(`- **Deployment:** ${targets}`);
2679
+ }
2680
+ if (options.buildContainer) {
2681
+ let containerInfo = "Docker container builds enabled";
2682
+ if (options.containerRegistry) {
2683
+ const registryNames = {
2684
+ dockerhub: "Docker Hub",
2685
+ ghcr: "GitHub Container Registry",
2686
+ gcr: "Google Container Registry",
2687
+ ecr: "AWS ECR",
2688
+ acr: "Azure Container Registry",
2689
+ quay: "Quay.io",
2690
+ gitlab: "GitLab Registry",
2691
+ custom: "Custom registry"
2692
+ };
2693
+ containerInfo += ` \u2192 ${registryNames[options.containerRegistry] || options.containerRegistry}`;
2694
+ }
2695
+ sections.push(`- **Containers:** ${containerInfo}`);
2696
+ }
2697
+ if (options.exampleRepoUrl) {
2698
+ sections.push(`- **Example Repo:** ${options.exampleRepoUrl} (use as reference for style/structure)`);
2699
+ }
2700
+ if (options.documentationUrl) {
2701
+ sections.push(`- **Documentation:** ${options.documentationUrl}`);
2702
+ }
2259
2703
  sections.push("");
2260
2704
  }
2261
2705
  }
@@ -2326,6 +2770,14 @@ function generateFileContent(options, platform) {
2326
2770
  sections.push("");
2327
2771
  }
2328
2772
  }
2773
+ if (options.includePersonalData) {
2774
+ if (isMarkdown || isMdc) {
2775
+ sections.push("## Commit Identity");
2776
+ sections.push("");
2777
+ sections.push("> **Personal data enabled:** Use my name and email for git commits when making changes.");
2778
+ sections.push("");
2779
+ }
2780
+ }
2329
2781
  let boundaries = BOUNDARIES[options.boundaries];
2330
2782
  if (options.boundaryNever?.length || options.boundaryAsk?.length) {
2331
2783
  boundaries = {
@@ -2395,6 +2847,9 @@ function generateFileContent(options, platform) {
2395
2847
  sections.push(`- **Errors:** ${errorStyles[options.errorHandling]}`);
2396
2848
  }
2397
2849
  }
2850
+ if (options.loggingConventions) {
2851
+ sections.push(`- **Logging:** ${options.loggingConventions}`);
2852
+ }
2398
2853
  if (options.styleNotes) {
2399
2854
  sections.push(`- **Notes:** ${options.styleNotes}`);
2400
2855
  }
@@ -2526,6 +2981,63 @@ function generateYamlConfig(options, platform) {
2526
2981
  }
2527
2982
 
2528
2983
  // src/commands/wizard.ts
2984
+ var STATIC_FILE_PATHS2 = {
2985
+ editorconfig: ".editorconfig",
2986
+ contributing: "CONTRIBUTING.md",
2987
+ codeOfConduct: "CODE_OF_CONDUCT.md",
2988
+ security: "SECURITY.md",
2989
+ roadmap: "ROADMAP.md",
2990
+ gitignore: ".gitignore",
2991
+ funding: ".github/FUNDING.yml",
2992
+ license: "LICENSE",
2993
+ readme: "README.md",
2994
+ architecture: "ARCHITECTURE.md",
2995
+ changelog: "CHANGELOG.md"
2996
+ };
2997
+ async function readExistingFile(filePath) {
2998
+ try {
2999
+ await access3(filePath);
3000
+ const content = await readFile5(filePath, "utf-8");
3001
+ return content;
3002
+ } catch {
3003
+ return null;
3004
+ }
3005
+ }
3006
+ async function readMultilineInput(prompt) {
3007
+ console.log(chalk8.white(prompt));
3008
+ console.log(chalk8.gray(" (Paste your content, then type EOF on a new line and press Enter to finish)"));
3009
+ console.log(chalk8.gray(" (Press Enter twice to skip)"));
3010
+ console.log();
3011
+ const rl = readline.createInterface({
3012
+ input: process.stdin,
3013
+ output: process.stdout
3014
+ });
3015
+ return new Promise((resolve) => {
3016
+ const lines = [];
3017
+ let emptyLineCount = 0;
3018
+ rl.on("line", (line) => {
3019
+ if (line.trim() === "EOF") {
3020
+ rl.close();
3021
+ resolve(lines.join("\n"));
3022
+ return;
3023
+ }
3024
+ if (line === "") {
3025
+ emptyLineCount++;
3026
+ if (emptyLineCount >= 2 && lines.length === 0) {
3027
+ rl.close();
3028
+ resolve("");
3029
+ return;
3030
+ }
3031
+ } else {
3032
+ emptyLineCount = 0;
3033
+ }
3034
+ lines.push(line);
3035
+ });
3036
+ rl.on("close", () => {
3037
+ resolve(lines.join("\n"));
3038
+ });
3039
+ });
3040
+ }
2529
3041
  var WIZARD_STEPS = [
2530
3042
  { id: "format", title: "Output Format", icon: "\u{1F4E4}", tier: "basic" },
2531
3043
  { id: "project", title: "Project Basics", icon: "\u2728", tier: "basic" },
@@ -2557,14 +3069,6 @@ var ALL_PLATFORMS = [
2557
3069
  { id: "void", name: "Void", file: ".void/config.json", icon: "\u{1F573}\uFE0F", note: "Open-source Cursor alt" },
2558
3070
  { id: "goose", name: "Goose", file: ".goosehints", icon: "\u{1FABF}", note: "Block AI agent" }
2559
3071
  ];
2560
- var OUTPUT_FORMATS = [
2561
- { title: "\u{1F310} AGENTS.md (Universal)", value: "agents", description: "Works with Claude, Copilot, Aider, Devin & more", recommended: true },
2562
- { title: "\u26A1 Cursor", value: "cursor", description: ".cursor/rules/ native format" },
2563
- { title: "\u{1F9E0} Claude Code", value: "claude", description: "CLAUDE.md format" },
2564
- { title: "\u{1F419} GitHub Copilot", value: "copilot", description: ".github/copilot-instructions.md" },
2565
- { title: "\u{1F3C4} Windsurf", value: "windsurf", description: ".windsurfrules configuration" },
2566
- { title: "\u{1F4E6} Multiple platforms...", value: "multiple", description: "Select from 16+ supported AI editors" }
2567
- ];
2568
3072
  var LANGUAGES = [
2569
3073
  { title: "\u{1F537} TypeScript", value: "typescript" },
2570
3074
  { title: "\u{1F7E1} JavaScript", value: "javascript" },
@@ -2625,6 +3129,42 @@ var LICENSES = [
2625
3129
  { id: "unlicense", label: "Unlicense" },
2626
3130
  { id: "none", label: "None / Proprietary" }
2627
3131
  ];
3132
+ var CICD_OPTIONS = [
3133
+ { id: "github_actions", label: "GitHub Actions", icon: "\u{1F419}" },
3134
+ { id: "gitlab_ci", label: "GitLab CI", icon: "\u{1F98A}" },
3135
+ { id: "jenkins", label: "Jenkins", icon: "\u{1F527}" },
3136
+ { id: "circleci", label: "CircleCI", icon: "\u26AB" },
3137
+ { id: "travis", label: "Travis CI", icon: "\u{1F528}" },
3138
+ { id: "azure_devops", label: "Azure DevOps", icon: "\u2601\uFE0F" },
3139
+ { id: "bitbucket", label: "Bitbucket Pipelines", icon: "\u{1FAA3}" },
3140
+ { id: "teamcity", label: "TeamCity", icon: "\u{1F3E2}" },
3141
+ { id: "drone", label: "Drone", icon: "\u{1F681}" },
3142
+ { id: "buildkite", label: "Buildkite", icon: "\u{1F9F1}" }
3143
+ ];
3144
+ var DEPLOYMENT_TARGETS = [
3145
+ { id: "vercel", label: "Vercel", icon: "\u25B2" },
3146
+ { id: "netlify", label: "Netlify", icon: "\u{1F310}" },
3147
+ { id: "aws", label: "AWS", icon: "\u2601\uFE0F" },
3148
+ { id: "gcp", label: "Google Cloud", icon: "\u{1F308}" },
3149
+ { id: "azure", label: "Azure", icon: "\u{1F537}" },
3150
+ { id: "docker", label: "Docker", icon: "\u{1F433}" },
3151
+ { id: "kubernetes", label: "Kubernetes", icon: "\u2638\uFE0F" },
3152
+ { id: "heroku", label: "Heroku", icon: "\u{1F7E3}" },
3153
+ { id: "digitalocean", label: "DigitalOcean", icon: "\u{1F535}" },
3154
+ { id: "railway", label: "Railway", icon: "\u{1F682}" },
3155
+ { id: "fly", label: "Fly.io", icon: "\u2708\uFE0F" },
3156
+ { id: "cloudflare", label: "Cloudflare", icon: "\u{1F536}" }
3157
+ ];
3158
+ var CONTAINER_REGISTRIES = [
3159
+ { id: "dockerhub", label: "Docker Hub", icon: "\u{1F433}" },
3160
+ { id: "ghcr", label: "GitHub Container Registry", icon: "\u{1F419}" },
3161
+ { id: "gcr", label: "Google Container Registry", icon: "\u{1F308}" },
3162
+ { id: "ecr", label: "AWS ECR", icon: "\u2601\uFE0F" },
3163
+ { id: "acr", label: "Azure Container Registry", icon: "\u{1F537}" },
3164
+ { id: "quay", label: "Quay.io", icon: "\u{1F534}" },
3165
+ { id: "gitlab", label: "GitLab Registry", icon: "\u{1F98A}" },
3166
+ { id: "custom", label: "Custom/Self-hosted", icon: "\u{1F3E0}" }
3167
+ ];
2628
3168
  var COMMON_COMMANDS = {
2629
3169
  build: [
2630
3170
  "npm run build",
@@ -2806,6 +3346,23 @@ var PROJECT_TYPES = [
2806
3346
  { id: "opensource", label: "Open Source", icon: "\u{1F30D}", description: "Community-driven project" },
2807
3347
  { id: "learning", label: "Learning", icon: "\u{1F4DA}", description: "Educational/experimental" }
2808
3348
  ];
3349
+ var DEV_OS_OPTIONS = [
3350
+ { id: "macos", label: "macOS", icon: "\u{1F34E}" },
3351
+ { id: "linux", label: "Linux", icon: "\u{1F427}" },
3352
+ { id: "windows", label: "Windows", icon: "\u{1FA9F}" },
3353
+ { id: "wsl", label: "WSL", icon: "\u{1F427}" },
3354
+ { id: "remote", label: "Remote/SSH", icon: "\u2601\uFE0F" }
3355
+ ];
3356
+ var ARCHITECTURE_PATTERNS = [
3357
+ { id: "monolith", label: "Monolith" },
3358
+ { id: "microservices", label: "Microservices" },
3359
+ { id: "serverless", label: "Serverless" },
3360
+ { id: "mvc", label: "MVC" },
3361
+ { id: "layered", label: "Layered/N-tier" },
3362
+ { id: "event_driven", label: "Event-driven" },
3363
+ { id: "modular", label: "Modular monolith" },
3364
+ { id: "other", label: "Other" }
3365
+ ];
2809
3366
  function canAccessTier(userTier, requiredTier) {
2810
3367
  const tierLevels = { free: 0, pro: 1, max: 2, teams: 2 };
2811
3368
  const requiredLevels = { basic: 0, intermediate: 1, advanced: 2 };
@@ -2890,16 +3447,19 @@ async function wizardCommand(options) {
2890
3447
  const userTier = ["pro", "max", "teams"].includes(userPlanRaw) ? userPlanRaw : "free";
2891
3448
  const userPlanDisplay = user?.plan?.toUpperCase() || "FREE";
2892
3449
  if (!authenticated) {
2893
- console.log(chalk8.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
2894
- console.log(chalk8.yellow("\u2502") + chalk8.white(" \u{1F4A1} ") + chalk8.gray("Log in for full wizard features:") + " " + chalk8.yellow("\u2502"));
2895
- console.log(chalk8.yellow("\u2502") + " " + chalk8.yellow("\u2502"));
2896
- console.log(chalk8.yellow("\u2502") + chalk8.gray(" \u2022 ") + chalk8.white("Commands & Code Style") + chalk8.cyan(" [PRO]") + " " + chalk8.yellow("\u2502"));
2897
- console.log(chalk8.yellow("\u2502") + chalk8.gray(" \u2022 ") + chalk8.white("Boundaries, Testing, Static Files") + chalk8.magenta(" [MAX]") + " " + chalk8.yellow("\u2502"));
2898
- console.log(chalk8.yellow("\u2502") + chalk8.gray(" \u2022 ") + chalk8.white("Push configs to cloud") + chalk8.gray(" (lynxp push)") + " " + chalk8.yellow("\u2502"));
2899
- console.log(chalk8.yellow("\u2502") + chalk8.gray(" \u2022 ") + chalk8.white("Sync across devices") + chalk8.gray(" (lynxp sync)") + " " + chalk8.yellow("\u2502"));
2900
- console.log(chalk8.yellow("\u2502") + " " + chalk8.yellow("\u2502"));
2901
- console.log(chalk8.yellow("\u2502") + chalk8.cyan(" Run: lynxp login") + " " + chalk8.yellow("\u2502"));
2902
- console.log(chalk8.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
3450
+ const W = 55;
3451
+ const y = chalk8.yellow;
3452
+ const pad = (s, len) => s + " ".repeat(Math.max(0, len - s.length));
3453
+ console.log(y("\u250C" + "\u2500".repeat(W) + "\u2510"));
3454
+ console.log(y("\u2502") + pad(" \u{1F4A1} Log in for full wizard features:", W - 1) + y("\u2502"));
3455
+ console.log(y("\u2502") + " ".repeat(W) + y("\u2502"));
3456
+ console.log(y("\u2502") + pad(" \u2022 Commands & Code Style [PRO]", W) + y("\u2502"));
3457
+ console.log(y("\u2502") + pad(" \u2022 Boundaries, Testing, Static Files [MAX]", W) + y("\u2502"));
3458
+ console.log(y("\u2502") + pad(" \u2022 Push configs to cloud (lynxp push)", W) + y("\u2502"));
3459
+ console.log(y("\u2502") + pad(" \u2022 Sync across devices (lynxp sync)", W) + y("\u2502"));
3460
+ console.log(y("\u2502") + " ".repeat(W) + y("\u2502"));
3461
+ console.log(y("\u2502") + pad(" Run: " + chalk8.cyan("lynxp login"), W + 10) + y("\u2502"));
3462
+ console.log(y("\u2514" + "\u2500".repeat(W) + "\u2518"));
2903
3463
  console.log();
2904
3464
  } else {
2905
3465
  const planEmoji = userTier === "teams" ? "\u{1F465}" : userTier === "max" ? "\u{1F680}" : userTier === "pro" ? "\u26A1" : "\u{1F193}";
@@ -3026,40 +3586,26 @@ async function runInteractiveWizard(options, detected, userTier) {
3026
3586
  platforms = options.format.split(",").map((f) => f.trim());
3027
3587
  console.log(chalk8.gray(` Using format from flag: ${platforms.join(", ")}`));
3028
3588
  } else {
3029
- const formatResponse = await prompts4({
3030
- type: "select",
3031
- name: "format",
3032
- message: chalk8.white("Where will you use this?"),
3033
- choices: OUTPUT_FORMATS.map((f) => ({
3034
- title: f.recommended ? `${f.title} ${chalk8.green.bold("\u2605 recommended")}` : f.title,
3035
- value: f.value,
3036
- description: chalk8.gray(f.description)
3589
+ console.log(chalk8.gray(" Select the AI editors you want to generate config for:"));
3590
+ console.log(chalk8.gray(" (AGENTS.md is recommended - works with most AI tools)"));
3591
+ console.log();
3592
+ const platformResponse = await prompts4({
3593
+ type: "multiselect",
3594
+ name: "platforms",
3595
+ message: chalk8.white("Select AI editors (16 supported):"),
3596
+ choices: ALL_PLATFORMS.map((p) => ({
3597
+ title: p.id === "agents" ? `${p.icon} ${p.name} ${chalk8.green.bold("\u2605 recommended")}` : `${p.icon} ${p.name}`,
3598
+ value: p.id,
3599
+ description: chalk8.gray(p.note),
3600
+ selected: p.id === "agents"
3601
+ // Pre-select AGENTS.md
3037
3602
  })),
3038
- initial: 0,
3039
- hint: chalk8.gray("\u2191\u2193 navigate \u2022 enter select")
3603
+ hint: chalk8.gray("space select \u2022 a toggle all \u2022 enter confirm"),
3604
+ min: 1,
3605
+ instructions: false
3040
3606
  }, promptConfig);
3041
- if (formatResponse.format === "multiple") {
3042
- console.log();
3043
- console.log(chalk8.gray(" Select the AI editors you want to generate config for:"));
3044
- console.log();
3045
- const platformResponse = await prompts4({
3046
- type: "multiselect",
3047
- name: "platforms",
3048
- message: chalk8.white("Select AI editors (16 supported):"),
3049
- choices: ALL_PLATFORMS.map((p) => ({
3050
- title: `${p.icon} ${p.name}`,
3051
- value: p.id,
3052
- description: chalk8.gray(p.note)
3053
- })),
3054
- hint: chalk8.gray("space select \u2022 a toggle all \u2022 enter confirm"),
3055
- min: 1,
3056
- instructions: false
3057
- }, promptConfig);
3058
- platforms = platformResponse.platforms || ["agents"];
3059
- console.log(chalk8.green(` \u2713 Selected ${platforms.length} platform${platforms.length === 1 ? "" : "s"}`));
3060
- } else {
3061
- platforms = [formatResponse.format || "agents"];
3062
- }
3607
+ platforms = platformResponse.platforms || ["agents"];
3608
+ console.log(chalk8.green(` \u2713 Selected ${platforms.length} platform${platforms.length === 1 ? "" : "s"}`));
3063
3609
  }
3064
3610
  answers.platforms = platforms;
3065
3611
  const projectStep = getCurrentStep("project");
@@ -3084,20 +3630,63 @@ async function runInteractiveWizard(options, detected, userTier) {
3084
3630
  type: "select",
3085
3631
  name: "projectType",
3086
3632
  message: chalk8.white("Project type:"),
3087
- choices: PROJECT_TYPES.map((t) => ({
3088
- title: `${t.icon} ${t.label}`,
3089
- value: t.id,
3090
- description: chalk8.gray(t.description)
3091
- })),
3633
+ choices: [
3634
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3635
+ ...PROJECT_TYPES.map((t) => ({
3636
+ title: `${t.icon} ${t.label}`,
3637
+ value: t.id,
3638
+ description: chalk8.gray(t.description)
3639
+ }))
3640
+ ],
3092
3641
  initial: 0
3093
3642
  }, promptConfig);
3094
- answers.projectType = typeResponse.projectType || "work";
3643
+ answers.projectType = typeResponse.projectType || "";
3644
+ const devOsResponse = await prompts4({
3645
+ type: "select",
3646
+ name: "devOS",
3647
+ message: chalk8.white("Development environment:"),
3648
+ choices: [
3649
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3650
+ ...DEV_OS_OPTIONS.map((o) => ({
3651
+ title: `${o.icon} ${o.label}`,
3652
+ value: o.id
3653
+ }))
3654
+ ],
3655
+ initial: 0,
3656
+ hint: chalk8.gray("Helps generate compatible commands")
3657
+ }, promptConfig);
3658
+ answers.devOS = devOsResponse.devOS || "";
3659
+ const archResponse = await prompts4({
3660
+ type: "select",
3661
+ name: "architecture",
3662
+ message: chalk8.white("Architecture pattern:"),
3663
+ choices: [
3664
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3665
+ ...ARCHITECTURE_PATTERNS.map((a) => ({
3666
+ title: a.label,
3667
+ value: a.id
3668
+ }))
3669
+ ],
3670
+ initial: 0
3671
+ }, promptConfig);
3672
+ answers.architecture = archResponse.architecture || "";
3095
3673
  const techStep = getCurrentStep("tech");
3096
3674
  showStep(currentStepNum, techStep, userTier);
3675
+ const letAiResponse = await prompts4({
3676
+ type: "toggle",
3677
+ name: "letAiDecide",
3678
+ message: chalk8.white("Let AI help choose additional technologies?"),
3679
+ initial: false,
3680
+ active: "Yes",
3681
+ inactive: "No"
3682
+ }, promptConfig);
3683
+ answers.letAiDecide = letAiResponse.letAiDecide || false;
3684
+ console.log();
3685
+ console.log(chalk8.gray(" You can also select specific technologies below:"));
3686
+ console.log();
3097
3687
  const allStackOptions = [...LANGUAGES, ...FRAMEWORKS, ...DATABASES];
3098
- const detectedStackSet = new Set(detected?.stack || []);
3099
- if (detectedStackSet.size > 0) {
3100
- console.log(chalk8.gray(` Auto-selected: ${detected?.stack?.join(", ")}`));
3688
+ if (detected?.stack && detected.stack.length > 0) {
3689
+ console.log(chalk8.gray(` Detected in project: ${detected.stack.join(", ")}`));
3101
3690
  console.log();
3102
3691
  }
3103
3692
  const stackResponse = await prompts4({
@@ -3106,8 +3695,8 @@ async function runInteractiveWizard(options, detected, userTier) {
3106
3695
  message: chalk8.white("Languages, frameworks & databases:"),
3107
3696
  choices: allStackOptions.map((s) => ({
3108
3697
  title: s.title,
3109
- value: s.value,
3110
- selected: detectedStackSet.has(s.value)
3698
+ value: s.value
3699
+ // No pre-selection - user must explicitly choose
3111
3700
  })),
3112
3701
  hint: chalk8.gray("space select \u2022 a toggle all \u2022 enter confirm"),
3113
3702
  instructions: false
@@ -3115,17 +3704,29 @@ async function runInteractiveWizard(options, detected, userTier) {
3115
3704
  answers.stack = stackResponse.stack || [];
3116
3705
  const repoStep = getCurrentStep("repo");
3117
3706
  showStep(currentStepNum, repoStep, userTier);
3707
+ if (detected?.repoHost || detected?.license || detected?.cicd) {
3708
+ console.log(chalk8.green(" \u2713 Auto-detected from your project:"));
3709
+ if (detected.repoHost) console.log(chalk8.gray(` \u2022 Repository: ${detected.repoHost}${detected.repoUrl ? ` (${detected.repoUrl})` : ""}`));
3710
+ if (detected.license) console.log(chalk8.gray(` \u2022 License: ${detected.license}`));
3711
+ if (detected.cicd) console.log(chalk8.gray(` \u2022 CI/CD: ${detected.cicd}`));
3712
+ console.log();
3713
+ }
3714
+ const repoHostChoices = [
3715
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3716
+ ...REPO_HOSTS.map((h) => ({
3717
+ title: detected?.repoHost === h.id ? `${h.icon} ${h.label} ${chalk8.green("(detected)")}` : `${h.icon} ${h.label}`,
3718
+ value: h.id
3719
+ }))
3720
+ ];
3721
+ const detectedRepoIndex = detected?.repoHost ? repoHostChoices.findIndex((c) => c.value === detected.repoHost) : 0;
3118
3722
  const repoHostResponse = await prompts4({
3119
3723
  type: "select",
3120
3724
  name: "repoHost",
3121
3725
  message: chalk8.white("Repository host:"),
3122
- choices: REPO_HOSTS.map((h) => ({
3123
- title: `${h.icon} ${h.label}`,
3124
- value: h.id
3125
- })),
3126
- initial: 0
3726
+ choices: repoHostChoices,
3727
+ initial: detectedRepoIndex > 0 ? detectedRepoIndex : 0
3127
3728
  }, promptConfig);
3128
- answers.repoHost = repoHostResponse.repoHost || "github";
3729
+ answers.repoHost = repoHostResponse.repoHost || "";
3129
3730
  const visibilityResponse = await prompts4({
3130
3731
  type: "toggle",
3131
3732
  name: "isPublic",
@@ -3135,26 +3736,119 @@ async function runInteractiveWizard(options, detected, userTier) {
3135
3736
  inactive: "No"
3136
3737
  }, promptConfig);
3137
3738
  answers.isPublic = visibilityResponse.isPublic || false;
3739
+ const licenseChoices = [
3740
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3741
+ ...LICENSES.map((l) => ({
3742
+ title: detected?.license === l.id ? `${l.label} ${chalk8.green("(detected)")}` : l.label,
3743
+ value: l.id
3744
+ }))
3745
+ ];
3746
+ const detectedLicenseIndex = detected?.license ? licenseChoices.findIndex((c) => c.value === detected.license) : 0;
3138
3747
  const licenseResponse = await prompts4({
3139
3748
  type: "select",
3140
3749
  name: "license",
3141
3750
  message: chalk8.white("License:"),
3142
- choices: LICENSES.map((l) => ({
3143
- title: l.label,
3144
- value: l.id
3145
- })),
3146
- initial: 0
3751
+ choices: licenseChoices,
3752
+ initial: detectedLicenseIndex > 0 ? detectedLicenseIndex : 0
3147
3753
  }, promptConfig);
3148
- answers.license = licenseResponse.license || "mit";
3754
+ answers.license = licenseResponse.license || "";
3149
3755
  const conventionalResponse = await prompts4({
3150
3756
  type: "toggle",
3151
3757
  name: "conventionalCommits",
3152
3758
  message: chalk8.white("Use Conventional Commits?"),
3153
- initial: true,
3759
+ initial: false,
3760
+ active: "Yes",
3761
+ inactive: "No"
3762
+ }, promptConfig);
3763
+ answers.conventionalCommits = conventionalResponse.conventionalCommits || false;
3764
+ const semverResponse = await prompts4({
3765
+ type: "toggle",
3766
+ name: "semver",
3767
+ message: chalk8.white("Use Semantic Versioning?"),
3768
+ initial: false,
3769
+ active: "Yes",
3770
+ inactive: "No"
3771
+ }, promptConfig);
3772
+ answers.semver = semverResponse.semver || false;
3773
+ if (answers.repoHost === "github" || answers.repoHost === "gitlab") {
3774
+ const dependabotResponse = await prompts4({
3775
+ type: "toggle",
3776
+ name: "dependabot",
3777
+ message: chalk8.white("Enable Dependabot/dependency updates?"),
3778
+ initial: false,
3779
+ active: "Yes",
3780
+ inactive: "No"
3781
+ }, promptConfig);
3782
+ answers.dependabot = dependabotResponse.dependabot || false;
3783
+ }
3784
+ const cicdChoices = [
3785
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3786
+ ...CICD_OPTIONS.map((c) => ({
3787
+ title: detected?.cicd === c.id ? `${c.icon} ${c.label} ${chalk8.green("(detected)")}` : `${c.icon} ${c.label}`,
3788
+ value: c.id
3789
+ }))
3790
+ ];
3791
+ const detectedCicdIndex = detected?.cicd ? cicdChoices.findIndex((c) => c.value === detected.cicd) : 0;
3792
+ const cicdResponse = await prompts4({
3793
+ type: "select",
3794
+ name: "cicd",
3795
+ message: chalk8.white("CI/CD Platform:"),
3796
+ choices: cicdChoices,
3797
+ initial: detectedCicdIndex > 0 ? detectedCicdIndex : 0
3798
+ }, promptConfig);
3799
+ answers.cicd = cicdResponse.cicd || "";
3800
+ const deployResponse = await prompts4({
3801
+ type: "multiselect",
3802
+ name: "deploymentTargets",
3803
+ message: chalk8.white("Deployment targets:"),
3804
+ choices: DEPLOYMENT_TARGETS.map((t) => ({
3805
+ title: t.id === "docker" && detected?.hasDocker ? `${t.icon} ${t.label} ${chalk8.green("(detected)")}` : `${t.icon} ${t.label}`,
3806
+ selected: t.id === "docker" && detected?.hasDocker,
3807
+ value: t.id
3808
+ })),
3809
+ hint: chalk8.gray("space select \u2022 enter to skip/confirm"),
3810
+ instructions: false
3811
+ }, promptConfig);
3812
+ answers.deploymentTargets = deployResponse.deploymentTargets || [];
3813
+ const containerResponse = await prompts4({
3814
+ type: "toggle",
3815
+ name: "buildContainer",
3816
+ message: chalk8.white("Build container images (Docker)?"),
3817
+ initial: false,
3154
3818
  active: "Yes",
3155
3819
  inactive: "No"
3156
3820
  }, promptConfig);
3157
- answers.conventionalCommits = conventionalResponse.conventionalCommits ?? true;
3821
+ answers.buildContainer = containerResponse.buildContainer || false;
3822
+ if (answers.buildContainer) {
3823
+ const registryResponse = await prompts4({
3824
+ type: "select",
3825
+ name: "containerRegistry",
3826
+ message: chalk8.white("Container registry:"),
3827
+ choices: [
3828
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3829
+ ...CONTAINER_REGISTRIES.map((r) => ({
3830
+ title: `${r.icon} ${r.label}`,
3831
+ value: r.id
3832
+ }))
3833
+ ],
3834
+ initial: 0
3835
+ }, promptConfig);
3836
+ answers.containerRegistry = registryResponse.containerRegistry || "";
3837
+ }
3838
+ const exampleRepoResponse = await prompts4({
3839
+ type: "text",
3840
+ name: "exampleRepoUrl",
3841
+ message: chalk8.white("Example repository URL (optional):"),
3842
+ hint: chalk8.gray("A similar public repo for AI to learn from")
3843
+ }, promptConfig);
3844
+ answers.exampleRepoUrl = exampleRepoResponse.exampleRepoUrl || "";
3845
+ const docsUrlResponse = await prompts4({
3846
+ type: "text",
3847
+ name: "documentationUrl",
3848
+ message: chalk8.white("External documentation URL (optional):"),
3849
+ hint: chalk8.gray("Confluence, Notion, GitBook, etc.")
3850
+ }, promptConfig);
3851
+ answers.documentationUrl = docsUrlResponse.documentationUrl || "";
3158
3852
  if (canAccessTier(userTier, "intermediate")) {
3159
3853
  const commandsStep = getCurrentStep("commands");
3160
3854
  showStep(currentStepNum, commandsStep, userTier);
@@ -3233,25 +3927,38 @@ async function runInteractiveWizard(options, detected, userTier) {
3233
3927
  type: "select",
3234
3928
  name: "naming",
3235
3929
  message: chalk8.white("Naming convention:"),
3236
- choices: NAMING_CONVENTIONS.map((n) => ({
3237
- title: n.label,
3238
- value: n.id,
3239
- description: chalk8.gray(n.desc)
3240
- })),
3930
+ choices: [
3931
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3932
+ ...NAMING_CONVENTIONS.map((n) => ({
3933
+ title: n.label,
3934
+ value: n.id,
3935
+ description: chalk8.gray(n.desc)
3936
+ }))
3937
+ ],
3241
3938
  initial: 0
3242
3939
  }, promptConfig);
3243
- answers.namingConvention = namingResponse.naming || "language_default";
3940
+ answers.namingConvention = namingResponse.naming || "";
3244
3941
  const errorResponse = await prompts4({
3245
3942
  type: "select",
3246
3943
  name: "errorHandling",
3247
3944
  message: chalk8.white("Error handling pattern:"),
3248
- choices: ERROR_PATTERNS.map((e) => ({
3249
- title: e.label,
3250
- value: e.id
3251
- })),
3945
+ choices: [
3946
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3947
+ ...ERROR_PATTERNS.map((e) => ({
3948
+ title: e.label,
3949
+ value: e.id
3950
+ }))
3951
+ ],
3252
3952
  initial: 0
3253
3953
  }, promptConfig);
3254
- answers.errorHandling = errorResponse.errorHandling || "try_catch";
3954
+ answers.errorHandling = errorResponse.errorHandling || "";
3955
+ const loggingResponse = await prompts4({
3956
+ type: "text",
3957
+ name: "loggingConventions",
3958
+ message: chalk8.white("Logging conventions (optional):"),
3959
+ hint: chalk8.gray("e.g., use structured logging, JSON format, specific lib")
3960
+ }, promptConfig);
3961
+ answers.loggingConventions = loggingResponse.loggingConventions || "";
3255
3962
  const styleNotesResponse = await prompts4({
3256
3963
  type: "text",
3257
3964
  name: "styleNotes",
@@ -3267,11 +3974,11 @@ async function runInteractiveWizard(options, detected, userTier) {
3267
3974
  name: "aiBehavior",
3268
3975
  message: chalk8.white("AI behavior rules:"),
3269
3976
  choices: AI_BEHAVIOR_RULES.map((r) => ({
3270
- title: r.recommended ? `${r.label} ${chalk8.green("\u2605")}` : r.label,
3271
- value: r.id,
3272
- selected: r.recommended
3977
+ title: r.recommended ? `${r.label} ${chalk8.green("\u2605 recommended")}` : r.label,
3978
+ value: r.id
3979
+ // No pre-selection - user must explicitly choose
3273
3980
  })),
3274
- hint: chalk8.gray("space select \u2022 enter confirm"),
3981
+ hint: chalk8.gray("space select \u2022 enter to skip/confirm"),
3275
3982
  instructions: false
3276
3983
  }, promptConfig);
3277
3984
  answers.aiBehavior = aiBehaviorResponse.aiBehavior || [];
@@ -3281,10 +3988,10 @@ async function runInteractiveWizard(options, detected, userTier) {
3281
3988
  message: chalk8.white("Important files AI should read:"),
3282
3989
  choices: IMPORTANT_FILES.map((f) => ({
3283
3990
  title: `${f.icon} ${f.label}`,
3284
- value: f.id,
3285
- selected: f.id === "readme" || f.id === "package"
3991
+ value: f.id
3992
+ // No pre-selection - user must explicitly choose
3286
3993
  })),
3287
- hint: chalk8.gray("space select \u2022 enter confirm"),
3994
+ hint: chalk8.gray("space select \u2022 enter to skip/confirm"),
3288
3995
  instructions: false
3289
3996
  }, promptConfig);
3290
3997
  answers.importantFiles = importantFilesResponse.importantFiles || [];
@@ -3297,6 +4004,15 @@ async function runInteractiveWizard(options, detected, userTier) {
3297
4004
  inactive: "No"
3298
4005
  }, promptConfig);
3299
4006
  answers.selfImprove = selfImproveResponse.selfImprove || false;
4007
+ const includePersonalResponse = await prompts4({
4008
+ type: "toggle",
4009
+ name: "includePersonalData",
4010
+ message: chalk8.white("Include personal data (name/email for commits)?"),
4011
+ initial: false,
4012
+ active: "Yes",
4013
+ inactive: "No"
4014
+ }, promptConfig);
4015
+ answers.includePersonalData = includePersonalResponse.includePersonalData || false;
3300
4016
  if (canAccessTier(userTier, "advanced")) {
3301
4017
  const boundariesStep = getCurrentStep("boundaries");
3302
4018
  showStep(currentStepNum, boundariesStep, userTier);
@@ -3304,14 +4020,17 @@ async function runInteractiveWizard(options, detected, userTier) {
3304
4020
  type: "select",
3305
4021
  name: "boundaryPreset",
3306
4022
  message: chalk8.white("Boundary preset:"),
3307
- choices: BOUNDARY_PRESETS.map((b) => ({
3308
- title: b.title,
3309
- value: b.value,
3310
- description: chalk8.gray(b.description)
3311
- })),
4023
+ choices: [
4024
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
4025
+ ...BOUNDARY_PRESETS.map((b) => ({
4026
+ title: b.title,
4027
+ value: b.value,
4028
+ description: chalk8.gray(b.description)
4029
+ }))
4030
+ ],
3312
4031
  initial: 0
3313
4032
  }, promptConfig);
3314
- answers.boundaries = presetResponse.boundaryPreset || "standard";
4033
+ answers.boundaries = presetResponse.boundaryPreset || "";
3315
4034
  const selectedPreset = BOUNDARY_PRESETS.find((b) => b.value === answers.boundaries);
3316
4035
  if (selectedPreset) {
3317
4036
  console.log();
@@ -3411,32 +4130,104 @@ async function runInteractiveWizard(options, detected, userTier) {
3411
4130
  showStep(currentStepNum, staticStep, userTier);
3412
4131
  console.log(chalk8.gray(" Generate additional project files:"));
3413
4132
  console.log();
4133
+ const STATIC_FILE_OPTIONS = [
4134
+ { title: "\u{1F4DD} .editorconfig", value: "editorconfig", desc: "Consistent code formatting" },
4135
+ { title: "\u{1F91D} CONTRIBUTING.md", value: "contributing", desc: "Contributor guidelines" },
4136
+ { title: "\u{1F4DC} CODE_OF_CONDUCT.md", value: "codeOfConduct", desc: "Community standards" },
4137
+ { title: "\u{1F512} SECURITY.md", value: "security", desc: "Vulnerability reporting" },
4138
+ { title: "\u{1F5FA}\uFE0F ROADMAP.md", value: "roadmap", desc: "Project roadmap" },
4139
+ { title: "\u{1F4CB} .gitignore", value: "gitignore", desc: "Git ignore patterns" },
4140
+ { title: "\u{1F4B0} FUNDING.yml", value: "funding", desc: "GitHub Sponsors config" },
4141
+ { title: "\u{1F4C4} LICENSE", value: "license", desc: "License file" },
4142
+ { title: "\u{1F4D6} README.md", value: "readme", desc: "Project readme" },
4143
+ { title: "\u{1F3D7}\uFE0F ARCHITECTURE.md", value: "architecture", desc: "Architecture docs" },
4144
+ { title: "\u{1F4DD} CHANGELOG.md", value: "changelog", desc: "Version history" }
4145
+ ];
4146
+ const existingFiles = {};
4147
+ for (const opt of STATIC_FILE_OPTIONS) {
4148
+ const filePath = STATIC_FILE_PATHS2[opt.value];
4149
+ if (filePath) {
4150
+ const content = await readExistingFile(join6(process.cwd(), filePath));
4151
+ if (content) {
4152
+ existingFiles[opt.value] = content;
4153
+ }
4154
+ }
4155
+ }
4156
+ const existingCount = Object.keys(existingFiles).length;
4157
+ if (existingCount > 0) {
4158
+ console.log(chalk8.green(` \u2713 Found ${existingCount} existing file(s) in your project`));
4159
+ console.log();
4160
+ }
3414
4161
  const staticFilesResponse = await prompts4({
3415
4162
  type: "multiselect",
3416
4163
  name: "staticFiles",
3417
4164
  message: chalk8.white("Include static files:"),
3418
- choices: [
3419
- { title: "\u{1F4DD} .editorconfig", value: "editorconfig", description: chalk8.gray("Consistent code formatting") },
3420
- { title: "\u{1F91D} CONTRIBUTING.md", value: "contributing", description: chalk8.gray("Contributor guidelines") },
3421
- { title: "\u{1F4DC} CODE_OF_CONDUCT.md", value: "codeOfConduct", description: chalk8.gray("Community standards") },
3422
- { title: "\u{1F512} SECURITY.md", value: "security", description: chalk8.gray("Vulnerability reporting") },
3423
- { title: "\u{1F5FA}\uFE0F ROADMAP.md", value: "roadmap", description: chalk8.gray("Project roadmap") },
3424
- { title: "\u{1F4CB} .gitignore", value: "gitignore", description: chalk8.gray("Git ignore patterns"), selected: true }
3425
- ],
3426
- hint: chalk8.gray("space select \u2022 enter confirm"),
4165
+ choices: STATIC_FILE_OPTIONS.map((f) => ({
4166
+ title: existingFiles[f.value] ? `${f.title} ${chalk8.green("(exists)")}` : f.title,
4167
+ value: f.value,
4168
+ description: chalk8.gray(f.desc)
4169
+ })),
4170
+ hint: chalk8.gray("space select \u2022 enter to skip/confirm"),
3427
4171
  instructions: false
3428
4172
  }, promptConfig);
3429
4173
  answers.staticFiles = staticFilesResponse.staticFiles || [];
3430
- if (answers.repoHost === "github" && answers.isPublic) {
3431
- const fundingResponse = await prompts4({
3432
- type: "toggle",
3433
- name: "funding",
3434
- message: chalk8.white("Generate FUNDING.yml for GitHub Sponsors?"),
3435
- initial: false,
3436
- active: "Yes",
3437
- inactive: "No"
3438
- }, promptConfig);
3439
- answers.includeFunding = fundingResponse.funding || false;
4174
+ if (answers.staticFiles?.length > 0) {
4175
+ console.log();
4176
+ console.log(chalk8.cyan(" \u{1F4DD} Customize file contents:"));
4177
+ console.log(chalk8.gray(" For each file, choose to use existing content, write new, or use defaults."));
4178
+ console.log();
4179
+ answers.staticFileContents = {};
4180
+ for (const fileKey of answers.staticFiles) {
4181
+ const fileOpt = STATIC_FILE_OPTIONS.find((f) => f.value === fileKey);
4182
+ if (!fileOpt) continue;
4183
+ const filePath = STATIC_FILE_PATHS2[fileKey];
4184
+ const existingContent = existingFiles[fileKey];
4185
+ if (existingContent) {
4186
+ const preview = existingContent.split("\n").slice(0, 3).join("\n");
4187
+ console.log(chalk8.gray(` \u2500\u2500\u2500 ${filePath} (existing) \u2500\u2500\u2500`));
4188
+ console.log(chalk8.gray(preview.substring(0, 150) + (preview.length > 150 ? "..." : "")));
4189
+ console.log();
4190
+ const actionResponse = await prompts4({
4191
+ type: "select",
4192
+ name: "action",
4193
+ message: chalk8.white(`${filePath}:`),
4194
+ choices: [
4195
+ { title: chalk8.green("\u2713 Use existing content"), value: "existing" },
4196
+ { title: chalk8.yellow("\u270F\uFE0F Write new content"), value: "new" },
4197
+ { title: chalk8.gray("\u26A1 Generate default"), value: "default" }
4198
+ ],
4199
+ initial: 0
4200
+ }, promptConfig);
4201
+ if (actionResponse.action === "existing") {
4202
+ answers.staticFileContents[fileKey] = existingContent;
4203
+ } else if (actionResponse.action === "new") {
4204
+ console.log();
4205
+ const content = await readMultilineInput(` Content for ${filePath}:`);
4206
+ if (content.trim()) {
4207
+ answers.staticFileContents[fileKey] = content;
4208
+ }
4209
+ }
4210
+ } else {
4211
+ const actionResponse = await prompts4({
4212
+ type: "select",
4213
+ name: "action",
4214
+ message: chalk8.white(`${filePath}:`),
4215
+ choices: [
4216
+ { title: chalk8.gray("\u26A1 Generate default"), value: "default" },
4217
+ { title: chalk8.yellow("\u270F\uFE0F Write custom content"), value: "new" }
4218
+ ],
4219
+ initial: 0
4220
+ }, promptConfig);
4221
+ if (actionResponse.action === "new") {
4222
+ console.log();
4223
+ const content = await readMultilineInput(` Content for ${filePath}:`);
4224
+ if (content.trim()) {
4225
+ answers.staticFileContents[fileKey] = content;
4226
+ }
4227
+ }
4228
+ }
4229
+ console.log();
4230
+ }
3440
4231
  }
3441
4232
  }
3442
4233
  const extraStep = getCurrentStep("extra");
@@ -3446,6 +4237,7 @@ async function runInteractiveWizard(options, detected, userTier) {
3446
4237
  name: "persona",
3447
4238
  message: chalk8.white("AI assistant persona:"),
3448
4239
  choices: [
4240
+ { title: chalk8.gray("\u23ED Skip"), value: "" },
3449
4241
  { title: "\u{1F9D1}\u200D\u{1F4BB} Full-Stack Developer", value: "fullstack", description: chalk8.gray("Complete application development") },
3450
4242
  { title: "\u2699\uFE0F Backend Developer", value: "backend", description: chalk8.gray("APIs, databases, services") },
3451
4243
  { title: "\u{1F3A8} Frontend Developer", value: "frontend", description: chalk8.gray("UI, components, styling") },
@@ -3463,9 +4255,9 @@ async function runInteractiveWizard(options, detected, userTier) {
3463
4255
  message: chalk8.white("Describe the custom persona:"),
3464
4256
  hint: chalk8.gray("e.g., 'ML engineer focused on PyTorch'")
3465
4257
  }, promptConfig);
3466
- answers.persona = customPersona.value || "fullstack";
4258
+ answers.persona = customPersona.value || "";
3467
4259
  } else {
3468
- answers.persona = personaResponse.persona || "fullstack";
4260
+ answers.persona = personaResponse.persona || "";
3469
4261
  }
3470
4262
  const extraNotesResponse = await prompts4({
3471
4263
  type: "text",
@@ -3487,6 +4279,8 @@ async function runInteractiveWizard(options, detected, userTier) {
3487
4279
  commands: typeof answers.commands === "object" ? answers.commands : detected?.commands || {},
3488
4280
  // Extended config for Pro/Max users
3489
4281
  projectType: answers.projectType,
4282
+ devOS: answers.devOS,
4283
+ architecture: answers.architecture,
3490
4284
  repoHost: answers.repoHost,
3491
4285
  isPublic: answers.isPublic,
3492
4286
  license: answers.license,
@@ -3572,7 +4366,7 @@ function handleApiError3(error) {
3572
4366
 
3573
4367
  // src/commands/status.ts
3574
4368
  import chalk10 from "chalk";
3575
- import { readFile as readFile5, readdir, access as access4 } from "fs/promises";
4369
+ import { readFile as readFile6, readdir, access as access4 } from "fs/promises";
3576
4370
  import { join as join7 } from "path";
3577
4371
  import { existsSync as existsSync4 } from "fs";
3578
4372
  var CONFIG_FILES = [
@@ -3602,7 +4396,7 @@ async function statusCommand() {
3602
4396
  const configPath = join7(cwd, ".lynxprompt/conf.yml");
3603
4397
  if (existsSync4(configPath)) {
3604
4398
  try {
3605
- const content = await readFile5(configPath, "utf-8");
4399
+ const content = await readFile6(configPath, "utf-8");
3606
4400
  const { parse: parse5 } = await import("yaml");
3607
4401
  const config2 = parse5(content);
3608
4402
  if (config2?.exporters?.length > 0) {
@@ -3646,7 +4440,7 @@ async function statusCommand() {
3646
4440
  const filePath = join7(cwd, config2.path);
3647
4441
  try {
3648
4442
  await access4(filePath);
3649
- const content = await readFile5(filePath, "utf-8");
4443
+ const content = await readFile6(filePath, "utf-8");
3650
4444
  const lines = content.split("\n").length;
3651
4445
  const size = formatBytes(content.length);
3652
4446
  foundAny = true;
@@ -3725,7 +4519,7 @@ function formatBytes(bytes) {
3725
4519
  import chalk11 from "chalk";
3726
4520
  import ora9 from "ora";
3727
4521
  import prompts5 from "prompts";
3728
- import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir2 } from "fs/promises";
4522
+ import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir2 } from "fs/promises";
3729
4523
  import { join as join8, dirname as dirname5 } from "path";
3730
4524
  import { existsSync as existsSync5 } from "fs";
3731
4525
  import * as yaml3 from "yaml";
@@ -3746,7 +4540,7 @@ async function syncCommand(options = {}) {
3746
4540
  const spinner = ora9("Loading configuration...").start();
3747
4541
  let config2;
3748
4542
  try {
3749
- const configContent = await readFile6(configPath, "utf-8");
4543
+ const configContent = await readFile7(configPath, "utf-8");
3750
4544
  config2 = yaml3.parse(configContent);
3751
4545
  spinner.succeed("Configuration loaded");
3752
4546
  } catch (error) {
@@ -3848,7 +4642,7 @@ async function loadRules(rulesPath) {
3848
4642
  if (!entry.isFile()) continue;
3849
4643
  if (!entry.name.endsWith(".md")) continue;
3850
4644
  const filePath = join8(rulesPath, entry.name);
3851
- const content = await readFile6(filePath, "utf-8");
4645
+ const content = await readFile7(filePath, "utf-8");
3852
4646
  if (content.trim()) {
3853
4647
  files.push({ name: entry.name, content: content.trim() });
3854
4648
  }
@@ -3936,7 +4730,7 @@ function formatAsJson(content, _agent) {
3936
4730
  // src/commands/agents.ts
3937
4731
  import chalk12 from "chalk";
3938
4732
  import prompts6 from "prompts";
3939
- import { readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
4733
+ import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
3940
4734
  import { join as join9 } from "path";
3941
4735
  import { existsSync as existsSync6 } from "fs";
3942
4736
  import * as yaml4 from "yaml";
@@ -4138,7 +4932,7 @@ async function loadConfig() {
4138
4932
  return null;
4139
4933
  }
4140
4934
  try {
4141
- const content = await readFile7(configPath, "utf-8");
4935
+ const content = await readFile8(configPath, "utf-8");
4142
4936
  return yaml4.parse(content);
4143
4937
  } catch {
4144
4938
  return null;
@@ -4154,7 +4948,7 @@ async function saveConfig(config2) {
4154
4948
  // src/commands/check.ts
4155
4949
  import chalk13 from "chalk";
4156
4950
  import ora10 from "ora";
4157
- import { readFile as readFile8, readdir as readdir3, stat } from "fs/promises";
4951
+ import { readFile as readFile9, readdir as readdir3, stat } from "fs/promises";
4158
4952
  import { join as join10 } from "path";
4159
4953
  import { existsSync as existsSync7 } from "fs";
4160
4954
  import * as yaml5 from "yaml";
@@ -4220,7 +5014,7 @@ async function validateLynxPromptConfig(cwd) {
4220
5014
  return { errors, warnings };
4221
5015
  }
4222
5016
  try {
4223
- const content = await readFile8(configPath, "utf-8");
5017
+ const content = await readFile9(configPath, "utf-8");
4224
5018
  const config2 = yaml5.parse(content);
4225
5019
  if (!config2.version) {
4226
5020
  warnings.push(".lynxprompt/conf.yml: Missing 'version' field");
@@ -4293,7 +5087,7 @@ async function checkCommand(options = {}) {
4293
5087
  if (existsSync7(filePath)) {
4294
5088
  result.files.push(file.path);
4295
5089
  try {
4296
- const content = await readFile8(filePath, "utf-8");
5090
+ const content = await readFile9(filePath, "utf-8");
4297
5091
  const validation = validateMarkdown(content, file.path);
4298
5092
  result.errors.push(...validation.errors);
4299
5093
  result.warnings.push(...validation.warnings);
@@ -4312,7 +5106,7 @@ async function checkCommand(options = {}) {
4312
5106
  const fileStat = await stat(filePath);
4313
5107
  if (fileStat.isFile()) {
4314
5108
  result.files.push(`${dir.path}/${file}`);
4315
- const content = await readFile8(filePath, "utf-8");
5109
+ const content = await readFile9(filePath, "utf-8");
4316
5110
  if (file.endsWith(".mdc")) {
4317
5111
  const validation = validateMdc(content, `${dir.path}/${file}`);
4318
5112
  result.errors.push(...validation.errors);
@@ -4388,7 +5182,7 @@ async function checkCommand(options = {}) {
4388
5182
  // src/commands/diff.ts
4389
5183
  import chalk14 from "chalk";
4390
5184
  import ora11 from "ora";
4391
- import { readFile as readFile9 } from "fs/promises";
5185
+ import { readFile as readFile10 } from "fs/promises";
4392
5186
  import { join as join11 } from "path";
4393
5187
  import { existsSync as existsSync8 } from "fs";
4394
5188
  function computeDiff(oldText, newText) {
@@ -4550,7 +5344,7 @@ async function diffFileWithBlueprint(cwd, file, blueprintId, compact = false) {
4550
5344
  console.log(chalk14.red(`\u2717 Blueprint has no content`));
4551
5345
  return;
4552
5346
  }
4553
- const localContent = await readFile9(filePath, "utf-8");
5347
+ const localContent = await readFile10(filePath, "utf-8");
4554
5348
  const diff = computeDiff(blueprint.content, localContent);
4555
5349
  const stats = getDiffStats(diff);
4556
5350
  if (stats.added === 0 && stats.removed === 0) {
@@ -4606,7 +5400,7 @@ async function diffWithBlueprintId(cwd, blueprintId) {
4606
5400
  const fullPath = join11(cwd, path2);
4607
5401
  if (existsSync8(fullPath)) {
4608
5402
  try {
4609
- localContent = await readFile9(fullPath, "utf-8");
5403
+ localContent = await readFile10(fullPath, "utf-8");
4610
5404
  localPath = path2;
4611
5405
  break;
4612
5406
  } catch {
@@ -4668,7 +5462,7 @@ async function diffLocal(cwd) {
4668
5462
  }
4669
5463
  let rulesContent;
4670
5464
  try {
4671
- rulesContent = await readFile9(rulesPath, "utf-8");
5465
+ rulesContent = await readFile10(rulesPath, "utf-8");
4672
5466
  } catch {
4673
5467
  console.log(chalk14.red("\u2717 Could not read .lynxprompt/rules/agents.md"));
4674
5468
  return;
@@ -4682,7 +5476,7 @@ async function diffLocal(cwd) {
4682
5476
  const filePath = join11(cwd, file.path);
4683
5477
  if (existsSync8(filePath)) {
4684
5478
  try {
4685
- const exportedContent = await readFile9(filePath, "utf-8");
5479
+ const exportedContent = await readFile10(filePath, "utf-8");
4686
5480
  let compareContent = exportedContent;
4687
5481
  if (file.path.endsWith(".mdc")) {
4688
5482
  const frontmatterEnd = exportedContent.indexOf("---", 3);