lynxprompt 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +177 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1059,6 +1059,39 @@ import fs from "fs";
|
|
|
1059
1059
|
import path from "path";
|
|
1060
1060
|
import { createHash as createHash2 } from "crypto";
|
|
1061
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
|
+
}
|
|
1062
1095
|
async function detectHierarchyInfo(cwd, file) {
|
|
1063
1096
|
const repositoryRoot = createRepositoryRoot(cwd);
|
|
1064
1097
|
const result = {
|
|
@@ -1088,7 +1121,7 @@ async function detectHierarchyInfo(cwd, file) {
|
|
|
1088
1121
|
}
|
|
1089
1122
|
return result;
|
|
1090
1123
|
}
|
|
1091
|
-
async function ensureHierarchy(
|
|
1124
|
+
async function ensureHierarchy(_cwd, repositoryRoot, name) {
|
|
1092
1125
|
try {
|
|
1093
1126
|
const response = await api.createHierarchy({
|
|
1094
1127
|
name,
|
|
@@ -1190,6 +1223,37 @@ async function updateBlueprint(cwd, file, blueprintId, content, options, expecte
|
|
|
1190
1223
|
}
|
|
1191
1224
|
}
|
|
1192
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
|
+
}
|
|
1193
1257
|
console.log(chalk6.cyan("\n\u{1F4E4} Push new blueprint"));
|
|
1194
1258
|
console.log(chalk6.gray(` File: ${file}`));
|
|
1195
1259
|
let name = options.name;
|
|
@@ -1265,7 +1329,9 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
|
1265
1329
|
name: result.blueprint.name,
|
|
1266
1330
|
file,
|
|
1267
1331
|
content,
|
|
1268
|
-
source: "private"
|
|
1332
|
+
source: "private",
|
|
1333
|
+
hierarchyId: hierarchyId || void 0,
|
|
1334
|
+
repositoryPath: hierarchyInfo.repositoryPath || void 0
|
|
1269
1335
|
});
|
|
1270
1336
|
console.log();
|
|
1271
1337
|
console.log(chalk6.green(`\u2705 Created blueprint ${chalk6.bold(result.blueprint.name)}`));
|
|
@@ -1290,6 +1356,113 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
|
|
|
1290
1356
|
handleError(error);
|
|
1291
1357
|
}
|
|
1292
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
|
+
}
|
|
1293
1466
|
function findDefaultFile() {
|
|
1294
1467
|
const candidates = [
|
|
1295
1468
|
"AGENTS.md",
|
|
@@ -3186,7 +3359,7 @@ function generateYamlConfig(options, platform2) {
|
|
|
3186
3359
|
|
|
3187
3360
|
// src/commands/wizard.ts
|
|
3188
3361
|
var DRAFTS_DIR = ".lynxprompt/drafts";
|
|
3189
|
-
var CLI_VERSION = "1.2.
|
|
3362
|
+
var CLI_VERSION = "1.2.3";
|
|
3190
3363
|
async function saveDraftLocally(name, config2, stepReached) {
|
|
3191
3364
|
const draftsPath = join4(process.cwd(), DRAFTS_DIR);
|
|
3192
3365
|
await mkdir3(draftsPath, { recursive: true });
|
|
@@ -7849,7 +8022,7 @@ function handleError2(error) {
|
|
|
7849
8022
|
}
|
|
7850
8023
|
|
|
7851
8024
|
// src/index.ts
|
|
7852
|
-
var CLI_VERSION2 = "1.2.
|
|
8025
|
+
var CLI_VERSION2 = "1.2.3";
|
|
7853
8026
|
var program = new Command();
|
|
7854
8027
|
program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
|
|
7855
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);
|