lynxprompt 1.2.0 → 1.2.2
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 +224 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -606,7 +606,10 @@ async function trackBlueprint(cwd, blueprint) {
|
|
|
606
606
|
checksum: calculateChecksum(blueprint.content),
|
|
607
607
|
version: blueprint.version,
|
|
608
608
|
editable,
|
|
609
|
-
canPull
|
|
609
|
+
canPull,
|
|
610
|
+
hierarchyId: blueprint.hierarchyId,
|
|
611
|
+
hierarchyName: blueprint.hierarchyName,
|
|
612
|
+
repositoryPath: blueprint.repositoryPath
|
|
610
613
|
});
|
|
611
614
|
await saveBlueprints(cwd, config2);
|
|
612
615
|
}
|
|
@@ -793,7 +796,10 @@ async function pullHierarchy(id, options) {
|
|
|
793
796
|
name: blueprint.name,
|
|
794
797
|
file: filename,
|
|
795
798
|
content: blueprint.content,
|
|
796
|
-
source
|
|
799
|
+
source,
|
|
800
|
+
hierarchyId: id,
|
|
801
|
+
hierarchyName: hierarchy.name,
|
|
802
|
+
repositoryPath: bp.repository_path || void 0
|
|
797
803
|
});
|
|
798
804
|
}
|
|
799
805
|
console.log(chalk5.green(` \u2713 ${filename}`));
|
|
@@ -962,7 +968,9 @@ async function pullBlueprint(id, options) {
|
|
|
962
968
|
name: blueprint.name,
|
|
963
969
|
file: filename,
|
|
964
970
|
content: blueprint.content,
|
|
965
|
-
source
|
|
971
|
+
source,
|
|
972
|
+
hierarchyId: blueprint.hierarchy_id || void 0,
|
|
973
|
+
repositoryPath: blueprint.repository_path || void 0
|
|
966
974
|
});
|
|
967
975
|
}
|
|
968
976
|
console.log(chalk5.green(`\u2705 Downloaded: ${chalk5.bold(outputPath)}`));
|
|
@@ -1051,6 +1059,39 @@ import fs from "fs";
|
|
|
1051
1059
|
import path from "path";
|
|
1052
1060
|
import { createHash as createHash2 } from "crypto";
|
|
1053
1061
|
import prompts2 from "prompts";
|
|
1062
|
+
function scanForAgentFiles(cwd, maxDepth = 5) {
|
|
1063
|
+
const results = [];
|
|
1064
|
+
function scan(dir, depth) {
|
|
1065
|
+
if (depth > maxDepth) return;
|
|
1066
|
+
try {
|
|
1067
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1068
|
+
for (const entry of entries) {
|
|
1069
|
+
const fullPath = path.join(dir, entry.name);
|
|
1070
|
+
if (entry.isDirectory()) {
|
|
1071
|
+
if (["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv"].includes(entry.name)) {
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
scan(fullPath, depth + 1);
|
|
1075
|
+
} else if (entry.name === "AGENTS.md") {
|
|
1076
|
+
const relativePath = path.relative(cwd, fullPath);
|
|
1077
|
+
results.push({
|
|
1078
|
+
path: relativePath,
|
|
1079
|
+
absolutePath: fullPath,
|
|
1080
|
+
isRoot: relativePath === "AGENTS.md"
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} catch {
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
scan(cwd, 0);
|
|
1088
|
+
results.sort((a, b) => {
|
|
1089
|
+
if (a.isRoot && !b.isRoot) return -1;
|
|
1090
|
+
if (!a.isRoot && b.isRoot) return 1;
|
|
1091
|
+
return a.path.localeCompare(b.path);
|
|
1092
|
+
});
|
|
1093
|
+
return results;
|
|
1094
|
+
}
|
|
1054
1095
|
async function detectHierarchyInfo(cwd, file) {
|
|
1055
1096
|
const repositoryRoot = createRepositoryRoot(cwd);
|
|
1056
1097
|
const result = {
|
|
@@ -1182,6 +1223,37 @@ async function updateBlueprint(cwd, file, blueprintId, content, options, expecte
|
|
|
1182
1223
|
}
|
|
1183
1224
|
}
|
|
1184
1225
|
async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
1226
|
+
const isAgentsMd = filename === "AGENTS.md";
|
|
1227
|
+
if (isAgentsMd) {
|
|
1228
|
+
const discoveredFiles = scanForAgentFiles(cwd);
|
|
1229
|
+
if (discoveredFiles.length > 1) {
|
|
1230
|
+
console.log();
|
|
1231
|
+
console.log(chalk6.cyan(`\u{1F4C1} Found ${discoveredFiles.length} AGENTS.md files:`));
|
|
1232
|
+
console.log();
|
|
1233
|
+
for (const f of discoveredFiles) {
|
|
1234
|
+
const icon = f.isRoot ? "\u{1F4C4}" : " \u2514\u2500";
|
|
1235
|
+
console.log(chalk6.gray(` ${icon} ${f.path}`));
|
|
1236
|
+
}
|
|
1237
|
+
console.log();
|
|
1238
|
+
let shouldCreateHierarchy = options.yes;
|
|
1239
|
+
if (!options.yes) {
|
|
1240
|
+
const { createHierarchy } = await prompts2({
|
|
1241
|
+
type: "confirm",
|
|
1242
|
+
name: "createHierarchy",
|
|
1243
|
+
message: `Create a hierarchy with all ${discoveredFiles.length} AGENTS.md files?`,
|
|
1244
|
+
initial: true
|
|
1245
|
+
});
|
|
1246
|
+
shouldCreateHierarchy = createHierarchy;
|
|
1247
|
+
} else {
|
|
1248
|
+
console.log(chalk6.cyan(`Auto-creating hierarchy with ${discoveredFiles.length} files...`));
|
|
1249
|
+
}
|
|
1250
|
+
if (shouldCreateHierarchy) {
|
|
1251
|
+
await pushHierarchy(cwd, discoveredFiles, options);
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
console.log(chalk6.gray("Proceeding with single file push..."));
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1185
1257
|
console.log(chalk6.cyan("\n\u{1F4E4} Push new blueprint"));
|
|
1186
1258
|
console.log(chalk6.gray(` File: ${file}`));
|
|
1187
1259
|
let name = options.name;
|
|
@@ -1257,7 +1329,9 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
|
1257
1329
|
name: result.blueprint.name,
|
|
1258
1330
|
file,
|
|
1259
1331
|
content,
|
|
1260
|
-
source: "private"
|
|
1332
|
+
source: "private",
|
|
1333
|
+
hierarchyId: hierarchyId || void 0,
|
|
1334
|
+
repositoryPath: hierarchyInfo.repositoryPath || void 0
|
|
1261
1335
|
});
|
|
1262
1336
|
console.log();
|
|
1263
1337
|
console.log(chalk6.green(`\u2705 Created blueprint ${chalk6.bold(result.blueprint.name)}`));
|
|
@@ -1282,6 +1356,113 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
|
1282
1356
|
handleError(error);
|
|
1283
1357
|
}
|
|
1284
1358
|
}
|
|
1359
|
+
async function pushHierarchy(cwd, files, options) {
|
|
1360
|
+
let hierarchyName = options.name || path.basename(cwd);
|
|
1361
|
+
let visibility = options.visibility || "PRIVATE";
|
|
1362
|
+
if (!options.yes) {
|
|
1363
|
+
const responses = await prompts2([
|
|
1364
|
+
{
|
|
1365
|
+
type: "text",
|
|
1366
|
+
name: "name",
|
|
1367
|
+
message: "Hierarchy name:",
|
|
1368
|
+
initial: hierarchyName,
|
|
1369
|
+
validate: (v) => v.length > 0 || "Name is required"
|
|
1370
|
+
},
|
|
1371
|
+
{
|
|
1372
|
+
type: "select",
|
|
1373
|
+
name: "visibility",
|
|
1374
|
+
message: "Visibility for all blueprints:",
|
|
1375
|
+
choices: [
|
|
1376
|
+
{ title: "Private (only you)", value: "PRIVATE" },
|
|
1377
|
+
{ title: "Team (your team members)", value: "TEAM" },
|
|
1378
|
+
{ title: "Public (visible to everyone)", value: "PUBLIC" }
|
|
1379
|
+
],
|
|
1380
|
+
initial: 0
|
|
1381
|
+
}
|
|
1382
|
+
]);
|
|
1383
|
+
if (!responses.name) {
|
|
1384
|
+
console.log(chalk6.yellow("Push cancelled."));
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
hierarchyName = responses.name;
|
|
1388
|
+
visibility = responses.visibility || visibility;
|
|
1389
|
+
}
|
|
1390
|
+
console.log();
|
|
1391
|
+
console.log(chalk6.cyan(`\u{1F4C1} Creating hierarchy "${hierarchyName}" with ${files.length} files...`));
|
|
1392
|
+
console.log();
|
|
1393
|
+
const repositoryRoot = createRepositoryRoot(cwd);
|
|
1394
|
+
let hierarchyId;
|
|
1395
|
+
try {
|
|
1396
|
+
const hierarchyResponse = await api.createHierarchy({
|
|
1397
|
+
name: hierarchyName,
|
|
1398
|
+
repository_root: repositoryRoot
|
|
1399
|
+
});
|
|
1400
|
+
hierarchyId = hierarchyResponse.hierarchy.id;
|
|
1401
|
+
console.log(chalk6.green(`\u2713 Created hierarchy: ${hierarchyId}`));
|
|
1402
|
+
} catch (error) {
|
|
1403
|
+
console.log(chalk6.red("Failed to create hierarchy"));
|
|
1404
|
+
handleError(error);
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
let rootBlueprintId = null;
|
|
1408
|
+
let successCount = 0;
|
|
1409
|
+
let failCount = 0;
|
|
1410
|
+
for (const file of files) {
|
|
1411
|
+
const spinner = ora5(`Uploading ${file.path}...`).start();
|
|
1412
|
+
try {
|
|
1413
|
+
const content = fs.readFileSync(file.absolutePath, "utf-8");
|
|
1414
|
+
let blueprintName;
|
|
1415
|
+
if (file.isRoot) {
|
|
1416
|
+
blueprintName = hierarchyName;
|
|
1417
|
+
} else {
|
|
1418
|
+
const dirname5 = path.dirname(file.path);
|
|
1419
|
+
blueprintName = dirname5.replace(/[/\\]/g, " / ");
|
|
1420
|
+
}
|
|
1421
|
+
const result = await api.createBlueprint({
|
|
1422
|
+
name: blueprintName,
|
|
1423
|
+
description: "",
|
|
1424
|
+
content,
|
|
1425
|
+
visibility,
|
|
1426
|
+
tags: [],
|
|
1427
|
+
hierarchy_id: hierarchyId,
|
|
1428
|
+
parent_id: file.isRoot ? null : rootBlueprintId,
|
|
1429
|
+
repository_path: file.path
|
|
1430
|
+
});
|
|
1431
|
+
if (file.isRoot) {
|
|
1432
|
+
rootBlueprintId = result.blueprint.id;
|
|
1433
|
+
}
|
|
1434
|
+
await trackBlueprint(cwd, {
|
|
1435
|
+
id: result.blueprint.id,
|
|
1436
|
+
name: blueprintName,
|
|
1437
|
+
file: file.path,
|
|
1438
|
+
content,
|
|
1439
|
+
source: "private",
|
|
1440
|
+
hierarchyId,
|
|
1441
|
+
hierarchyName,
|
|
1442
|
+
repositoryPath: file.path
|
|
1443
|
+
});
|
|
1444
|
+
spinner.succeed(`${file.path} \u2192 ${result.blueprint.id}`);
|
|
1445
|
+
successCount++;
|
|
1446
|
+
} catch (error) {
|
|
1447
|
+
spinner.fail(`${file.path} failed`);
|
|
1448
|
+
if (error instanceof ApiRequestError) {
|
|
1449
|
+
console.log(chalk6.red(` Error: ${error.message}`));
|
|
1450
|
+
}
|
|
1451
|
+
failCount++;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
console.log();
|
|
1455
|
+
console.log(chalk6.green(`\u2705 Hierarchy created successfully!`));
|
|
1456
|
+
console.log(chalk6.gray(` Hierarchy: ${hierarchyId}`));
|
|
1457
|
+
console.log(chalk6.gray(` Name: ${hierarchyName}`));
|
|
1458
|
+
console.log(chalk6.gray(` Blueprints: ${successCount} uploaded${failCount > 0 ? `, ${failCount} failed` : ""}`));
|
|
1459
|
+
console.log();
|
|
1460
|
+
console.log(chalk6.cyan("Tips:"));
|
|
1461
|
+
console.log(chalk6.gray(` \u2022 Run 'lynxp status' to see all tracked blueprints`));
|
|
1462
|
+
console.log(chalk6.gray(` \u2022 Run 'lynxp pull ${hierarchyId}' to download the entire hierarchy`));
|
|
1463
|
+
console.log(chalk6.gray(` \u2022 Run 'lynxp push' in any subfolder to update individual blueprints`));
|
|
1464
|
+
console.log();
|
|
1465
|
+
}
|
|
1285
1466
|
function findDefaultFile() {
|
|
1286
1467
|
const candidates = [
|
|
1287
1468
|
"AGENTS.md",
|
|
@@ -3178,7 +3359,7 @@ function generateYamlConfig(options, platform2) {
|
|
|
3178
3359
|
|
|
3179
3360
|
// src/commands/wizard.ts
|
|
3180
3361
|
var DRAFTS_DIR = ".lynxprompt/drafts";
|
|
3181
|
-
var CLI_VERSION = "1.2.
|
|
3362
|
+
var CLI_VERSION = "1.2.2";
|
|
3182
3363
|
async function saveDraftLocally(name, config2, stepReached) {
|
|
3183
3364
|
const draftsPath = join4(process.cwd(), DRAFTS_DIR);
|
|
3184
3365
|
await mkdir3(draftsPath, { recursive: true });
|
|
@@ -5869,28 +6050,47 @@ async function statusCommand() {
|
|
|
5869
6050
|
}
|
|
5870
6051
|
const trackedStatus = await checkSyncStatus(cwd);
|
|
5871
6052
|
if (trackedStatus.length > 0) {
|
|
6053
|
+
const byHierarchy = /* @__PURE__ */ new Map();
|
|
6054
|
+
for (const item of trackedStatus) {
|
|
6055
|
+
const key = item.blueprint.hierarchyId || null;
|
|
6056
|
+
const group = byHierarchy.get(key) || [];
|
|
6057
|
+
group.push(item);
|
|
6058
|
+
byHierarchy.set(key, group);
|
|
6059
|
+
}
|
|
5872
6060
|
console.log(chalk9.cyan("\u{1F4E6} Tracked Blueprints"));
|
|
5873
6061
|
console.log();
|
|
5874
|
-
for (const
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
}
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
6062
|
+
for (const [hierarchyId, items] of byHierarchy.entries()) {
|
|
6063
|
+
if (hierarchyId) {
|
|
6064
|
+
const hierarchyName = items[0].blueprint.hierarchyName || "Unknown Hierarchy";
|
|
6065
|
+
console.log(chalk9.magenta(` \u{1F4C1} ${hierarchyName}`));
|
|
6066
|
+
console.log(chalk9.gray(` Hierarchy: ${hierarchyId}`));
|
|
6067
|
+
console.log();
|
|
6068
|
+
}
|
|
6069
|
+
for (const { blueprint, localModified, fileExists: fileExists2 } of items) {
|
|
6070
|
+
const statusIcon = !fileExists2 ? chalk9.red("\u2717") : localModified ? chalk9.yellow("\u25CF") : chalk9.green("\u2713");
|
|
6071
|
+
const sourceLabel = {
|
|
6072
|
+
marketplace: chalk9.gray("[marketplace]"),
|
|
6073
|
+
team: chalk9.blue("[team]"),
|
|
6074
|
+
private: chalk9.green("[private]"),
|
|
6075
|
+
local: chalk9.gray("[local]")
|
|
6076
|
+
}[blueprint.source];
|
|
6077
|
+
const indent = hierarchyId ? " " : " ";
|
|
6078
|
+
console.log(`${indent}${statusIcon} ${chalk9.bold(blueprint.file)} ${sourceLabel}`);
|
|
6079
|
+
console.log(`${indent} ${chalk9.gray(`ID: ${blueprint.id} \u2022 ${blueprint.name}`)}`);
|
|
6080
|
+
if (blueprint.repositoryPath && blueprint.repositoryPath !== blueprint.file) {
|
|
6081
|
+
console.log(`${indent} ${chalk9.gray(`Path: ${blueprint.repositoryPath}`)}`);
|
|
5891
6082
|
}
|
|
6083
|
+
if (!fileExists2) {
|
|
6084
|
+
console.log(chalk9.red(`${indent} \u26A0 File missing - run 'lynxp pull ${blueprint.id}' to restore`));
|
|
6085
|
+
} else if (localModified) {
|
|
6086
|
+
if (blueprint.source === "marketplace") {
|
|
6087
|
+
console.log(chalk9.yellow(`${indent} \u26A0 Local changes (marketplace = read-only, won't sync back)`));
|
|
6088
|
+
} else {
|
|
6089
|
+
console.log(chalk9.yellow(`${indent} \u26A0 Local changes - run 'lynxp push ${blueprint.file}' to sync`));
|
|
6090
|
+
}
|
|
6091
|
+
}
|
|
6092
|
+
console.log();
|
|
5892
6093
|
}
|
|
5893
|
-
console.log();
|
|
5894
6094
|
}
|
|
5895
6095
|
}
|
|
5896
6096
|
console.log(chalk9.cyan("\u{1F4C4} AI Config Files"));
|
|
@@ -7822,7 +8022,7 @@ function handleError2(error) {
|
|
|
7822
8022
|
}
|
|
7823
8023
|
|
|
7824
8024
|
// src/index.ts
|
|
7825
|
-
var CLI_VERSION2 = "1.2.
|
|
8025
|
+
var CLI_VERSION2 = "1.2.2";
|
|
7826
8026
|
var program = new Command();
|
|
7827
8027
|
program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
|
|
7828
8028
|
program.command("wizard").description("Generate AI IDE configuration (recommended for most users)").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-s, --stack <stack>", "Tech stack (comma-separated)").option("-f, --format <format>", "Output format: agents, cursor, or comma-separated for multiple").option("-p, --platforms <platforms>", "Alias for --format (deprecated)").option("--persona <persona>", "AI persona (fullstack, backend, frontend, devops, data, security)").option("--boundaries <level>", "Boundary preset (conservative, standard, permissive)").option("-y, --yes", "Skip prompts, use defaults (generates AGENTS.md)").option("-o, --output <dir>", "Output directory (default: current directory)").option("--repo-url <url>", "Analyze remote repository URL (GitHub/GitLab supported)").option("--blueprint", "Generate with [[VARIABLE|default]] placeholders for templates").option("--license <type>", "License type (mit, apache-2.0, gpl-3.0, etc.)").option("--ci-cd <platform>", "CI/CD platform (github_actions, gitlab_ci, jenkins, etc.)").option("--project-type <type>", "Project type (work, leisure, opensource, learning)").option("--detect-only", "Only detect project info, don't generate files").option("--load-draft <name>", "Load a saved wizard draft").option("--save-draft <name>", "Save wizard state as a draft (auto-saves at end)").option("--vars <values>", "Fill variables: VAR1=value1,VAR2=value2").action(wizardCommand);
|