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 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(cwd, repositoryRoot, name) {
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.1";
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.1";
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);