lynxprompt 1.1.0 → 1.2.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk17 from "chalk";
5
+ import chalk18 from "chalk";
6
6
 
7
7
  // src/commands/login.ts
8
8
  import chalk from "chalk";
@@ -151,6 +151,35 @@ var ApiClient = class {
151
151
  body: JSON.stringify(data)
152
152
  });
153
153
  }
154
+ // Hierarchy endpoints
155
+ async listHierarchies(options = {}) {
156
+ const params = new URLSearchParams();
157
+ if (options.limit) params.set("limit", options.limit.toString());
158
+ if (options.offset) params.set("offset", options.offset.toString());
159
+ const query = params.toString();
160
+ return this.request(
161
+ `/api/v1/hierarchies${query ? `?${query}` : ""}`
162
+ );
163
+ }
164
+ async getHierarchy(id) {
165
+ let apiId = id;
166
+ if (!id.startsWith("ha_")) {
167
+ apiId = `ha_${id}`;
168
+ }
169
+ return this.request(`/api/v1/hierarchies/${apiId}`);
170
+ }
171
+ async createHierarchy(data) {
172
+ return this.request("/api/v1/hierarchies", {
173
+ method: "POST",
174
+ body: JSON.stringify(data)
175
+ });
176
+ }
177
+ async deleteHierarchy(id) {
178
+ const apiId = id.startsWith("ha_") ? id : `ha_${id}`;
179
+ return this.request(`/api/v1/hierarchies/${apiId}`, {
180
+ method: "DELETE"
181
+ });
182
+ }
154
183
  // AI endpoints
