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 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.0";
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 { blueprint, localModified, fileExists: fileExists2 } of trackedStatus) {
5875
- const statusIcon = !fileExists2 ? chalk9.red("\u2717") : localModified ? chalk9.yellow("\u25CF") : chalk9.green("\u2713");
5876
- const sourceLabel = {
5877
- marketplace: chalk9.gray("[marketplace]"),
5878
- team: chalk9.blue("[team]"),
5879
- private: chalk9.green("[private]"),
5880
- local: chalk9.gray("[local]")
5881
- }[blueprint.source];
5882
- console.log(` ${statusIcon} ${chalk9.bold(blueprint.file)} ${sourceLabel}`);
5883
- console.log(` ${chalk9.gray(`ID: ${blueprint.id} \u2022 ${blueprint.name}`)}`);
5884
- if (!fileExists2) {
5885
- console.log(chalk9.red(` \u26A0 File missing - run 'lynxp pull ${blueprint.id}' to restore`));
5886
- } else if (localModified) {
5887
- if (blueprint.source === "marketplace") {
5888
- console.log(chalk9.yellow(` \u26A0 Local changes (marketplace = read-only, won't sync back)`));
5889
- } else {
5890
- console.log(chalk9.yellow(` \u26A0 Local changes - run 'lynxp push ${blueprint.file}' to sync`));
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.0";
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);