lynxprompt 0.4.6 → 0.5.1
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 +570 -223
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -181,13 +181,16 @@ var ApiClient = class {
|
|
|
181
181
|
if (data.codeStyle.loggingConventions) {
|
|
182
182
|
preferences.push({ category: "code_style", key: "loggingConventions", value: data.codeStyle.loggingConventions, isDefault: true });
|
|
183
183
|
}
|
|
184
|
+
if (data.codeStyle.loggingConventionsOther) {
|
|
185
|
+
preferences.push({ category: "code_style", key: "loggingConventionsOther", value: data.codeStyle.loggingConventionsOther, isDefault: true });
|
|
186
|
+
}
|
|
184
187
|
if (data.codeStyle.notes) {
|
|
185
188
|
preferences.push({ category: "code_style", key: "notes", value: data.codeStyle.notes, isDefault: true });
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
if (data.boundaries) {
|
|
189
|
-
if (data.boundaries.
|
|
190
|
-
preferences.push({ category: "boundaries", key: "
|
|
192
|
+
if (data.boundaries.always?.length) {
|
|
193
|
+
preferences.push({ category: "boundaries", key: "always", value: JSON.stringify(data.boundaries.always), isDefault: true });
|
|
191
194
|
}
|
|
192
195
|
if (data.boundaries.never?.length) {
|
|
193
196
|
preferences.push({ category: "boundaries", key: "never", value: JSON.stringify(data.boundaries.never), isDefault: true });
|
|
@@ -3114,9 +3117,10 @@ function generateFileContent(options, platform2) {
|
|
|
3114
3117
|
}
|
|
3115
3118
|
}
|
|
3116
3119
|
let boundaries = BOUNDARIES[options.boundaries];
|
|
3117
|
-
if (options.boundaryNever?.length || options.boundaryAsk?.length) {
|
|
3120
|
+
if (options.boundaryAlways?.length || options.boundaryNever?.length || options.boundaryAsk?.length) {
|
|
3118
3121
|
boundaries = {
|
|
3119
3122
|
...boundaries,
|
|
3123
|
+
always: options.boundaryAlways?.length ? options.boundaryAlways : boundaries.always,
|
|
3120
3124
|
never: options.boundaryNever?.length ? options.boundaryNever : boundaries.never,
|
|
3121
3125
|
askFirst: options.boundaryAsk?.length ? options.boundaryAsk : boundaries.askFirst
|
|
3122
3126
|
};
|
|
@@ -3183,7 +3187,8 @@ function generateFileContent(options, platform2) {
|
|
|
3183
3187
|
}
|
|
3184
3188
|
}
|
|
3185
3189
|
if (options.loggingConventions) {
|
|
3186
|
-
|
|
3190
|
+
const loggingValue = options.loggingConventions === "other" && options.loggingConventionsOther ? options.loggingConventionsOther : options.loggingConventions.replace(/_/g, " ");
|
|
3191
|
+
sections.push(`- **Logging:** ${loggingValue}`);
|
|
3187
3192
|
}
|
|
3188
3193
|
if (options.styleNotes) {
|
|
3189
3194
|
sections.push(`- **Notes:** ${options.styleNotes}`);
|
|
@@ -3317,13 +3322,14 @@ function generateYamlConfig(options, platform2) {
|
|
|
3317
3322
|
|
|
3318
3323
|
// src/commands/wizard.ts
|
|
3319
3324
|
var DRAFTS_DIR = ".lynxprompt/drafts";
|
|
3320
|
-
async function saveDraftLocally(name, config2) {
|
|
3325
|
+
async function saveDraftLocally(name, config2, stepReached) {
|
|
3321
3326
|
const draftsPath = join6(process.cwd(), DRAFTS_DIR);
|
|
3322
3327
|
await mkdir4(draftsPath, { recursive: true });
|
|
3323
3328
|
const draft = {
|
|
3324
3329
|
name,
|
|
3325
3330
|
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3326
|
-
config: config2
|
|
3331
|
+
config: config2,
|
|
3332
|
+
stepReached
|
|
3327
3333
|
};
|
|
3328
3334
|
const filename = `${name.replace(/[^a-zA-Z0-9-_]/g, "_")}.json`;
|
|
3329
3335
|
await writeFile4(join6(draftsPath, filename), JSON.stringify(draft, null, 2), "utf-8");
|
|
@@ -3535,6 +3541,7 @@ var CONTAINER_REGISTRIES = [
|
|
|
3535
3541
|
];
|
|
3536
3542
|
var COMMON_COMMANDS = {
|
|
3537
3543
|
build: [
|
|
3544
|
+
// JavaScript/Node
|
|
3538
3545
|
"npm run build",
|
|
3539
3546
|
"pnpm build",
|
|
3540
3547
|
"yarn build",
|
|
@@ -3543,16 +3550,46 @@ var COMMON_COMMANDS = {
|
|
|
3543
3550
|
"vite build",
|
|
3544
3551
|
"tsc",
|
|
3545
3552
|
"tsc --noEmit",
|
|
3553
|
+
"esbuild",
|
|
3554
|
+
"rollup -c",
|
|
3555
|
+
"webpack",
|
|
3556
|
+
"parcel build",
|
|
3557
|
+
// Python
|
|
3558
|
+
"python setup.py build",
|
|
3559
|
+
"pip install -e .",
|
|
3560
|
+
"poetry build",
|
|
3561
|
+
"pdm build",
|
|
3562
|
+
"hatch build",
|
|
3563
|
+
// Go
|
|
3546
3564
|
"go build",
|
|
3565
|
+
"go build ./...",
|
|
3566
|
+
"go install",
|
|
3567
|
+
// Rust
|
|
3547
3568
|
"cargo build",
|
|
3548
3569
|
"cargo build --release",
|
|
3570
|
+
// Java/JVM
|
|
3549
3571
|
"mvn package",
|
|
3572
|
+
"mvn clean install",
|
|
3550
3573
|
"gradle build",
|
|
3574
|
+
// .NET
|
|
3551
3575
|
"dotnet build",
|
|
3576
|
+
"dotnet publish",
|
|
3577
|
+
// Ruby
|
|
3578
|
+
"bundle exec rake build",
|
|
3579
|
+
"gem build",
|
|
3580
|
+
// PHP
|
|
3581
|
+
"composer install",
|
|
3582
|
+
"composer dump-autoload",
|
|
3583
|
+
// Docker
|
|
3552
3584
|
"docker build -t app .",
|
|
3553
|
-
"docker compose build"
|
|
3585
|
+
"docker compose build",
|
|
3586
|
+
// Make
|
|
3587
|
+
"make",
|
|
3588
|
+
"make build",
|
|
3589
|
+
"make all"
|
|
3554
3590
|
],
|
|
3555
3591
|
test: [
|
|
3592
|
+
// JavaScript/Node
|
|
3556
3593
|
"npm test",
|
|
3557
3594
|
"pnpm test",
|
|
3558
3595
|
"yarn test",
|
|
@@ -3561,31 +3598,86 @@ var COMMON_COMMANDS = {
|
|
|
3561
3598
|
"vitest run",
|
|
3562
3599
|
"jest",
|
|
3563
3600
|
"jest --coverage",
|
|
3601
|
+
"mocha",
|
|
3602
|
+
"ava",
|
|
3603
|
+
"tap",
|
|
3604
|
+
// E2E
|
|
3605
|
+
"playwright test",
|
|
3606
|
+
"cypress run",
|
|
3607
|
+
"cypress open",
|
|
3608
|
+
"puppeteer",
|
|
3609
|
+
"selenium",
|
|
3610
|
+
// Python
|
|
3564
3611
|
"pytest",
|
|
3565
3612
|
"pytest --cov",
|
|
3613
|
+
"pytest -xvs",
|
|
3614
|
+
"unittest",
|
|
3615
|
+
"nose2",
|
|
3616
|
+
"hypothesis",
|
|
3617
|
+
// Go
|
|
3566
3618
|
"go test ./...",
|
|
3619
|
+
"go test -v ./...",
|
|
3620
|
+
"go test -race ./...",
|
|
3621
|
+
// Rust
|
|
3567
3622
|
"cargo test",
|
|
3623
|
+
"cargo test --release",
|
|
3624
|
+
// Java/JVM
|
|
3568
3625
|
"mvn test",
|
|
3569
3626
|
"gradle test",
|
|
3570
|
-
"
|
|
3571
|
-
|
|
3627
|
+
"mvn verify",
|
|
3628
|
+
// .NET
|
|
3629
|
+
"dotnet test",
|
|
3630
|
+
// Ruby
|
|
3631
|
+
"bundle exec rspec",
|
|
3632
|
+
"rake test",
|
|
3633
|
+
// PHP
|
|
3634
|
+
"phpunit",
|
|
3635
|
+
"pest",
|
|
3636
|
+
// Docker
|
|
3637
|
+
"docker compose run test"
|
|
3572
3638
|
],
|
|
3573
3639
|
lint: [
|
|
3640
|
+
// JavaScript/Node
|
|
3574
3641
|
"npm run lint",
|
|
3575
3642
|
"pnpm lint",
|
|
3576
3643
|
"eslint .",
|
|
3577
3644
|
"eslint . --fix",
|
|
3578
3645
|
"prettier --check .",
|
|
3579
3646
|
"prettier --write .",
|
|
3647
|
+
"biome check",
|
|
3648
|
+
"biome check --apply",
|
|
3649
|
+
// Python
|
|
3580
3650
|
"ruff check",
|
|
3651
|
+
"ruff check --fix",
|
|
3581
3652
|
"ruff format",
|
|
3582
3653
|
"black .",
|
|
3654
|
+
"black --check .",
|
|
3583
3655
|
"flake8",
|
|
3656
|
+
"pylint",
|
|
3657
|
+
"mypy .",
|
|
3658
|
+
// Go
|
|
3584
3659
|
"golangci-lint run",
|
|
3660
|
+
"go fmt ./...",
|
|
3661
|
+
"go vet ./...",
|
|
3662
|
+
// Rust
|
|
3585
3663
|
"cargo clippy",
|
|
3586
|
-
"
|
|
3664
|
+
"cargo fmt",
|
|
3665
|
+
"cargo fmt --check",
|
|
3666
|
+
// Java
|
|
3667
|
+
"mvn checkstyle:check",
|
|
3668
|
+
"gradle spotlessCheck",
|
|
3669
|
+
// Ruby
|
|
3670
|
+
"rubocop",
|
|
3671
|
+
"rubocop -a",
|
|
3672
|
+
// PHP
|
|
3673
|
+
"php-cs-fixer fix",
|
|
3674
|
+
"phpcs",
|
|
3675
|
+
"phpstan analyse",
|
|
3676
|
+
// General
|
|
3677
|
+
"pre-commit run --all-files"
|
|
3587
3678
|
],
|
|
3588
3679
|
dev: [
|
|
3680
|
+
// JavaScript/Node
|
|
3589
3681
|
"npm run dev",
|
|
3590
3682
|
"pnpm dev",
|
|
3591
3683
|
"yarn dev",
|
|
@@ -3593,12 +3685,64 @@ var COMMON_COMMANDS = {
|
|
|
3593
3685
|
"next dev",
|
|
3594
3686
|
"vite",
|
|
3595
3687
|
"vite dev",
|
|
3688
|
+
"nodemon",
|
|
3689
|
+
"ts-node-dev",
|
|
3690
|
+
// Python
|
|
3596
3691
|
"uvicorn main:app --reload",
|
|
3597
3692
|
"flask run",
|
|
3598
|
-
"
|
|
3693
|
+
"python manage.py runserver",
|
|
3694
|
+
"gunicorn --reload",
|
|
3695
|
+
"hypercorn --reload",
|
|
3696
|
+
// Go
|
|
3599
3697
|
"go run .",
|
|
3698
|
+
"air",
|
|
3699
|
+
"reflex",
|
|
3700
|
+
// Rust
|
|
3600
3701
|
"cargo run",
|
|
3601
|
-
"
|
|
3702
|
+
"cargo watch -x run",
|
|
3703
|
+
// Java
|
|
3704
|
+
"mvn spring-boot:run",
|
|
3705
|
+
"gradle bootRun",
|
|
3706
|
+
// .NET
|
|
3707
|
+
"dotnet run",
|
|
3708
|
+
"dotnet watch run",
|
|
3709
|
+
// Ruby
|
|
3710
|
+
"rails server",
|
|
3711
|
+
"bundle exec rails s",
|
|
3712
|
+
// PHP
|
|
3713
|
+
"php artisan serve",
|
|
3714
|
+
"symfony server:start",
|
|
3715
|
+
// Docker
|
|
3716
|
+
"docker compose up",
|
|
3717
|
+
"docker compose up -d"
|
|
3718
|
+
],
|
|
3719
|
+
additional: [
|
|
3720
|
+
// Database
|
|
3721
|
+
"npm run db:push",
|
|
3722
|
+
"npm run db:migrate",
|
|
3723
|
+
"prisma migrate dev",
|
|
3724
|
+
"alembic upgrade head",
|
|
3725
|
+
"flask db upgrade",
|
|
3726
|
+
"rails db:migrate",
|
|
3727
|
+
"rake db:migrate",
|
|
3728
|
+
// Codegen
|
|
3729
|
+
"npm run codegen",
|
|
3730
|
+
"graphql-codegen",
|
|
3731
|
+
"prisma generate",
|
|
3732
|
+
// Docs
|
|
3733
|
+
"npm run docs",
|
|
3734
|
+
"mkdocs serve",
|
|
3735
|
+
"sphinx-build",
|
|
3736
|
+
// Deploy
|
|
3737
|
+
"npm run deploy",
|
|
3738
|
+
"vercel",
|
|
3739
|
+
"netlify deploy",
|
|
3740
|
+
"flyctl deploy",
|
|
3741
|
+
"railway up",
|
|
3742
|
+
// Clean
|
|
3743
|
+
"npm run clean",
|
|
3744
|
+
"make clean",
|
|
3745
|
+
"cargo clean"
|
|
3602
3746
|
]
|
|
3603
3747
|
};
|
|
3604
3748
|
var NAMING_CONVENTIONS = [
|
|
@@ -3615,15 +3759,26 @@ var ERROR_PATTERNS = [
|
|
|
3615
3759
|
{ id: "exceptions", label: "Custom exceptions" },
|
|
3616
3760
|
{ id: "other", label: "Other" }
|
|
3617
3761
|
];
|
|
3762
|
+
var LOGGING_OPTIONS = [
|
|
3763
|
+
{ id: "structured_json", label: "Structured JSON" },
|
|
3764
|
+
{ id: "console_log", label: "Console.log (dev)" },
|
|
3765
|
+
{ id: "log_levels", label: "Log Levels (debug/info/warn/error)" },
|
|
3766
|
+
{ id: "pino", label: "Pino" },
|
|
3767
|
+
{ id: "winston", label: "Winston" },
|
|
3768
|
+
{ id: "bunyan", label: "Bunyan" },
|
|
3769
|
+
{ id: "python_logging", label: "Python logging" },
|
|
3770
|
+
{ id: "log4j", label: "Log4j / SLF4J" },
|
|
3771
|
+
{ id: "serilog", label: "Serilog" },
|
|
3772
|
+
{ id: "opentelemetry", label: "OpenTelemetry" },
|
|
3773
|
+
{ id: "other", label: "Other" }
|
|
3774
|
+
];
|
|
3618
3775
|
var AI_BEHAVIOR_RULES = [
|
|
3619
|
-
{ id: "
|
|
3620
|
-
{ id: "
|
|
3621
|
-
{ id: "
|
|
3622
|
-
{ id: "
|
|
3623
|
-
{ id: "
|
|
3624
|
-
{ id: "
|
|
3625
|
-
{ id: "no_console", label: "Remove console.log/print before committing", recommended: false },
|
|
3626
|
-
{ id: "type_strict", label: "Be strict with types (no any/Any)", recommended: false }
|
|
3776
|
+
{ id: "always_debug_after_build", label: "Always Debug After Building", description: "Run and test locally after making changes", recommended: true },
|
|
3777
|
+
{ id: "check_logs_after_build", label: "Check Logs After Build/Commit", description: "Check logs when build or commit finishes", recommended: true },
|
|
3778
|
+
{ id: "run_tests_before_commit", label: "Run Tests Before Commit", description: "Ensure tests pass before committing", recommended: true },
|
|
3779
|
+
{ id: "follow_existing_patterns", label: "Follow Existing Patterns", description: "Match the codebase's existing style", recommended: true },
|
|
3780
|
+
{ id: "ask_before_large_refactors", label: "Ask Before Large Refactors", description: "Confirm before significant changes", recommended: true },
|
|
3781
|
+
{ id: "check_for_security_issues", label: "Check for Security Issues", description: "Review for common vulnerabilities", recommended: false }
|
|
3627
3782
|
];
|
|
3628
3783
|
var IMPORTANT_FILES = [
|
|
3629
3784
|
{ id: "readme", label: "README.md", icon: "\u{1F4D6}" },
|
|
@@ -3632,32 +3787,6 @@ var IMPORTANT_FILES = [
|
|
|
3632
3787
|
{ id: "architecture", label: "ARCHITECTURE.md", icon: "\u{1F3D7}\uFE0F" },
|
|
3633
3788
|
{ id: "contributing", label: "CONTRIBUTING.md", icon: "\u{1F91D}" }
|
|
3634
3789
|
];
|
|
3635
|
-
var BOUNDARY_PRESETS = [
|
|
3636
|
-
{
|
|
3637
|
-
title: "\u{1F7E2} Standard",
|
|
3638
|
-
value: "standard",
|
|
3639
|
-
description: "Balanced freedom & safety",
|
|
3640
|
-
always: ["Read any file", "Modify files in src/", "Run build/test/lint", "Create test files"],
|
|
3641
|
-
askFirst: ["Add new dependencies", "Modify config files", "Create new modules"],
|
|
3642
|
-
never: ["Delete production data", "Modify .env secrets", "Force push"]
|
|
3643
|
-
},
|
|
3644
|
-
{
|
|
3645
|
-
title: "\u{1F7E1} Conservative",
|
|
3646
|
-
value: "conservative",
|
|
3647
|
-
description: "Ask before most changes",
|
|
3648
|
-
always: ["Read any file", "Run lint/format commands"],
|
|
3649
|
-
askFirst: ["Modify any file", "Add dependencies", "Create files", "Run tests"],
|
|
3650
|
-
never: ["Delete files", "Modify .env", "Push to git"]
|
|
3651
|
-
},
|
|
3652
|
-
{
|
|
3653
|
-
title: "\u{1F7E0} Permissive",
|
|
3654
|
-
value: "permissive",
|
|
3655
|
-
description: "AI can modify freely",
|
|
3656
|
-
always: ["Modify any file in src/", "Run any script", "Add dependencies", "Create files"],
|
|
3657
|
-
askFirst: ["Modify root configs", "Delete directories"],
|
|
3658
|
-
never: ["Modify .env", "Access external APIs without confirmation"]
|
|
3659
|
-
}
|
|
3660
|
-
];
|
|
3661
3790
|
var BOUNDARY_OPTIONS = [
|
|
3662
3791
|
"Delete files",
|
|
3663
3792
|
"Create new files",
|
|
@@ -3678,29 +3807,118 @@ var BOUNDARY_OPTIONS = [
|
|
|
3678
3807
|
"Skip tests temporarily"
|
|
3679
3808
|
];
|
|
3680
3809
|
var TEST_FRAMEWORKS = [
|
|
3810
|
+
// JavaScript/TypeScript
|
|
3681
3811
|
"jest",
|
|
3682
3812
|
"vitest",
|
|
3683
3813
|
"mocha",
|
|
3684
3814
|
"ava",
|
|
3685
3815
|
"tap",
|
|
3816
|
+
"bun:test",
|
|
3817
|
+
// E2E/Integration
|
|
3818
|
+
"playwright",
|
|
3819
|
+
"cypress",
|
|
3820
|
+
"puppeteer",
|
|
3821
|
+
"selenium",
|
|
3822
|
+
"webdriverio",
|
|
3823
|
+
"testcafe",
|
|
3824
|
+
// React/Frontend
|
|
3825
|
+
"rtl",
|
|
3826
|
+
"enzyme",
|
|
3827
|
+
"storybook",
|
|
3828
|
+
"chromatic",
|
|
3829
|
+
// API/Mocking
|
|
3830
|
+
"msw",
|
|
3831
|
+
"supertest",
|
|
3832
|
+
"pact",
|
|
3833
|
+
"dredd",
|
|
3834
|
+
"karate",
|
|
3835
|
+
"postman",
|
|
3836
|
+
"insomnia",
|
|
3837
|
+
// Python
|
|
3686
3838
|
"pytest",
|
|
3687
3839
|
"unittest",
|
|
3688
3840
|
"nose2",
|
|
3689
|
-
"
|
|
3841
|
+
"hypothesis",
|
|
3842
|
+
"behave",
|
|
3843
|
+
"robot",
|
|
3844
|
+
// Go
|
|
3845
|
+
"go-test",
|
|
3690
3846
|
"testify",
|
|
3691
|
-
"
|
|
3692
|
-
"
|
|
3847
|
+
"ginkgo",
|
|
3848
|
+
"gomega",
|
|
3849
|
+
// Java/JVM
|
|
3693
3850
|
"junit",
|
|
3694
3851
|
"testng",
|
|
3852
|
+
"mockito",
|
|
3695
3853
|
"spock",
|
|
3854
|
+
"cucumber-jvm",
|
|
3855
|
+
// Ruby
|
|
3696
3856
|
"rspec",
|
|
3697
3857
|
"minitest",
|
|
3858
|
+
"capybara",
|
|
3859
|
+
"factory_bot",
|
|
3860
|
+
// .NET
|
|
3861
|
+
"xunit",
|
|
3862
|
+
"nunit",
|
|
3863
|
+
"mstest",
|
|
3864
|
+
"specflow",
|
|
3865
|
+
// Infrastructure/DevOps
|
|
3866
|
+
"terratest",
|
|
3867
|
+
"conftest",
|
|
3868
|
+
"opa",
|
|
3869
|
+
"inspec",
|
|
3870
|
+
"serverspec",
|
|
3871
|
+
"molecule",
|
|
3872
|
+
"kitchen",
|
|
3873
|
+
"goss",
|
|
3874
|
+
// Kubernetes
|
|
3875
|
+
"kubetest",
|
|
3876
|
+
"kuttl",
|
|
3877
|
+
"chainsaw",
|
|
3878
|
+
"helm-unittest",
|
|
3879
|
+
// Security
|
|
3880
|
+
"owasp-zap",
|
|
3881
|
+
"burpsuite",
|
|
3882
|
+
"nuclei",
|
|
3883
|
+
"semgrep",
|
|
3884
|
+
// Load/Performance
|
|
3885
|
+
"k6",
|
|
3886
|
+
"locust",
|
|
3887
|
+
"jmeter",
|
|
3888
|
+
"artillery",
|
|
3889
|
+
"gatling",
|
|
3890
|
+
"vegeta",
|
|
3891
|
+
"wrk",
|
|
3892
|
+
"ab",
|
|
3893
|
+
// Chaos Engineering
|
|
3894
|
+
"chaos-mesh",
|
|
3895
|
+
"litmus",
|
|
3896
|
+
"gremlin",
|
|
3897
|
+
"toxiproxy",
|
|
3898
|
+
// Contract Testing
|
|
3899
|
+
"spring-cloud-contract",
|
|
3900
|
+
"specmatic",
|
|
3901
|
+
// BDD
|
|
3902
|
+
"cucumber",
|
|
3903
|
+
"gauge",
|
|
3904
|
+
"concordion",
|
|
3905
|
+
// Mutation Testing
|
|
3906
|
+
"stryker",
|
|
3907
|
+
"pitest",
|
|
3908
|
+
"mutmut",
|
|
3909
|
+
// Fuzzing
|
|
3910
|
+
"go-fuzz",
|
|
3911
|
+
"afl",
|
|
3912
|
+
"libfuzzer",
|
|
3913
|
+
"jazzer",
|
|
3914
|
+
// PHP
|
|
3698
3915
|
"phpunit",
|
|
3699
3916
|
"pest",
|
|
3700
|
-
"
|
|
3701
|
-
|
|
3702
|
-
"
|
|
3703
|
-
"
|
|
3917
|
+
"codeception",
|
|
3918
|
+
// Rust
|
|
3919
|
+
"cargo-test",
|
|
3920
|
+
"rstest",
|
|
3921
|
+
"proptest"
|
|
3704
3922
|
];
|
|
3705
3923
|
var TEST_LEVELS = [
|
|
3706
3924
|
{ id: "smoke", label: "Smoke", desc: "Quick sanity checks" },
|
|
@@ -3845,12 +4063,40 @@ function showWizardOverview(userTier) {
|
|
|
3845
4063
|
}
|
|
3846
4064
|
console.log();
|
|
3847
4065
|
}
|
|
4066
|
+
var wizardState = {
|
|
4067
|
+
inProgress: false,
|
|
4068
|
+
answers: {},
|
|
4069
|
+
stepReached: 0
|
|
4070
|
+
};
|
|
4071
|
+
async function saveDraftOnExit() {
|
|
4072
|
+
if (!wizardState.inProgress || Object.keys(wizardState.answers).length === 0) {
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
try {
|
|
4076
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
4077
|
+
const draftName = `autosave-${timestamp}`;
|
|
4078
|
+
console.log();
|
|
4079
|
+
console.log(chalk8.yellow(` \u{1F4BE} Saving wizard state to draft: ${draftName}...`));
|
|
4080
|
+
await saveDraftLocally(draftName, wizardState.answers, wizardState.stepReached);
|
|
4081
|
+
console.log(chalk8.green(` \u2713 Draft saved! Resume with: lynxp wizard --load-draft ${draftName}`));
|
|
4082
|
+
console.log(chalk8.gray(` Saved at step ${wizardState.stepReached}`));
|
|
4083
|
+
console.log();
|
|
4084
|
+
} catch (err) {
|
|
4085
|
+
console.log(chalk8.red(` \u2717 Could not save draft: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
3848
4088
|
var promptConfig = {
|
|
3849
|
-
onCancel: () => {
|
|
4089
|
+
onCancel: async () => {
|
|
4090
|
+
await saveDraftOnExit();
|
|
3850
4091
|
console.log(chalk8.yellow("\n Cancelled. Run 'lynxp wizard' anytime to restart.\n"));
|
|
3851
4092
|
process.exit(0);
|
|
3852
4093
|
}
|
|
3853
4094
|
};
|
|
4095
|
+
process.on("SIGINT", async () => {
|
|
4096
|
+
await saveDraftOnExit();
|
|
4097
|
+
console.log(chalk8.yellow("\n Interrupted. Run 'lynxp wizard' anytime to restart.\n"));
|
|
4098
|
+
process.exit(0);
|
|
4099
|
+
});
|
|
3854
4100
|
async function wizardCommand(options) {
|
|
3855
4101
|
console.log();
|
|
3856
4102
|
console.log(chalk8.cyan.bold(" \u{1F431} LynxPrompt Wizard"));
|
|
@@ -3859,9 +4105,13 @@ async function wizardCommand(options) {
|
|
|
3859
4105
|
if (options.loadDraft) {
|
|
3860
4106
|
const draft = await loadDraftLocally(options.loadDraft);
|
|
3861
4107
|
if (draft) {
|
|
3862
|
-
|
|
4108
|
+
const stepInfo = draft.stepReached ? ` at step ${draft.stepReached}` : "";
|
|
4109
|
+
console.log(chalk8.green(` \u2713 Loaded draft: ${draft.name} (saved ${new Date(draft.savedAt).toLocaleString()}${stepInfo})`));
|
|
3863
4110
|
console.log();
|
|
3864
|
-
|
|
4111
|
+
options._draftAnswers = draft.config;
|
|
4112
|
+
options._resumeFromStep = draft.stepReached;
|
|
4113
|
+
if (draft.config.name) options.name = draft.config.name;
|
|
4114
|
+
if (draft.config.description) options.description = draft.config.description;
|
|
3865
4115
|
} else {
|
|
3866
4116
|
const availableDrafts = await listLocalDrafts();
|
|
3867
4117
|
console.log(chalk8.red(` \u2717 Draft "${options.loadDraft}" not found.`));
|
|
@@ -3972,7 +4222,7 @@ async function wizardCommand(options) {
|
|
|
3972
4222
|
if (canDetectRemote) {
|
|
3973
4223
|
console.log();
|
|
3974
4224
|
console.log(chalk8.magenta.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\u2510"));
|
|
3975
|
-
console.log(chalk8.magenta.bold(" \u2502 \u2728 AUTO-DETECT FROM REPOSITORY (MAX/TEAMS)
|
|
4225
|
+
console.log(chalk8.magenta.bold(" \u2502 \u2728 AUTO-DETECT FROM REPOSITORY (MAX/TEAMS) \u2502"));
|
|
3976
4226
|
console.log(chalk8.magenta.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\u2518"));
|
|
3977
4227
|
console.log(chalk8.gray(" Analyze any public GitHub/GitLab repo, or private with git credentials."));
|
|
3978
4228
|
console.log(chalk8.gray(" We'll detect: languages, frameworks, commands, license, CI/CD, and more!"));
|
|
@@ -4114,33 +4364,73 @@ async function wizardCommand(options) {
|
|
|
4114
4364
|
initial: true
|
|
4115
4365
|
});
|
|
4116
4366
|
if (savePrefsResponse.savePrefs) {
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4367
|
+
let saved = false;
|
|
4368
|
+
let attempts = 0;
|
|
4369
|
+
const maxAttempts = 3;
|
|
4370
|
+
while (!saved && attempts < maxAttempts) {
|
|
4371
|
+
attempts++;
|
|
4372
|
+
const saveSpinner = ora7("Saving preferences to your profile...").start();
|
|
4373
|
+
try {
|
|
4374
|
+
await api.saveWizardPreferences({
|
|
4375
|
+
commands: config2.commands,
|
|
4376
|
+
codeStyle: {
|
|
4377
|
+
naming: config2.namingConvention,
|
|
4378
|
+
errorHandling: config2.errorHandling,
|
|
4379
|
+
loggingConventions: config2.loggingConventions,
|
|
4380
|
+
loggingConventionsOther: config2.loggingConventionsOther,
|
|
4381
|
+
notes: config2.styleNotes
|
|
4382
|
+
},
|
|
4383
|
+
boundaries: {
|
|
4384
|
+
always: config2.boundaryAlways,
|
|
4385
|
+
never: config2.boundaryNever,
|
|
4386
|
+
ask: config2.boundaryAsk
|
|
4387
|
+
},
|
|
4388
|
+
testing: {
|
|
4389
|
+
levels: config2.testLevels,
|
|
4390
|
+
frameworks: config2.testFrameworks,
|
|
4391
|
+
coverage: config2.coverageTarget,
|
|
4392
|
+
notes: config2.testNotes
|
|
4393
|
+
}
|
|
4394
|
+
});
|
|
4395
|
+
saveSpinner.succeed("Preferences saved to your profile");
|
|
4396
|
+
saved = true;
|
|
4397
|
+
} catch (err) {
|
|
4398
|
+
saveSpinner.fail("Could not save preferences");
|
|
4399
|
+
let errorType = "unknown";
|
|
4400
|
+
if (err instanceof ApiRequestError) {
|
|
4401
|
+
if (err.statusCode === 401) {
|
|
4402
|
+
console.log(chalk8.yellow(" Your session may have expired. Try: lynxp login"));
|
|
4403
|
+
break;
|
|
4404
|
+
} else {
|
|
4405
|
+
console.log(chalk8.gray(` ${err.message} (status: ${err.statusCode})`));
|
|
4406
|
+
errorType = "api";
|
|
4407
|
+
}
|
|
4408
|
+
} else if (err instanceof Error) {
|
|
4409
|
+
if (err.message.includes("fetch failed") || err.message.includes("ENOTFOUND")) {
|
|
4410
|
+
console.log(chalk8.yellow(" Network error. Check your internet connection."));
|
|
4411
|
+
errorType = "network";
|
|
4412
|
+
} else {
|
|
4413
|
+
console.log(chalk8.gray(` ${err.message}`));
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
if (errorType === "network" || errorType === "api") {
|
|
4417
|
+
if (attempts < maxAttempts) {
|
|
4418
|
+
const retryResponse = await prompts4({
|
|
4419
|
+
type: "confirm",
|
|
4420
|
+
name: "retry",
|
|
4421
|
+
message: chalk8.white("Would you like to retry?"),
|
|
4422
|
+
initial: true
|
|
4423
|
+
});
|
|
4424
|
+
if (!retryResponse.retry) {
|
|
4425
|
+
console.log(chalk8.gray(" Skipping preference save. Your config files are still generated."));
|
|
4426
|
+
break;
|
|
4427
|
+
}
|
|
4428
|
+
} else {
|
|
4429
|
+
console.log(chalk8.gray(` Max retries (${maxAttempts}) reached. Your config files are still generated.`));
|
|
4430
|
+
}
|
|
4431
|
+
} else {
|
|
4432
|
+
break;
|
|
4137
4433
|
}
|
|
4138
|
-
});
|
|
4139
|
-
saveSpinner.succeed("Preferences saved to your profile");
|
|
4140
|
-
} catch (err) {
|
|
4141
|
-
saveSpinner.fail("Could not save preferences (you can still use the generated files)");
|
|
4142
|
-
if (err instanceof Error) {
|
|
4143
|
-
console.log(chalk8.gray(` ${err.message}`));
|
|
4144
4434
|
}
|
|
4145
4435
|
}
|
|
4146
4436
|
}
|
|
@@ -4156,24 +4446,46 @@ async function wizardCommand(options) {
|
|
|
4156
4446
|
}
|
|
4157
4447
|
}
|
|
4158
4448
|
async function runInteractiveWizard(options, detected, userTier) {
|
|
4159
|
-
const answers = {};
|
|
4449
|
+
const answers = options._draftAnswers ? { ...options._draftAnswers } : {};
|
|
4450
|
+
const resumeFromStep = options._resumeFromStep || 0;
|
|
4160
4451
|
const availableSteps = getAvailableSteps(userTier);
|
|
4161
4452
|
let currentStepNum = 0;
|
|
4453
|
+
wizardState.inProgress = true;
|
|
4454
|
+
wizardState.answers = answers;
|
|
4455
|
+
wizardState.stepReached = resumeFromStep;
|
|
4456
|
+
if (resumeFromStep > 0 && Object.keys(answers).length > 0) {
|
|
4457
|
+
console.log(chalk8.cyan(` \u{1F4CB} Resuming from step ${resumeFromStep}...`));
|
|
4458
|
+
console.log(chalk8.gray(" Previously saved answers:"));
|
|
4459
|
+
if (answers.name) console.log(chalk8.gray(` \u2022 Name: ${answers.name}`));
|
|
4460
|
+
if (answers.platforms) console.log(chalk8.gray(` \u2022 Platforms: ${answers.platforms.join(", ")}`));
|
|
4461
|
+
if (answers.stack) console.log(chalk8.gray(` \u2022 Stack: ${answers.stack.slice(0, 5).join(", ")}${answers.stack.length > 5 ? "..." : ""}`));
|
|
4462
|
+
console.log();
|
|
4463
|
+
console.log(chalk8.yellow(" Steps 1-" + (resumeFromStep - 1) + " will use saved values. Continuing from step " + resumeFromStep + "."));
|
|
4464
|
+
console.log();
|
|
4465
|
+
}
|
|
4162
4466
|
const getCurrentStep = (stepId) => {
|
|
4163
4467
|
const step = availableSteps.find((s) => s.id === stepId);
|
|
4164
4468
|
if (step) {
|
|
4165
4469
|
currentStepNum++;
|
|
4470
|
+
wizardState.stepReached = currentStepNum;
|
|
4166
4471
|
return step;
|
|
4167
4472
|
}
|
|
4168
4473
|
return null;
|
|
4169
4474
|
};
|
|
4475
|
+
const shouldSkipStep = (stepNum) => {
|
|
4476
|
+
return resumeFromStep > 0 && stepNum < resumeFromStep;
|
|
4477
|
+
};
|
|
4170
4478
|
const formatStep = getCurrentStep("format");
|
|
4171
|
-
showStep(currentStepNum, formatStep, userTier);
|
|
4172
4479
|
let platforms;
|
|
4173
|
-
if (
|
|
4480
|
+
if (shouldSkipStep(currentStepNum) && answers.platforms) {
|
|
4481
|
+
platforms = answers.platforms;
|
|
4482
|
+
console.log(chalk8.gray(` Step 1 (Output Format): Using saved platforms: ${platforms.join(", ")}`));
|
|
4483
|
+
} else if (options.format) {
|
|
4484
|
+
showStep(currentStepNum, formatStep, userTier);
|
|
4174
4485
|
platforms = options.format.split(",").map((f) => f.trim());
|
|
4175
4486
|
console.log(chalk8.gray(` Using format from flag: ${platforms.join(", ")}`));
|
|
4176
4487
|
} else {
|
|
4488
|
+
showStep(currentStepNum, formatStep, userTier);
|
|
4177
4489
|
console.log(chalk8.gray(" Select the AI editors you want to generate config for:"));
|
|
4178
4490
|
console.log(chalk8.gray(" (AGENTS.md is recommended - works with most AI tools)"));
|
|
4179
4491
|
console.log(chalk8.gray(" Type to search/filter the list."));
|
|
@@ -4259,6 +4571,15 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4259
4571
|
initial: 0
|
|
4260
4572
|
}, promptConfig);
|
|
4261
4573
|
answers.architecture = archResponse.architecture || "";
|
|
4574
|
+
if (answers.architecture === "other") {
|
|
4575
|
+
const customArchResponse = await prompts4({
|
|
4576
|
+
type: "text",
|
|
4577
|
+
name: "customArchitecture",
|
|
4578
|
+
message: chalk8.white("Describe your architecture pattern:"),
|
|
4579
|
+
hint: chalk8.gray("e.g., CQRS, Hexagonal, Clean Architecture")
|
|
4580
|
+
}, promptConfig);
|
|
4581
|
+
answers.architectureOther = customArchResponse.customArchitecture || "";
|
|
4582
|
+
}
|
|
4262
4583
|
console.log();
|
|
4263
4584
|
console.log(chalk8.yellow(" \u{1F9E9} Blueprint Template Mode"));
|
|
4264
4585
|
console.log(chalk8.gray(" Create a reusable template with [[VARIABLE|default]] placeholders"));
|
|
@@ -4364,12 +4685,12 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4364
4685
|
type: "toggle",
|
|
4365
4686
|
name: "isPublic",
|
|
4366
4687
|
message: chalk8.white("Public repository?"),
|
|
4367
|
-
initial:
|
|
4368
|
-
// Default
|
|
4688
|
+
initial: true,
|
|
4689
|
+
// Default Yes
|
|
4369
4690
|
active: "Yes",
|
|
4370
4691
|
inactive: "No"
|
|
4371
4692
|
}, promptConfig);
|
|
4372
|
-
answers.isPublic = visibilityResponse.isPublic ??
|
|
4693
|
+
answers.isPublic = visibilityResponse.isPublic ?? true;
|
|
4373
4694
|
const licenseChoices = [
|
|
4374
4695
|
{ title: chalk8.gray("\u23ED Skip"), value: "" },
|
|
4375
4696
|
...LICENSES.map((l) => ({
|
|
@@ -4390,30 +4711,33 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4390
4711
|
type: "toggle",
|
|
4391
4712
|
name: "conventionalCommits",
|
|
4392
4713
|
message: chalk8.white("Use Conventional Commits?"),
|
|
4393
|
-
initial:
|
|
4714
|
+
initial: true,
|
|
4715
|
+
// Default Yes
|
|
4394
4716
|
active: "Yes",
|
|
4395
4717
|
inactive: "No"
|
|
4396
4718
|
}, promptConfig);
|
|
4397
|
-
answers.conventionalCommits = conventionalResponse.conventionalCommits
|
|
4719
|
+
answers.conventionalCommits = conventionalResponse.conventionalCommits ?? true;
|
|
4398
4720
|
const semverResponse = await prompts4({
|
|
4399
4721
|
type: "toggle",
|
|
4400
4722
|
name: "semver",
|
|
4401
4723
|
message: chalk8.white("Use Semantic Versioning?"),
|
|
4402
|
-
initial:
|
|
4724
|
+
initial: true,
|
|
4725
|
+
// Default Yes
|
|
4403
4726
|
active: "Yes",
|
|
4404
4727
|
inactive: "No"
|
|
4405
4728
|
}, promptConfig);
|
|
4406
|
-
answers.semver = semverResponse.semver
|
|
4729
|
+
answers.semver = semverResponse.semver ?? true;
|
|
4407
4730
|
if (answers.repoHost === "github" || answers.repoHost === "gitlab") {
|
|
4408
4731
|
const dependabotResponse = await prompts4({
|
|
4409
4732
|
type: "toggle",
|
|
4410
4733
|
name: "dependabot",
|
|
4411
4734
|
message: chalk8.white("Enable Dependabot/dependency updates?"),
|
|
4412
|
-
initial:
|
|
4735
|
+
initial: true,
|
|
4736
|
+
// Default Yes
|
|
4413
4737
|
active: "Yes",
|
|
4414
4738
|
inactive: "No"
|
|
4415
4739
|
}, promptConfig);
|
|
4416
|
-
answers.dependabot = dependabotResponse.dependabot
|
|
4740
|
+
answers.dependabot = dependabotResponse.dependabot ?? true;
|
|
4417
4741
|
}
|
|
4418
4742
|
const cicdChoices = [
|
|
4419
4743
|
{ title: chalk8.gray("\u23ED Skip"), value: "" },
|
|
@@ -4432,15 +4756,15 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4432
4756
|
}, promptConfig);
|
|
4433
4757
|
answers.cicd = cicdResponse.cicd || "";
|
|
4434
4758
|
const deployResponse = await prompts4({
|
|
4435
|
-
type: "
|
|
4759
|
+
type: "autocompleteMultiselect",
|
|
4436
4760
|
name: "deploymentTargets",
|
|
4437
|
-
message: chalk8.white("Deployment targets:"),
|
|
4761
|
+
message: chalk8.white("Deployment targets (type to search):"),
|
|
4438
4762
|
choices: DEPLOYMENT_TARGETS.map((t) => ({
|
|
4439
4763
|
title: t.id === "docker" && detected?.hasDocker ? `${t.icon} ${t.label} ${chalk8.green("(detected)")}` : `${t.icon} ${t.label}`,
|
|
4440
4764
|
selected: t.id === "docker" && detected?.hasDocker,
|
|
4441
4765
|
value: t.id
|
|
4442
4766
|
})),
|
|
4443
|
-
hint: chalk8.gray("space select \u2022 enter
|
|
4767
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4444
4768
|
instructions: false
|
|
4445
4769
|
}, promptConfig);
|
|
4446
4770
|
answers.deploymentTargets = deployResponse.deploymentTargets || [];
|
|
@@ -4486,66 +4810,78 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4486
4810
|
if (canAccessTier(userTier, "intermediate")) {
|
|
4487
4811
|
const commandsStep = getCurrentStep("commands");
|
|
4488
4812
|
showStep(currentStepNum, commandsStep, userTier);
|
|
4489
|
-
console.log(chalk8.gray(" Select common commands for your project:"));
|
|
4813
|
+
console.log(chalk8.gray(" Select common commands for your project (type to search):"));
|
|
4490
4814
|
console.log();
|
|
4491
4815
|
const buildResponse = await prompts4({
|
|
4492
|
-
type: "
|
|
4816
|
+
type: "autocompleteMultiselect",
|
|
4493
4817
|
name: "build",
|
|
4494
|
-
message: chalk8.white("Build commands:"),
|
|
4495
|
-
choices: COMMON_COMMANDS.build.
|
|
4818
|
+
message: chalk8.white("Build commands (type to search):"),
|
|
4819
|
+
choices: COMMON_COMMANDS.build.map((c) => ({
|
|
4496
4820
|
title: chalk8.cyan(c),
|
|
4497
4821
|
value: c,
|
|
4498
4822
|
selected: detected?.commands?.build === c
|
|
4499
4823
|
})),
|
|
4500
|
-
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4824
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4501
4825
|
instructions: false
|
|
4502
4826
|
}, promptConfig);
|
|
4503
4827
|
const testResponse = await prompts4({
|
|
4504
|
-
type: "
|
|
4828
|
+
type: "autocompleteMultiselect",
|
|
4505
4829
|
name: "test",
|
|
4506
|
-
message: chalk8.white("Test commands:"),
|
|
4507
|
-
choices: COMMON_COMMANDS.test.
|
|
4830
|
+
message: chalk8.white("Test commands (type to search):"),
|
|
4831
|
+
choices: COMMON_COMMANDS.test.map((c) => ({
|
|
4508
4832
|
title: chalk8.yellow(c),
|
|
4509
4833
|
value: c,
|
|
4510
4834
|
selected: detected?.commands?.test === c
|
|
4511
4835
|
})),
|
|
4512
|
-
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4836
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4513
4837
|
instructions: false
|
|
4514
4838
|
}, promptConfig);
|
|
4515
4839
|
const lintResponse = await prompts4({
|
|
4516
|
-
type: "
|
|
4840
|
+
type: "autocompleteMultiselect",
|
|
4517
4841
|
name: "lint",
|
|
4518
|
-
message: chalk8.white("Lint/format commands:"),
|
|
4519
|
-
choices: COMMON_COMMANDS.lint.
|
|
4842
|
+
message: chalk8.white("Lint/format commands (type to search):"),
|
|
4843
|
+
choices: COMMON_COMMANDS.lint.map((c) => ({
|
|
4520
4844
|
title: chalk8.green(c),
|
|
4521
4845
|
value: c,
|
|
4522
4846
|
selected: detected?.commands?.lint === c
|
|
4523
4847
|
})),
|
|
4524
|
-
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4848
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4525
4849
|
instructions: false
|
|
4526
4850
|
}, promptConfig);
|
|
4527
4851
|
const devResponse = await prompts4({
|
|
4528
|
-
type: "
|
|
4852
|
+
type: "autocompleteMultiselect",
|
|
4529
4853
|
name: "dev",
|
|
4530
|
-
message: chalk8.white("Dev server commands:"),
|
|
4531
|
-
choices: COMMON_COMMANDS.dev.
|
|
4854
|
+
message: chalk8.white("Dev server commands (type to search):"),
|
|
4855
|
+
choices: COMMON_COMMANDS.dev.map((c) => ({
|
|
4532
4856
|
title: chalk8.magenta(c),
|
|
4533
4857
|
value: c,
|
|
4534
4858
|
selected: detected?.commands?.dev === c
|
|
4535
4859
|
})),
|
|
4536
|
-
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4860
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4861
|
+
instructions: false
|
|
4862
|
+
}, promptConfig);
|
|
4863
|
+
const additionalResponse = await prompts4({
|
|
4864
|
+
type: "autocompleteMultiselect",
|
|
4865
|
+
name: "additional",
|
|
4866
|
+
message: chalk8.white("Additional commands (type to search):"),
|
|
4867
|
+
choices: COMMON_COMMANDS.additional.map((c) => ({
|
|
4868
|
+
title: chalk8.blue(c),
|
|
4869
|
+
value: c
|
|
4870
|
+
})),
|
|
4871
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4537
4872
|
instructions: false
|
|
4538
4873
|
}, promptConfig);
|
|
4539
4874
|
answers.commands = {
|
|
4540
4875
|
build: buildResponse.build || [],
|
|
4541
4876
|
test: testResponse.test || [],
|
|
4542
4877
|
lint: lintResponse.lint || [],
|
|
4543
|
-
dev: devResponse.dev || []
|
|
4878
|
+
dev: devResponse.dev || [],
|
|
4879
|
+
additional: additionalResponse.additional || []
|
|
4544
4880
|
};
|
|
4545
4881
|
const customCmdResponse = await prompts4({
|
|
4546
4882
|
type: "text",
|
|
4547
4883
|
name: "custom",
|
|
4548
|
-
message: chalk8.white("
|
|
4884
|
+
message: chalk8.white("Custom command (optional):"),
|
|
4549
4885
|
hint: chalk8.gray("e.g., npm run migrate, make deploy")
|
|
4550
4886
|
}, promptConfig);
|
|
4551
4887
|
if (customCmdResponse.custom) {
|
|
@@ -4586,13 +4922,38 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4586
4922
|
initial: 0
|
|
4587
4923
|
}, promptConfig);
|
|
4588
4924
|
answers.errorHandling = errorResponse.errorHandling || "";
|
|
4925
|
+
if (answers.errorHandling === "other") {
|
|
4926
|
+
const customErrorResponse = await prompts4({
|
|
4927
|
+
type: "text",
|
|
4928
|
+
name: "customErrorHandling",
|
|
4929
|
+
message: chalk8.white("Describe your error handling approach:"),
|
|
4930
|
+
hint: chalk8.gray("e.g., Railway-oriented, custom error boundaries")
|
|
4931
|
+
}, promptConfig);
|
|
4932
|
+
answers.errorHandlingOther = customErrorResponse.customErrorHandling || "";
|
|
4933
|
+
}
|
|
4589
4934
|
const loggingResponse = await prompts4({
|
|
4590
|
-
type: "
|
|
4935
|
+
type: "autocomplete",
|
|
4591
4936
|
name: "loggingConventions",
|
|
4592
|
-
message: chalk8.white("Logging conventions (
|
|
4593
|
-
|
|
4937
|
+
message: chalk8.white("Logging conventions (type to search):"),
|
|
4938
|
+
choices: [
|
|
4939
|
+
{ title: chalk8.gray("\u23ED Skip"), value: "" },
|
|
4940
|
+
...LOGGING_OPTIONS.map((l) => ({
|
|
4941
|
+
title: l.label,
|
|
4942
|
+
value: l.id
|
|
4943
|
+
}))
|
|
4944
|
+
],
|
|
4945
|
+
initial: 0
|
|
4594
4946
|
}, promptConfig);
|
|
4595
4947
|
answers.loggingConventions = loggingResponse.loggingConventions || "";
|
|
4948
|
+
if (answers.loggingConventions === "other") {
|
|
4949
|
+
const customLoggingResponse = await prompts4({
|
|
4950
|
+
type: "text",
|
|
4951
|
+
name: "customLogging",
|
|
4952
|
+
message: chalk8.white("Describe your logging convention:"),
|
|
4953
|
+
hint: chalk8.gray("e.g., custom logger, file-based logging")
|
|
4954
|
+
}, promptConfig);
|
|
4955
|
+
answers.loggingConventionsOther = customLoggingResponse.customLogging || "";
|
|
4956
|
+
}
|
|
4596
4957
|
const styleNotesResponse = await prompts4({
|
|
4597
4958
|
type: "text",
|
|
4598
4959
|
name: "styleNotes",
|
|
@@ -4604,28 +4965,36 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4604
4965
|
const aiStep = getCurrentStep("ai");
|
|
4605
4966
|
showStep(currentStepNum, aiStep, userTier);
|
|
4606
4967
|
const aiBehaviorResponse = await prompts4({
|
|
4607
|
-
type: "
|
|
4968
|
+
type: "autocompleteMultiselect",
|
|
4608
4969
|
name: "aiBehavior",
|
|
4609
|
-
message: chalk8.white("AI behavior rules:"),
|
|
4970
|
+
message: chalk8.white("AI behavior rules (type to filter):"),
|
|
4610
4971
|
choices: AI_BEHAVIOR_RULES.map((r) => ({
|
|
4611
|
-
title: r.recommended ? `${r.label} ${chalk8.green("\u2605
|
|
4612
|
-
value: r.id
|
|
4972
|
+
title: r.recommended ? `${r.label} ${chalk8.green("\u2605")}` : r.label,
|
|
4973
|
+
value: r.id,
|
|
4974
|
+
description: chalk8.gray(r.description)
|
|
4613
4975
|
// No pre-selection - user must explicitly choose
|
|
4614
4976
|
})),
|
|
4615
|
-
hint: chalk8.gray("space select \u2022 enter
|
|
4977
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4616
4978
|
instructions: false
|
|
4617
4979
|
}, promptConfig);
|
|
4618
4980
|
answers.aiBehavior = aiBehaviorResponse.aiBehavior || [];
|
|
4981
|
+
if (answers.aiBehavior.length > 0) {
|
|
4982
|
+
console.log(chalk8.green(" \u2713 Selected:"));
|
|
4983
|
+
for (const ruleId of answers.aiBehavior) {
|
|
4984
|
+
const rule = AI_BEHAVIOR_RULES.find((r) => r.id === ruleId);
|
|
4985
|
+
if (rule) console.log(chalk8.cyan(` \u2022 ${rule.label}`));
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4619
4988
|
const importantFilesResponse = await prompts4({
|
|
4620
|
-
type: "
|
|
4989
|
+
type: "autocompleteMultiselect",
|
|
4621
4990
|
name: "importantFiles",
|
|
4622
|
-
message: chalk8.white("Important files AI should read:"),
|
|
4991
|
+
message: chalk8.white("Important files AI should read (type to search):"),
|
|
4623
4992
|
choices: IMPORTANT_FILES.map((f) => ({
|
|
4624
4993
|
title: `${f.icon} ${f.label}`,
|
|
4625
4994
|
value: f.id
|
|
4626
4995
|
// No pre-selection - user must explicitly choose
|
|
4627
4996
|
})),
|
|
4628
|
-
hint: chalk8.gray("space select \u2022 enter
|
|
4997
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4629
4998
|
instructions: false
|
|
4630
4999
|
}, promptConfig);
|
|
4631
5000
|
answers.importantFiles = importantFilesResponse.importantFiles || [];
|
|
@@ -4641,7 +5010,7 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4641
5010
|
const includePersonalResponse = await prompts4({
|
|
4642
5011
|
type: "toggle",
|
|
4643
5012
|
name: "includePersonalData",
|
|
4644
|
-
message: chalk8.white("Include personal data (
|
|
5013
|
+
message: chalk8.white("Include personal data (as saved in WebUI)?"),
|
|
4645
5014
|
initial: false,
|
|
4646
5015
|
active: "Yes",
|
|
4647
5016
|
inactive: "No"
|
|
@@ -4650,65 +5019,65 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4650
5019
|
if (canAccessTier(userTier, "advanced")) {
|
|
4651
5020
|
const boundariesStep = getCurrentStep("boundaries");
|
|
4652
5021
|
showStep(currentStepNum, boundariesStep, userTier);
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
5022
|
+
console.log(chalk8.gray(" Define what AI should never do, ask first, or always do."));
|
|
5023
|
+
console.log(chalk8.gray(" Each option can only be in one category."));
|
|
5024
|
+
console.log();
|
|
5025
|
+
const usedOptions = /* @__PURE__ */ new Set();
|
|
5026
|
+
console.log(chalk8.red.bold(" \u2717 NEVER ALLOW - AI will refuse to do"));
|
|
5027
|
+
const neverResponse = await prompts4({
|
|
5028
|
+
type: "autocompleteMultiselect",
|
|
5029
|
+
name: "never",
|
|
5030
|
+
message: chalk8.white("Never allow (type to filter):"),
|
|
5031
|
+
choices: BOUNDARY_OPTIONS.map((o) => ({
|
|
5032
|
+
title: chalk8.red(o),
|
|
5033
|
+
value: o
|
|
5034
|
+
})),
|
|
5035
|
+
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
5036
|
+
instructions: false
|
|
4666
5037
|
}, promptConfig);
|
|
4667
|
-
answers.
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
inactive: "No"
|
|
5038
|
+
answers.boundaryNever = neverResponse.never || [];
|
|
5039
|
+
answers.boundaryNever.forEach((o) => usedOptions.add(o));
|
|
5040
|
+
console.log();
|
|
5041
|
+
console.log(chalk8.yellow.bold(" ? ASK FIRST - AI will ask before doing"));
|
|
5042
|
+
const availableForAsk = BOUNDARY_OPTIONS.filter((o) => !usedOptions.has(o));
|
|
5043
|
+
const askResponse = await prompts4({
|
|
5044
|
+
type: "autocompleteMultiselect",
|
|
5045
|
+
name: "ask",
|
|
5046
|
+
message: chalk8.white("Ask first (type to filter):"),
|
|
5047
|
+
choices: availableForAsk.map((o) => ({
|
|
5048
|
+
title: chalk8.yellow(o),
|
|
5049
|
+
value: o
|
|
5050
|
+
})),
|
|
5051
|
+
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
5052
|
+
instructions: false
|
|
4683
5053
|
}, promptConfig);
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
answers.boundaryAsk = askResponse.ask || [];
|
|
5054
|
+
answers.boundaryAsk = askResponse.ask || [];
|
|
5055
|
+
answers.boundaryAsk.forEach((o) => usedOptions.add(o));
|
|
5056
|
+
console.log();
|
|
5057
|
+
console.log(chalk8.green.bold(" \u2713 ALWAYS ALLOW - AI will do these automatically"));
|
|
5058
|
+
const availableForAlways = BOUNDARY_OPTIONS.filter((o) => !usedOptions.has(o));
|
|
5059
|
+
const alwaysResponse = await prompts4({
|
|
5060
|
+
type: "autocompleteMultiselect",
|
|
5061
|
+
name: "always",
|
|
5062
|
+
message: chalk8.white("Always allow (type to filter):"),
|
|
5063
|
+
choices: availableForAlways.map((o) => ({
|
|
5064
|
+
title: chalk8.green(o),
|
|
5065
|
+
value: o
|
|
5066
|
+
})),
|
|
5067
|
+
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
5068
|
+
instructions: false
|
|
5069
|
+
}, promptConfig);
|
|
5070
|
+
answers.boundaryAlways = alwaysResponse.always || [];
|
|
5071
|
+
console.log();
|
|
5072
|
+
console.log(chalk8.gray(" Boundary summary:"));
|
|
5073
|
+
if (answers.boundaryAlways.length > 0) {
|
|
5074
|
+
console.log(chalk8.green(` \u2713 Always: ${answers.boundaryAlways.join(", ")}`));
|
|
5075
|
+
}
|
|
5076
|
+
if (answers.boundaryAsk.length > 0) {
|
|
5077
|
+
console.log(chalk8.yellow(` ? Ask: ${answers.boundaryAsk.join(", ")}`));
|
|
5078
|
+
}
|
|
5079
|
+
if (answers.boundaryNever.length > 0) {
|
|
5080
|
+
console.log(chalk8.red(` \u2717 Never: ${answers.boundaryNever.join(", ")}`));
|
|
4712
5081
|
}
|
|
4713
5082
|
} else {
|
|
4714
5083
|
answers.boundaries = options.boundaries || "standard";
|
|
@@ -4717,28 +5086,29 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4717
5086
|
const testingStep = getCurrentStep("testing");
|
|
4718
5087
|
showStep(currentStepNum, testingStep, userTier);
|
|
4719
5088
|
const testLevelsResponse = await prompts4({
|
|
4720
|
-
type: "
|
|
5089
|
+
type: "autocompleteMultiselect",
|
|
4721
5090
|
name: "testLevels",
|
|
4722
|
-
message: chalk8.white("Test levels:"),
|
|
5091
|
+
message: chalk8.white("Test levels (type to search):"),
|
|
4723
5092
|
choices: TEST_LEVELS.map((l) => ({
|
|
4724
5093
|
title: `${l.label} - ${chalk8.gray(l.desc)}`,
|
|
4725
5094
|
value: l.id,
|
|
4726
5095
|
selected: l.id === "unit" || l.id === "integration"
|
|
4727
5096
|
})),
|
|
5097
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4728
5098
|
instructions: false
|
|
4729
5099
|
}, promptConfig);
|
|
4730
5100
|
answers.testLevels = testLevelsResponse.testLevels || [];
|
|
4731
5101
|
const detectedFrameworks = answers.stack?.includes("typescript") || answers.stack?.includes("javascript") ? ["jest", "vitest"] : answers.stack?.includes("python") ? ["pytest"] : [];
|
|
4732
5102
|
const testFrameworkResponse = await prompts4({
|
|
4733
|
-
type: "
|
|
5103
|
+
type: "autocompleteMultiselect",
|
|
4734
5104
|
name: "testFrameworks",
|
|
4735
|
-
message: chalk8.white("Testing frameworks:"),
|
|
4736
|
-
choices: TEST_FRAMEWORKS.
|
|
5105
|
+
message: chalk8.white("Testing frameworks (type to search):"),
|
|
5106
|
+
choices: TEST_FRAMEWORKS.map((f) => ({
|
|
4737
5107
|
title: f,
|
|
4738
5108
|
value: f,
|
|
4739
5109
|
selected: detectedFrameworks.includes(f)
|
|
4740
5110
|
})),
|
|
4741
|
-
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
5111
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4742
5112
|
instructions: false
|
|
4743
5113
|
}, promptConfig);
|
|
4744
5114
|
answers.testFrameworks = testFrameworkResponse.testFrameworks || [];
|
|
@@ -4793,15 +5163,15 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4793
5163
|
console.log();
|
|
4794
5164
|
}
|
|
4795
5165
|
const staticFilesResponse = await prompts4({
|
|
4796
|
-
type: "
|
|
5166
|
+
type: "autocompleteMultiselect",
|
|
4797
5167
|
name: "staticFiles",
|
|
4798
|
-
message: chalk8.white("Include static files:"),
|
|
5168
|
+
message: chalk8.white("Include static files (type to search):"),
|
|
4799
5169
|
choices: STATIC_FILE_OPTIONS.map((f) => ({
|
|
4800
5170
|
title: existingFiles[f.value] ? `${f.title} ${chalk8.green("(exists)")}` : f.title,
|
|
4801
5171
|
value: f.value,
|
|
4802
5172
|
description: chalk8.gray(f.desc)
|
|
4803
5173
|
})),
|
|
4804
|
-
hint: chalk8.gray("space select \u2022 enter
|
|
5174
|
+
hint: chalk8.gray("type to filter \u2022 space select \u2022 enter confirm"),
|
|
4805
5175
|
instructions: false
|
|
4806
5176
|
}, promptConfig);
|
|
4807
5177
|
answers.staticFiles = staticFilesResponse.staticFiles || [];
|
|
@@ -4903,33 +5273,7 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4903
5273
|
}
|
|
4904
5274
|
const extraStep = getCurrentStep("extra");
|
|
4905
5275
|
showStep(currentStepNum, extraStep, userTier);
|
|
4906
|
-
|
|
4907
|
-
type: "select",
|
|
4908
|
-
name: "persona",
|
|
4909
|
-
message: chalk8.white("AI assistant persona:"),
|
|
4910
|
-
choices: [
|
|
4911
|
-
{ title: chalk8.gray("\u23ED Skip"), value: "" },
|
|
4912
|
-
{ title: "\u{1F9D1}\u200D\u{1F4BB} Full-Stack Developer", value: "fullstack", description: chalk8.gray("Complete application development") },
|
|
4913
|
-
{ title: "\u2699\uFE0F Backend Developer", value: "backend", description: chalk8.gray("APIs, databases, services") },
|
|
4914
|
-
{ title: "\u{1F3A8} Frontend Developer", value: "frontend", description: chalk8.gray("UI, components, styling") },
|
|
4915
|
-
{ title: "\u{1F680} DevOps Engineer", value: "devops", description: chalk8.gray("Infrastructure, CI/CD") },
|
|
4916
|
-
{ title: "\u{1F4CA} Data Engineer", value: "data", description: chalk8.gray("Pipelines, ETL, analytics") },
|
|
4917
|
-
{ title: "\u{1F512} Security Engineer", value: "security", description: chalk8.gray("Secure code, auditing") },
|
|
4918
|
-
{ title: "\u270F\uFE0F Custom...", value: "custom", description: chalk8.gray("Define your own") }
|
|
4919
|
-
],
|
|
4920
|
-
initial: 0
|
|
4921
|
-
}, promptConfig);
|
|
4922
|
-
if (personaResponse.persona === "custom") {
|
|
4923
|
-
const customPersona = await prompts4({
|
|
4924
|
-
type: "text",
|
|
4925
|
-
name: "value",
|
|
4926
|
-
message: chalk8.white("Describe the custom persona:"),
|
|
4927
|
-
hint: chalk8.gray("e.g., 'ML engineer focused on PyTorch'")
|
|
4928
|
-
}, promptConfig);
|
|
4929
|
-
answers.persona = customPersona.value || "";
|
|
4930
|
-
} else {
|
|
4931
|
-
answers.persona = personaResponse.persona || "";
|
|
4932
|
-
}
|
|
5276
|
+
answers.persona = "";
|
|
4933
5277
|
const hasAIAccess = canAccessAI(userTier);
|
|
4934
5278
|
if (hasAIAccess) {
|
|
4935
5279
|
console.log();
|
|
@@ -4978,6 +5322,7 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4978
5322
|
console.log();
|
|
4979
5323
|
console.log(chalk8.green(" \u2705 All steps completed!"));
|
|
4980
5324
|
console.log();
|
|
5325
|
+
wizardState.inProgress = false;
|
|
4981
5326
|
return {
|
|
4982
5327
|
name: answers.name,
|
|
4983
5328
|
description: answers.description,
|
|
@@ -5004,6 +5349,7 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
5004
5349
|
importantFiles: answers.importantFiles,
|
|
5005
5350
|
selfImprove: answers.selfImprove,
|
|
5006
5351
|
includePersonalData: answers.includePersonalData,
|
|
5352
|
+
boundaryAlways: answers.boundaryAlways,
|
|
5007
5353
|
boundaryNever: answers.boundaryNever,
|
|
5008
5354
|
boundaryAsk: answers.boundaryAsk,
|
|
5009
5355
|
testLevels: answers.testLevels,
|
|
@@ -5022,7 +5368,8 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
5022
5368
|
containerRegistry: answers.containerRegistry,
|
|
5023
5369
|
exampleRepoUrl: answers.exampleRepoUrl,
|
|
5024
5370
|
documentationUrl: answers.documentationUrl,
|
|
5025
|
-
loggingConventions: answers.loggingConventions
|
|
5371
|
+
loggingConventions: answers.loggingConventions,
|
|
5372
|
+
loggingConventionsOther: answers.loggingConventionsOther
|
|
5026
5373
|
};
|
|
5027
5374
|
}
|
|
5028
5375
|
|