155
184
  async aiEditBlueprint(data) {
156
185
  return this.request("/api/ai/edit-blueprint", {
@@ -670,6 +699,9 @@ function getSourceFromVisibility(visibility) {
670
699
  return "marketplace";
671
700
  }
672
701
  }
702
+ function isHierarchyId(id) {
703
+ return id.startsWith("ha_");
704
+ }
673
705
  async function pullCommand(id, options) {
674
706
  if (!isAuthenticated()) {
675
707
  console.log(
@@ -677,6 +709,113 @@ async function pullCommand(id, options) {
677
709
  );
678
710
  process.exit(1);
679
711
  }
712
+ if (isHierarchyId(id)) {
713
+ await pullHierarchy(id, options);
714
+ } else {
715
+ await pullBlueprint(id, options);
716
+ }
717
+ }
718
+ async function pullHierarchy(id, options) {
719
+ const cwd = process.cwd();
720
+ const spinner = ora4(`Fetching hierarchy ${chalk5.cyan(id)}...`).start();
721
+ try {
722
+ const response = await api.getHierarchy(id);
723
+ const { hierarchy, blueprints } = response;
724
+ spinner.stop();
725
+ console.log();
726
+ console.log(chalk5.cyan(`\u{1F4C1} Hierarchy: ${chalk5.bold(hierarchy.name)}`));
727
+ if (hierarchy.description) {
728
+ console.log(chalk5.gray(` ${hierarchy.description}`));
729
+ }
730
+ console.log(chalk5.gray(` Repository: ${hierarchy.repository_root}`));
731
+ console.log(chalk5.gray(` Blueprints: ${blueprints.length}`));
732
+ console.log();
733
+ if (options.preview) {
734
+ console.log(chalk5.yellow("\u{1F4CB} Hierarchy structure:"));
735
+ console.log();
736
+ for (const bp of blueprints) {
737
+ const indent = bp.parent_id ? " \u21B3 " : " ";
738
+ const path2 = bp.repository_path || TYPE_TO_FILENAME[bp.type] || "unknown";
739
+ console.log(chalk5.gray(`${indent}${path2}`));
740
+ console.log(chalk5.gray(`${indent} \u2514\u2500 ${bp.name} (${bp.id})`));
741
+ }
742
+ console.log();
743
+ console.log(chalk5.gray("Run without --preview to download this hierarchy."));
744
+ return;
745
+ }
746
+ if (!options.yes && blueprints.length > 1) {
747
+ const { proceed } = await prompts({
748
+ type: "confirm",
749
+ name: "proceed",
750
+ message: `Download ${blueprints.length} blueprints to ${options.output}?`,
751
+ initial: true
752
+ });
753
+ if (!proceed) {
754
+ console.log(chalk5.gray("Cancelled."));
755
+ return;
756
+ }
757
+ }
758
+ console.log(chalk5.cyan("\u{1F4E5} Downloading blueprints..."));
759
+ console.log();
760
+ let downloaded = 0;
761
+ let skipped = 0;
762
+ for (const bp of blueprints) {
763
+ const filename = bp.repository_path || TYPE_TO_FILENAME[bp.type] || "ai-config.md";
764
+ const outputPath = join2(options.output, filename);
765
+ if (existsSync(outputPath) && !options.yes) {
766
+ const { overwrite } = await prompts({
767
+ type: "confirm",
768
+ name: "overwrite",
769
+ message: `File exists: ${filename}. Overwrite?`,
770
+ initial: false
771
+ });
772
+ if (!overwrite) {
773
+ console.log(chalk5.gray(` \u23ED Skipped: ${filename}`));
774
+ skipped++;
775
+ continue;
776
+ }
777
+ }
778
+ const { blueprint } = await api.getBlueprint(bp.id);
779
+ if (!blueprint.content) {
780
+ console.log(chalk5.yellow(` \u26A0 No content: ${filename}`));
781
+ skipped++;
782
+ continue;
783
+ }
784
+ const dir = dirname2(outputPath);
785
+ if (dir !== "." && dir !== options.output) {
786
+ await mkdir2(dir, { recursive: true });
787
+ }
788
+ await writeFile2(outputPath, blueprint.content, "utf-8");
789
+ if (options.track !== false) {
790
+ const source = getSourceFromVisibility(blueprint.visibility);
791
+ await trackBlueprint(cwd, {
792
+ id: blueprint.id,
793
+ name: blueprint.name,
794
+ file: filename,
795
+ content: blueprint.content,
796
+ source
797
+ });
798
+ }
799
+ console.log(chalk5.green(` \u2713 ${filename}`));
800
+ downloaded++;
801
+ }
802
+ console.log();
803
+ console.log(chalk5.green(`\u2705 Downloaded ${downloaded} blueprint(s)`));
804
+ if (skipped > 0) {
805
+ console.log(chalk5.gray(` Skipped: ${skipped}`));
806
+ }
807
+ console.log();
808
+ console.log(chalk5.gray("Tips:"));
809
+ console.log(chalk5.gray(` \u2022 Run 'lynxp status' to see tracked blueprints`));
810
+ console.log(chalk5.gray(` \u2022 Run 'lynxp sync' to push local changes`));
811
+ console.log(chalk5.gray(` \u2022 Run 'lynxp pull ${id}' again to refresh all files`));
812
+ console.log();
813
+ } catch (error) {
814
+ spinner.fail("Failed to pull hierarchy");
815
+ handleApiError2(error);
816
+ }
817
+ }
818
+ async function pullBlueprint(id, options) {
680
819
  const cwd = process.cwd();
681
820
  const spinner = ora4(`Fetching blueprint ${chalk5.cyan(id)}...`).start();
682
821
  try {
@@ -694,6 +833,12 @@ async function pullCommand(id, options) {
694
833
  console.log(chalk5.gray(` ${blueprint.description}`));
695
834
  }
696
835
  console.log(chalk5.gray(` Type: ${blueprint.type} \u2022 Tier: ${blueprint.tier} \u2022 Visibility: ${blueprint.visibility}`));
836
+ if (blueprint.hierarchy_id) {
837
+ console.log(chalk5.blue(` \u{1F4C1} Part of hierarchy: ${blueprint.hierarchy_id}`));
838
+ if (blueprint.repository_path) {
839
+ console.log(chalk5.gray(` Path in hierarchy: ${blueprint.repository_path}`));
840
+ }
841
+ }
697
842
  if (isMarketplace) {
698
843
  console.log(chalk5.yellow(` \u{1F4E6} Marketplace blueprint (read-only - changes won't sync back)`));
699
844
  } else if (source === "team") {
@@ -730,7 +875,7 @@ async function pullCommand(id, options) {
730
875
  console.log(chalk5.gray("Run without --preview to download this blueprint."));
731
876
  return;
732
877
  }
733
- const filename = TYPE_TO_FILENAME[blueprint.type] || "ai-config.md";
878
+ const filename = blueprint.repository_path || TYPE_TO_FILENAME[blueprint.type] || "ai-config.md";
734
879
  const outputPath = join2(options.output, filename);
735
880
  let localContent = null;
736
881
  if (existsSync(outputPath)) {
@@ -823,6 +968,9 @@ async function pullCommand(id, options) {
823
968
  console.log(chalk5.green(`\u2705 Downloaded: ${chalk5.bold(outputPath)}`));
824
969
  if (options.track !== false) {
825
970
  console.log(chalk5.gray(` Linked to: ${blueprint.id}`));
971
+ if (blueprint.content_checksum) {
972
+ console.log(chalk5.gray(` Checksum: ${blueprint.content_checksum}`));
973
+ }
826
974
  if (isMarketplace) {
827
975
  console.log(chalk5.gray(` Updates: Run 'lynxp pull ${id}' to sync updates`));
828
976
  } else {
@@ -873,18 +1021,18 @@ function handleApiError2(error) {
873
1021
  );
874
1022
  } else if (error.statusCode === 403) {
875
1023
  console.error(
876
- chalk5.red("\u2717 You don't have access to this blueprint.")
1024
+ chalk5.red("\u2717 You don't have access to this blueprint or hierarchy.")
877
1025
  );
878
1026
  console.error(
879
1027
  chalk5.gray(
880
- " This might be a private blueprint or require a higher subscription tier."
1028
+ " This might be a private resource or require a higher subscription tier."
881
1029
  )
882
1030
  );
883
1031
  } else if (error.statusCode === 404) {
884
- console.error(chalk5.red("\u2717 Blueprint not found."));
1032
+ console.error(chalk5.red("\u2717 Blueprint or hierarchy not found."));
885
1033
  console.error(
886
1034
  chalk5.gray(
887
- " Make sure you have the correct blueprint ID. Use 'lynxp list' to see your blueprints."
1035
+ " Make sure you have the correct ID. Use 'lynxp list' or 'lynxp hierarchies' to see your resources."
888
1036
  )
889
1037
  );
890
1038
  } else {
@@ -904,64 +1052,46 @@ import path from "path";
904
1052
  import { createHash as createHash2 } from "crypto";
905
1053
  import prompts2 from "prompts";
906
1054
  async function detectHierarchyInfo(cwd, file) {
1055
+ const repositoryRoot = createRepositoryRoot(cwd);
907
1056
  const result = {
908
1057
  repositoryPath: null,
909
- repositoryRoot: null,
910
- parentId: null
1058
+ hierarchyId: null,
1059
+ parentId: null,
1060
+ repositoryRoot
911
1061
  };
912
1062
  try {
913
- const hierarchyPath = path.join(cwd, ".lynxprompt", "hierarchy.json");
914
- if (fs.existsSync(hierarchyPath)) {
915
- const hierarchyData = JSON.parse(fs.readFileSync(hierarchyPath, "utf-8"));
916
- const relativePath = path.relative(cwd, path.resolve(file));
917
- for (const group of hierarchyData.hierarchy || []) {
918
- if (group.rootFile === relativePath) {
919
- result.repositoryPath = relativePath;
920
- result.repositoryRoot = createRepositoryRoot(hierarchyData.rootPath || cwd);
921
- break;
922
- }
923
- for (const child of group.children || []) {
924
- if (child.path === relativePath) {
925
- result.repositoryPath = relativePath;
926
- result.repositoryRoot = createRepositoryRoot(hierarchyData.rootPath || cwd);
927
- if (group.rootFile) {
928
- const blueprints = await loadBlueprints(cwd);
929
- const parentBlueprint = blueprints.blueprints.find(
930
- (b) => b.file === group.rootFile
931
- );
932
- if (parentBlueprint) {
933
- result.parentId = parentBlueprint.id;
934
- }
935
- }
936
- break;
937
- }
938
- }
939
- }
940
- }
941
- if (!result.repositoryPath) {
942
- const relativePath = path.relative(cwd, path.resolve(file));
943
- if (relativePath.includes(path.sep) && !relativePath.startsWith("..")) {
944
- result.repositoryPath = relativePath;
945
- result.repositoryRoot = createRepositoryRoot(cwd);
946
- const rootAgentsMd = path.join(cwd, "AGENTS.md");
947
- if (fs.existsSync(rootAgentsMd) && path.resolve(file) !== rootAgentsMd) {
948
- const blueprints = await loadBlueprints(cwd);
949
- const parentBlueprint = blueprints.blueprints.find(
950
- (b) => b.file === "AGENTS.md"
951
- );
952
- if (parentBlueprint) {
953
- result.parentId = parentBlueprint.id;
954
- }
1063
+ const relativePath = path.relative(cwd, path.resolve(file));
1064
+ if (relativePath.includes(path.sep) && !relativePath.startsWith("..")) {
1065
+ result.repositoryPath = relativePath;
1066
+ const rootAgentsMd = path.join(cwd, "AGENTS.md");
1067
+ if (fs.existsSync(rootAgentsMd) && path.resolve(file) !== rootAgentsMd) {
1068
+ const blueprints = await loadBlueprints(cwd);
1069
+ const parentBlueprint = blueprints.blueprints.find(
1070
+ (b) => b.file === "AGENTS.md"
1071
+ );
1072
+ if (parentBlueprint) {
1073
+ result.parentId = parentBlueprint.id;
955
1074
  }
956
- } else if (relativePath === "AGENTS.md" || relativePath === path.basename(file)) {
957
- result.repositoryPath = relativePath;
958
- result.repositoryRoot = createRepositoryRoot(cwd);
959
1075
  }
1076
+ } else if (relativePath === "AGENTS.md" || relativePath === path.basename(file)) {
1077
+ result.repositoryPath = relativePath;
960
1078
  }
961
- } catch (error) {
1079
+ } catch {
962
1080
  }
963
1081
  return result;
964
1082
  }
1083
+ async function ensureHierarchy(cwd, repositoryRoot, name) {
1084
+ try {
1085
+ const response = await api.createHierarchy({
1086
+ name,
1087
+ repository_root: repositoryRoot
1088
+ });
1089
+ return response.hierarchy.id;
1090
+ } catch (error) {
1091
+ console.log(chalk6.gray(" Note: Hierarchy creation skipped"));
1092
+ return null;
1093
+ }
1094
+ }
965
1095
  function createRepositoryRoot(rootPath) {
966
1096
  try {
967
1097
  const gitConfigPath = path.join(rootPath, ".git", "config");
@@ -999,12 +1129,12 @@ async function pushCommand(fileArg, options) {
999
1129
  const filename = path.basename(file);
1000
1130
  const linked = await findBlueprintByFile(cwd, file);
1001
1131
  if (linked) {
1002
- await updateBlueprint(cwd, file, linked.id, content, options);
1132
+ await updateBlueprint(cwd, file, linked.id, content, options, linked.checksum);
1003
1133
  } else {
1004
1134
  await createOrLinkBlueprint(cwd, file, filename, content, options);
1005
1135
  }
1006
1136
  }
1007
- async function updateBlueprint(cwd, file, blueprintId, content, options) {
1137
+ async function updateBlueprint(cwd, file, blueprintId, content, options, expectedChecksum) {
1008
1138
  console.log(chalk6.cyan(`
1009
1139
  \u{1F4E4} Updating blueprint ${chalk6.bold(blueprintId)}...`));
1010
1140
  console.log(chalk6.gray(` File: ${file}`));
@@ -1022,15 +1152,32 @@ async function updateBlueprint(cwd, file, blueprintId, content, options) {
1022
1152
  }
1023
1153
  const spinner = ora5("Pushing changes...").start();
1024
1154
  try {
1025
- const result = await api.updateBlueprint(blueprintId, { content });
1155
+ const updateData = { content };
1156
+ if (expectedChecksum && !options.force) {
1157
+ updateData.expected_checksum = expectedChecksum;
1158
+ }
1159
+ const result = await api.updateBlueprint(blueprintId, updateData);
1026
1160
  spinner.succeed("Blueprint updated!");
1027
1161
  await updateChecksum(cwd, file, content);
1028
1162
  console.log();
1029
1163
  console.log(chalk6.green(`\u2705 Successfully updated ${chalk6.bold(result.blueprint.name)}`));
1030
1164
  console.log(chalk6.gray(` ID: ${blueprintId}`));
1165
+ if (result.blueprint.content_checksum) {
1166
+ console.log(chalk6.gray(` Checksum: ${result.blueprint.content_checksum}`));
1167
+ }
1031
1168
  console.log(chalk6.gray(` View: https://lynxprompt.com/templates/${blueprintId.replace("bp_", "")}`));
1032
1169
  } catch (error) {
1033
1170
  spinner.fail("Failed to update blueprint");
1171
+ if (error instanceof ApiRequestError && error.statusCode === 409) {
1172
+ console.log();
1173
+ console.log(chalk6.yellow("\u26A0 Conflict: The blueprint has been modified since you last pulled it."));
1174
+ console.log(chalk6.gray(" Someone else may have pushed changes."));
1175
+ console.log();
1176
+ console.log(chalk6.gray("Options:"));
1177
+ console.log(chalk6.gray(" 1. Run 'lynxp pull " + blueprintId + "' to get the latest version"));
1178
+ console.log(chalk6.gray(" 2. Run 'lynxp push --force' to overwrite remote changes"));
1179
+ process.exit(1);
1180
+ }
1034
1181
  handleError(error);
1035
1182
  }
1036
1183
  }
@@ -1087,6 +1234,10 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
1087
1234
  name = filename.replace(/\.(md|mdc|json|yml|yaml)$/, "");
1088
1235
  }
1089
1236
  const hierarchyInfo = await detectHierarchyInfo(cwd, file);
1237
+ let hierarchyId = null;
1238
+ if (hierarchyInfo.repositoryPath) {
1239
+ hierarchyId = await ensureHierarchy(cwd, hierarchyInfo.repositoryRoot, path.basename(cwd));
1240
+ }
1090
1241
  const spinner = ora5("Creating blueprint...").start();
1091
1242
  try {
1092
1243
  const result = await api.createBlueprint({
@@ -1096,9 +1247,9 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
1096
1247
  visibility,
1097
1248
  tags,
1098
1249
  // Include hierarchy info if detected
1250
+ hierarchy_id: hierarchyId,
1099
1251
  parent_id: hierarchyInfo.parentId,
1100
- repository_path: hierarchyInfo.repositoryPath,
1101
- repository_root: hierarchyInfo.repositoryRoot
1252
+ repository_path: hierarchyInfo.repositoryPath
1102
1253
  });
1103
1254
  spinner.succeed("Blueprint created!");
1104
1255
  await trackBlueprint(cwd, {
@@ -1115,6 +1266,9 @@ async function createOrLinkBlueprint(cwd, file, filename, content, options) {
1115
1266
  if (hierarchyInfo.repositoryPath) {
1116
1267
  console.log(chalk6.gray(` Path: ${hierarchyInfo.repositoryPath}`));
1117
1268
  }
1269
+ if (result.blueprint.hierarchy_id) {
1270
+ console.log(chalk6.gray(` Hierarchy: ${result.blueprint.hierarchy_id}`));
1271
+ }
1118
1272
  if (hierarchyInfo.parentId) {
1119
1273
  console.log(chalk6.cyan(` \u21B3 Linked to parent blueprint: ${hierarchyInfo.parentId}`));
1120
1274
  }
@@ -3024,7 +3178,7 @@ function generateYamlConfig(options, platform2) {
3024
3178
 
3025
3179
  // src/commands/wizard.ts
3026
3180
  var DRAFTS_DIR = ".lynxprompt/drafts";
3027
- var CLI_VERSION = "1.1.0";
3181
+ var CLI_VERSION = "1.2.0";
3028
3182
  async function saveDraftLocally(name, config2, stepReached) {
3029
3183
  const draftsPath = join4(process.cwd(), DRAFTS_DIR);
3030
3184
  await mkdir3(draftsPath, { recursive: true });
@@ -7599,8 +7753,76 @@ async function saveHierarchyInfo(rootPath, result) {
7599
7753
  }
7600
7754
  }
7601
7755
 
7756
+ // src/commands/hierarchies.ts
7757
+ import chalk17 from "chalk";
7758
+ import ora15 from "ora";
7759
+ async function hierarchiesCommand(options) {
7760
+ if (!isAuthenticated()) {
7761
+ console.log(chalk17.yellow("You need to be logged in to view hierarchies."));
7762
+ console.log(chalk17.gray("Run 'lynxp login' to authenticate."));
7763
+ process.exit(1);
7764
+ }
7765
+ const spinner = ora15("Fetching hierarchies...").start();
7766
+ try {
7767
+ const response = await api.listHierarchies({
7768
+ limit: options.limit || 50
7769
+ });
7770
+ spinner.stop();
7771
+ if (options.json) {
7772
+ console.log(JSON.stringify(response, null, 2));
7773
+ return;
7774
+ }
7775
+ const { hierarchies, total } = response;
7776
+ if (hierarchies.length === 0) {
7777
+ console.log();
7778
+ console.log(chalk17.yellow("No hierarchies found."));
7779
+ console.log();
7780
+ console.log(chalk17.gray("Hierarchies are created automatically when you push AGENTS.md files from a repository."));
7781
+ console.log(chalk17.gray("Run 'lynxp push AGENTS.md' in a git repository to create a hierarchy."));
7782
+ console.log();
7783
+ return;
7784
+ }
7785
+ console.log();
7786
+ console.log(chalk17.cyan(`\u{1F4C1} Your Hierarchies (${total} total)`));
7787
+ console.log();
7788
+ for (const hierarchy of hierarchies) {
7789
+ console.log(chalk17.bold(` ${hierarchy.name}`));
7790
+ console.log(chalk17.gray(` ID: ${hierarchy.id}`));
7791
+ if (hierarchy.description) {
7792
+ console.log(chalk17.gray(` ${hierarchy.description}`));
7793
+ }
7794
+ console.log(chalk17.gray(` Blueprints: ${hierarchy.blueprint_count || 0}`));
7795
+ console.log(chalk17.gray(` Repository: ${hierarchy.repository_root.slice(0, 16)}...`));
7796
+ console.log();
7797
+ }
7798
+ console.log(chalk17.gray("\u2500".repeat(50)));
7799
+ console.log();
7800
+ console.log(chalk17.gray("Tips:"));
7801
+ console.log(chalk17.gray(` \u2022 Pull entire hierarchy: lynxp pull <hierarchy_id>`));
7802
+ console.log(chalk17.gray(` \u2022 View hierarchy details: lynxp hierarchy <hierarchy_id>`));
7803
+ console.log(chalk17.gray(` \u2022 Sync local changes: lynxp sync`));
7804
+ console.log();
7805
+ } catch (error) {
7806
+ spinner.fail("Failed to fetch hierarchies");
7807
+ handleError2(error);
7808
+ }
7809
+ }
7810
+ function handleError2(error) {
7811
+ if (error instanceof ApiRequestError) {
7812
+ console.error(chalk17.red(`Error: ${error.message}`));
7813
+ if (error.statusCode === 401) {
7814
+ console.error(chalk17.gray("Your session may have expired. Run 'lynxp login' to re-authenticate."));
7815
+ } else if (error.statusCode === 403) {
7816
+ console.error(chalk17.gray("You don't have permission to access hierarchies."));
7817
+ }
7818
+ } else {
7819
+ console.error(chalk17.red("An unexpected error occurred."));
7820
+ }
7821
+ process.exit(1);
7822
+ }
7823
+
7602
7824
  // src/index.ts
7603
- var CLI_VERSION2 = "1.1.0";
7825
+ var CLI_VERSION2 = "1.2.0";
7604
7826
  var program = new Command();
7605
7827
  program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
7606
7828
  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);
@@ -7610,10 +7832,11 @@ program.command("convert [source] <target>").description("Convert AI config betw
7610
7832
  program.command("merge <files...>").description("Merge multiple AI configuration files into one").option("-o, --output <file>", "Output filename (default: merged.md)").option("-s, --strategy <type>", "Merge strategy: concat, sections, smart (default: smart)").option("-f, --force", "Overwrite existing output file").option("-i, --interactive", "Review and select sections to include").action(mergeCommand);
7611
7833
  program.command("import [path]").description("Scan and import AGENTS.md files from a repository").option("--dry-run", "Preview what would be imported without changes").option("--no-recursive", "Don't scan subdirectories").option("--depth <n>", "Max directory depth to scan", "10").option("--pattern <file>", "Custom config filename to look for").option("--link", "Link imported files to cloud (requires login)").option("-v, --verbose", "Show detailed section information").option("-j, --json", "Output as JSON").action(importCommand);
7612
7834
  program.command("status").description("Show current AI configuration and tracked blueprints").action(statusCommand);
7613
- 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);
7835
+ program.command("pull <id>").description("Download a blueprint (bp_xxx) or entire hierarchy (ha_xxx)").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);
7614
7836
  program.command("search <query>").description("Search public blueprints in the marketplace").option("-l, --limit <number>", "Number of results", "20").action(searchCommand);
7615
7837
  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);
7616
- 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);
7838
+ 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").option("-f, --force", "Force push (overwrite remote changes)").action(pushCommand);
7839
+ program.command("hierarchies").description("List your blueprint hierarchies (monorepo groupings)").option("-l, --limit <number>", "Number of results", "50").option("-j, --json", "Output as JSON").action(hierarchiesCommand);
7617
7840
  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);
7618
7841
  program.command("unlink [file]").description("Disconnect a local file from its cloud blueprint").action(unlinkCommand);
7619
7842
  program.command("diff [file-or-id]").description("Compare tracked files with their cloud blueprints").option("--local", "Compare .lynxprompt/rules/ with exported files").action(diffCommand);
@@ -7623,42 +7846,44 @@ program.command("whoami").description("Show current authenticated user").action(
7623
7846
  program.addHelpText(
7624
7847
  "beforeAll",
7625
7848
  `
7626
- ${chalk17.cyan("\u{1F431} LynxPrompt CLI")} ${chalk17.gray("(also available as: lynxp)")}
7627
- ${chalk17.gray("Generate AI IDE configuration files from your terminal")}
7849
+ ${chalk18.cyan("\u{1F431} LynxPrompt CLI")} ${chalk18.gray("(also available as: lynxp)")}
7850
+ ${chalk18.gray("Generate AI IDE configuration files from your terminal")}
7628
7851
  `
7629
7852
  );
7630
7853
  program.addHelpText(
7631
7854
  "after",
7632
7855
  `
7633
- ${chalk17.cyan("Quick Start:")}
7634
- ${chalk17.white("$ lynxp wizard")} ${chalk17.gray("Generate config interactively")}
7635
- ${chalk17.white("$ lynxp wizard -y")} ${chalk17.gray("Generate AGENTS.md with defaults")}
7636
- ${chalk17.white("$ lynxp wizard -f cursor")} ${chalk17.gray("Generate .cursor/rules/")}
7637
- ${chalk17.white("$ lynxp wizard --blueprint")} ${chalk17.gray("Generate with [[VAR|default]] placeholders")}
7856
+ ${chalk18.cyan("Quick Start:")}
7857
+ ${chalk18.white("$ lynxp wizard")} ${chalk18.gray("Generate config interactively")}
7858
+ ${chalk18.white("$ lynxp wizard -y")} ${chalk18.gray("Generate AGENTS.md with defaults")}
7859
+ ${chalk18.white("$ lynxp wizard -f cursor")} ${chalk18.gray("Generate .cursor/rules/")}
7860
+ ${chalk18.white("$ lynxp wizard --blueprint")} ${chalk18.gray("Generate with [[VAR|default]] placeholders")}
7638
7861
 
7639
- ${chalk17.cyan("Analysis & Tools:")}
7640
- ${chalk17.white("$ lynxp analyze")} ${chalk17.gray("Analyze project tech stack")}
7641
- ${chalk17.white("$ lynxp analyze -r <url>")} ${chalk17.gray("Analyze remote repository")}
7642
- ${chalk17.white("$ lynxp import")} ${chalk17.gray("Scan repo for AGENTS.md files")}
7643
- ${chalk17.white("$ lynxp import --dry-run")} ${chalk17.gray("Preview monorepo hierarchy")}
7644
- ${chalk17.white("$ lynxp convert AGENTS.md cursor")} ${chalk17.gray("Convert to Cursor format")}
7645
- ${chalk17.white("$ lynxp merge a.md b.md -o out.md")} ${chalk17.gray("Merge multiple configs")}
7862
+ ${chalk18.cyan("Analysis & Tools:")}
7863
+ ${chalk18.white("$ lynxp analyze")} ${chalk18.gray("Analyze project tech stack")}
7864
+ ${chalk18.white("$ lynxp analyze -r <url>")} ${chalk18.gray("Analyze remote repository")}
7865
+ ${chalk18.white("$ lynxp import")} ${chalk18.gray("Scan repo for AGENTS.md files")}
7866
+ ${chalk18.white("$ lynxp import --dry-run")} ${chalk18.gray("Preview monorepo hierarchy")}
7867
+ ${chalk18.white("$ lynxp convert AGENTS.md cursor")} ${chalk18.gray("Convert to Cursor format")}
7868
+ ${chalk18.white("$ lynxp merge a.md b.md -o out.md")} ${chalk18.gray("Merge multiple configs")}
7646
7869
 
7647
- ${chalk17.cyan("Marketplace:")}
7648
- ${chalk17.white("$ lynxp search nextjs")} ${chalk17.gray("Search blueprints")}
7649
- ${chalk17.white("$ lynxp pull bp_abc123")} ${chalk17.gray("Download and track a blueprint")}
7650
- ${chalk17.white("$ lynxp push")} ${chalk17.gray("Push local file to cloud")}
7651
- ${chalk17.white("$ lynxp link --list")} ${chalk17.gray("Show tracked blueprints")}
7870
+ ${chalk18.cyan("Marketplace:")}
7871
+ ${chalk18.white("$ lynxp search nextjs")} ${chalk18.gray("Search blueprints")}
7872
+ ${chalk18.white("$ lynxp pull bp_abc123")} ${chalk18.gray("Download and track a blueprint")}
7873
+ ${chalk18.white("$ lynxp pull ha_xyz789")} ${chalk18.gray("Download entire hierarchy")}
7874
+ ${chalk18.white("$ lynxp push")} ${chalk18.gray("Push local file to cloud")}
7875
+ ${chalk18.white("$ lynxp hierarchies")} ${chalk18.gray("List your hierarchies")}
7876
+ ${chalk18.white("$ lynxp link --list")} ${chalk18.gray("Show tracked blueprints")}
7652
7877
 
7653
- ${chalk17.cyan("Blueprint Tracking:")}
7654
- ${chalk17.white("$ lynxp link AGENTS.md bp_xyz")} ${chalk17.gray("Link existing file to blueprint")}
7655
- ${chalk17.white("$ lynxp unlink AGENTS.md")} ${chalk17.gray("Disconnect from cloud")}
7656
- ${chalk17.white("$ lynxp diff bp_abc123")} ${chalk17.gray("Show changes vs cloud version")}
7878
+ ${chalk18.cyan("Blueprint Tracking:")}
7879
+ ${chalk18.white("$ lynxp link AGENTS.md bp_xyz")} ${chalk18.gray("Link existing file to blueprint")}
7880
+ ${chalk18.white("$ lynxp unlink AGENTS.md")} ${chalk18.gray("Disconnect from cloud")}
7881
+ ${chalk18.white("$ lynxp diff bp_abc123")} ${chalk18.gray("Show changes vs cloud version")}
7657
7882
 
7658
- ${chalk17.cyan("CI/CD:")}
7659
- ${chalk17.white("$ lynxp check --ci")} ${chalk17.gray("Validate config (exit code)")}
7883
+ ${chalk18.cyan("CI/CD:")}
7884
+ ${chalk18.white("$ lynxp check --ci")} ${chalk18.gray("Validate config (exit code)")}
7660
7885
 
7661
- ${chalk17.gray("Docs: https://lynxprompt.com/docs/cli")}
7886
+ ${chalk18.gray("Docs: https://lynxprompt.com/docs/cli")}
7662
7887
  `
7663
7888
  );
7664
7889
  program.parse();