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 +942 -148
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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(
|
|
269
|
-
console.log(
|
|
270
|
-
console.log(
|
|
271
|
-
console.log(
|
|
272
|
-
console.log(
|
|
273
|
-
console.log(
|
|
274
|
-
console.log(
|
|
275
|
-
console.log(
|
|
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
|
|
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.
|
|
2622
|
+
if (options.letAiDecide) {
|
|
2247
2623
|
if (isMarkdown || isMdc) {
|
|
2248
|
-
sections.push("
|
|
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
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
console.log(
|
|
2897
|
-
console.log(
|
|
2898
|
-
console.log(
|
|
2899
|
-
console.log(
|
|
2900
|
-
console.log(
|
|
2901
|
-
console.log(
|
|
2902
|
-
console.log(
|
|
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
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
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
|
-
|
|
3039
|
-
|
|
3603
|
+
hint: chalk8.gray("space select \u2022 a toggle all \u2022 enter confirm"),
|
|
3604
|
+
min: 1,
|
|
3605
|
+
instructions: false
|
|
3040
3606
|
}, promptConfig);
|
|
3041
|
-
|
|
3042
|
-
|
|
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:
|
|
3088
|
-
title:
|
|
3089
|
-
|
|
3090
|
-
|
|
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 || "
|
|
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
|
-
|
|
3099
|
-
|
|
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
|
-
|
|
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:
|
|
3123
|
-
|
|
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 || "
|
|
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:
|
|
3143
|
-
|
|
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 || "
|
|
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:
|
|
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.
|
|
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:
|
|
3237
|
-
title:
|
|
3238
|
-
|
|
3239
|
-
|
|
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 || "
|
|
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:
|
|
3249
|
-
title:
|
|
3250
|
-
|
|
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 || "
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
3308
|
-
title:
|
|
3309
|
-
|
|
3310
|
-
|
|
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 || "
|
|
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
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
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.
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
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 || "
|
|
4258
|
+
answers.persona = customPersona.value || "";
|
|
3467
4259
|
} else {
|
|
3468
|
-
answers.persona = personaResponse.persona || "
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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);
|