lynxprompt 0.2.0 → 0.2.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/README.md +0 -25
- package/dist/index.js +355 -560
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk15 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/commands/login.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -135,19 +135,6 @@ var ApiClient = class {
|
|
|
135
135
|
});
|
|
136
136
|
return this.request(`/api/blueprints?${params}`);
|
|
137
137
|
}
|
|
138
|
-
async createBlueprint(data) {
|
|
139
|
-
return this.request("/api/v1/blueprints", {
|
|
140
|
-
method: "POST",
|
|
141
|
-
body: JSON.stringify(data)
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
async updateBlueprint(id, data) {
|
|
145
|
-
const apiId = id.startsWith("bp_") ? id : `bp_${id}`;
|
|
146
|
-
return this.request(`/api/v1/blueprints/${apiId}`, {
|
|
147
|
-
method: "PUT",
|
|
148
|
-
body: JSON.stringify(data)
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
138
|
};
|
|
152
139
|
var ApiRequestError = class extends Error {
|
|
153
140
|
constructor(message, statusCode, response) {
|
|
@@ -487,15 +474,6 @@ async function hasLocalChanges(cwd, tracked) {
|
|
|
487
474
|
return false;
|
|
488
475
|
}
|
|
489
476
|
}
|
|
490
|
-
async function updateChecksum(cwd, file, content) {
|
|
491
|
-
const config2 = await loadBlueprints(cwd);
|
|
492
|
-
const blueprint = config2.blueprints.find((b) => b.file === file);
|
|
493
|
-
if (blueprint) {
|
|
494
|
-
blueprint.checksum = calculateChecksum(content);
|
|
495
|
-
blueprint.pulledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
496
|
-
await saveBlueprints(cwd, config2);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
477
|
async function untrackBlueprint(cwd, file) {
|
|
500
478
|
const config2 = await loadBlueprints(cwd);
|
|
501
479
|
const initialCount = config2.blueprints.length;
|
|
@@ -788,191 +766,10 @@ function handleApiError2(error) {
|
|
|
788
766
|
process.exit(1);
|
|
789
767
|
}
|
|
790
768
|
|
|
791
|
-
// src/commands/
|
|
769
|
+
// src/commands/init.ts
|
|
792
770
|
import chalk6 from "chalk";
|
|
793
|
-
import ora5 from "ora";
|
|
794
|
-
import fs from "fs";
|
|
795
|
-
import path from "path";
|
|
796
771
|
import prompts2 from "prompts";
|
|
797
|
-
|
|
798
|
-
const cwd = process.cwd();
|
|
799
|
-
if (!isAuthenticated()) {
|
|
800
|
-
console.log(chalk6.yellow("You need to be logged in to push blueprints."));
|
|
801
|
-
console.log(chalk6.gray("Run 'lynxp login' to authenticate."));
|
|
802
|
-
process.exit(1);
|
|
803
|
-
}
|
|
804
|
-
const file = fileArg || findDefaultFile();
|
|
805
|
-
if (!file) {
|
|
806
|
-
console.log(chalk6.red("No AI configuration file found."));
|
|
807
|
-
console.log(
|
|
808
|
-
chalk6.gray("Specify a file or run in a directory with AGENTS.md, CLAUDE.md, etc.")
|
|
809
|
-
);
|
|
810
|
-
process.exit(1);
|
|
811
|
-
}
|
|
812
|
-
if (!fs.existsSync(file)) {
|
|
813
|
-
console.log(chalk6.red(`File not found: ${file}`));
|
|
814
|
-
process.exit(1);
|
|
815
|
-
}
|
|
816
|
-
const content = fs.readFileSync(file, "utf-8");
|
|
817
|
-
const filename = path.basename(file);
|
|
818
|
-
const linked = await findBlueprintByFile(cwd, file);
|
|
819
|
-
if (linked) {
|
|
820
|
-
await updateBlueprint(cwd, file, linked.id, content, options);
|
|
821
|
-
} else {
|
|
822
|
-
await createOrLinkBlueprint(cwd, file, filename, content, options);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
async function updateBlueprint(cwd, file, blueprintId, content, options) {
|
|
826
|
-
console.log(chalk6.cyan(`
|
|
827
|
-
\u{1F4E4} Updating blueprint ${chalk6.bold(blueprintId)}...`));
|
|
828
|
-
console.log(chalk6.gray(` File: ${file}`));
|
|
829
|
-
if (!options.yes) {
|
|
830
|
-
const confirm = await prompts2({
|
|
831
|
-
type: "confirm",
|
|
832
|
-
name: "value",
|
|
833
|
-
message: `Push changes to ${blueprintId}?`,
|
|
834
|
-
initial: true
|
|
835
|
-
});
|
|
836
|
-
if (!confirm.value) {
|
|
837
|
-
console.log(chalk6.yellow("Push cancelled."));
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
const spinner = ora5("Pushing changes...").start();
|
|
842
|
-
try {
|
|
843
|
-
const result = await api.updateBlueprint(blueprintId, { content });
|
|
844
|
-
spinner.succeed("Blueprint updated!");
|
|
845
|
-
await updateChecksum(cwd, file, content);
|
|
846
|
-
console.log();
|
|
847
|
-
console.log(chalk6.green(`\u2705 Successfully updated ${chalk6.bold(result.blueprint.name)}`));
|
|
848
|
-
console.log(chalk6.gray(` ID: ${blueprintId}`));
|
|
849
|
-
console.log(chalk6.gray(` View: https://lynxprompt.com/templates/${blueprintId.replace("bp_", "")}`));
|
|
850
|
-
} catch (error) {
|
|
851
|
-
spinner.fail("Failed to update blueprint");
|
|
852
|
-
handleError(error);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
856
|
-
console.log(chalk6.cyan("\n\u{1F4E4} Push new blueprint"));
|
|
857
|
-
console.log(chalk6.gray(` File: ${file}`));
|
|
858
|
-
let name = options.name;
|
|
859
|
-
let description = options.description;
|
|
860
|
-
let visibility = options.visibility || "PRIVATE";
|
|
861
|
-
let tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : [];
|
|
862
|
-
if (!options.yes) {
|
|
863
|
-
const responses = await prompts2([
|
|
864
|
-
{
|
|
865
|
-
type: name ? null : "text",
|
|
866
|
-
name: "name",
|
|
867
|
-
message: "Blueprint name:",
|
|
868
|
-
initial: filename.replace(/\.(md|mdc|json|yml|yaml)$/, ""),
|
|
869
|
-
validate: (v) => v.length > 0 || "Name is required"
|
|
870
|
-
},
|
|
871
|
-
{
|
|
872
|
-
type: description ? null : "text",
|
|
873
|
-
name: "description",
|
|
874
|
-
message: "Description:",
|
|
875
|
-
initial: ""
|
|
876
|
-
},
|
|
877
|
-
{
|
|
878
|
-
type: "select",
|
|
879
|
-
name: "visibility",
|
|
880
|
-
message: "Visibility:",
|
|
881
|
-
choices: [
|
|
882
|
-
{ title: "Private (only you)", value: "PRIVATE" },
|
|
883
|
-
{ title: "Team (your team members)", value: "TEAM" },
|
|
884
|
-
{ title: "Public (visible to everyone)", value: "PUBLIC" }
|
|
885
|
-
],
|
|
886
|
-
initial: 0
|
|
887
|
-
},
|
|
888
|
-
{
|
|
889
|
-
type: "text",
|
|
890
|
-
name: "tags",
|
|
891
|
-
message: "Tags (comma-separated):",
|
|
892
|
-
initial: ""
|
|
893
|
-
}
|
|
894
|
-
]);
|
|
895
|
-
if (!responses.name && !name) {
|
|
896
|
-
console.log(chalk6.yellow("Push cancelled."));
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
name = name || responses.name;
|
|
900
|
-
description = description || responses.description || "";
|
|
901
|
-
visibility = responses.visibility || visibility;
|
|
902
|
-
tags = responses.tags ? responses.tags.split(",").map((t) => t.trim()).filter(Boolean) : tags;
|
|
903
|
-
}
|
|
904
|
-
if (!name) {
|
|
905
|
-
name = filename.replace(/\.(md|mdc|json|yml|yaml)$/, "");
|
|
906
|
-
}
|
|
907
|
-
const spinner = ora5("Creating blueprint...").start();
|
|
908
|
-
try {
|
|
909
|
-
const result = await api.createBlueprint({
|
|
910
|
-
name,
|
|
911
|
-
description: description || "",
|
|
912
|
-
content,
|
|
913
|
-
visibility,
|
|
914
|
-
tags
|
|
915
|
-
});
|
|
916
|
-
spinner.succeed("Blueprint created!");
|
|
917
|
-
await trackBlueprint(cwd, {
|
|
918
|
-
id: result.blueprint.id,
|
|
919
|
-
name: result.blueprint.name,
|
|
920
|
-
file,
|
|
921
|
-
content,
|
|
922
|
-
source: "private"
|
|
923
|
-
});
|
|
924
|
-
console.log();
|
|
925
|
-
console.log(chalk6.green(`\u2705 Created blueprint ${chalk6.bold(result.blueprint.name)}`));
|
|
926
|
-
console.log(chalk6.gray(` ID: ${result.blueprint.id}`));
|
|
927
|
-
console.log(chalk6.gray(` Visibility: ${visibility}`));
|
|
928
|
-
if (visibility === "PUBLIC") {
|
|
929
|
-
console.log(chalk6.gray(` View: https://lynxprompt.com/templates/${result.blueprint.id.replace("bp_", "")}`));
|
|
930
|
-
}
|
|
931
|
-
console.log();
|
|
932
|
-
console.log(chalk6.cyan("The file is now linked. Future 'lynxp push' will update this blueprint."));
|
|
933
|
-
} catch (error) {
|
|
934
|
-
spinner.fail("Failed to create blueprint");
|
|
935
|
-
handleError(error);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
function findDefaultFile() {
|
|
939
|
-
const candidates = [
|
|
940
|
-
"AGENTS.md",
|
|
941
|
-
"CLAUDE.md",
|
|
942
|
-
".cursor/rules/project.mdc",
|
|
943
|
-
".github/copilot-instructions.md",
|
|
944
|
-
".windsurfrules",
|
|
945
|
-
"AIDER.md",
|
|
946
|
-
"GEMINI.md",
|
|
947
|
-
".clinerules"
|
|
948
|
-
];
|
|
949
|
-
for (const candidate of candidates) {
|
|
950
|
-
if (fs.existsSync(candidate)) {
|
|
951
|
-
return candidate;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
return null;
|
|
955
|
-
}
|
|
956
|
-
function handleError(error) {
|
|
957
|
-
if (error instanceof ApiRequestError) {
|
|
958
|
-
console.error(chalk6.red(`Error: ${error.message}`));
|
|
959
|
-
if (error.statusCode === 401) {
|
|
960
|
-
console.error(chalk6.gray("Your session may have expired. Run 'lynxp login' to re-authenticate."));
|
|
961
|
-
} else if (error.statusCode === 403) {
|
|
962
|
-
console.error(chalk6.gray("You don't have permission to modify this blueprint."));
|
|
963
|
-
} else if (error.statusCode === 404) {
|
|
964
|
-
console.error(chalk6.gray("Blueprint not found. It may have been deleted."));
|
|
965
|
-
}
|
|
966
|
-
} else {
|
|
967
|
-
console.error(chalk6.red("An unexpected error occurred."));
|
|
968
|
-
}
|
|
969
|
-
process.exit(1);
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// src/commands/init.ts
|
|
973
|
-
import chalk7 from "chalk";
|
|
974
|
-
import prompts3 from "prompts";
|
|
975
|
-
import ora6 from "ora";
|
|
772
|
+
import ora5 from "ora";
|
|
976
773
|
import { writeFile as writeFile3, mkdir as mkdir3, readFile as readFile4 } from "fs/promises";
|
|
977
774
|
import { join as join5, dirname as dirname3, basename } from "path";
|
|
978
775
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -1330,9 +1127,9 @@ function countSections(content) {
|
|
|
1330
1127
|
const headings = content.match(/^#{1,6}\s+.+$/gm);
|
|
1331
1128
|
return headings ? headings.length : content.trim().length > 0 ? 1 : 0;
|
|
1332
1129
|
}
|
|
1333
|
-
function safeReadFile(
|
|
1130
|
+
function safeReadFile(path) {
|
|
1334
1131
|
try {
|
|
1335
|
-
return readFileSync(
|
|
1132
|
+
return readFileSync(path, "utf-8");
|
|
1336
1133
|
} catch {
|
|
1337
1134
|
return null;
|
|
1338
1135
|
}
|
|
@@ -1582,9 +1379,9 @@ async function detectProject(cwd) {
|
|
|
1582
1379
|
}
|
|
1583
1380
|
return detected.stack.length > 0 || detected.name ? detected : null;
|
|
1584
1381
|
}
|
|
1585
|
-
async function fileExists(
|
|
1382
|
+
async function fileExists(path) {
|
|
1586
1383
|
try {
|
|
1587
|
-
await access3(
|
|
1384
|
+
await access3(path);
|
|
1588
1385
|
return true;
|
|
1589
1386
|
} catch {
|
|
1590
1387
|
return false;
|
|
@@ -1756,14 +1553,14 @@ This exports your rules to the configured agent formats (AGENTS.md, .cursor/rule
|
|
|
1756
1553
|
}
|
|
1757
1554
|
async function initCommand(options) {
|
|
1758
1555
|
console.log();
|
|
1759
|
-
console.log(
|
|
1760
|
-
console.log(
|
|
1556
|
+
console.log(chalk6.cyan("\u{1F431} LynxPrompt Init"));
|
|
1557
|
+
console.log(chalk6.gray("Advanced mode: Multi-editor rule management"));
|
|
1761
1558
|
console.log();
|
|
1762
1559
|
if (!options.yes && !options.force) {
|
|
1763
|
-
console.log(
|
|
1764
|
-
console.log(
|
|
1560
|
+
console.log(chalk6.yellow("\u{1F4A1} Tip: Most users should use 'lynxp wizard' instead."));
|
|
1561
|
+
console.log(chalk6.gray(" The wizard generates files directly without the .lynxprompt/ folder."));
|
|
1765
1562
|
console.log();
|
|
1766
|
-
const { proceed } = await
|
|
1563
|
+
const { proceed } = await prompts2({
|
|
1767
1564
|
type: "confirm",
|
|
1768
1565
|
name: "proceed",
|
|
1769
1566
|
message: "Continue with advanced setup?",
|
|
@@ -1771,7 +1568,7 @@ async function initCommand(options) {
|
|
|
1771
1568
|
});
|
|
1772
1569
|
if (!proceed) {
|
|
1773
1570
|
console.log();
|
|
1774
|
-
console.log(
|
|
1571
|
+
console.log(chalk6.gray("Run 'lynxp wizard' for simple file generation."));
|
|
1775
1572
|
return;
|
|
1776
1573
|
}
|
|
1777
1574
|
console.log();
|
|
@@ -1782,15 +1579,15 @@ async function initCommand(options) {
|
|
|
1782
1579
|
const configPath = join5(cwd, LYNXPROMPT_CONFIG);
|
|
1783
1580
|
const rulesDir = join5(cwd, LYNXPROMPT_RULES);
|
|
1784
1581
|
if (existsSync3(configPath) && !options.force) {
|
|
1785
|
-
console.log(
|
|
1786
|
-
console.log(
|
|
1787
|
-
console.log(
|
|
1582
|
+
console.log(chalk6.yellow("LynxPrompt is already initialized in this project."));
|
|
1583
|
+
console.log(chalk6.gray(`Config: ${LYNXPROMPT_CONFIG}`));
|
|
1584
|
+
console.log(chalk6.gray(`Rules: ${LYNXPROMPT_RULES}/`));
|
|
1788
1585
|
console.log();
|
|
1789
|
-
console.log(
|
|
1790
|
-
console.log(
|
|
1586
|
+
console.log(chalk6.gray("Run 'lynxp sync' to export rules to your agents."));
|
|
1587
|
+
console.log(chalk6.gray("Run 'lynxp wizard' to generate new configurations."));
|
|
1791
1588
|
return;
|
|
1792
1589
|
}
|
|
1793
|
-
const spinner =
|
|
1590
|
+
const spinner = ora5("Scanning project...").start();
|
|
1794
1591
|
const [projectInfo, agentDetection] = await Promise.all([
|
|
1795
1592
|
detectProject(cwd),
|
|
1796
1593
|
Promise.resolve(detectAgents(cwd))
|
|
@@ -1798,28 +1595,28 @@ async function initCommand(options) {
|
|
|
1798
1595
|
const existingFiles = await scanForExistingFiles(cwd);
|
|
1799
1596
|
spinner.stop();
|
|
1800
1597
|
if (projectInfo) {
|
|
1801
|
-
console.log(
|
|
1802
|
-
if (projectInfo.name) console.log(
|
|
1803
|
-
if (projectInfo.stack.length > 0) console.log(
|
|
1804
|
-
if (projectInfo.packageManager) console.log(
|
|
1598
|
+
console.log(chalk6.green("\u2713 Detected project:"));
|
|
1599
|
+
if (projectInfo.name) console.log(chalk6.gray(` Name: ${projectInfo.name}`));
|
|
1600
|
+
if (projectInfo.stack.length > 0) console.log(chalk6.gray(` Stack: ${projectInfo.stack.join(", ")}`));
|
|
1601
|
+
if (projectInfo.packageManager) console.log(chalk6.gray(` Package manager: ${projectInfo.packageManager}`));
|
|
1805
1602
|
console.log();
|
|
1806
1603
|
}
|
|
1807
1604
|
if (agentDetection.detected.length > 0) {
|
|
1808
|
-
console.log(
|
|
1605
|
+
console.log(chalk6.green(`\u2713 Detected ${agentDetection.detected.length} AI agent${agentDetection.detected.length === 1 ? "" : "s"}:`));
|
|
1809
1606
|
for (const detected of agentDetection.detected) {
|
|
1810
|
-
const rules = detected.ruleCount > 0 ?
|
|
1811
|
-
console.log(` ${
|
|
1607
|
+
const rules = detected.ruleCount > 0 ? chalk6.gray(` (${detected.ruleCount} sections)`) : "";
|
|
1608
|
+
console.log(` ${chalk6.cyan("\u2022")} ${detected.agent.name}${rules}`);
|
|
1812
1609
|
}
|
|
1813
1610
|
console.log();
|
|
1814
1611
|
}
|
|
1815
1612
|
if (existingFiles.length > 0) {
|
|
1816
|
-
console.log(
|
|
1613
|
+
console.log(chalk6.green("\u2713 Found existing AI configuration files:"));
|
|
1817
1614
|
for (const file of existingFiles) {
|
|
1818
|
-
console.log(` ${
|
|
1615
|
+
console.log(` ${chalk6.cyan(file.path)} ${chalk6.gray(`(${file.agent})`)}`);
|
|
1819
1616
|
}
|
|
1820
1617
|
console.log();
|
|
1821
1618
|
if (!options.yes) {
|
|
1822
|
-
const { action } = await
|
|
1619
|
+
const { action } = await prompts2({
|
|
1823
1620
|
type: "select",
|
|
1824
1621
|
name: "action",
|
|
1825
1622
|
message: "What would you like to do?",
|
|
@@ -1830,7 +1627,7 @@ async function initCommand(options) {
|
|
|
1830
1627
|
]
|
|
1831
1628
|
});
|
|
1832
1629
|
if (action === "cancel" || !action) {
|
|
1833
|
-
console.log(
|
|
1630
|
+
console.log(chalk6.gray("Cancelled."));
|
|
1834
1631
|
return;
|
|
1835
1632
|
}
|
|
1836
1633
|
if (action === "import") {
|
|
@@ -1841,20 +1638,20 @@ async function initCommand(options) {
|
|
|
1841
1638
|
const ruleName = file.path.replace(/^\./, "").replace(/\//g, "-").replace(/\.md$/, "") + ".md";
|
|
1842
1639
|
const rulePath = join5(rulesDir, ruleName);
|
|
1843
1640
|
await writeFile3(rulePath, file.content, "utf-8");
|
|
1844
|
-
console.log(
|
|
1641
|
+
console.log(chalk6.gray(` Imported: ${file.path} \u2192 .lynxprompt/rules/${ruleName}`));
|
|
1845
1642
|
importedCount++;
|
|
1846
1643
|
}
|
|
1847
1644
|
}
|
|
1848
1645
|
if (importedCount === 0) {
|
|
1849
1646
|
const starterPath = join5(rulesDir, "agents.md");
|
|
1850
1647
|
await writeFile3(starterPath, createStarterAgentsMd(projectName), "utf-8");
|
|
1851
|
-
console.log(
|
|
1648
|
+
console.log(chalk6.gray(" Created starter: .lynxprompt/rules/agents.md"));
|
|
1852
1649
|
}
|
|
1853
1650
|
} else {
|
|
1854
1651
|
await mkdir3(rulesDir, { recursive: true });
|
|
1855
1652
|
const starterPath = join5(rulesDir, "agents.md");
|
|
1856
1653
|
await writeFile3(starterPath, createStarterAgentsMd(projectName), "utf-8");
|
|
1857
|
-
console.log(
|
|
1654
|
+
console.log(chalk6.gray("Created starter: .lynxprompt/rules/agents.md"));
|
|
1858
1655
|
}
|
|
1859
1656
|
} else {
|
|
1860
1657
|
await mkdir3(rulesDir, { recursive: true });
|
|
@@ -1867,30 +1664,30 @@ async function initCommand(options) {
|
|
|
1867
1664
|
}
|
|
1868
1665
|
}
|
|
1869
1666
|
} else {
|
|
1870
|
-
console.log(
|
|
1667
|
+
console.log(chalk6.gray("No existing AI configuration files found."));
|
|
1871
1668
|
console.log();
|
|
1872
1669
|
if (!options.yes) {
|
|
1873
|
-
const { create } = await
|
|
1670
|
+
const { create } = await prompts2({
|
|
1874
1671
|
type: "confirm",
|
|
1875
1672
|
name: "create",
|
|
1876
1673
|
message: "Create a starter template?",
|
|
1877
1674
|
initial: true
|
|
1878
1675
|
});
|
|
1879
1676
|
if (!create) {
|
|
1880
|
-
console.log(
|
|
1677
|
+
console.log(chalk6.gray("Cancelled."));
|
|
1881
1678
|
return;
|
|
1882
1679
|
}
|
|
1883
1680
|
}
|
|
1884
1681
|
await mkdir3(rulesDir, { recursive: true });
|
|
1885
1682
|
const starterPath = join5(rulesDir, "agents.md");
|
|
1886
1683
|
await writeFile3(starterPath, createStarterAgentsMd(projectName), "utf-8");
|
|
1887
|
-
console.log(
|
|
1684
|
+
console.log(chalk6.gray("Created: .lynxprompt/rules/agents.md"));
|
|
1888
1685
|
}
|
|
1889
1686
|
let exporters = [];
|
|
1890
1687
|
if (agentDetection.detected.length > 0) {
|
|
1891
1688
|
exporters = agentDetection.detected.map((d) => d.agent.id);
|
|
1892
1689
|
if (agentDetection.detected.length > 3 && !options.yes) {
|
|
1893
|
-
const { selected } = await
|
|
1690
|
+
const { selected } = await prompts2({
|
|
1894
1691
|
type: "multiselect",
|
|
1895
1692
|
name: "selected",
|
|
1896
1693
|
message: "Select agents to enable:",
|
|
@@ -1909,7 +1706,7 @@ async function initCommand(options) {
|
|
|
1909
1706
|
exporters = ["agents"];
|
|
1910
1707
|
if (!options.yes) {
|
|
1911
1708
|
const popular = getPopularAgents();
|
|
1912
|
-
const { selected } = await
|
|
1709
|
+
const { selected } = await prompts2({
|
|
1913
1710
|
type: "multiselect",
|
|
1914
1711
|
name: "selected",
|
|
1915
1712
|
message: "Select AI agents to sync to:",
|
|
@@ -1926,7 +1723,7 @@ async function initCommand(options) {
|
|
|
1926
1723
|
}
|
|
1927
1724
|
}
|
|
1928
1725
|
}
|
|
1929
|
-
console.log(
|
|
1726
|
+
console.log(chalk6.gray(`Enabling ${exporters.length} exporter${exporters.length === 1 ? "" : "s"}: ${exporters.join(", ")}`));
|
|
1930
1727
|
await mkdir3(dirname3(configPath), { recursive: true });
|
|
1931
1728
|
await writeFile3(configPath, createDefaultConfig(exporters), "utf-8");
|
|
1932
1729
|
const readmePath = join5(lynxpromptDir, "README.md");
|
|
@@ -1938,23 +1735,23 @@ async function initCommand(options) {
|
|
|
1938
1735
|
`;
|
|
1939
1736
|
await writeFile3(gitignorePath, gitignoreContent, "utf-8");
|
|
1940
1737
|
console.log();
|
|
1941
|
-
console.log(
|
|
1738
|
+
console.log(chalk6.green("\u2705 LynxPrompt initialized!"));
|
|
1942
1739
|
console.log();
|
|
1943
|
-
console.log(
|
|
1944
|
-
console.log(
|
|
1945
|
-
console.log(
|
|
1740
|
+
console.log(chalk6.gray("Created:"));
|
|
1741
|
+
console.log(chalk6.gray(` ${LYNXPROMPT_CONFIG} - Configuration`));
|
|
1742
|
+
console.log(chalk6.gray(` ${LYNXPROMPT_RULES}/ - Your rules (edit here)`));
|
|
1946
1743
|
console.log();
|
|
1947
|
-
console.log(
|
|
1948
|
-
console.log(
|
|
1949
|
-
console.log(
|
|
1950
|
-
console.log(
|
|
1744
|
+
console.log(chalk6.cyan("Next steps:"));
|
|
1745
|
+
console.log(chalk6.gray(" 1. Edit your rules in .lynxprompt/rules/"));
|
|
1746
|
+
console.log(chalk6.gray(" 2. Run 'lynxp sync' to export to your AI agents"));
|
|
1747
|
+
console.log(chalk6.gray(" 3. Or run 'lynxp agents' to manage which agents to sync to"));
|
|
1951
1748
|
console.log();
|
|
1952
1749
|
}
|
|
1953
1750
|
|
|
1954
1751
|
// src/commands/wizard.ts
|
|
1955
|
-
import
|
|
1956
|
-
import
|
|
1957
|
-
import
|
|
1752
|
+
import chalk7 from "chalk";
|
|
1753
|
+
import prompts3 from "prompts";
|
|
1754
|
+
import ora6 from "ora";
|
|
1958
1755
|
import { writeFile as writeFile4, mkdir as mkdir4, access as access5 } from "fs/promises";
|
|
1959
1756
|
import { join as join6, dirname as dirname4 } from "path";
|
|
1960
1757
|
|
|
@@ -2320,17 +2117,17 @@ var BOUNDARY_PRESETS = [
|
|
|
2320
2117
|
];
|
|
2321
2118
|
async function wizardCommand(options) {
|
|
2322
2119
|
console.log();
|
|
2323
|
-
console.log(
|
|
2324
|
-
console.log(
|
|
2120
|
+
console.log(chalk7.cyan("\u{1F431} LynxPrompt Wizard"));
|
|
2121
|
+
console.log(chalk7.gray("Generate AI IDE configuration in seconds"));
|
|
2325
2122
|
console.log();
|
|
2326
2123
|
const detected = await detectProject(process.cwd());
|
|
2327
2124
|
if (detected) {
|
|
2328
|
-
console.log(
|
|
2329
|
-
if (detected.name) console.log(
|
|
2330
|
-
if (detected.stack.length > 0) console.log(
|
|
2331
|
-
if (detected.packageManager) console.log(
|
|
2332
|
-
if (detected.commands.build) console.log(
|
|
2333
|
-
if (detected.commands.test) console.log(
|
|
2125
|
+
console.log(chalk7.green("\u2713 Detected project:"));
|
|
2126
|
+
if (detected.name) console.log(chalk7.gray(` Name: ${detected.name}`));
|
|
2127
|
+
if (detected.stack.length > 0) console.log(chalk7.gray(` Stack: ${detected.stack.join(", ")}`));
|
|
2128
|
+
if (detected.packageManager) console.log(chalk7.gray(` Package manager: ${detected.packageManager}`));
|
|
2129
|
+
if (detected.commands.build) console.log(chalk7.gray(` Build: ${detected.commands.build}`));
|
|
2130
|
+
if (detected.commands.test) console.log(chalk7.gray(` Test: ${detected.commands.test}`));
|
|
2334
2131
|
console.log();
|
|
2335
2132
|
}
|
|
2336
2133
|
let config2;
|
|
@@ -2355,12 +2152,12 @@ async function wizardCommand(options) {
|
|
|
2355
2152
|
} else {
|
|
2356
2153
|
config2 = await runInteractiveWizard(options, detected);
|
|
2357
2154
|
}
|
|
2358
|
-
const spinner =
|
|
2155
|
+
const spinner = ora6("Generating configuration...").start();
|
|
2359
2156
|
try {
|
|
2360
2157
|
const files = generateConfig(config2);
|
|
2361
2158
|
spinner.stop();
|
|
2362
2159
|
console.log();
|
|
2363
|
-
console.log(
|
|
2160
|
+
console.log(chalk7.green("\u2705 Generated:"));
|
|
2364
2161
|
for (const [filename, content] of Object.entries(files)) {
|
|
2365
2162
|
const outputPath = join6(process.cwd(), filename);
|
|
2366
2163
|
let exists = false;
|
|
@@ -2370,14 +2167,14 @@ async function wizardCommand(options) {
|
|
|
2370
2167
|
} catch {
|
|
2371
2168
|
}
|
|
2372
2169
|
if (exists && !options.yes) {
|
|
2373
|
-
const response = await
|
|
2170
|
+
const response = await prompts3({
|
|
2374
2171
|
type: "confirm",
|
|
2375
2172
|
name: "overwrite",
|
|
2376
2173
|
message: `${filename} already exists. Overwrite?`,
|
|
2377
2174
|
initial: false
|
|
2378
2175
|
});
|
|
2379
2176
|
if (!response.overwrite) {
|
|
2380
|
-
console.log(
|
|
2177
|
+
console.log(chalk7.yellow(` Skipped: ${filename}`));
|
|
2381
2178
|
continue;
|
|
2382
2179
|
}
|
|
2383
2180
|
}
|
|
@@ -2386,23 +2183,23 @@ async function wizardCommand(options) {
|
|
|
2386
2183
|
await mkdir4(dir, { recursive: true });
|
|
2387
2184
|
}
|
|
2388
2185
|
await writeFile4(outputPath, content, "utf-8");
|
|
2389
|
-
console.log(` ${
|
|
2186
|
+
console.log(` ${chalk7.cyan(filename)}`);
|
|
2390
2187
|
}
|
|
2391
2188
|
console.log();
|
|
2392
|
-
console.log(
|
|
2189
|
+
console.log(chalk7.gray("Your AI assistant will now follow these instructions."));
|
|
2393
2190
|
console.log();
|
|
2394
|
-
console.log(
|
|
2395
|
-
console.log(
|
|
2396
|
-
console.log(
|
|
2397
|
-
console.log(
|
|
2191
|
+
console.log(chalk7.gray("Tips:"));
|
|
2192
|
+
console.log(chalk7.gray(" \u2022 Edit the generated file anytime to customize rules"));
|
|
2193
|
+
console.log(chalk7.gray(" \u2022 Run 'lynxp wizard' again to regenerate"));
|
|
2194
|
+
console.log(chalk7.gray(" \u2022 Run 'lynxp check' to validate your configuration"));
|
|
2398
2195
|
console.log();
|
|
2399
2196
|
} catch (error) {
|
|
2400
2197
|
spinner.fail("Failed to generate files");
|
|
2401
|
-
console.error(
|
|
2198
|
+
console.error(chalk7.red("\n\u2717 An error occurred while generating configuration files."));
|
|
2402
2199
|
if (error instanceof Error) {
|
|
2403
|
-
console.error(
|
|
2200
|
+
console.error(chalk7.gray(` ${error.message}`));
|
|
2404
2201
|
}
|
|
2405
|
-
console.error(
|
|
2202
|
+
console.error(chalk7.gray("\nTry running with --yes flag for default settings."));
|
|
2406
2203
|
process.exit(1);
|
|
2407
2204
|
}
|
|
2408
2205
|
}
|
|
@@ -2412,12 +2209,12 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2412
2209
|
if (options.format) {
|
|
2413
2210
|
platforms = options.format.split(",").map((f) => f.trim());
|
|
2414
2211
|
} else {
|
|
2415
|
-
const formatResponse = await
|
|
2212
|
+
const formatResponse = await prompts3({
|
|
2416
2213
|
type: "select",
|
|
2417
2214
|
name: "format",
|
|
2418
2215
|
message: "Select output format:",
|
|
2419
2216
|
choices: OUTPUT_FORMATS.map((f) => ({
|
|
2420
|
-
title: f.recommended ? `${f.title} ${
|
|
2217
|
+
title: f.recommended ? `${f.title} ${chalk7.green("(recommended)")}` : f.title,
|
|
2421
2218
|
value: f.value,
|
|
2422
2219
|
description: f.description
|
|
2423
2220
|
})),
|
|
@@ -2425,7 +2222,7 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2425
2222
|
// AGENTS.md is default
|
|
2426
2223
|
});
|
|
2427
2224
|
if (formatResponse.format === "multiple") {
|
|
2428
|
-
const platformResponse = await
|
|
2225
|
+
const platformResponse = await prompts3({
|
|
2429
2226
|
type: "multiselect",
|
|
2430
2227
|
name: "platforms",
|
|
2431
2228
|
message: "Select AI editors:",
|
|
@@ -2439,14 +2236,14 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2439
2236
|
}
|
|
2440
2237
|
}
|
|
2441
2238
|
answers.platforms = platforms;
|
|
2442
|
-
const nameResponse = await
|
|
2239
|
+
const nameResponse = await prompts3({
|
|
2443
2240
|
type: "text",
|
|
2444
2241
|
name: "name",
|
|
2445
2242
|
message: "Project name:",
|
|
2446
2243
|
initial: options.name || detected?.name || "my-project"
|
|
2447
2244
|
});
|
|
2448
2245
|
answers.name = nameResponse.name || "my-project";
|
|
2449
|
-
const descResponse = await
|
|
2246
|
+
const descResponse = await prompts3({
|
|
2450
2247
|
type: "text",
|
|
2451
2248
|
name: "description",
|
|
2452
2249
|
message: "Brief description (optional):",
|
|
@@ -2455,7 +2252,7 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2455
2252
|
answers.description = descResponse.description || "";
|
|
2456
2253
|
const allStackOptions = [...TECH_STACKS, ...FRAMEWORKS];
|
|
2457
2254
|
const detectedStackSet = new Set(detected?.stack || []);
|
|
2458
|
-
const stackResponse = await
|
|
2255
|
+
const stackResponse = await prompts3({
|
|
2459
2256
|
type: "multiselect",
|
|
2460
2257
|
name: "stack",
|
|
2461
2258
|
message: "Tech stack:",
|
|
@@ -2467,7 +2264,7 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2467
2264
|
hint: "- Space to select, Enter to confirm"
|
|
2468
2265
|
});
|
|
2469
2266
|
answers.stack = stackResponse.stack || [];
|
|
2470
|
-
const personaResponse = await
|
|
2267
|
+
const personaResponse = await prompts3({
|
|
2471
2268
|
type: "select",
|
|
2472
2269
|
name: "persona",
|
|
2473
2270
|
message: "AI persona:",
|
|
@@ -2476,7 +2273,7 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2476
2273
|
// Full-stack by default
|
|
2477
2274
|
});
|
|
2478
2275
|
if (personaResponse.persona === "custom") {
|
|
2479
|
-
const customPersona = await
|
|
2276
|
+
const customPersona = await prompts3({
|
|
2480
2277
|
type: "text",
|
|
2481
2278
|
name: "value",
|
|
2482
2279
|
message: "Describe the custom persona:"
|
|
@@ -2485,7 +2282,7 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2485
2282
|
} else {
|
|
2486
2283
|
answers.persona = personaResponse.persona || "fullstack";
|
|
2487
2284
|
}
|
|
2488
|
-
const boundaryResponse = await
|
|
2285
|
+
const boundaryResponse = await prompts3({
|
|
2489
2286
|
type: "select",
|
|
2490
2287
|
name: "boundaries",
|
|
2491
2288
|
message: "AI boundaries:",
|
|
@@ -2496,19 +2293,19 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2496
2293
|
answers.boundaries = boundaryResponse.boundaries || "standard";
|
|
2497
2294
|
if (detected?.commands && Object.keys(detected.commands).length > 0) {
|
|
2498
2295
|
console.log();
|
|
2499
|
-
console.log(
|
|
2500
|
-
if (detected.commands.build) console.log(
|
|
2501
|
-
if (detected.commands.test) console.log(
|
|
2502
|
-
if (detected.commands.lint) console.log(
|
|
2503
|
-
if (detected.commands.dev) console.log(
|
|
2504
|
-
const editCommands = await
|
|
2296
|
+
console.log(chalk7.gray("Auto-detected commands:"));
|
|
2297
|
+
if (detected.commands.build) console.log(chalk7.gray(` Build: ${detected.commands.build}`));
|
|
2298
|
+
if (detected.commands.test) console.log(chalk7.gray(` Test: ${detected.commands.test}`));
|
|
2299
|
+
if (detected.commands.lint) console.log(chalk7.gray(` Lint: ${detected.commands.lint}`));
|
|
2300
|
+
if (detected.commands.dev) console.log(chalk7.gray(` Dev: ${detected.commands.dev}`));
|
|
2301
|
+
const editCommands = await prompts3({
|
|
2505
2302
|
type: "confirm",
|
|
2506
2303
|
name: "edit",
|
|
2507
2304
|
message: "Edit commands?",
|
|
2508
2305
|
initial: false
|
|
2509
2306
|
});
|
|
2510
2307
|
if (editCommands.edit) {
|
|
2511
|
-
const commandsResponse = await
|
|
2308
|
+
const commandsResponse = await prompts3([
|
|
2512
2309
|
{ type: "text", name: "build", message: "Build:", initial: detected.commands.build },
|
|
2513
2310
|
{ type: "text", name: "test", message: "Test:", initial: detected.commands.test },
|
|
2514
2311
|
{ type: "text", name: "lint", message: "Lint:", initial: detected.commands.lint },
|
|
@@ -2533,52 +2330,52 @@ async function runInteractiveWizard(options, detected) {
|
|
|
2533
2330
|
}
|
|
2534
2331
|
|
|
2535
2332
|
// src/commands/search.ts
|
|
2536
|
-
import
|
|
2537
|
-
import
|
|
2333
|
+
import chalk8 from "chalk";
|
|
2334
|
+
import ora7 from "ora";
|
|
2538
2335
|
async function searchCommand(query, options) {
|
|
2539
|
-
const spinner =
|
|
2336
|
+
const spinner = ora7(`Searching for "${query}"...`).start();
|
|
2540
2337
|
try {
|
|
2541
2338
|
const limit = parseInt(options.limit, 10) || 20;
|
|
2542
2339
|
const { templates, total, hasMore } = await api.searchBlueprints(query, limit);
|
|
2543
2340
|
spinner.stop();
|
|
2544
2341
|
if (templates.length === 0) {
|
|
2545
2342
|
console.log();
|
|
2546
|
-
console.log(
|
|
2547
|
-
console.log(
|
|
2343
|
+
console.log(chalk8.yellow(`No blueprints found for "${query}".`));
|
|
2344
|
+
console.log(chalk8.gray("Try different keywords or browse at https://lynxprompt.com/blueprints"));
|
|
2548
2345
|
return;
|
|
2549
2346
|
}
|
|
2550
2347
|
console.log();
|
|
2551
|
-
console.log(
|
|
2348
|
+
console.log(chalk8.cyan(`\u{1F50D} Search Results for "${query}" (${total} found)`));
|
|
2552
2349
|
console.log();
|
|
2553
2350
|
for (const result of templates) {
|
|
2554
2351
|
printSearchResult(result);
|
|
2555
2352
|
}
|
|
2556
2353
|
if (hasMore) {
|
|
2557
|
-
console.log(
|
|
2354
|
+
console.log(chalk8.gray(`Showing ${templates.length} of ${total}. Use --limit to see more.`));
|
|
2558
2355
|
}
|
|
2559
2356
|
console.log();
|
|
2560
|
-
console.log(
|
|
2357
|
+
console.log(chalk8.gray("Use 'lynxprompt pull <id>' to download a blueprint."));
|
|
2561
2358
|
} catch (error) {
|
|
2562
2359
|
spinner.fail("Search failed");
|
|
2563
2360
|
handleApiError3(error);
|
|
2564
2361
|
}
|
|
2565
2362
|
}
|
|
2566
2363
|
function printSearchResult(result) {
|
|
2567
|
-
const priceInfo = result.price ?
|
|
2568
|
-
const officialBadge = result.isOfficial ?
|
|
2569
|
-
console.log(` ${
|
|
2570
|
-
console.log(` ${
|
|
2364
|
+
const priceInfo = result.price ? chalk8.yellow(`\u20AC${(result.price / 100).toFixed(2)}`) : chalk8.green("Free");
|
|
2365
|
+
const officialBadge = result.isOfficial ? chalk8.magenta(" \u2605 Official") : "";
|
|
2366
|
+
console.log(` ${chalk8.bold(result.name)}${officialBadge}`);
|
|
2367
|
+
console.log(` ${chalk8.cyan(result.id)} \u2022 ${priceInfo}`);
|
|
2571
2368
|
if (result.description) {
|
|
2572
|
-
console.log(` ${
|
|
2369
|
+
console.log(` ${chalk8.gray(truncate2(result.description, 60))}`);
|
|
2573
2370
|
}
|
|
2574
|
-
console.log(` ${
|
|
2371
|
+
console.log(` ${chalk8.gray(`by ${result.author}`)} \u2022 ${chalk8.gray(`\u2193${result.downloads}`)} ${chalk8.gray(`\u2665${result.likes}`)}`);
|
|
2575
2372
|
if (result.tags && result.tags.length > 0) {
|
|
2576
2373
|
console.log(` ${formatTags2(result.tags)}`);
|
|
2577
2374
|
}
|
|
2578
2375
|
console.log();
|
|
2579
2376
|
}
|
|
2580
2377
|
function formatTags2(tags) {
|
|
2581
|
-
return tags.slice(0, 4).map((t) =>
|
|
2378
|
+
return tags.slice(0, 4).map((t) => chalk8.gray(`#${t}`)).join(" ");
|
|
2582
2379
|
}
|
|
2583
2380
|
function truncate2(str, maxLength) {
|
|
2584
2381
|
if (str.length <= maxLength) return str;
|
|
@@ -2586,15 +2383,15 @@ function truncate2(str, maxLength) {
|
|
|
2586
2383
|
}
|
|
2587
2384
|
function handleApiError3(error) {
|
|
2588
2385
|
if (error instanceof ApiRequestError) {
|
|
2589
|
-
console.error(
|
|
2386
|
+
console.error(chalk8.red(`Error: ${error.message}`));
|
|
2590
2387
|
} else {
|
|
2591
|
-
console.error(
|
|
2388
|
+
console.error(chalk8.red("An unexpected error occurred."));
|
|
2592
2389
|
}
|
|
2593
2390
|
process.exit(1);
|
|
2594
2391
|
}
|
|
2595
2392
|
|
|
2596
2393
|
// src/commands/status.ts
|
|
2597
|
-
import
|
|
2394
|
+
import chalk9 from "chalk";
|
|
2598
2395
|
import { access as access6, readFile as readFile6, readdir as readdir3 } from "fs/promises";
|
|
2599
2396
|
import { join as join7 } from "path";
|
|
2600
2397
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -2616,12 +2413,12 @@ var CONFIG_DIRS = [
|
|
|
2616
2413
|
async function statusCommand() {
|
|
2617
2414
|
const cwd = process.cwd();
|
|
2618
2415
|
console.log();
|
|
2619
|
-
console.log(
|
|
2620
|
-
console.log(
|
|
2416
|
+
console.log(chalk9.cyan("\u{1F431} LynxPrompt Status"));
|
|
2417
|
+
console.log(chalk9.gray(` Directory: ${cwd}`));
|
|
2621
2418
|
console.log();
|
|
2622
2419
|
const lynxpromptExists = existsSync4(join7(cwd, ".lynxprompt"));
|
|
2623
2420
|
if (lynxpromptExists) {
|
|
2624
|
-
console.log(
|
|
2421
|
+
console.log(chalk9.green("\u2713 LynxPrompt initialized"));
|
|
2625
2422
|
const configPath = join7(cwd, ".lynxprompt/conf.yml");
|
|
2626
2423
|
if (existsSync4(configPath)) {
|
|
2627
2424
|
try {
|
|
@@ -2629,7 +2426,7 @@ async function statusCommand() {
|
|
|
2629
2426
|
const { parse: parse5 } = await import("yaml");
|
|
2630
2427
|
const config2 = parse5(content);
|
|
2631
2428
|
if (config2?.exporters?.length > 0) {
|
|
2632
|
-
console.log(
|
|
2429
|
+
console.log(chalk9.gray(` Exporters: ${config2.exporters.join(", ")}`));
|
|
2633
2430
|
}
|
|
2634
2431
|
} catch {
|
|
2635
2432
|
}
|
|
@@ -2638,31 +2435,31 @@ async function statusCommand() {
|
|
|
2638
2435
|
}
|
|
2639
2436
|
const trackedStatus = await checkSyncStatus(cwd);
|
|
2640
2437
|
if (trackedStatus.length > 0) {
|
|
2641
|
-
console.log(
|
|
2438
|
+
console.log(chalk9.cyan("\u{1F4E6} Tracked Blueprints"));
|
|
2642
2439
|
console.log();
|
|
2643
2440
|
for (const { blueprint, localModified, fileExists: fileExists2 } of trackedStatus) {
|
|
2644
|
-
const statusIcon = !fileExists2 ?
|
|
2441
|
+
const statusIcon = !fileExists2 ? chalk9.red("\u2717") : localModified ? chalk9.yellow("\u25CF") : chalk9.green("\u2713");
|
|
2645
2442
|
const sourceLabel = {
|
|
2646
|
-
marketplace:
|
|
2647
|
-
team:
|
|
2648
|
-
private:
|
|
2649
|
-
local:
|
|
2443
|
+
marketplace: chalk9.gray("[marketplace]"),
|
|
2444
|
+
team: chalk9.blue("[team]"),
|
|
2445
|
+
private: chalk9.green("[private]"),
|
|
2446
|
+
local: chalk9.gray("[local]")
|
|
2650
2447
|
}[blueprint.source];
|
|
2651
|
-
console.log(` ${statusIcon} ${
|
|
2652
|
-
console.log(` ${
|
|
2448
|
+
console.log(` ${statusIcon} ${chalk9.bold(blueprint.file)} ${sourceLabel}`);
|
|
2449
|
+
console.log(` ${chalk9.gray(`ID: ${blueprint.id} \u2022 ${blueprint.name}`)}`);
|
|
2653
2450
|
if (!fileExists2) {
|
|
2654
|
-
console.log(
|
|
2451
|
+
console.log(chalk9.red(` \u26A0 File missing - run 'lynxp pull ${blueprint.id}' to restore`));
|
|
2655
2452
|
} else if (localModified) {
|
|
2656
2453
|
if (blueprint.source === "marketplace") {
|
|
2657
|
-
console.log(
|
|
2454
|
+
console.log(chalk9.yellow(` \u26A0 Local changes (marketplace = read-only, won't sync back)`));
|
|
2658
2455
|
} else {
|
|
2659
|
-
console.log(
|
|
2456
|
+
console.log(chalk9.yellow(` \u26A0 Local changes - run 'lynxp push ${blueprint.file}' to sync`));
|
|
2660
2457
|
}
|
|
2661
2458
|
}
|
|
2662
2459
|
console.log();
|
|
2663
2460
|
}
|
|
2664
2461
|
}
|
|
2665
|
-
console.log(
|
|
2462
|
+
console.log(chalk9.cyan("\u{1F4C4} AI Config Files"));
|
|
2666
2463
|
console.log();
|
|
2667
2464
|
let foundAny = false;
|
|
2668
2465
|
for (const config2 of CONFIG_FILES) {
|
|
@@ -2674,13 +2471,13 @@ async function statusCommand() {
|
|
|
2674
2471
|
const size = formatBytes(content.length);
|
|
2675
2472
|
foundAny = true;
|
|
2676
2473
|
const tracked = trackedStatus.find((t) => t.blueprint.file === config2.path);
|
|
2677
|
-
const trackedLabel = tracked ?
|
|
2678
|
-
console.log(` ${
|
|
2679
|
-
console.log(` ${
|
|
2680
|
-
console.log(` ${
|
|
2474
|
+
const trackedLabel = tracked ? chalk9.cyan(" (tracked)") : "";
|
|
2475
|
+
console.log(` ${chalk9.green("\u2713")} ${chalk9.bold(config2.name)}${trackedLabel}`);
|
|
2476
|
+
console.log(` ${chalk9.gray(`Platform: ${config2.platform}`)}`);
|
|
2477
|
+
console.log(` ${chalk9.gray(`Size: ${size} (${lines} lines)`)}`);
|
|
2681
2478
|
const preview = getPreview(content);
|
|
2682
2479
|
if (preview) {
|
|
2683
|
-
console.log(` ${
|
|
2480
|
+
console.log(` ${chalk9.gray(`Preview: ${preview}`)}`);
|
|
2684
2481
|
}
|
|
2685
2482
|
console.log();
|
|
2686
2483
|
} catch {
|
|
@@ -2694,14 +2491,14 @@ async function statusCommand() {
|
|
|
2694
2491
|
const ruleFiles = files.filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
2695
2492
|
if (ruleFiles.length > 0) {
|
|
2696
2493
|
foundAny = true;
|
|
2697
|
-
console.log(` ${
|
|
2698
|
-
console.log(` ${
|
|
2699
|
-
console.log(` ${
|
|
2494
|
+
console.log(` ${chalk9.green("\u2713")} ${chalk9.bold(config2.name)}`);
|
|
2495
|
+
console.log(` ${chalk9.gray(`Platform: ${config2.platform}`)}`);
|
|
2496
|
+
console.log(` ${chalk9.gray(`Rules: ${ruleFiles.length} file${ruleFiles.length === 1 ? "" : "s"}`)}`);
|
|
2700
2497
|
for (const file of ruleFiles.slice(0, 3)) {
|
|
2701
|
-
console.log(` ${
|
|
2498
|
+
console.log(` ${chalk9.gray(` \u2022 ${file}`)}`);
|
|
2702
2499
|
}
|
|
2703
2500
|
if (ruleFiles.length > 3) {
|
|
2704
|
-
console.log(` ${
|
|
2501
|
+
console.log(` ${chalk9.gray(` ... and ${ruleFiles.length - 3} more`)}`);
|
|
2705
2502
|
}
|
|
2706
2503
|
console.log();
|
|
2707
2504
|
}
|
|
@@ -2710,17 +2507,17 @@ async function statusCommand() {
|
|
|
2710
2507
|
}
|
|
2711
2508
|
}
|
|
2712
2509
|
if (!foundAny) {
|
|
2713
|
-
console.log(
|
|
2510
|
+
console.log(chalk9.yellow(" No AI configuration files found."));
|
|
2714
2511
|
console.log();
|
|
2715
|
-
console.log(
|
|
2716
|
-
console.log(
|
|
2717
|
-
console.log(
|
|
2718
|
-
console.log(
|
|
2512
|
+
console.log(chalk9.gray(" Get started:"));
|
|
2513
|
+
console.log(chalk9.gray(" lynxp wizard Generate a configuration"));
|
|
2514
|
+
console.log(chalk9.gray(" lynxp pull <id> Download from marketplace"));
|
|
2515
|
+
console.log(chalk9.gray(" lynxp search <query> Search for blueprints"));
|
|
2719
2516
|
} else {
|
|
2720
|
-
console.log(
|
|
2721
|
-
console.log(
|
|
2722
|
-
console.log(
|
|
2723
|
-
console.log(
|
|
2517
|
+
console.log(chalk9.gray("Commands:"));
|
|
2518
|
+
console.log(chalk9.gray(" lynxp wizard Regenerate configuration"));
|
|
2519
|
+
console.log(chalk9.gray(" lynxp check Validate files"));
|
|
2520
|
+
console.log(chalk9.gray(" lynxp link --list Show tracked blueprints"));
|
|
2724
2521
|
}
|
|
2725
2522
|
console.log();
|
|
2726
2523
|
}
|
|
@@ -2745,9 +2542,9 @@ function formatBytes(bytes) {
|
|
|
2745
2542
|
}
|
|
2746
2543
|
|
|
2747
2544
|
// src/commands/sync.ts
|
|
2748
|
-
import
|
|
2749
|
-
import
|
|
2750
|
-
import
|
|
2545
|
+
import chalk10 from "chalk";
|
|
2546
|
+
import ora8 from "ora";
|
|
2547
|
+
import prompts4 from "prompts";
|
|
2751
2548
|
import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir4 } from "fs/promises";
|
|
2752
2549
|
import { join as join8, dirname as dirname5 } from "path";
|
|
2753
2550
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -2756,17 +2553,17 @@ var CONFIG_FILE = ".lynxprompt/conf.yml";
|
|
|
2756
2553
|
var RULES_DIR = ".lynxprompt/rules";
|
|
2757
2554
|
async function syncCommand(options = {}) {
|
|
2758
2555
|
console.log();
|
|
2759
|
-
console.log(
|
|
2556
|
+
console.log(chalk10.cyan("\u{1F431} LynxPrompt Sync"));
|
|
2760
2557
|
console.log();
|
|
2761
2558
|
const cwd = process.cwd();
|
|
2762
2559
|
const configPath = join8(cwd, CONFIG_FILE);
|
|
2763
2560
|
if (!existsSync5(configPath)) {
|
|
2764
|
-
console.log(
|
|
2561
|
+
console.log(chalk10.yellow("LynxPrompt is not initialized in this project."));
|
|
2765
2562
|
console.log();
|
|
2766
|
-
console.log(
|
|
2563
|
+
console.log(chalk10.gray("Run 'lynxp init' first to set up LynxPrompt."));
|
|
2767
2564
|
return;
|
|
2768
2565
|
}
|
|
2769
|
-
const spinner =
|
|
2566
|
+
const spinner = ora8("Loading configuration...").start();
|
|
2770
2567
|
let config2;
|
|
2771
2568
|
try {
|
|
2772
2569
|
const configContent = await readFile7(configPath, "utf-8");
|
|
@@ -2774,13 +2571,13 @@ async function syncCommand(options = {}) {
|
|
|
2774
2571
|
spinner.succeed("Configuration loaded");
|
|
2775
2572
|
} catch (error) {
|
|
2776
2573
|
spinner.fail("Failed to load configuration");
|
|
2777
|
-
console.log(
|
|
2574
|
+
console.log(chalk10.red("Could not parse .lynxprompt/conf.yml"));
|
|
2778
2575
|
return;
|
|
2779
2576
|
}
|
|
2780
2577
|
if (!config2.exporters || config2.exporters.length === 0) {
|
|
2781
|
-
console.log(
|
|
2578
|
+
console.log(chalk10.yellow("No exporters configured."));
|
|
2782
2579
|
console.log();
|
|
2783
|
-
console.log(
|
|
2580
|
+
console.log(chalk10.gray("Add exporters to .lynxprompt/conf.yml or run 'lynxp agents enable <agent>'"));
|
|
2784
2581
|
return;
|
|
2785
2582
|
}
|
|
2786
2583
|
const validExporters = [];
|
|
@@ -2794,51 +2591,51 @@ async function syncCommand(options = {}) {
|
|
|
2794
2591
|
}
|
|
2795
2592
|
}
|
|
2796
2593
|
if (invalidExporters.length > 0) {
|
|
2797
|
-
console.log(
|
|
2594
|
+
console.log(chalk10.yellow(`Unknown exporters: ${invalidExporters.join(", ")}`));
|
|
2798
2595
|
}
|
|
2799
2596
|
if (validExporters.length === 0) {
|
|
2800
|
-
console.log(
|
|
2597
|
+
console.log(chalk10.red("No valid exporters configured."));
|
|
2801
2598
|
return;
|
|
2802
2599
|
}
|
|
2803
|
-
console.log(
|
|
2600
|
+
console.log(chalk10.gray(`Exporters: ${validExporters.map((e) => e.name).join(", ")}`));
|
|
2804
2601
|
console.log();
|
|
2805
2602
|
const rulesPath = join8(cwd, RULES_DIR);
|
|
2806
2603
|
if (!existsSync5(rulesPath)) {
|
|
2807
|
-
console.log(
|
|
2808
|
-
console.log(
|
|
2604
|
+
console.log(chalk10.yellow("No rules found."));
|
|
2605
|
+
console.log(chalk10.gray(`Create rules in ${RULES_DIR}/ to sync them.`));
|
|
2809
2606
|
return;
|
|
2810
2607
|
}
|
|
2811
2608
|
const rulesContent = await loadRules(rulesPath);
|
|
2812
2609
|
if (!rulesContent) {
|
|
2813
|
-
console.log(
|
|
2610
|
+
console.log(chalk10.yellow("No rule files found in .lynxprompt/rules/"));
|
|
2814
2611
|
return;
|
|
2815
2612
|
}
|
|
2816
|
-
console.log(
|
|
2613
|
+
console.log(chalk10.gray(`Loaded ${rulesContent.fileCount} rule file${rulesContent.fileCount === 1 ? "" : "s"}`));
|
|
2817
2614
|
console.log();
|
|
2818
2615
|
if (options.dryRun) {
|
|
2819
|
-
console.log(
|
|
2616
|
+
console.log(chalk10.cyan("Dry run - no files will be written"));
|
|
2820
2617
|
console.log();
|
|
2821
2618
|
console.log("Would write:");
|
|
2822
2619
|
for (const exporter of validExporters) {
|
|
2823
|
-
console.log(
|
|
2620
|
+
console.log(chalk10.gray(` ${exporter.output}`));
|
|
2824
2621
|
}
|
|
2825
2622
|
console.log();
|
|
2826
2623
|
return;
|
|
2827
2624
|
}
|
|
2828
2625
|
if (!options.force) {
|
|
2829
|
-
const { confirm } = await
|
|
2626
|
+
const { confirm } = await prompts4({
|
|
2830
2627
|
type: "confirm",
|
|
2831
2628
|
name: "confirm",
|
|
2832
2629
|
message: `Sync to ${validExporters.length} agent${validExporters.length === 1 ? "" : "s"}?`,
|
|
2833
2630
|
initial: true
|
|
2834
2631
|
});
|
|
2835
2632
|
if (!confirm) {
|
|
2836
|
-
console.log(
|
|
2633
|
+
console.log(chalk10.gray("Cancelled."));
|
|
2837
2634
|
return;
|
|
2838
2635
|
}
|
|
2839
2636
|
}
|
|
2840
2637
|
const result = { written: [], skipped: [], errors: [] };
|
|
2841
|
-
const syncSpinner =
|
|
2638
|
+
const syncSpinner = ora8("Syncing rules...").start();
|
|
2842
2639
|
for (const exporter of validExporters) {
|
|
2843
2640
|
try {
|
|
2844
2641
|
await syncToAgent(cwd, exporter, rulesContent.combined);
|
|
@@ -2849,16 +2646,16 @@ async function syncCommand(options = {}) {
|
|
|
2849
2646
|
}
|
|
2850
2647
|
syncSpinner.stop();
|
|
2851
2648
|
if (result.written.length > 0) {
|
|
2852
|
-
console.log(
|
|
2649
|
+
console.log(chalk10.green(`\u2713 Synced to ${result.written.length} agent${result.written.length === 1 ? "" : "s"}:`));
|
|
2853
2650
|
for (const file of result.written) {
|
|
2854
|
-
console.log(
|
|
2651
|
+
console.log(chalk10.gray(` ${file}`));
|
|
2855
2652
|
}
|
|
2856
2653
|
}
|
|
2857
2654
|
if (result.errors.length > 0) {
|
|
2858
2655
|
console.log();
|
|
2859
|
-
console.log(
|
|
2656
|
+
console.log(chalk10.red("Errors:"));
|
|
2860
2657
|
for (const error of result.errors) {
|
|
2861
|
-
console.log(
|
|
2658
|
+
console.log(chalk10.red(` ${error}`));
|
|
2862
2659
|
}
|
|
2863
2660
|
}
|
|
2864
2661
|
console.log();
|
|
@@ -2957,8 +2754,8 @@ function formatAsJson(content, agent) {
|
|
|
2957
2754
|
}
|
|
2958
2755
|
|
|
2959
2756
|
// src/commands/agents.ts
|
|
2960
|
-
import
|
|
2961
|
-
import
|
|
2757
|
+
import chalk11 from "chalk";
|
|
2758
|
+
import prompts5 from "prompts";
|
|
2962
2759
|
import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
2963
2760
|
import { join as join9 } from "path";
|
|
2964
2761
|
import { existsSync as existsSync6 } from "fs";
|
|
@@ -2983,18 +2780,18 @@ async function agentsCommand(action, agentId, options = {}) {
|
|
|
2983
2780
|
}
|
|
2984
2781
|
}
|
|
2985
2782
|
async function listAgents() {
|
|
2986
|
-
console.log(
|
|
2783
|
+
console.log(chalk11.cyan("\u{1F431} LynxPrompt Agents"));
|
|
2987
2784
|
console.log();
|
|
2988
2785
|
const config2 = await loadConfig();
|
|
2989
2786
|
const enabledSet = new Set(config2?.exporters ?? []);
|
|
2990
2787
|
const detection = detectAgents();
|
|
2991
2788
|
if (enabledSet.size > 0) {
|
|
2992
|
-
console.log(
|
|
2789
|
+
console.log(chalk11.green("Enabled:"));
|
|
2993
2790
|
for (const id of enabledSet) {
|
|
2994
2791
|
const agent = getAgent(id);
|
|
2995
2792
|
const detected = detection.detected.find((d) => d.agent.id === id);
|
|
2996
|
-
const status = detected ?
|
|
2997
|
-
console.log(` ${
|
|
2793
|
+
const status = detected ? chalk11.gray("(detected)") : "";
|
|
2794
|
+
console.log(` ${chalk11.green("\u2713")} ${agent?.name ?? id} ${status}`);
|
|
2998
2795
|
}
|
|
2999
2796
|
console.log();
|
|
3000
2797
|
}
|
|
@@ -3002,10 +2799,10 @@ async function listAgents() {
|
|
|
3002
2799
|
(d) => !enabledSet.has(d.agent.id)
|
|
3003
2800
|
);
|
|
3004
2801
|
if (detectedNotEnabled.length > 0) {
|
|
3005
|
-
console.log(
|
|
2802
|
+
console.log(chalk11.yellow("Detected (not enabled):"));
|
|
3006
2803
|
for (const detected of detectedNotEnabled) {
|
|
3007
|
-
const rules = detected.ruleCount > 0 ?
|
|
3008
|
-
console.log(` ${
|
|
2804
|
+
const rules = detected.ruleCount > 0 ? chalk11.gray(` (${detected.ruleCount} rules)`) : "";
|
|
2805
|
+
console.log(` ${chalk11.yellow("\u25CB")} ${detected.agent.name}${rules}`);
|
|
3009
2806
|
}
|
|
3010
2807
|
console.log();
|
|
3011
2808
|
}
|
|
@@ -3013,30 +2810,30 @@ async function listAgents() {
|
|
|
3013
2810
|
(a) => !enabledSet.has(a.id) && !detectedNotEnabled.some((d) => d.agent.id === a.id)
|
|
3014
2811
|
);
|
|
3015
2812
|
if (popular.length > 0) {
|
|
3016
|
-
console.log(
|
|
2813
|
+
console.log(chalk11.gray("Popular (available):"));
|
|
3017
2814
|
for (const agent of popular) {
|
|
3018
|
-
console.log(` ${
|
|
2815
|
+
console.log(` ${chalk11.gray("-")} ${agent.name} - ${agent.description}`);
|
|
3019
2816
|
}
|
|
3020
2817
|
console.log();
|
|
3021
2818
|
}
|
|
3022
|
-
console.log(
|
|
2819
|
+
console.log(chalk11.gray(`Total: ${AGENTS.length} agents supported`));
|
|
3023
2820
|
console.log();
|
|
3024
|
-
console.log(
|
|
3025
|
-
console.log(
|
|
3026
|
-
console.log(
|
|
3027
|
-
console.log(
|
|
2821
|
+
console.log(chalk11.gray("Commands:"));
|
|
2822
|
+
console.log(chalk11.gray(" lynxp agents enable <agent> Enable an agent"));
|
|
2823
|
+
console.log(chalk11.gray(" lynxp agents disable <agent> Disable an agent"));
|
|
2824
|
+
console.log(chalk11.gray(" lynxp agents detect Auto-detect agents"));
|
|
3028
2825
|
console.log();
|
|
3029
2826
|
}
|
|
3030
2827
|
async function enableAgent(agentId, options = {}) {
|
|
3031
2828
|
const cwd = process.cwd();
|
|
3032
2829
|
const configPath = join9(cwd, CONFIG_FILE2);
|
|
3033
2830
|
if (!existsSync6(configPath)) {
|
|
3034
|
-
console.log(
|
|
2831
|
+
console.log(chalk11.yellow("LynxPrompt not initialized. Run 'lynxp init' first."));
|
|
3035
2832
|
return;
|
|
3036
2833
|
}
|
|
3037
2834
|
let config2 = await loadConfig();
|
|
3038
2835
|
if (!config2) {
|
|
3039
|
-
console.log(
|
|
2836
|
+
console.log(chalk11.red("Could not load configuration."));
|
|
3040
2837
|
return;
|
|
3041
2838
|
}
|
|
3042
2839
|
if (!agentId || options.interactive) {
|
|
@@ -3046,7 +2843,7 @@ async function enableAgent(agentId, options = {}) {
|
|
|
3046
2843
|
value: agent2.id,
|
|
3047
2844
|
selected: enabledSet.has(agent2.id)
|
|
3048
2845
|
}));
|
|
3049
|
-
const { selected } = await
|
|
2846
|
+
const { selected } = await prompts5({
|
|
3050
2847
|
type: "multiselect",
|
|
3051
2848
|
name: "selected",
|
|
3052
2849
|
message: "Select agents to enable:",
|
|
@@ -3054,14 +2851,14 @@ async function enableAgent(agentId, options = {}) {
|
|
|
3054
2851
|
hint: "- Space to select, Enter to confirm"
|
|
3055
2852
|
});
|
|
3056
2853
|
if (!selected || selected.length === 0) {
|
|
3057
|
-
console.log(
|
|
2854
|
+
console.log(chalk11.yellow("No agents selected."));
|
|
3058
2855
|
return;
|
|
3059
2856
|
}
|
|
3060
2857
|
config2.exporters = selected;
|
|
3061
2858
|
await saveConfig(config2);
|
|
3062
|
-
console.log(
|
|
2859
|
+
console.log(chalk11.green(`\u2713 Enabled ${selected.length} agent${selected.length === 1 ? "" : "s"}`));
|
|
3063
2860
|
console.log();
|
|
3064
|
-
console.log(
|
|
2861
|
+
console.log(chalk11.gray("Run 'lynxp sync' to sync your rules."));
|
|
3065
2862
|
return;
|
|
3066
2863
|
}
|
|
3067
2864
|
const agent = getAgent(agentId);
|
|
@@ -3069,12 +2866,12 @@ async function enableAgent(agentId, options = {}) {
|
|
|
3069
2866
|
const similar = AGENTS.filter(
|
|
3070
2867
|
(a) => a.id.includes(agentId.toLowerCase()) || a.name.toLowerCase().includes(agentId.toLowerCase())
|
|
3071
2868
|
);
|
|
3072
|
-
console.log(
|
|
2869
|
+
console.log(chalk11.red(`Unknown agent: ${agentId}`));
|
|
3073
2870
|
if (similar.length > 0) {
|
|
3074
2871
|
console.log();
|
|
3075
|
-
console.log(
|
|
2872
|
+
console.log(chalk11.gray("Did you mean:"));
|
|
3076
2873
|
for (const a of similar.slice(0, 5)) {
|
|
3077
|
-
console.log(
|
|
2874
|
+
console.log(chalk11.gray(` ${a.id} - ${a.name}`));
|
|
3078
2875
|
}
|
|
3079
2876
|
}
|
|
3080
2877
|
return;
|
|
@@ -3083,48 +2880,48 @@ async function enableAgent(agentId, options = {}) {
|
|
|
3083
2880
|
config2.exporters = [];
|
|
3084
2881
|
}
|
|
3085
2882
|
if (config2.exporters.includes(agent.id)) {
|
|
3086
|
-
console.log(
|
|
2883
|
+
console.log(chalk11.yellow(`${agent.name} is already enabled.`));
|
|
3087
2884
|
return;
|
|
3088
2885
|
}
|
|
3089
2886
|
config2.exporters.push(agent.id);
|
|
3090
2887
|
await saveConfig(config2);
|
|
3091
|
-
console.log(
|
|
2888
|
+
console.log(chalk11.green(`\u2713 Enabled ${agent.name}`));
|
|
3092
2889
|
console.log();
|
|
3093
|
-
console.log(
|
|
3094
|
-
console.log(
|
|
2890
|
+
console.log(chalk11.gray(`Output: ${agent.output}`));
|
|
2891
|
+
console.log(chalk11.gray("Run 'lynxp sync' to sync your rules."));
|
|
3095
2892
|
}
|
|
3096
2893
|
async function disableAgent(agentId) {
|
|
3097
2894
|
if (!agentId) {
|
|
3098
|
-
console.log(
|
|
2895
|
+
console.log(chalk11.yellow("Usage: lynxp agents disable <agent>"));
|
|
3099
2896
|
return;
|
|
3100
2897
|
}
|
|
3101
2898
|
const cwd = process.cwd();
|
|
3102
2899
|
const configPath = join9(cwd, CONFIG_FILE2);
|
|
3103
2900
|
if (!existsSync6(configPath)) {
|
|
3104
|
-
console.log(
|
|
2901
|
+
console.log(chalk11.yellow("LynxPrompt not initialized. Run 'lynxp init' first."));
|
|
3105
2902
|
return;
|
|
3106
2903
|
}
|
|
3107
2904
|
const config2 = await loadConfig();
|
|
3108
2905
|
if (!config2) {
|
|
3109
|
-
console.log(
|
|
2906
|
+
console.log(chalk11.red("Could not load configuration."));
|
|
3110
2907
|
return;
|
|
3111
2908
|
}
|
|
3112
2909
|
if (!config2.exporters || !config2.exporters.includes(agentId)) {
|
|
3113
2910
|
const agent2 = getAgent(agentId);
|
|
3114
|
-
console.log(
|
|
2911
|
+
console.log(chalk11.yellow(`${agent2?.name ?? agentId} is not enabled.`));
|
|
3115
2912
|
return;
|
|
3116
2913
|
}
|
|
3117
2914
|
if (config2.exporters.length === 1) {
|
|
3118
|
-
console.log(
|
|
2915
|
+
console.log(chalk11.yellow("Cannot disable the last agent. At least one must be enabled."));
|
|
3119
2916
|
return;
|
|
3120
2917
|
}
|
|
3121
2918
|
config2.exporters = config2.exporters.filter((e) => e !== agentId);
|
|
3122
2919
|
await saveConfig(config2);
|
|
3123
2920
|
const agent = getAgent(agentId);
|
|
3124
|
-
console.log(
|
|
2921
|
+
console.log(chalk11.green(`\u2713 Disabled ${agent?.name ?? agentId}`));
|
|
3125
2922
|
}
|
|
3126
2923
|
async function detectAgentsInProject() {
|
|
3127
|
-
console.log(
|
|
2924
|
+
console.log(chalk11.cyan("\u{1F50D} Detecting AI agents..."));
|
|
3128
2925
|
console.log();
|
|
3129
2926
|
const detection = detectAgents();
|
|
3130
2927
|
console.log(formatDetectionResults(detection));
|
|
@@ -3136,10 +2933,10 @@ async function detectAgentsInProject() {
|
|
|
3136
2933
|
const enabledSet = new Set(config2?.exporters ?? []);
|
|
3137
2934
|
const newAgents = detection.detected.filter((d) => !enabledSet.has(d.agent.id));
|
|
3138
2935
|
if (newAgents.length === 0) {
|
|
3139
|
-
console.log(
|
|
2936
|
+
console.log(chalk11.gray("All detected agents are already enabled."));
|
|
3140
2937
|
return;
|
|
3141
2938
|
}
|
|
3142
|
-
const { enable } = await
|
|
2939
|
+
const { enable } = await prompts5({
|
|
3143
2940
|
type: "confirm",
|
|
3144
2941
|
name: "enable",
|
|
3145
2942
|
message: `Enable ${newAgents.length} detected agent${newAgents.length === 1 ? "" : "s"}?`,
|
|
@@ -3151,7 +2948,7 @@ async function detectAgentsInProject() {
|
|
|
3151
2948
|
...newAgents.map((d) => d.agent.id)
|
|
3152
2949
|
];
|
|
3153
2950
|
await saveConfig(config2);
|
|
3154
|
-
console.log(
|
|
2951
|
+
console.log(chalk11.green(`\u2713 Enabled ${newAgents.length} agent${newAgents.length === 1 ? "" : "s"}`));
|
|
3155
2952
|
}
|
|
3156
2953
|
}
|
|
3157
2954
|
async function loadConfig() {
|
|
@@ -3175,8 +2972,8 @@ async function saveConfig(config2) {
|
|
|
3175
2972
|
}
|
|
3176
2973
|
|
|
3177
2974
|
// src/commands/check.ts
|
|
3178
|
-
import
|
|
3179
|
-
import
|
|
2975
|
+
import chalk12 from "chalk";
|
|
2976
|
+
import ora9 from "ora";
|
|
3180
2977
|
import { readFile as readFile9, readdir as readdir5, stat as stat2 } from "fs/promises";
|
|
3181
2978
|
import { join as join10 } from "path";
|
|
3182
2979
|
import { existsSync as existsSync7 } from "fs";
|
|
@@ -3301,7 +3098,7 @@ async function checkCommand(options = {}) {
|
|
|
3301
3098
|
const cwd = process.cwd();
|
|
3302
3099
|
if (!isCi) {
|
|
3303
3100
|
console.log();
|
|
3304
|
-
console.log(
|
|
3101
|
+
console.log(chalk12.cyan("\u{1F431} LynxPrompt Check"));
|
|
3305
3102
|
console.log();
|
|
3306
3103
|
}
|
|
3307
3104
|
const result = {
|
|
@@ -3310,7 +3107,7 @@ async function checkCommand(options = {}) {
|
|
|
3310
3107
|
warnings: [],
|
|
3311
3108
|
files: []
|
|
3312
3109
|
};
|
|
3313
|
-
const spinner = !isCi ?
|
|
3110
|
+
const spinner = !isCi ? ora9("Scanning for configuration files...").start() : null;
|
|
3314
3111
|
for (const file of CONFIG_FILES2) {
|
|
3315
3112
|
const filePath = join10(cwd, file.path);
|
|
3316
3113
|
if (existsSync7(filePath)) {
|
|
@@ -3375,42 +3172,42 @@ async function checkCommand(options = {}) {
|
|
|
3375
3172
|
}
|
|
3376
3173
|
} else {
|
|
3377
3174
|
if (result.files.length === 0) {
|
|
3378
|
-
console.log(
|
|
3175
|
+
console.log(chalk12.yellow("\u26A0 No AI configuration files found."));
|
|
3379
3176
|
console.log();
|
|
3380
|
-
console.log(
|
|
3177
|
+
console.log(chalk12.gray("Run 'lynxp wizard' to create a configuration."));
|
|
3381
3178
|
return;
|
|
3382
3179
|
}
|
|
3383
|
-
console.log(
|
|
3180
|
+
console.log(chalk12.green(`\u2713 Found ${result.files.length} configuration file${result.files.length === 1 ? "" : "s"}:`));
|
|
3384
3181
|
for (const file of result.files) {
|
|
3385
|
-
console.log(
|
|
3182
|
+
console.log(chalk12.gray(` ${file}`));
|
|
3386
3183
|
}
|
|
3387
3184
|
console.log();
|
|
3388
3185
|
if (result.errors.length > 0) {
|
|
3389
|
-
console.log(
|
|
3186
|
+
console.log(chalk12.red(`\u2717 ${result.errors.length} error${result.errors.length === 1 ? "" : "s"}:`));
|
|
3390
3187
|
for (const error of result.errors) {
|
|
3391
|
-
console.log(
|
|
3188
|
+
console.log(chalk12.red(` ${error}`));
|
|
3392
3189
|
}
|
|
3393
3190
|
console.log();
|
|
3394
3191
|
}
|
|
3395
3192
|
if (result.warnings.length > 0) {
|
|
3396
|
-
console.log(
|
|
3193
|
+
console.log(chalk12.yellow(`\u26A0 ${result.warnings.length} warning${result.warnings.length === 1 ? "" : "s"}:`));
|
|
3397
3194
|
for (const warning of result.warnings) {
|
|
3398
|
-
console.log(
|
|
3195
|
+
console.log(chalk12.yellow(` ${warning}`));
|
|
3399
3196
|
}
|
|
3400
3197
|
console.log();
|
|
3401
3198
|
}
|
|
3402
3199
|
if (result.valid) {
|
|
3403
|
-
console.log(
|
|
3200
|
+
console.log(chalk12.green("\u2705 Validation passed!"));
|
|
3404
3201
|
} else {
|
|
3405
|
-
console.log(
|
|
3202
|
+
console.log(chalk12.red("\u274C Validation failed. Fix the errors above."));
|
|
3406
3203
|
}
|
|
3407
3204
|
console.log();
|
|
3408
3205
|
}
|
|
3409
3206
|
}
|
|
3410
3207
|
|
|
3411
3208
|
// src/commands/diff.ts
|
|
3412
|
-
import
|
|
3413
|
-
import
|
|
3209
|
+
import chalk13 from "chalk";
|
|
3210
|
+
import ora10 from "ora";
|
|
3414
3211
|
import { readFile as readFile10 } from "fs/promises";
|
|
3415
3212
|
import { join as join11 } from "path";
|
|
3416
3213
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -3478,21 +3275,21 @@ function formatDiff(diff, contextLines = 3) {
|
|
|
3478
3275
|
let inHunk = false;
|
|
3479
3276
|
const changeIndices = diff.map((d, i) => d.type !== "same" ? i : -1).filter((i) => i !== -1);
|
|
3480
3277
|
if (changeIndices.length === 0) {
|
|
3481
|
-
return
|
|
3278
|
+
return chalk13.gray(" (no changes)");
|
|
3482
3279
|
}
|
|
3483
3280
|
for (let i = 0; i < diff.length; i++) {
|
|
3484
3281
|
const item = diff[i];
|
|
3485
3282
|
const nearChange = changeIndices.some((ci) => Math.abs(ci - i) <= contextLines);
|
|
3486
3283
|
if (nearChange) {
|
|
3487
3284
|
if (lastPrintedIndex !== -1 && i - lastPrintedIndex > 1) {
|
|
3488
|
-
output.push(
|
|
3285
|
+
output.push(chalk13.gray(" ..."));
|
|
3489
3286
|
}
|
|
3490
3287
|
if (item.type === "add") {
|
|
3491
|
-
output.push(
|
|
3288
|
+
output.push(chalk13.green(`+ ${item.line}`));
|
|
3492
3289
|
} else if (item.type === "remove") {
|
|
3493
|
-
output.push(
|
|
3290
|
+
output.push(chalk13.red(`- ${item.line}`));
|
|
3494
3291
|
} else {
|
|
3495
|
-
output.push(
|
|
3292
|
+
output.push(chalk13.gray(` ${item.line}`));
|
|
3496
3293
|
}
|
|
3497
3294
|
lastPrintedIndex = i;
|
|
3498
3295
|
}
|
|
@@ -3508,7 +3305,7 @@ function getDiffStats(diff) {
|
|
|
3508
3305
|
}
|
|
3509
3306
|
async function diffCommand(blueprintId, options = {}) {
|
|
3510
3307
|
console.log();
|
|
3511
|
-
console.log(
|
|
3308
|
+
console.log(chalk13.cyan("\u{1F431} LynxPrompt Diff"));
|
|
3512
3309
|
console.log();
|
|
3513
3310
|
const cwd = process.cwd();
|
|
3514
3311
|
if (options.local) {
|
|
@@ -3516,29 +3313,29 @@ async function diffCommand(blueprintId, options = {}) {
|
|
|
3516
3313
|
return;
|
|
3517
3314
|
}
|
|
3518
3315
|
if (!blueprintId) {
|
|
3519
|
-
console.log(
|
|
3316
|
+
console.log(chalk13.red("\u2717 Please provide a blueprint ID to compare with."));
|
|
3520
3317
|
console.log();
|
|
3521
|
-
console.log(
|
|
3522
|
-
console.log(
|
|
3523
|
-
console.log(
|
|
3318
|
+
console.log(chalk13.gray("Usage:"));
|
|
3319
|
+
console.log(chalk13.gray(" lynxp diff <blueprint-id> Compare local with remote blueprint"));
|
|
3320
|
+
console.log(chalk13.gray(" lynxp diff --local Compare .lynxprompt/rules/ with exports"));
|
|
3524
3321
|
return;
|
|
3525
3322
|
}
|
|
3526
3323
|
if (!isAuthenticated()) {
|
|
3527
|
-
console.log(
|
|
3528
|
-
console.log(
|
|
3324
|
+
console.log(chalk13.yellow("\u26A0 Not logged in. Some blueprints may not be accessible."));
|
|
3325
|
+
console.log(chalk13.gray("Run 'lynxp login' to authenticate."));
|
|
3529
3326
|
console.log();
|
|
3530
3327
|
}
|
|
3531
|
-
const spinner =
|
|
3328
|
+
const spinner = ora10("Fetching blueprint...").start();
|
|
3532
3329
|
try {
|
|
3533
3330
|
const { blueprint } = await api.getBlueprint(blueprintId);
|
|
3534
3331
|
spinner.stop();
|
|
3535
3332
|
if (!blueprint || !blueprint.content) {
|
|
3536
|
-
console.log(
|
|
3333
|
+
console.log(chalk13.red(`\u2717 Blueprint not found or has no content: ${blueprintId}`));
|
|
3537
3334
|
return;
|
|
3538
3335
|
}
|
|
3539
|
-
console.log(
|
|
3336
|
+
console.log(chalk13.green(`\u2713 Blueprint: ${blueprint.name || blueprintId}`));
|
|
3540
3337
|
if (blueprint.description) {
|
|
3541
|
-
console.log(
|
|
3338
|
+
console.log(chalk13.gray(` ${blueprint.description}`));
|
|
3542
3339
|
}
|
|
3543
3340
|
console.log();
|
|
3544
3341
|
const localPaths = [
|
|
@@ -3550,52 +3347,52 @@ async function diffCommand(blueprintId, options = {}) {
|
|
|
3550
3347
|
];
|
|
3551
3348
|
let localContent = null;
|
|
3552
3349
|
let localPath = null;
|
|
3553
|
-
for (const
|
|
3554
|
-
const fullPath = join11(cwd,
|
|
3350
|
+
for (const path of localPaths) {
|
|
3351
|
+
const fullPath = join11(cwd, path);
|
|
3555
3352
|
if (existsSync8(fullPath)) {
|
|
3556
3353
|
try {
|
|
3557
3354
|
localContent = await readFile10(fullPath, "utf-8");
|
|
3558
|
-
localPath =
|
|
3355
|
+
localPath = path;
|
|
3559
3356
|
break;
|
|
3560
3357
|
} catch {
|
|
3561
3358
|
}
|
|
3562
3359
|
}
|
|
3563
3360
|
}
|
|
3564
3361
|
if (!localContent) {
|
|
3565
|
-
console.log(
|
|
3566
|
-
console.log(
|
|
3362
|
+
console.log(chalk13.yellow("\u26A0 No local AI configuration file found."));
|
|
3363
|
+
console.log(chalk13.gray("Run 'lynxp wizard' to create one, or 'lynxp pull' to download the blueprint."));
|
|
3567
3364
|
return;
|
|
3568
3365
|
}
|
|
3569
|
-
console.log(
|
|
3366
|
+
console.log(chalk13.gray(`Comparing with: ${localPath}`));
|
|
3570
3367
|
console.log();
|
|
3571
3368
|
const diff = computeDiff(blueprint.content, localContent);
|
|
3572
3369
|
const stats = getDiffStats(diff);
|
|
3573
3370
|
if (stats.added === 0 && stats.removed === 0) {
|
|
3574
|
-
console.log(
|
|
3371
|
+
console.log(chalk13.green("\u2713 Files are identical!"));
|
|
3575
3372
|
} else {
|
|
3576
|
-
console.log(
|
|
3373
|
+
console.log(chalk13.gray("Changes (remote \u2192 local):"));
|
|
3577
3374
|
console.log();
|
|
3578
3375
|
console.log(formatDiff(diff));
|
|
3579
3376
|
console.log();
|
|
3580
|
-
console.log(
|
|
3377
|
+
console.log(chalk13.gray(`Summary: ${chalk13.green(`+${stats.added}`)} ${chalk13.red(`-${stats.removed}`)} lines changed`));
|
|
3581
3378
|
}
|
|
3582
3379
|
console.log();
|
|
3583
3380
|
} catch (error) {
|
|
3584
3381
|
spinner.stop();
|
|
3585
3382
|
if (error instanceof ApiRequestError) {
|
|
3586
3383
|
if (error.statusCode === 401) {
|
|
3587
|
-
console.log(
|
|
3384
|
+
console.log(chalk13.red("\u2717 Authentication required. Run 'lynxp login' first."));
|
|
3588
3385
|
} else if (error.statusCode === 404) {
|
|
3589
|
-
console.log(
|
|
3386
|
+
console.log(chalk13.red(`\u2717 Blueprint not found: ${blueprintId}`));
|
|
3590
3387
|
} else if (error.statusCode === 403) {
|
|
3591
|
-
console.log(
|
|
3388
|
+
console.log(chalk13.red("\u2717 Access denied to this blueprint."));
|
|
3592
3389
|
} else {
|
|
3593
|
-
console.log(
|
|
3390
|
+
console.log(chalk13.red(`\u2717 API error: ${error.message}`));
|
|
3594
3391
|
}
|
|
3595
3392
|
} else {
|
|
3596
|
-
console.log(
|
|
3393
|
+
console.log(chalk13.red("\u2717 Failed to fetch blueprint"));
|
|
3597
3394
|
if (error instanceof Error) {
|
|
3598
|
-
console.log(
|
|
3395
|
+
console.log(chalk13.gray(` ${error.message}`));
|
|
3599
3396
|
}
|
|
3600
3397
|
}
|
|
3601
3398
|
}
|
|
@@ -3603,22 +3400,22 @@ async function diffCommand(blueprintId, options = {}) {
|
|
|
3603
3400
|
async function diffLocal(cwd) {
|
|
3604
3401
|
const rulesDir = join11(cwd, ".lynxprompt/rules");
|
|
3605
3402
|
if (!existsSync8(rulesDir)) {
|
|
3606
|
-
console.log(
|
|
3607
|
-
console.log(
|
|
3403
|
+
console.log(chalk13.yellow("\u26A0 No .lynxprompt/rules/ directory found."));
|
|
3404
|
+
console.log(chalk13.gray("Run 'lynxp init' to set up the advanced workflow, or 'lynxp wizard' for simple file generation."));
|
|
3608
3405
|
return;
|
|
3609
3406
|
}
|
|
3610
|
-
console.log(
|
|
3407
|
+
console.log(chalk13.gray("Comparing .lynxprompt/rules/ with exported files..."));
|
|
3611
3408
|
console.log();
|
|
3612
3409
|
const rulesPath = join11(rulesDir, "agents.md");
|
|
3613
3410
|
if (!existsSync8(rulesPath)) {
|
|
3614
|
-
console.log(
|
|
3411
|
+
console.log(chalk13.yellow("\u26A0 No rules files found in .lynxprompt/rules/"));
|
|
3615
3412
|
return;
|
|
3616
3413
|
}
|
|
3617
3414
|
let rulesContent;
|
|
3618
3415
|
try {
|
|
3619
3416
|
rulesContent = await readFile10(rulesPath, "utf-8");
|
|
3620
3417
|
} catch {
|
|
3621
|
-
console.log(
|
|
3418
|
+
console.log(chalk13.red("\u2717 Could not read .lynxprompt/rules/agents.md"));
|
|
3622
3419
|
return;
|
|
3623
3420
|
}
|
|
3624
3421
|
const exportedFiles = [
|
|
@@ -3643,12 +3440,12 @@ async function diffLocal(cwd) {
|
|
|
3643
3440
|
const stats = getDiffStats(diff);
|
|
3644
3441
|
if (stats.added > 0 || stats.removed > 0) {
|
|
3645
3442
|
hasChanges = true;
|
|
3646
|
-
console.log(
|
|
3443
|
+
console.log(chalk13.yellow(`\u26A0 ${file.name} differs from source:`));
|
|
3647
3444
|
console.log(formatDiff(diff));
|
|
3648
|
-
console.log(
|
|
3445
|
+
console.log(chalk13.gray(` ${chalk13.green(`+${stats.added}`)} ${chalk13.red(`-${stats.removed}`)} lines`));
|
|
3649
3446
|
console.log();
|
|
3650
3447
|
} else {
|
|
3651
|
-
console.log(
|
|
3448
|
+
console.log(chalk13.green(`\u2713 ${file.name} is in sync`));
|
|
3652
3449
|
}
|
|
3653
3450
|
} catch {
|
|
3654
3451
|
}
|
|
@@ -3656,18 +3453,18 @@ async function diffLocal(cwd) {
|
|
|
3656
3453
|
}
|
|
3657
3454
|
if (!hasChanges) {
|
|
3658
3455
|
console.log();
|
|
3659
|
-
console.log(
|
|
3456
|
+
console.log(chalk13.green("\u2713 All exported files are in sync with .lynxprompt/rules/"));
|
|
3660
3457
|
} else {
|
|
3661
3458
|
console.log();
|
|
3662
|
-
console.log(
|
|
3459
|
+
console.log(chalk13.gray("Run 'lynxp sync' to update exported files from .lynxprompt/rules/"));
|
|
3663
3460
|
}
|
|
3664
3461
|
console.log();
|
|
3665
3462
|
}
|
|
3666
3463
|
|
|
3667
3464
|
// src/commands/link.ts
|
|
3668
|
-
import
|
|
3669
|
-
import
|
|
3670
|
-
import
|
|
3465
|
+
import chalk14 from "chalk";
|
|
3466
|
+
import ora11 from "ora";
|
|
3467
|
+
import prompts6 from "prompts";
|
|
3671
3468
|
import { join as join12 } from "path";
|
|
3672
3469
|
import { existsSync as existsSync9 } from "fs";
|
|
3673
3470
|
function getSourceFromVisibility2(visibility) {
|
|
@@ -3689,182 +3486,182 @@ async function linkCommand(file, blueprintId, options = {}) {
|
|
|
3689
3486
|
return;
|
|
3690
3487
|
}
|
|
3691
3488
|
if (!file) {
|
|
3692
|
-
console.log(
|
|
3489
|
+
console.log(chalk14.red("\u2717 Please provide a file path to link."));
|
|
3693
3490
|
console.log();
|
|
3694
|
-
console.log(
|
|
3695
|
-
console.log(
|
|
3696
|
-
console.log(
|
|
3491
|
+
console.log(chalk14.gray("Usage:"));
|
|
3492
|
+
console.log(chalk14.gray(" lynxp link <file> <blueprint-id> Link a local file to a cloud blueprint"));
|
|
3493
|
+
console.log(chalk14.gray(" lynxp link --list List all tracked blueprints"));
|
|
3697
3494
|
console.log();
|
|
3698
|
-
console.log(
|
|
3699
|
-
console.log(
|
|
3495
|
+
console.log(chalk14.gray("Example:"));
|
|
3496
|
+
console.log(chalk14.gray(" lynxp link AGENTS.md bp_abc123"));
|
|
3700
3497
|
return;
|
|
3701
3498
|
}
|
|
3702
3499
|
if (!blueprintId) {
|
|
3703
|
-
console.log(
|
|
3500
|
+
console.log(chalk14.red("\u2717 Please provide a blueprint ID to link to."));
|
|
3704
3501
|
console.log();
|
|
3705
|
-
console.log(
|
|
3706
|
-
console.log(
|
|
3502
|
+
console.log(chalk14.gray("Usage: lynxp link <file> <blueprint-id>"));
|
|
3503
|
+
console.log(chalk14.gray("Example: lynxp link AGENTS.md bp_abc123"));
|
|
3707
3504
|
console.log();
|
|
3708
|
-
console.log(
|
|
3709
|
-
console.log(
|
|
3710
|
-
console.log(
|
|
3505
|
+
console.log(chalk14.gray("To find blueprint IDs:"));
|
|
3506
|
+
console.log(chalk14.gray(" lynxp list - Show your blueprints"));
|
|
3507
|
+
console.log(chalk14.gray(" lynxp search <query> - Search marketplace"));
|
|
3711
3508
|
return;
|
|
3712
3509
|
}
|
|
3713
3510
|
const filePath = join12(cwd, file);
|
|
3714
3511
|
if (!existsSync9(filePath)) {
|
|
3715
|
-
console.log(
|
|
3512
|
+
console.log(chalk14.red(`\u2717 File not found: ${file}`));
|
|
3716
3513
|
return;
|
|
3717
3514
|
}
|
|
3718
3515
|
const existing = await findBlueprintByFile(cwd, file);
|
|
3719
3516
|
if (existing) {
|
|
3720
|
-
console.log(
|
|
3721
|
-
const { proceed } = await
|
|
3517
|
+
console.log(chalk14.yellow(`\u26A0 This file is already linked to: ${existing.id}`));
|
|
3518
|
+
const { proceed } = await prompts6({
|
|
3722
3519
|
type: "confirm",
|
|
3723
3520
|
name: "proceed",
|
|
3724
3521
|
message: "Replace the existing link?",
|
|
3725
3522
|
initial: false
|
|
3726
3523
|
});
|
|
3727
3524
|
if (!proceed) {
|
|
3728
|
-
console.log(
|
|
3525
|
+
console.log(chalk14.gray("Cancelled."));
|
|
3729
3526
|
return;
|
|
3730
3527
|
}
|
|
3731
3528
|
}
|
|
3732
3529
|
if (!isAuthenticated()) {
|
|
3733
3530
|
console.log(
|
|
3734
|
-
|
|
3531
|
+
chalk14.yellow("Not logged in. Run 'lynxp login' to authenticate.")
|
|
3735
3532
|
);
|
|
3736
3533
|
process.exit(1);
|
|
3737
3534
|
}
|
|
3738
|
-
const spinner =
|
|
3535
|
+
const spinner = ora11(`Fetching blueprint ${chalk14.cyan(blueprintId)}...`).start();
|
|
3739
3536
|
try {
|
|
3740
3537
|
const { blueprint } = await api.getBlueprint(blueprintId);
|
|
3741
3538
|
spinner.stop();
|
|
3742
3539
|
const source = getSourceFromVisibility2(blueprint.visibility);
|
|
3743
3540
|
const isMarketplace = source === "marketplace";
|
|
3744
3541
|
console.log();
|
|
3745
|
-
console.log(
|
|
3542
|
+
console.log(chalk14.cyan(`\u{1F431} Blueprint: ${chalk14.bold(blueprint.name)}`));
|
|
3746
3543
|
if (blueprint.description) {
|
|
3747
|
-
console.log(
|
|
3544
|
+
console.log(chalk14.gray(` ${blueprint.description}`));
|
|
3748
3545
|
}
|
|
3749
|
-
console.log(
|
|
3546
|
+
console.log(chalk14.gray(` Visibility: ${blueprint.visibility}`));
|
|
3750
3547
|
console.log();
|
|
3751
3548
|
if (isMarketplace) {
|
|
3752
|
-
console.log(
|
|
3753
|
-
console.log(
|
|
3754
|
-
console.log(
|
|
3549
|
+
console.log(chalk14.yellow("\u26A0 This is a marketplace blueprint."));
|
|
3550
|
+
console.log(chalk14.gray(" Your local changes will NOT sync back to the cloud."));
|
|
3551
|
+
console.log(chalk14.gray(" To make changes, you'll need to create your own copy."));
|
|
3755
3552
|
console.log();
|
|
3756
3553
|
}
|
|
3757
|
-
const { confirm } = await
|
|
3554
|
+
const { confirm } = await prompts6({
|
|
3758
3555
|
type: "confirm",
|
|
3759
3556
|
name: "confirm",
|
|
3760
|
-
message: `Link ${
|
|
3557
|
+
message: `Link ${chalk14.cyan(file)} to ${chalk14.cyan(blueprint.name)}?`,
|
|
3761
3558
|
initial: true
|
|
3762
3559
|
});
|
|
3763
3560
|
if (!confirm) {
|
|
3764
|
-
console.log(
|
|
3561
|
+
console.log(chalk14.gray("Cancelled."));
|
|
3765
3562
|
return;
|
|
3766
3563
|
}
|
|
3767
3564
|
await linkBlueprint(cwd, file, blueprint.id, blueprint.name, source);
|
|
3768
3565
|
console.log();
|
|
3769
|
-
console.log(
|
|
3566
|
+
console.log(chalk14.green(`\u2705 Linked: ${file} \u2192 ${blueprint.id}`));
|
|
3770
3567
|
console.log();
|
|
3771
|
-
console.log(
|
|
3772
|
-
console.log(
|
|
3773
|
-
console.log(
|
|
3774
|
-
console.log(
|
|
3568
|
+
console.log(chalk14.gray("Next steps:"));
|
|
3569
|
+
console.log(chalk14.gray(` \u2022 Run 'lynxp pull ${blueprintId}' to update local file from cloud`));
|
|
3570
|
+
console.log(chalk14.gray(` \u2022 Run 'lynxp diff ${blueprintId}' to see differences`));
|
|
3571
|
+
console.log(chalk14.gray(` \u2022 Run 'lynxp status' to see all tracked blueprints`));
|
|
3775
3572
|
if (!isMarketplace) {
|
|
3776
|
-
console.log(
|
|
3573
|
+
console.log(chalk14.gray(` \u2022 Run 'lynxp push ${file}' to push local changes to cloud`));
|
|
3777
3574
|
}
|
|
3778
3575
|
console.log();
|
|
3779
3576
|
} catch (error) {
|
|
3780
3577
|
spinner.stop();
|
|
3781
3578
|
if (error instanceof ApiRequestError) {
|
|
3782
3579
|
if (error.statusCode === 404) {
|
|
3783
|
-
console.log(
|
|
3784
|
-
console.log(
|
|
3580
|
+
console.log(chalk14.red(`\u2717 Blueprint not found: ${blueprintId}`));
|
|
3581
|
+
console.log(chalk14.gray(" Make sure the ID is correct. Use 'lynxp list' or 'lynxp search' to find blueprints."));
|
|
3785
3582
|
} else if (error.statusCode === 403) {
|
|
3786
|
-
console.log(
|
|
3583
|
+
console.log(chalk14.red("\u2717 You don't have access to this blueprint."));
|
|
3787
3584
|
} else {
|
|
3788
|
-
console.log(
|
|
3585
|
+
console.log(chalk14.red(`\u2717 Error: ${error.message}`));
|
|
3789
3586
|
}
|
|
3790
3587
|
} else {
|
|
3791
|
-
console.log(
|
|
3588
|
+
console.log(chalk14.red("\u2717 An unexpected error occurred."));
|
|
3792
3589
|
}
|
|
3793
3590
|
}
|
|
3794
3591
|
}
|
|
3795
3592
|
async function unlinkCommand(file) {
|
|
3796
3593
|
const cwd = process.cwd();
|
|
3797
3594
|
if (!file) {
|
|
3798
|
-
console.log(
|
|
3595
|
+
console.log(chalk14.red("\u2717 Please provide a file path to unlink."));
|
|
3799
3596
|
console.log();
|
|
3800
|
-
console.log(
|
|
3801
|
-
console.log(
|
|
3597
|
+
console.log(chalk14.gray("Usage: lynxp unlink <file>"));
|
|
3598
|
+
console.log(chalk14.gray("Example: lynxp unlink AGENTS.md"));
|
|
3802
3599
|
return;
|
|
3803
3600
|
}
|
|
3804
3601
|
const tracked = await findBlueprintByFile(cwd, file);
|
|
3805
3602
|
if (!tracked) {
|
|
3806
|
-
console.log(
|
|
3603
|
+
console.log(chalk14.yellow(`\u26A0 File is not linked to any blueprint: ${file}`));
|
|
3807
3604
|
return;
|
|
3808
3605
|
}
|
|
3809
3606
|
console.log();
|
|
3810
|
-
console.log(
|
|
3811
|
-
console.log(
|
|
3812
|
-
console.log(
|
|
3607
|
+
console.log(chalk14.cyan(`Currently linked to: ${tracked.id}`));
|
|
3608
|
+
console.log(chalk14.gray(` Name: ${tracked.name}`));
|
|
3609
|
+
console.log(chalk14.gray(` Source: ${tracked.source}`));
|
|
3813
3610
|
console.log();
|
|
3814
|
-
const { confirm } = await
|
|
3611
|
+
const { confirm } = await prompts6({
|
|
3815
3612
|
type: "confirm",
|
|
3816
3613
|
name: "confirm",
|
|
3817
|
-
message: `Unlink ${
|
|
3614
|
+
message: `Unlink ${chalk14.cyan(file)} from ${chalk14.cyan(tracked.name)}?`,
|
|
3818
3615
|
initial: true
|
|
3819
3616
|
});
|
|
3820
3617
|
if (!confirm) {
|
|
3821
|
-
console.log(
|
|
3618
|
+
console.log(chalk14.gray("Cancelled."));
|
|
3822
3619
|
return;
|
|
3823
3620
|
}
|
|
3824
3621
|
const success = await untrackBlueprint(cwd, file);
|
|
3825
3622
|
if (success) {
|
|
3826
3623
|
console.log();
|
|
3827
|
-
console.log(
|
|
3828
|
-
console.log(
|
|
3829
|
-
console.log(
|
|
3624
|
+
console.log(chalk14.green(`\u2705 Unlinked: ${file}`));
|
|
3625
|
+
console.log(chalk14.gray(" The file is now a standalone local file."));
|
|
3626
|
+
console.log(chalk14.gray(" It will no longer receive updates from the cloud blueprint."));
|
|
3830
3627
|
console.log();
|
|
3831
3628
|
} else {
|
|
3832
|
-
console.log(
|
|
3629
|
+
console.log(chalk14.red("\u2717 Failed to unlink file."));
|
|
3833
3630
|
}
|
|
3834
3631
|
}
|
|
3835
3632
|
async function listTrackedBlueprints(cwd) {
|
|
3836
3633
|
console.log();
|
|
3837
|
-
console.log(
|
|
3634
|
+
console.log(chalk14.cyan("\u{1F431} Tracked Blueprints"));
|
|
3838
3635
|
console.log();
|
|
3839
3636
|
const status = await checkSyncStatus(cwd);
|
|
3840
3637
|
if (status.length === 0) {
|
|
3841
|
-
console.log(
|
|
3638
|
+
console.log(chalk14.gray("No blueprints are currently tracked."));
|
|
3842
3639
|
console.log();
|
|
3843
|
-
console.log(
|
|
3844
|
-
console.log(
|
|
3845
|
-
console.log(
|
|
3640
|
+
console.log(chalk14.gray("To track a blueprint:"));
|
|
3641
|
+
console.log(chalk14.gray(" lynxp pull <blueprint-id> Download and track a blueprint"));
|
|
3642
|
+
console.log(chalk14.gray(" lynxp link <file> <id> Link an existing file to a blueprint"));
|
|
3846
3643
|
return;
|
|
3847
3644
|
}
|
|
3848
3645
|
for (const { blueprint, localModified, fileExists: fileExists2 } of status) {
|
|
3849
|
-
const statusIcon = !fileExists2 ?
|
|
3646
|
+
const statusIcon = !fileExists2 ? chalk14.red("\u2717") : localModified ? chalk14.yellow("\u25CF") : chalk14.green("\u2713");
|
|
3850
3647
|
const sourceLabel = {
|
|
3851
|
-
marketplace:
|
|
3852
|
-
team:
|
|
3853
|
-
private:
|
|
3854
|
-
local:
|
|
3648
|
+
marketplace: chalk14.gray("[marketplace]"),
|
|
3649
|
+
team: chalk14.blue("[team]"),
|
|
3650
|
+
private: chalk14.green("[private]"),
|
|
3651
|
+
local: chalk14.gray("[local]")
|
|
3855
3652
|
}[blueprint.source];
|
|
3856
|
-
console.log(`${statusIcon} ${
|
|
3653
|
+
console.log(`${statusIcon} ${chalk14.cyan(blueprint.file)}`);
|
|
3857
3654
|
console.log(` ${sourceLabel} ${blueprint.name}`);
|
|
3858
|
-
console.log(` ${
|
|
3655
|
+
console.log(` ${chalk14.gray(`ID: ${blueprint.id}`)}`);
|
|
3859
3656
|
if (!fileExists2) {
|
|
3860
|
-
console.log(
|
|
3657
|
+
console.log(chalk14.red(` \u26A0 File not found`));
|
|
3861
3658
|
} else if (localModified) {
|
|
3862
|
-
console.log(
|
|
3659
|
+
console.log(chalk14.yellow(` \u26A0 Local changes detected`));
|
|
3863
3660
|
}
|
|
3864
3661
|
console.log();
|
|
3865
3662
|
}
|
|
3866
|
-
console.log(
|
|
3867
|
-
console.log(
|
|
3663
|
+
console.log(chalk14.gray("Legend:"));
|
|
3664
|
+
console.log(chalk14.gray(` ${chalk14.green("\u2713")} In sync ${chalk14.yellow("\u25CF")} Modified locally ${chalk14.red("\u2717")} Missing`));
|
|
3868
3665
|
console.log();
|
|
3869
3666
|
}
|
|
3870
3667
|
|
|
@@ -3877,7 +3674,6 @@ program.command("status").description("Show current AI configuration and tracked
|
|
|
3877
3674
|
program.command("pull <id>").description("Download and track a blueprint from the marketplace").option("-o, --output <path>", "Output directory", ".").option("-y, --yes", "Overwrite existing files without prompting").option("--preview", "Preview content without downloading").option("--no-track", "Don't track the blueprint for future syncs").action(pullCommand);
|
|
3878
3675
|
program.command("search <query>").description("Search public blueprints in the marketplace").option("-l, --limit <number>", "Number of results", "20").action(searchCommand);
|
|
3879
3676
|
program.command("list").description("List your blueprints").option("-l, --limit <number>", "Number of results", "20").option("-v, --visibility <visibility>", "Filter: PRIVATE, TEAM, PUBLIC, or all").action(listCommand);
|
|
3880
|
-
program.command("push [file]").description("Push local file to LynxPrompt cloud as a blueprint").option("-n, --name <name>", "Blueprint name").option("-d, --description <desc>", "Blueprint description").option("-v, --visibility <vis>", "Visibility: PRIVATE, TEAM, or PUBLIC", "PRIVATE").option("-t, --tags <tags>", "Tags (comma-separated)").option("-y, --yes", "Skip prompts").action(pushCommand);
|
|
3881
3677
|
program.command("link [file] [blueprint-id]").description("Link a local file to a cloud blueprint for tracking").option("--list", "List all tracked blueprints").action(linkCommand);
|
|
3882
3678
|
program.command("unlink <file>").description("Disconnect a local file from its cloud blueprint").action(unlinkCommand);
|
|
3883
3679
|
program.command("diff [blueprint-id]").description("Show changes between local and remote blueprint").option("--local", "Compare .lynxprompt/rules/ with exported files").action(diffCommand);
|
|
@@ -3890,33 +3686,32 @@ program.command("whoami").description("Show current authenticated user").action(
|
|
|
3890
3686
|
program.addHelpText(
|
|
3891
3687
|
"beforeAll",
|
|
3892
3688
|
`
|
|
3893
|
-
${
|
|
3894
|
-
${
|
|
3689
|
+
${chalk15.cyan("\u{1F431} LynxPrompt CLI")} ${chalk15.gray("(also available as: lynxp)")}
|
|
3690
|
+
${chalk15.gray("Generate AI IDE configuration files from your terminal")}
|
|
3895
3691
|
`
|
|
3896
3692
|
);
|
|
3897
3693
|
program.addHelpText(
|
|
3898
3694
|
"after",
|
|
3899
3695
|
`
|
|
3900
|
-
${
|
|
3901
|
-
${
|
|
3902
|
-
${
|
|
3903
|
-
${
|
|
3904
|
-
|
|
3905
|
-
${
|
|
3906
|
-
${
|
|
3907
|
-
${
|
|
3908
|
-
${
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
${
|
|
3912
|
-
${
|
|
3913
|
-
${
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
${
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
${chalk16.gray("Docs: https://lynxprompt.com/docs/cli")}
|
|
3696
|
+
${chalk15.cyan("Quick Start:")}
|
|
3697
|
+
${chalk15.white("$ lynxp wizard")} ${chalk15.gray("Generate config interactively")}
|
|
3698
|
+
${chalk15.white("$ lynxp wizard -y")} ${chalk15.gray("Generate AGENTS.md with defaults")}
|
|
3699
|
+
${chalk15.white("$ lynxp wizard -f cursor")} ${chalk15.gray("Generate .cursor/rules/")}
|
|
3700
|
+
|
|
3701
|
+
${chalk15.cyan("Marketplace:")}
|
|
3702
|
+
${chalk15.white("$ lynxp search nextjs")} ${chalk15.gray("Search blueprints")}
|
|
3703
|
+
${chalk15.white("$ lynxp pull bp_abc123")} ${chalk15.gray("Download and track a blueprint")}
|
|
3704
|
+
${chalk15.white("$ lynxp link --list")} ${chalk15.gray("Show tracked blueprints")}
|
|
3705
|
+
|
|
3706
|
+
${chalk15.cyan("Blueprint Tracking:")}
|
|
3707
|
+
${chalk15.white("$ lynxp link AGENTS.md bp_xyz")} ${chalk15.gray("Link existing file to blueprint")}
|
|
3708
|
+
${chalk15.white("$ lynxp unlink AGENTS.md")} ${chalk15.gray("Disconnect from cloud")}
|
|
3709
|
+
${chalk15.white("$ lynxp diff bp_abc123")} ${chalk15.gray("Show changes vs cloud version")}
|
|
3710
|
+
|
|
3711
|
+
${chalk15.cyan("CI/CD:")}
|
|
3712
|
+
${chalk15.white("$ lynxp check --ci")} ${chalk15.gray("Validate config (exit code)")}
|
|
3713
|
+
|
|
3714
|
+
${chalk15.gray("Docs: https://lynxprompt.com/docs/cli")}
|
|
3920
3715
|
`
|
|
3921
3716
|
);
|
|
3922
3717
|
program.parse();
|