lynxprompt 0.5.0 → 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 +141 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3322,13 +3322,14 @@ function generateYamlConfig(options, platform2) {
|
|
|
3322
3322
|
|
|
3323
3323
|
// src/commands/wizard.ts
|
|
3324
3324
|
var DRAFTS_DIR = ".lynxprompt/drafts";
|
|
3325
|
-
async function saveDraftLocally(name, config2) {
|
|
3325
|
+
async function saveDraftLocally(name, config2, stepReached) {
|
|
3326
3326
|
const draftsPath = join6(process.cwd(), DRAFTS_DIR);
|
|
3327
3327
|
await mkdir4(draftsPath, { recursive: true });
|
|
3328
3328
|
const draft = {
|
|
3329
3329
|
name,
|
|
3330
3330
|
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3331
|
-
config: config2
|
|
3331
|
+
config: config2,
|
|
3332
|
+
stepReached
|
|
3332
3333
|
};
|
|
3333
3334
|
const filename = `${name.replace(/[^a-zA-Z0-9-_]/g, "_")}.json`;
|
|
3334
3335
|
await writeFile4(join6(draftsPath, filename), JSON.stringify(draft, null, 2), "utf-8");
|
|
@@ -4076,8 +4077,9 @@ async function saveDraftOnExit() {
|
|
|
4076
4077
|
const draftName = `autosave-${timestamp}`;
|
|
4077
4078
|
console.log();
|
|
4078
4079
|
console.log(chalk8.yellow(` \u{1F4BE} Saving wizard state to draft: ${draftName}...`));
|
|
4079
|
-
await saveDraftLocally(draftName, wizardState.answers);
|
|
4080
|
+
await saveDraftLocally(draftName, wizardState.answers, wizardState.stepReached);
|
|
4080
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}`));
|
|
4081
4083
|
console.log();
|
|
4082
4084
|
} catch (err) {
|
|
4083
4085
|
console.log(chalk8.red(` \u2717 Could not save draft: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
@@ -4103,9 +4105,13 @@ async function wizardCommand(options) {
|
|
|
4103
4105
|
if (options.loadDraft) {
|
|
4104
4106
|
const draft = await loadDraftLocally(options.loadDraft);
|
|
4105
4107
|
if (draft) {
|
|
4106
|
-
|
|
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})`));
|
|
4107
4110
|
console.log();
|
|
4108
|
-
|
|
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;
|
|
4109
4115
|
} else {
|
|
4110
4116
|
const availableDrafts = await listLocalDrafts();
|
|
4111
4117
|
console.log(chalk8.red(` \u2717 Draft "${options.loadDraft}" not found.`));
|
|
@@ -4358,43 +4364,72 @@ async function wizardCommand(options) {
|
|
|
4358
4364
|
initial: true
|
|
4359
4365
|
});
|
|
4360
4366
|
if (savePrefsResponse.savePrefs) {
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
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
|
+
}
|
|
4392
4415
|
}
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
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
|
+
}
|
|
4396
4431
|
} else {
|
|
4397
|
-
|
|
4432
|
+
break;
|
|
4398
4433
|
}
|
|
4399
4434
|
}
|
|
4400
4435
|
}
|
|
@@ -4411,12 +4446,23 @@ async function wizardCommand(options) {
|
|
|
4411
4446
|
}
|
|
4412
4447
|
}
|
|
4413
4448
|
async function runInteractiveWizard(options, detected, userTier) {
|
|
4414
|
-
const answers = {};
|
|
4449
|
+
const answers = options._draftAnswers ? { ...options._draftAnswers } : {};
|
|
4450
|
+
const resumeFromStep = options._resumeFromStep || 0;
|
|
4415
4451
|
const availableSteps = getAvailableSteps(userTier);
|
|
4416
4452
|
let currentStepNum = 0;
|
|
4417
4453
|
wizardState.inProgress = true;
|
|
4418
4454
|
wizardState.answers = answers;
|
|
4419
|
-
wizardState.stepReached =
|
|
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
|
+
}
|
|
4420
4466
|
const getCurrentStep = (stepId) => {
|
|
4421
4467
|
const step = availableSteps.find((s) => s.id === stepId);
|
|
4422
4468
|
if (step) {
|
|
@@ -4426,13 +4472,20 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4426
4472
|
}
|
|
4427
4473
|
return null;
|
|
4428
4474
|
};
|
|
4475
|
+
const shouldSkipStep = (stepNum) => {
|
|
4476
|
+
return resumeFromStep > 0 && stepNum < resumeFromStep;
|
|
4477
|
+
};
|
|
4429
4478
|
const formatStep = getCurrentStep("format");
|
|
4430
|
-
showStep(currentStepNum, formatStep, userTier);
|
|
4431
4479
|
let platforms;
|
|
4432
|
-
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);
|
|
4433
4485
|
platforms = options.format.split(",").map((f) => f.trim());
|
|
4434
4486
|
console.log(chalk8.gray(` Using format from flag: ${platforms.join(", ")}`));
|
|
4435
4487
|
} else {
|
|
4488
|
+
showStep(currentStepNum, formatStep, userTier);
|
|
4436
4489
|
console.log(chalk8.gray(" Select the AI editors you want to generate config for:"));
|
|
4437
4490
|
console.log(chalk8.gray(" (AGENTS.md is recommended - works with most AI tools)"));
|
|
4438
4491
|
console.log(chalk8.gray(" Type to search/filter the list."));
|
|
@@ -4518,6 +4571,15 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4518
4571
|
initial: 0
|
|
4519
4572
|
}, promptConfig);
|
|
4520
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
|
+
}
|
|
4521
4583
|
console.log();
|
|
4522
4584
|
console.log(chalk8.yellow(" \u{1F9E9} Blueprint Template Mode"));
|
|
4523
4585
|
console.log(chalk8.gray(" Create a reusable template with [[VARIABLE|default]] placeholders"));
|
|
@@ -4860,10 +4922,19 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4860
4922
|
initial: 0
|
|
4861
4923
|
}, promptConfig);
|
|
4862
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
|
+
}
|
|
4863
4934
|
const loggingResponse = await prompts4({
|
|
4864
|
-
type: "
|
|
4935
|
+
type: "autocomplete",
|
|
4865
4936
|
name: "loggingConventions",
|
|
4866
|
-
message: chalk8.white("Logging conventions:"),
|
|
4937
|
+
message: chalk8.white("Logging conventions (type to search):"),
|
|
4867
4938
|
choices: [
|
|
4868
4939
|
{ title: chalk8.gray("\u23ED Skip"), value: "" },
|
|
4869
4940
|
...LOGGING_OPTIONS.map((l) => ({
|
|
@@ -4893,14 +4964,6 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4893
4964
|
}
|
|
4894
4965
|
const aiStep = getCurrentStep("ai");
|
|
4895
4966
|
showStep(currentStepNum, aiStep, userTier);
|
|
4896
|
-
console.log(chalk8.gray(" Select which behaviors AI should follow:"));
|
|
4897
|
-
console.log();
|
|
4898
|
-
for (const rule of AI_BEHAVIOR_RULES) {
|
|
4899
|
-
const recBadge = rule.recommended ? chalk8.green(" \u2605 recommended") : "";
|
|
4900
|
-
console.log(chalk8.cyan(` \u2022 ${rule.label}${recBadge}`));
|
|
4901
|
-
console.log(chalk8.gray(` ${rule.description}`));
|
|
4902
|
-
}
|
|
4903
|
-
console.log();
|
|
4904
4967
|
const aiBehaviorResponse = await prompts4({
|
|
4905
4968
|
type: "autocompleteMultiselect",
|
|
4906
4969
|
name: "aiBehavior",
|
|
@@ -4915,6 +4978,13 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4915
4978
|
instructions: false
|
|
4916
4979
|
}, promptConfig);
|
|
4917
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
|
+
}
|
|
4918
4988
|
const importantFilesResponse = await prompts4({
|
|
4919
4989
|
type: "autocompleteMultiselect",
|
|
4920
4990
|
name: "importantFiles",
|
|
@@ -4940,7 +5010,7 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4940
5010
|
const includePersonalResponse = await prompts4({
|
|
4941
5011
|
type: "toggle",
|
|
4942
5012
|
name: "includePersonalData",
|
|
4943
|
-
message: chalk8.white("Include personal data (
|
|
5013
|
+
message: chalk8.white("Include personal data (as saved in WebUI)?"),
|
|
4944
5014
|
initial: false,
|
|
4945
5015
|
active: "Yes",
|
|
4946
5016
|
inactive: "No"
|
|
@@ -4949,24 +5019,24 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4949
5019
|
if (canAccessTier(userTier, "advanced")) {
|
|
4950
5020
|
const boundariesStep = getCurrentStep("boundaries");
|
|
4951
5021
|
showStep(currentStepNum, boundariesStep, userTier);
|
|
4952
|
-
console.log(chalk8.gray(" Define what AI should
|
|
5022
|
+
console.log(chalk8.gray(" Define what AI should never do, ask first, or always do."));
|
|
4953
5023
|
console.log(chalk8.gray(" Each option can only be in one category."));
|
|
4954
5024
|
console.log();
|
|
4955
5025
|
const usedOptions = /* @__PURE__ */ new Set();
|
|
4956
|
-
console.log(chalk8.
|
|
4957
|
-
const
|
|
5026
|
+
console.log(chalk8.red.bold(" \u2717 NEVER ALLOW - AI will refuse to do"));
|
|
5027
|
+
const neverResponse = await prompts4({
|
|
4958
5028
|
type: "autocompleteMultiselect",
|
|
4959
|
-
name: "
|
|
4960
|
-
message: chalk8.white("
|
|
5029
|
+
name: "never",
|
|
5030
|
+
message: chalk8.white("Never allow (type to filter):"),
|
|
4961
5031
|
choices: BOUNDARY_OPTIONS.map((o) => ({
|
|
4962
|
-
title: chalk8.
|
|
5032
|
+
title: chalk8.red(o),
|
|
4963
5033
|
value: o
|
|
4964
5034
|
})),
|
|
4965
5035
|
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4966
5036
|
instructions: false
|
|
4967
5037
|
}, promptConfig);
|
|
4968
|
-
answers.
|
|
4969
|
-
answers.
|
|
5038
|
+
answers.boundaryNever = neverResponse.never || [];
|
|
5039
|
+
answers.boundaryNever.forEach((o) => usedOptions.add(o));
|
|
4970
5040
|
console.log();
|
|
4971
5041
|
console.log(chalk8.yellow.bold(" ? ASK FIRST - AI will ask before doing"));
|
|
4972
5042
|
const availableForAsk = BOUNDARY_OPTIONS.filter((o) => !usedOptions.has(o));
|
|
@@ -4984,20 +5054,20 @@ async function runInteractiveWizard(options, detected, userTier) {
|
|
|
4984
5054
|
answers.boundaryAsk = askResponse.ask || [];
|
|
4985
5055
|
answers.boundaryAsk.forEach((o) => usedOptions.add(o));
|
|
4986
5056
|
console.log();
|
|
4987
|
-
console.log(chalk8.
|
|
4988
|
-
const
|
|
4989
|
-
const
|
|
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({
|
|
4990
5060
|
type: "autocompleteMultiselect",
|
|
4991
|
-
name: "
|
|
4992
|
-
message: chalk8.white("
|
|
4993
|
-
choices:
|
|
4994
|
-
title: chalk8.
|
|
5061
|
+
name: "always",
|
|
5062
|
+
message: chalk8.white("Always allow (type to filter):"),
|
|
5063
|
+
choices: availableForAlways.map((o) => ({
|
|
5064
|
+
title: chalk8.green(o),
|
|
4995
5065
|
value: o
|
|
4996
5066
|
})),
|
|
4997
5067
|
hint: chalk8.gray("space select \u2022 enter confirm"),
|
|
4998
5068
|
instructions: false
|
|
4999
5069
|
}, promptConfig);
|
|
5000
|
-
answers.
|
|
5070
|
+
answers.boundaryAlways = alwaysResponse.always || [];
|
|
5001
5071
|
console.log();
|
|
5002
5072
|
console.log(chalk8.gray(" Boundary summary:"));
|
|
5003
5073
|
if (answers.boundaryAlways.length > 0) {
|