lynxprompt 2.1.39 → 2.1.40

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 chalk20 from "chalk";
5
+ import chalk21 from "chalk";
6
6
 
7
7
  // src/commands/login.ts
8
8
  import chalk from "chalk";
@@ -32,8 +32,7 @@ var config = new Conf({
32
32
  properties: {
33
33
  id: { type: "string" },
34
34
  email: { type: "string" },
35
- name: { type: ["string", "null"] },
36
- plan: { type: "string" }
35
+ name: { type: ["string", "null"] }
37
36
  }
38
37
  }
39
38
  },
@@ -546,8 +545,7 @@ async function whoamiCommand() {
546
545
  setUser({
547
546
  id: user.id,
548
547
  email: user.email,
549
- name: user.name,
550
- plan: user.plan
548
+ name: user.name
551
549
  });
552
550
  console.log();
553
551
  console.log(chalk3.cyan("\u{1F431} LynxPrompt Account"));
@@ -735,7 +733,11 @@ async function trackBlueprint(cwd, blueprint) {
735
733
  canPull,
736
734
  hierarchyId: blueprint.hierarchyId,
737
735
  hierarchyName: blueprint.hierarchyName,
738
- repositoryPath: blueprint.repositoryPath
736
+ repositoryPath: blueprint.repositoryPath,
737
+ ...blueprint.variables ? {
738
+ variables: blueprint.variables,
739
+ localChecksum: calculateChecksum(blueprint.localContent ?? blueprint.content)
740
+ } : {}
739
741
  });
740
742
  await saveBlueprints(cwd, config2);
741
743
  }
@@ -748,7 +750,7 @@ async function hasLocalChanges(cwd, tracked) {
748
750
  const filePath = join(cwd, tracked.file);
749
751
  const content = await readFile(filePath, "utf-8");
750
752
  const currentChecksum = calculateChecksum(content);
751
- return currentChecksum !== tracked.checksum;
753
+ return currentChecksum !== (tracked.localChecksum ?? tracked.checksum);
752
754
  } catch {
753
755
  return false;
754
756
  }
@@ -758,10 +760,15 @@ async function updateChecksum(cwd, file, content) {
758
760
  const blueprint = config2.blueprints.find((b) => sameFile(cwd, b.file, file));
759
761
  if (blueprint) {
760
762
  blueprint.checksum = calculateChecksum(content);
763
+ delete blueprint.variables;
764
+ delete blueprint.localChecksum;
761
765
  blueprint.pulledAt = (/* @__PURE__ */ new Date()).toISOString();
762
766
  await saveBlueprints(cwd, config2);
763
767
  }
764
768
  }
769
+ function conflictFilePath(cwd, file) {
770
+ return join(cwd, `${file}.remote`);
771
+ }
765
772
  async function untrackBlueprint(cwd, file) {
766
773
  const config2 = await loadBlueprints(cwd);
767
774
  const initialCount = config2.blueprints.length;
@@ -2981,7 +2988,35 @@ function matchConfigFile(relativePath) {
2981
2988
  return null;
2982
2989
  }
2983
2990
 
2991
+ // src/utils/variables.ts
2992
+ var VARIABLE_PATTERN_SOURCE = String.raw`\[\[([A-Za-z_][A-Za-z0-9_]*)(?:\|((?:(?!\[\[)[\s\S])*?)\]\](?!\])|\]\])`;
2993
+ function fillBlueprintVariables(content, values) {
2994
+ const missing = /* @__PURE__ */ new Set();
2995
+ const filled = content.replace(
2996
+ new RegExp(VARIABLE_PATTERN_SOURCE, "g"),
2997
+ (match, name, fallback) => {
2998
+ const key = name.toUpperCase();
2999
+ if (Object.prototype.hasOwnProperty.call(values, key)) return values[key];
3000
+ if (fallback !== void 0) return fallback;
3001
+ missing.add(key);
3002
+ return match;
3003
+ }
3004
+ );
3005
+ return { content: filled, missing: [...missing] };
3006
+ }
3007
+
2984
3008
  // src/commands/pull.ts
3009
+ function contentToWrite(content, options, label) {
3010
+ if (options.vars === void 0) return content;
3011
+ const { content: filled, missing } = fillBlueprintVariables(content, parseVariablesString(options.vars));
3012
+ if (missing.length > 0) {
3013
+ console.log(chalk5.yellow(` \u26A0 ${label}: no value for ${missing.join(", ")} (left as [[...]])`));
3014
+ }
3015
+ return filled;
3016
+ }
3017
+ function pulledVariables(options, written, content) {
3018
+ return options.vars === void 0 || written === content ? void 0 : parseVariablesString(options.vars);
3019
+ }
2985
3020
  function getSourceFromVisibility(visibility) {
2986
3021
  switch (visibility) {
2987
3022
  case "PUBLIC":
@@ -3087,7 +3122,8 @@ async function pullHierarchy(id, options) {
3087
3122
  if (dir !== "." && dir !== options.output) {
3088
3123
  await mkdir2(dir, { recursive: true });
3089
3124
  }
3090
- await writeFile2(outputPath, blueprint.content, "utf-8");
3125
+ const written = contentToWrite(blueprint.content, options, filename);
3126
+ await writeFile2(outputPath, written, "utf-8");
3091
3127
  if (options.track !== false) {
3092
3128
  const source = getSourceFromVisibility(blueprint.visibility);
3093
3129
  await trackBlueprint(cwd, {
@@ -3099,7 +3135,9 @@ async function pullHierarchy(id, options) {
3099
3135
  source,
3100
3136
  hierarchyId: id,
3101
3137
  hierarchyName: hierarchy.name,
3102
- repositoryPath: bp.repository_path || void 0
3138
+ repositoryPath: bp.repository_path || void 0,
3139
+ localContent: written,
3140
+ variables: pulledVariables(options, written, blueprint.content)
3103
3141
  });
3104
3142
  }
3105
3143
  console.log(chalk5.green(` \u2713 ${filename}`));
@@ -3268,7 +3306,8 @@ async function pullBlueprint(id, options) {
3268
3306
  if (dir !== ".") {
3269
3307
  await mkdir2(dir, { recursive: true });
3270
3308
  }
3271
- await writeFile2(outputPath, blueprint.content, "utf-8");
3309
+ const written = contentToWrite(blueprint.content, options, filename);
3310
+ await writeFile2(outputPath, written, "utf-8");
3272
3311
  if (options.track !== false) {
3273
3312
  await trackBlueprint(cwd, {
3274
3313
  id: blueprint.id,
@@ -3277,7 +3316,9 @@ async function pullBlueprint(id, options) {
3277
3316
  content: blueprint.content,
3278
3317
  source,
3279
3318
  hierarchyId: blueprint.hierarchy_id || void 0,
3280
- repositoryPath: blueprint.repository_path || void 0
3319
+ repositoryPath: blueprint.repository_path || void 0,
3320
+ localContent: written,
3321
+ variables: pulledVariables(options, written, blueprint.content)
3281
3322
  });
3282
3323
  }
3283
3324
  console.log(chalk5.green(`\u2705 Downloaded: ${chalk5.bold(outputPath)}`));
@@ -3286,8 +3327,8 @@ async function pullBlueprint(id, options) {
3286
3327
  if (blueprint.content_checksum) {
3287
3328
  console.log(chalk5.gray(` Checksum: ${blueprint.content_checksum}`));
3288
3329
  }
3289
- if (isMarketplace) {
3290
- console.log(chalk5.gray(` Updates: Run 'lynxp pull ${id}' to sync updates`));
3330
+ if (isMarketplace || options.vars !== void 0) {
3331
+ console.log(chalk5.gray(` Updates: Run 'lynxp sync ${trackedFile}' to get cloud updates`));
3291
3332
  } else {
3292
3333
  console.log(chalk5.gray(` Sync: Run 'lynxp push ${trackedFile}' to push changes`));
3293
3334
  }
@@ -3629,11 +3670,26 @@ async function pushCommand(fileArg, options) {
3629
3670
  const filename = path2.basename(file);
3630
3671
  const linked = await findBlueprintByFile(cwd, file);
3631
3672
  if (linked) {
3673
+ const refusal = refusePush(cwd, linked, options);
3674
+ if (refusal) {
3675
+ console.log(chalk6.yellow(`\u26A0 Not pushed: ${refusal}`));
3676
+ process.exit(1);
3677
+ }
3632
3678
  await updateBlueprint(cwd, file, linked.id, content, options, linked.checksum);
3633
3679
  } else {
3634
3680
  await createOrLinkBlueprint(cwd, file, filename, content, options, fileArg !== void 0);
3635
3681
  }
3636
3682
  }
3683
+ function refusePush(cwd, tracked, options) {
3684
+ if (options.force) return null;
3685
+ if (fs.existsSync(conflictFilePath(cwd, tracked.file))) {
3686
+ return `${tracked.file} has an unresolved sync conflict. Merge ${tracked.file}.remote into it and delete ${tracked.file}.remote first, or use --force.`;
3687
+ }
3688
+ if (tracked.variables) {
3689
+ return `${tracked.file} was pulled with --vars, so pushing it would replace the blueprint's variables with your values. Use --force to push it anyway.`;
3690
+ }
3691
+ return null;
3692
+ }
3637
3693
  async function updateBlueprint(cwd, file, blueprintId, content, options, expectedChecksum) {
3638
3694
  console.log(chalk6.cyan(`
3639
3695
  \u{1F4E4} Updating blueprint ${chalk6.bold(blueprintId)}...`));
@@ -3924,6 +3980,11 @@ async function pushHierarchy(cwd, files, options) {
3924
3980
  const content = fs.readFileSync(file.absolutePath, "utf-8");
3925
3981
  const tracked = await findBlueprintByFile(cwd, file.path);
3926
3982
  if (tracked) {
3983
+ const refusal = refusePush(cwd, tracked, options);
3984
+ if (refusal) {
3985
+ spinner.warn(`${file.path} \u2192 skipped: ${refusal}`);
3986
+ continue;
3987
+ }
3927
3988
  const updateData = { content };
3928
3989
  if (tracked.checksum && !options.force) {
3929
3990
  updateData.expected_checksum = tracked.checksum;
@@ -6591,7 +6652,7 @@ var TEST_FRAMEWORKS2 = TEST_FRAMEWORKS;
6591
6652
 
6592
6653
  // src/commands/wizard.ts
6593
6654
  var DRAFTS_DIR = ".lynxprompt/drafts";
6594
- var CLI_VERSION = "2.1.39";
6655
+ var CLI_VERSION = "2.1.40";
6595
6656
  async function saveDraftLocally(name, config2, stepReached) {
6596
6657
  const draftsPath = join3(process.cwd(), DRAFTS_DIR);
6597
6658
  await mkdir3(draftsPath, { recursive: true });
@@ -10106,6 +10167,8 @@ async function statusCommand() {
10106
10167
  console.log();
10107
10168
  }
10108
10169
  }
10170
+ console.log(chalk9.gray(" \u2713 means no local edits. Run 'lynxp sync --dry-run' to check the cloud too."));
10171
+ console.log();
10109
10172
  }
10110
10173
  console.log(chalk9.cyan("\u{1F4C4} AI Config Files"));
10111
10174
  console.log();
@@ -10555,7 +10618,7 @@ async function diffCommand(fileOrId, options = {}) {
10555
10618
  if (fileOrId) {
10556
10619
  const tracked = await findBlueprintByFile(cwd, fileOrId);
10557
10620
  if (tracked) {
10558
- await diffFileWithBlueprint(cwd, fileOrId, tracked.id);
10621
+ await diffFileWithBlueprint(cwd, fileOrId, tracked.id, false, tracked.variables);
10559
10622
  return;
10560
10623
  }
10561
10624
  await diffWithBlueprintId(cwd, fileOrId);
@@ -10581,7 +10644,7 @@ async function diffCommand(fileOrId, options = {}) {
10581
10644
  }
10582
10645
  console.log(chalk12.cyan(`\u{1F4C4} ${blueprint.file}`));
10583
10646
  console.log(chalk12.gray(` Linked to: ${blueprint.name} (${blueprint.id})`));
10584
- const result = await diffFileWithBlueprint(cwd, blueprint.file, blueprint.id, true);
10647
+ const result = await diffFileWithBlueprint(cwd, blueprint.file, blueprint.id, true, blueprint.variables);
10585
10648
  if (result === "changed") {
10586
10649
  hasChanges = true;
10587
10650
  } else if (result === "same") {
@@ -10596,12 +10659,11 @@ async function diffCommand(fileOrId, options = {}) {
10596
10659
  } else if (!hasChanges) {
10597
10660
  console.log(chalk12.green("\u2713 All tracked files are in sync with their cloud blueprints!"));
10598
10661
  } else {
10599
- console.log(chalk12.gray("To push local changes: lynxp push"));
10600
- console.log(chalk12.gray("To pull cloud changes: lynxp pull <id>"));
10662
+ console.log(chalk12.gray("To bring both sides together: lynxp sync"));
10601
10663
  }
10602
10664
  console.log();
10603
10665
  }
10604
- async function diffFileWithBlueprint(cwd, file, blueprintId, compact = false) {
10666
+ async function diffFileWithBlueprint(cwd, file, blueprintId, compact = false, variables) {
10605
10667
  const filePath = join6(cwd, file);
10606
10668
  if (!existsSync4(filePath)) {
10607
10669
  console.log(chalk12.red(`\u2717 File not found: ${file}`));
@@ -10616,7 +10678,8 @@ async function diffFileWithBlueprint(cwd, file, blueprintId, compact = false) {
10616
10678
  return "error";
10617
10679
  }
10618
10680
  const localContent = await readFile7(filePath, "utf-8");
10619
- const diff = computeDiff(blueprint.content, localContent);
10681
+ const cloudContent = variables ? fillBlueprintVariables(blueprint.content, variables).content : blueprint.content;
10682
+ const diff = computeDiff(cloudContent, localContent);
10620
10683
  const stats = getDiffStats(diff);
10621
10684
  if (stats.added === 0 && stats.removed === 0) {
10622
10685
  if (!compact) {
@@ -10783,12 +10846,162 @@ async function diffLocal(cwd) {
10783
10846
  console.log();
10784
10847
  }
10785
10848
 
10786
- // src/commands/link.ts
10849
+ // src/commands/sync.ts
10787
10850
  import chalk13 from "chalk";
10851
+ import { readFile as readFile8, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
10852
+ import { existsSync as existsSync5 } from "fs";
10853
+ import { dirname as dirname4, join as join7 } from "path";
10854
+ async function syncCommand(fileArg, options = {}) {
10855
+ const cwd = process.cwd();
10856
+ if (!isAuthenticated()) {
10857
+ console.log(chalk13.yellow("Not logged in. Run 'lynxp login' to authenticate."));
10858
+ process.exit(1);
10859
+ }
10860
+ const { blueprints } = await loadBlueprints(cwd);
10861
+ const targets = fileArg ? blueprints.filter((b) => toTrackedPath(cwd, b.file) === toTrackedPath(cwd, fileArg)) : blueprints;
10862
+ if (targets.length === 0) {
10863
+ console.log(
10864
+ chalk13.yellow(fileArg ? `${fileArg} is not tracked.` : "No tracked blueprints found.")
10865
+ );
10866
+ console.log(chalk13.gray("Track a file with 'lynxp pull <id>' or 'lynxp link <file> <id>'."));
10867
+ if (fileArg) process.exit(1);
10868
+ return;
10869
+ }
10870
+ console.log();
10871
+ console.log(chalk13.cyan(options.dryRun ? "\u{1F431} LynxPrompt Sync (dry run)" : "\u{1F431} LynxPrompt Sync"));
10872
+ console.log();
10873
+ const counts = {
10874
+ "in-sync": 0,
10875
+ pulled: 0,
10876
+ pushed: 0,
10877
+ kept: 0,
10878
+ conflict: 0,
10879
+ error: 0
10880
+ };
10881
+ for (const tracked of targets) {
10882
+ counts[await syncOne(cwd, tracked, options)]++;
10883
+ }
10884
+ console.log();
10885
+ const parts = [
10886
+ `${counts.pulled} pulled`,
10887
+ `${counts.pushed} pushed`,
10888
+ `${counts["in-sync"]} in sync`
10889
+ ];
10890
+ if (counts.kept) parts.push(`${counts.kept} local only`);
10891
+ if (counts.conflict) parts.push(`${counts.conflict} conflict`);
10892
+ if (counts.error) parts.push(`${counts.error} failed`);
10893
+ console.log(chalk13.gray(`${options.dryRun ? "Would be: " : ""}${parts.join(", ")}`));
10894
+ console.log();
10895
+ if (counts.conflict || counts.error) process.exitCode = 1;
10896
+ }
10897
+ async function syncOne(cwd, tracked, options) {
10898
+ const file = tracked.file;
10899
+ const filePath = join7(cwd, file);
10900
+ const remoteFile = conflictFilePath(cwd, file);
10901
+ const dry = options.dryRun === true;
10902
+ if (existsSync5(remoteFile)) {
10903
+ console.log(chalk13.red(`\u2717 ${file}: unresolved conflict`));
10904
+ console.log(chalk13.gray(` Merge ${file}.remote into ${file}, delete ${file}.remote, then run 'lynxp sync' again.`));
10905
+ return "conflict";
10906
+ }
10907
+ if (!existsSync5(filePath)) {
10908
+ console.log(chalk13.red(`\u2717 ${file}: file not found`));
10909
+ console.log(chalk13.gray(` Run 'lynxp pull ${tracked.id}' to restore it or 'lynxp unlink ${file}' to stop tracking it.`));
10910
+ return "error";
10911
+ }
10912
+ let remote;
10913
+ try {
10914
+ const { blueprint } = await api.getBlueprint(tracked.id);
10915
+ if (!blueprint?.content) {
10916
+ console.log(chalk13.red(`\u2717 ${file}: the cloud blueprint ${tracked.id} has no content`));
10917
+ return "error";
10918
+ }
10919
+ remote = blueprint.content;
10920
+ } catch (error) {
10921
+ console.log(chalk13.red(`\u2717 ${file}: could not fetch ${tracked.id}: ${errorText(error)}`));
10922
+ return "error";
10923
+ }
10924
+ const local = await readFile8(filePath, "utf-8");
10925
+ const rendered = tracked.variables ? fillBlueprintVariables(remote, tracked.variables).content : remote;
10926
+ const localChanged = calculateChecksum(local) !== (tracked.localChecksum ?? tracked.checksum);
10927
+ const remoteChanged = calculateChecksum(remote) !== tracked.checksum;
10928
+ if (calculateChecksum(local) === calculateChecksum(rendered)) {
10929
+ if (!dry && (localChanged || remoteChanged)) await record(cwd, tracked, remote, local);
10930
+ console.log(chalk13.green(`\u2713 ${file}: in sync`));
10931
+ return "in-sync";
10932
+ }
10933
+ if (!localChanged) {
10934
+ if (!dry) {
10935
+ await writeFile4(filePath, rendered, "utf-8");
10936
+ await record(cwd, tracked, remote, rendered);
10937
+ }
10938
+ console.log(chalk13.cyan(`\u2193 ${file}: ${dry ? "would update from the cloud" : "updated from the cloud"}`));
10939
+ return "pulled";
10940
+ }
10941
+ if (!remoteChanged) {
10942
+ const reason = tracked.variables ? "it was pulled with --vars, so pushing it would replace the blueprint's variables with your values" : !tracked.editable ? "marketplace blueprints are read-only" : null;
10943
+ if (reason) {
10944
+ console.log(chalk13.yellow(`\u25CF ${file}: local changes kept, not pushed (${reason})`));
10945
+ return "kept";
10946
+ }
10947
+ if (dry) {
10948
+ console.log(chalk13.cyan(`\u2191 ${file}: would push local changes`));
10949
+ return "pushed";
10950
+ }
10951
+ try {
10952
+ await api.updateBlueprint(tracked.id, { content: local, expected_checksum: tracked.checksum });
10953
+ await updateChecksum(cwd, file, local);
10954
+ console.log(chalk13.cyan(`\u2191 ${file}: pushed local changes`));
10955
+ return "pushed";
10956
+ } catch (error) {
10957
+ if (error instanceof ApiRequestError && error.statusCode === 409) {
10958
+ console.log(chalk13.red(`\u2717 ${file}: the cloud changed while syncing; run 'lynxp sync' again`));
10959
+ } else {
10960
+ console.log(chalk13.red(`\u2717 ${file}: push failed: ${errorText(error)}`));
10961
+ console.log(chalk13.gray(` Try 'lynxp push ${file}' for the full prompts.`));
10962
+ }
10963
+ return "error";
10964
+ }
10965
+ }
10966
+ if (!dry) {
10967
+ await mkdir4(dirname4(remoteFile), { recursive: true });
10968
+ await writeFile4(remoteFile, rendered, "utf-8");
10969
+ await record(cwd, tracked, remote, rendered);
10970
+ }
10971
+ console.log(chalk13.red(`\u2717 ${file}: changed both locally and in the cloud`));
10972
+ console.log(
10973
+ chalk13.gray(
10974
+ dry ? ` Sync would write the cloud version to ${file}.remote and leave ${file} as it is.` : ` Cloud version written to ${file}.remote; ${file} was not touched.
10975
+ Merge what you need into ${file}, delete ${file}.remote, then run 'lynxp sync' again.`
10976
+ )
10977
+ );
10978
+ return "conflict";
10979
+ }
10980
+ async function record(cwd, t, remote, written) {
10981
+ await trackBlueprint(cwd, {
10982
+ id: t.id,
10983
+ name: t.name,
10984
+ file: t.file,
10985
+ content: remote,
10986
+ source: t.source,
10987
+ version: t.version,
10988
+ hierarchyId: t.hierarchyId,
10989
+ hierarchyName: t.hierarchyName,
10990
+ repositoryPath: t.repositoryPath,
10991
+ variables: t.variables,
10992
+ localContent: t.variables ? written : void 0
10993
+ });
10994
+ }
10995
+ function errorText(error) {
10996
+ return error instanceof Error ? error.message : String(error);
10997
+ }
10998
+
10999
+ // src/commands/link.ts
11000
+ import chalk14 from "chalk";
10788
11001
  import ora10 from "ora";
10789
11002
  import prompts4 from "prompts";
10790
- import { join as join7 } from "path";
10791
- import { existsSync as existsSync5 } from "fs";
11003
+ import { join as join8 } from "path";
11004
+ import { existsSync as existsSync6 } from "fs";
10792
11005
  function getSourceFromVisibility2(visibility) {
10793
11006
  switch (visibility) {
10794
11007
  case "PUBLIC":
@@ -10808,7 +11021,7 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10808
11021
  return;
10809
11022
  }
10810
11023
  console.log();
10811
- console.log(chalk13.cyan("\u{1F431} Link File to Blueprint"));
11024
+ console.log(chalk14.cyan("\u{1F431} Link File to Blueprint"));
10812
11025
  console.log();
10813
11026
  let file;
10814
11027
  let blueprintId = blueprintIdArg;
@@ -10822,13 +11035,13 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10822
11035
  ".rules",
10823
11036
  ".clinerules"
10824
11037
  ];
10825
- const foundFiles = configFiles.filter((f) => existsSync5(join7(cwd, f)));
11038
+ const foundFiles = configFiles.filter((f) => existsSync6(join8(cwd, f)));
10826
11039
  if (foundFiles.length === 0) {
10827
- console.log(chalk13.yellow("No AI configuration files found in this directory."));
11040
+ console.log(chalk14.yellow("No AI configuration files found in this directory."));
10828
11041
  console.log();
10829
- console.log(chalk13.gray("Create one first:"));
10830
- console.log(chalk13.gray(" lynxp wizard Generate a new config file"));
10831
- console.log(chalk13.gray(" lynxp pull <id> Download from marketplace"));
11042
+ console.log(chalk14.gray("Create one first:"));
11043
+ console.log(chalk14.gray(" lynxp wizard Generate a new config file"));
11044
+ console.log(chalk14.gray(" lynxp pull <id> Download from marketplace"));
10832
11045
  return;
10833
11046
  }
10834
11047
  const { selectedFile } = await prompts4({
@@ -10842,22 +11055,22 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10842
11055
  }))
10843
11056
  });
10844
11057
  if (!selectedFile) {
10845
- console.log(chalk13.gray("Cancelled."));
11058
+ console.log(chalk14.gray("Cancelled."));
10846
11059
  return;
10847
11060
  }
10848
11061
  file = selectedFile;
10849
11062
  } else {
10850
11063
  file = fileArg;
10851
11064
  }
10852
- const filePath = join7(cwd, file);
10853
- if (!existsSync5(filePath)) {
10854
- console.log(chalk13.red(`\u2717 File not found: ${file}`));
11065
+ const filePath = join8(cwd, file);
11066
+ if (!existsSync6(filePath)) {
11067
+ console.log(chalk14.red(`\u2717 File not found: ${file}`));
10855
11068
  return;
10856
11069
  }
10857
11070
  const existing = await findBlueprintByFile(cwd, file);
10858
11071
  if (existing) {
10859
- console.log(chalk13.yellow(`This file is already linked to: ${existing.name}`));
10860
- console.log(chalk13.gray(` ID: ${existing.id}`));
11072
+ console.log(chalk14.yellow(`This file is already linked to: ${existing.name}`));
11073
+ console.log(chalk14.gray(` ID: ${existing.id}`));
10861
11074
  console.log();
10862
11075
  const { proceed } = await prompts4({
10863
11076
  type: "confirm",
@@ -10866,13 +11079,13 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10866
11079
  initial: false
10867
11080
  });
10868
11081
  if (!proceed) {
10869
- console.log(chalk13.gray("Cancelled."));
11082
+ console.log(chalk14.gray("Cancelled."));
10870
11083
  return;
10871
11084
  }
10872
11085
  }
10873
11086
  if (!blueprintId) {
10874
11087
  if (!isAuthenticated()) {
10875
- console.log(chalk13.yellow("You need to login to access your blueprints."));
11088
+ console.log(chalk14.yellow("You need to login to access your blueprints."));
10876
11089
  const { doLogin } = await prompts4({
10877
11090
  type: "confirm",
10878
11091
  name: "doLogin",
@@ -10880,10 +11093,10 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10880
11093
  initial: true
10881
11094
  });
10882
11095
  if (doLogin) {
10883
- console.log(chalk13.gray("Run 'lynxp login' in another terminal, then come back here."));
11096
+ console.log(chalk14.gray("Run 'lynxp login' in another terminal, then come back here."));
10884
11097
  return;
10885
11098
  }
10886
- console.log(chalk13.gray("Cancelled."));
11099
+ console.log(chalk14.gray("Cancelled."));
10887
11100
  return;
10888
11101
  }
10889
11102
  const { searchMethod } = await prompts4({
@@ -10897,7 +11110,7 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10897
11110
  ]
10898
11111
  });
10899
11112
  if (!searchMethod) {
10900
- console.log(chalk13.gray("Cancelled."));
11113
+ console.log(chalk14.gray("Cancelled."));
10901
11114
  return;
10902
11115
  }
10903
11116
  if (searchMethod === "list") {
@@ -10906,8 +11119,8 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10906
11119
  const blueprints = await api.listAllBlueprints();
10907
11120
  spinner2.stop();
10908
11121
  if (!blueprints || blueprints.length === 0) {
10909
- console.log(chalk13.yellow("You don't have any blueprints yet."));
10910
- console.log(chalk13.gray("Create one with 'lynxp push' or search the marketplace."));
11122
+ console.log(chalk14.yellow("You don't have any blueprints yet."));
11123
+ console.log(chalk14.gray("Create one with 'lynxp push' or search the marketplace."));
10911
11124
  return;
10912
11125
  }
10913
11126
  const { selected } = await prompts4({
@@ -10921,13 +11134,13 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10921
11134
  }))
10922
11135
  });
10923
11136
  if (!selected) {
10924
- console.log(chalk13.gray("Cancelled."));
11137
+ console.log(chalk14.gray("Cancelled."));
10925
11138
  return;
10926
11139
  }
10927
11140
  blueprintId = selected;
10928
11141
  } catch {
10929
11142
  spinner2.stop();
10930
- console.log(chalk13.red("\u2717 Could not fetch blueprints"));
11143
+ console.log(chalk14.red("\u2717 Could not fetch blueprints"));
10931
11144
  return;
10932
11145
  }
10933
11146
  } else if (searchMethod === "search") {
@@ -10937,7 +11150,7 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10937
11150
  message: "Search for:"
10938
11151
  });
10939
11152
  if (!query) {
10940
- console.log(chalk13.gray("Cancelled."));
11153
+ console.log(chalk14.gray("Cancelled."));
10941
11154
  return;
10942
11155
  }
10943
11156
  const spinner2 = ora10(`Searching for "${query}"...`).start();
@@ -10945,7 +11158,7 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10945
11158
  const results = await api.searchBlueprints(query, 10);
10946
11159
  spinner2.stop();
10947
11160
  if (!results.templates || results.templates.length === 0) {
10948
- console.log(chalk13.yellow(`No blueprints found for "${query}"`));
11161
+ console.log(chalk14.yellow(`No blueprints found for "${query}"`));
10949
11162
  return;
10950
11163
  }
10951
11164
  const { selected } = await prompts4({
@@ -10959,13 +11172,13 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10959
11172
  }))
10960
11173
  });
10961
11174
  if (!selected) {
10962
- console.log(chalk13.gray("Cancelled."));
11175
+ console.log(chalk14.gray("Cancelled."));
10963
11176
  return;
10964
11177
  }
10965
11178
  blueprintId = selected;
10966
11179
  } catch {
10967
11180
  spinner2.stop();
10968
- console.log(chalk13.red("\u2717 Search failed"));
11181
+ console.log(chalk14.red("\u2717 Search failed"));
10969
11182
  return;
10970
11183
  }
10971
11184
  } else {
@@ -10975,82 +11188,82 @@ async function linkCommand(fileArg, blueprintIdArg, options = {}) {
10975
11188
  message: "Enter blueprint ID:"
10976
11189
  });
10977
11190
  if (!manualId) {
10978
- console.log(chalk13.gray("Cancelled."));
11191
+ console.log(chalk14.gray("Cancelled."));
10979
11192
  return;
10980
11193
  }
10981
11194
  blueprintId = manualId;
10982
11195
  }
10983
11196
  }
10984
11197
  if (!blueprintId) {
10985
- console.log(chalk13.red("\u2717 No blueprint ID provided."));
11198
+ console.log(chalk14.red("\u2717 No blueprint ID provided."));
10986
11199
  return;
10987
11200
  }
10988
- const spinner = ora10(`Fetching blueprint ${chalk13.cyan(blueprintId)}...`).start();
11201
+ const spinner = ora10(`Fetching blueprint ${chalk14.cyan(blueprintId)}...`).start();
10989
11202
  try {
10990
11203
  const { blueprint } = await api.getBlueprint(blueprintId);
10991
11204
  spinner.stop();
10992
11205
  const source = getSourceFromVisibility2(blueprint.visibility);
10993
11206
  const isMarketplace = source === "marketplace";
10994
11207
  console.log();
10995
- console.log(chalk13.cyan(`\u{1F431} Blueprint: ${chalk13.bold(safeText(blueprint.name))}`));
11208
+ console.log(chalk14.cyan(`\u{1F431} Blueprint: ${chalk14.bold(safeText(blueprint.name))}`));
10996
11209
  if (blueprint.description) {
10997
- console.log(chalk13.gray(` ${safeText(blueprint.description)}`));
11210
+ console.log(chalk14.gray(` ${safeText(blueprint.description)}`));
10998
11211
  }
10999
- console.log(chalk13.gray(` Visibility: ${blueprint.visibility}`));
11212
+ console.log(chalk14.gray(` Visibility: ${blueprint.visibility}`));
11000
11213
  console.log();
11001
11214
  if (isMarketplace) {
11002
- console.log(chalk13.yellow("\u26A0 This is a marketplace blueprint."));
11003
- console.log(chalk13.gray(" Your local changes will NOT sync back to the cloud."));
11004
- console.log(chalk13.gray(" To make changes, you'll need to create your own copy."));
11215
+ console.log(chalk14.yellow("\u26A0 This is a marketplace blueprint."));
11216
+ console.log(chalk14.gray(" Your local changes will NOT sync back to the cloud."));
11217
+ console.log(chalk14.gray(" To make changes, you'll need to create your own copy."));
11005
11218
  console.log();
11006
11219
  }
11007
11220
  const { confirm } = await prompts4({
11008
11221
  type: "confirm",
11009
11222
  name: "confirm",
11010
- message: `Link ${chalk13.cyan(file)} to ${chalk13.cyan(blueprint.name)}?`,
11223
+ message: `Link ${chalk14.cyan(file)} to ${chalk14.cyan(blueprint.name)}?`,
11011
11224
  initial: true
11012
11225
  });
11013
11226
  if (!confirm) {
11014
- console.log(chalk13.gray("Cancelled."));
11227
+ console.log(chalk14.gray("Cancelled."));
11015
11228
  return;
11016
11229
  }
11017
11230
  await linkBlueprint(cwd, file, blueprint.id, blueprint.name, source, blueprint.content);
11018
11231
  console.log();
11019
- console.log(chalk13.green(`\u2705 Linked: ${file} \u2192 ${blueprint.id}`));
11232
+ console.log(chalk14.green(`\u2705 Linked: ${file} \u2192 ${blueprint.id}`));
11020
11233
  console.log();
11021
- console.log(chalk13.gray("Next steps:"));
11022
- console.log(chalk13.gray(` \u2022 Run 'lynxp diff' to see differences`));
11023
- console.log(chalk13.gray(` \u2022 Run 'lynxp status' to see all tracked blueprints`));
11234
+ console.log(chalk14.gray("Next steps:"));
11235
+ console.log(chalk14.gray(` \u2022 Run 'lynxp diff' to see differences`));
11236
+ console.log(chalk14.gray(` \u2022 Run 'lynxp status' to see all tracked blueprints`));
11024
11237
  if (!isMarketplace) {
11025
- console.log(chalk13.gray(` \u2022 Run 'lynxp push' to push local changes to cloud`));
11238
+ console.log(chalk14.gray(` \u2022 Run 'lynxp push' to push local changes to cloud`));
11026
11239
  }
11027
11240
  console.log();
11028
11241
  } catch (error) {
11029
11242
  spinner.stop();
11030
11243
  if (error instanceof ApiRequestError) {
11031
11244
  if (error.statusCode === 404) {
11032
- console.log(chalk13.red(`\u2717 Blueprint not found: ${blueprintId}`));
11033
- console.log(chalk13.gray(" Make sure the ID is correct. Use 'lynxp list' or 'lynxp search' to find blueprints."));
11245
+ console.log(chalk14.red(`\u2717 Blueprint not found: ${blueprintId}`));
11246
+ console.log(chalk14.gray(" Make sure the ID is correct. Use 'lynxp list' or 'lynxp search' to find blueprints."));
11034
11247
  } else if (error.statusCode === 403) {
11035
- console.log(chalk13.red("\u2717 You don't have access to this blueprint."));
11248
+ console.log(chalk14.red("\u2717 You don't have access to this blueprint."));
11036
11249
  } else {
11037
- console.log(chalk13.red(`\u2717 Error: ${error.message}`));
11250
+ console.log(chalk14.red(`\u2717 Error: ${error.message}`));
11038
11251
  }
11039
11252
  } else {
11040
- console.log(chalk13.red("\u2717 An unexpected error occurred."));
11253
+ console.log(chalk14.red("\u2717 An unexpected error occurred."));
11041
11254
  }
11042
11255
  }
11043
11256
  }
11044
11257
  async function unlinkCommand(fileArg) {
11045
11258
  const cwd = process.cwd();
11046
11259
  console.log();
11047
- console.log(chalk13.cyan("\u{1F431} Unlink File from Blueprint"));
11260
+ console.log(chalk14.cyan("\u{1F431} Unlink File from Blueprint"));
11048
11261
  console.log();
11049
11262
  let file;
11050
11263
  if (!fileArg) {
11051
11264
  const status = await checkSyncStatus(cwd);
11052
11265
  if (status.length === 0) {
11053
- console.log(chalk13.yellow("No files are currently linked to blueprints."));
11266
+ console.log(chalk14.yellow("No files are currently linked to blueprints."));
11054
11267
  return;
11055
11268
  }
11056
11269
  const { selectedFile } = await prompts4({
@@ -11064,7 +11277,7 @@ async function unlinkCommand(fileArg) {
11064
11277
  }))
11065
11278
  });
11066
11279
  if (!selectedFile) {
11067
- console.log(chalk13.gray("Cancelled."));
11280
+ console.log(chalk14.gray("Cancelled."));
11068
11281
  return;
11069
11282
  }
11070
11283
  file = selectedFile;
@@ -11073,77 +11286,77 @@ async function unlinkCommand(fileArg) {
11073
11286
  }
11074
11287
  const tracked = await findBlueprintByFile(cwd, file);
11075
11288
  if (!tracked) {
11076
- console.log(chalk13.yellow(`File is not linked to any blueprint: ${file}`));
11289
+ console.log(chalk14.yellow(`File is not linked to any blueprint: ${file}`));
11077
11290
  return;
11078
11291
  }
11079
- console.log(chalk13.gray(`Currently linked to: ${tracked.name}`));
11080
- console.log(chalk13.gray(` ID: ${tracked.id}`));
11081
- console.log(chalk13.gray(` Source: ${tracked.source}`));
11292
+ console.log(chalk14.gray(`Currently linked to: ${tracked.name}`));
11293
+ console.log(chalk14.gray(` ID: ${tracked.id}`));
11294
+ console.log(chalk14.gray(` Source: ${tracked.source}`));
11082
11295
  console.log();
11083
11296
  const { confirm } = await prompts4({
11084
11297
  type: "confirm",
11085
11298
  name: "confirm",
11086
- message: `Unlink ${chalk13.cyan(file)} from ${chalk13.cyan(tracked.name)}?`,
11299
+ message: `Unlink ${chalk14.cyan(file)} from ${chalk14.cyan(tracked.name)}?`,
11087
11300
  initial: true
11088
11301
  });
11089
11302
  if (!confirm) {
11090
- console.log(chalk13.gray("Cancelled."));
11303
+ console.log(chalk14.gray("Cancelled."));
11091
11304
  return;
11092
11305
  }
11093
11306
  const success = await untrackBlueprint(cwd, file);
11094
11307
  if (success) {
11095
11308
  console.log();
11096
- console.log(chalk13.green(`\u2705 Unlinked: ${file}`));
11097
- console.log(chalk13.gray(" The file is now standalone. Changes won't sync with the cloud."));
11309
+ console.log(chalk14.green(`\u2705 Unlinked: ${file}`));
11310
+ console.log(chalk14.gray(" The file is now standalone. Changes won't sync with the cloud."));
11098
11311
  console.log();
11099
11312
  } else {
11100
- console.log(chalk13.red("\u2717 Failed to unlink file."));
11313
+ console.log(chalk14.red("\u2717 Failed to unlink file."));
11101
11314
  }
11102
11315
  }
11103
11316
  async function listTrackedBlueprints(cwd) {
11104
11317
  console.log();
11105
- console.log(chalk13.cyan("\u{1F431} Tracked Blueprints"));
11318
+ console.log(chalk14.cyan("\u{1F431} Tracked Blueprints"));
11106
11319
  console.log();
11107
11320
  const status = await checkSyncStatus(cwd);
11108
11321
  if (status.length === 0) {
11109
- console.log(chalk13.gray("No blueprints are currently tracked."));
11322
+ console.log(chalk14.gray("No blueprints are currently tracked."));
11110
11323
  console.log();
11111
- console.log(chalk13.gray("To track a blueprint:"));
11112
- console.log(chalk13.gray(" lynxp pull <blueprint-id> Download and track a blueprint"));
11113
- console.log(chalk13.gray(" lynxp link Link an existing file to a blueprint"));
11324
+ console.log(chalk14.gray("To track a blueprint:"));
11325
+ console.log(chalk14.gray(" lynxp pull <blueprint-id> Download and track a blueprint"));
11326
+ console.log(chalk14.gray(" lynxp link Link an existing file to a blueprint"));
11114
11327
  return;
11115
11328
  }
11116
11329
  for (const { blueprint, localModified, fileExists: fileExists2 } of status) {
11117
- const statusIcon = !fileExists2 ? chalk13.red("\u2717") : localModified ? chalk13.yellow("\u25CF") : chalk13.green("\u2713");
11330
+ const statusIcon = !fileExists2 ? chalk14.red("\u2717") : localModified ? chalk14.yellow("\u25CF") : chalk14.green("\u2713");
11118
11331
  const sourceLabel = {
11119
- marketplace: chalk13.gray("[marketplace]"),
11120
- team: chalk13.blue("[team]"),
11121
- private: chalk13.green("[private]"),
11122
- local: chalk13.gray("[local]")
11332
+ marketplace: chalk14.gray("[marketplace]"),
11333
+ team: chalk14.blue("[team]"),
11334
+ private: chalk14.green("[private]"),
11335
+ local: chalk14.gray("[local]")
11123
11336
  }[blueprint.source];
11124
- console.log(`${statusIcon} ${chalk13.cyan(blueprint.file)}`);
11337
+ console.log(`${statusIcon} ${chalk14.cyan(blueprint.file)}`);
11125
11338
  console.log(` ${sourceLabel} ${blueprint.name}`);
11126
- console.log(` ${chalk13.gray(`ID: ${blueprint.id}`)}`);
11339
+ console.log(` ${chalk14.gray(`ID: ${blueprint.id}`)}`);
11127
11340
  if (!fileExists2) {
11128
- console.log(chalk13.red(` \u26A0 File not found`));
11341
+ console.log(chalk14.red(` \u26A0 File not found`));
11129
11342
  } else if (localModified) {
11130
- console.log(chalk13.yellow(` \u26A0 Local changes detected`));
11343
+ console.log(chalk14.yellow(` \u26A0 Local changes detected`));
11131
11344
  }
11132
11345
  console.log();
11133
11346
  }
11134
- console.log(chalk13.gray("Legend:"));
11135
- console.log(chalk13.gray(` ${chalk13.green("\u2713")} In sync ${chalk13.yellow("\u25CF")} Modified locally ${chalk13.red("\u2717")} Missing`));
11347
+ console.log(chalk14.gray("Legend:"));
11348
+ console.log(chalk14.gray(` ${chalk14.green("\u2713")} In sync ${chalk14.yellow("\u25CF")} Modified locally ${chalk14.red("\u2717")} Missing`));
11136
11349
  console.log();
11137
11350
  }
11138
11351
 
11139
11352
  // src/commands/analyze.ts
11140
- import chalk14 from "chalk";
11353
+ import chalk15 from "chalk";
11141
11354
  import ora11 from "ora";
11142
11355
  async function analyzeCommand(options) {
11143
11356
  console.log();
11144
11357
  if (!options.json) {
11145
- console.log(chalk14.cyan.bold(" \u{1F50D} LynxPrompt Analyzer"));
11146
- console.log(chalk14.gray(" Detect project configuration and tech stack"));
11358
+ console.log(chalk15.cyan.bold(" \u{1F50D} LynxPrompt Analyzer"));
11359
+ console.log(chalk15.gray(" Detect project configuration and tech stack"));
11147
11360
  console.log();
11148
11361
  }
11149
11362
  let detected;
@@ -11151,7 +11364,7 @@ async function analyzeCommand(options) {
11151
11364
  if (options.remote) {
11152
11365
  if (!isGitUrl(options.remote)) {
11153
11366
  if (!options.json) {
11154
- console.log(chalk14.red(" \u2717 Invalid Git URL provided"));
11367
+ console.log(chalk15.red(" \u2717 Invalid Git URL provided"));
11155
11368
  }
11156
11369
  process.exit(1);
11157
11370
  }
@@ -11164,7 +11377,7 @@ async function analyzeCommand(options) {
11164
11377
  spinner.succeed("Remote repository analyzed");
11165
11378
  } else {
11166
11379
  spinner.fail("Could not analyze repository");
11167
- console.log(chalk14.gray(" The repository may be private or inaccessible."));
11380
+ console.log(chalk15.gray(" The repository may be private or inaccessible."));
11168
11381
  process.exit(1);
11169
11382
  }
11170
11383
  } else {
@@ -11197,57 +11410,57 @@ async function analyzeCommand(options) {
11197
11410
  }
11198
11411
  console.log();
11199
11412
  if (!detected) {
11200
- console.log(chalk14.yellow(" No project configuration detected."));
11413
+ console.log(chalk15.yellow(" No project configuration detected."));
11201
11414
  console.log();
11202
- console.log(chalk14.gray(" Tips:"));
11203
- console.log(chalk14.gray(" \u2022 Make sure you're in a project directory with a package.json, pyproject.toml, etc."));
11204
- console.log(chalk14.gray(" \u2022 Use --remote <url> to analyze a remote repository"));
11415
+ console.log(chalk15.gray(" Tips:"));
11416
+ console.log(chalk15.gray(" \u2022 Make sure you're in a project directory with a package.json, pyproject.toml, etc."));
11417
+ console.log(chalk15.gray(" \u2022 Use --remote <url> to analyze a remote repository"));
11205
11418
  console.log();
11206
11419
  return;
11207
11420
  }
11208
- console.log(chalk14.green.bold(" \u{1F4CA} Project Analysis"));
11421
+ console.log(chalk15.green.bold(" \u{1F4CA} Project Analysis"));
11209
11422
  console.log();
11210
- console.log(chalk14.white(" Basic Info"));
11211
- console.log(chalk14.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11212
- console.log(` ${chalk14.dim("Name:")} ${chalk14.white(detected.name || "unknown")}`);
11423
+ console.log(chalk15.white(" Basic Info"));
11424
+ console.log(chalk15.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11425
+ console.log(` ${chalk15.dim("Name:")} ${chalk15.white(detected.name || "unknown")}`);
11213
11426
  if (detected.description) {
11214
- console.log(` ${chalk14.dim("Description:")} ${chalk14.gray(detected.description)}`);
11427
+ console.log(` ${chalk15.dim("Description:")} ${chalk15.gray(detected.description)}`);
11215
11428
  }
11216
- console.log(` ${chalk14.dim("Type:")} ${chalk14.white(detected.type || "application")}`);
11429
+ console.log(` ${chalk15.dim("Type:")} ${chalk15.white(detected.type || "application")}`);
11217
11430
  if (detected.license) {
11218
- console.log(` ${chalk14.dim("License:")} ${chalk14.white(detected.license.toUpperCase())}`);
11431
+ console.log(` ${chalk15.dim("License:")} ${chalk15.white(detected.license.toUpperCase())}`);
11219
11432
  }
11220
11433
  console.log();
11221
- console.log(chalk14.white(" Tech Stack"));
11222
- console.log(chalk14.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11434
+ console.log(chalk15.white(" Tech Stack"));
11435
+ console.log(chalk15.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11223
11436
  if (detected.stack.length > 0) {
11224
11437
  for (const tech of detected.stack) {
11225
- console.log(` ${chalk14.cyan("\u2022")} ${tech}`);
11438
+ console.log(` ${chalk15.cyan("\u2022")} ${tech}`);
11226
11439
  }
11227
11440
  } else {
11228
- console.log(chalk14.gray(" No tech stack detected"));
11441
+ console.log(chalk15.gray(" No tech stack detected"));
11229
11442
  }
11230
11443
  console.log();
11231
- console.log(chalk14.white(" Infrastructure"));
11232
- console.log(chalk14.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11233
- console.log(` ${chalk14.dim("Package Manager:")} ${detected.packageManager || chalk14.gray("none detected")}`);
11234
- console.log(` ${chalk14.dim("Repo Host:")} ${detected.repoHost || chalk14.gray("none detected")}`);
11235
- console.log(` ${chalk14.dim("CI/CD:")} ${detected.cicd || chalk14.gray("none detected")}`);
11236
- console.log(` ${chalk14.dim("Docker:")} ${detected.hasDocker ? chalk14.green("yes") : chalk14.gray("no")}`);
11444
+ console.log(chalk15.white(" Infrastructure"));
11445
+ console.log(chalk15.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11446
+ console.log(` ${chalk15.dim("Package Manager:")} ${detected.packageManager || chalk15.gray("none detected")}`);
11447
+ console.log(` ${chalk15.dim("Repo Host:")} ${detected.repoHost || chalk15.gray("none detected")}`);
11448
+ console.log(` ${chalk15.dim("CI/CD:")} ${detected.cicd || chalk15.gray("none detected")}`);
11449
+ console.log(` ${chalk15.dim("Docker:")} ${detected.hasDocker ? chalk15.green("yes") : chalk15.gray("no")}`);
11237
11450
  console.log();
11238
11451
  if (detected.commands && Object.keys(detected.commands).length > 0) {
11239
- console.log(chalk14.white(" Commands"));
11240
- console.log(chalk14.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11452
+ console.log(chalk15.white(" Commands"));
11453
+ console.log(chalk15.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11241
11454
  for (const [key, value] of Object.entries(detected.commands)) {
11242
11455
  if (value) {
11243
11456
  const cmdValue = Array.isArray(value) ? value.join(", ") : value;
11244
- console.log(` ${chalk14.dim(key.padEnd(10))} ${chalk14.yellow(cmdValue)}`);
11457
+ console.log(` ${chalk15.dim(key.padEnd(10))} ${chalk15.yellow(cmdValue)}`);
11245
11458
  }
11246
11459
  }
11247
11460
  console.log();
11248
11461
  }
11249
- console.log(chalk14.white(" \u{1F4A1} Recommendations"));
11250
- console.log(chalk14.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11462
+ console.log(chalk15.white(" \u{1F4A1} Recommendations"));
11463
+ console.log(chalk15.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11251
11464
  const recommendations = [];
11252
11465
  if (!detected.cicd) {
11253
11466
  recommendations.push("Add CI/CD configuration (GitHub Actions, GitLab CI, etc.)");
@@ -11266,122 +11479,81 @@ async function analyzeCommand(options) {
11266
11479
  }
11267
11480
  if (recommendations.length > 0) {
11268
11481
  for (const rec of recommendations) {
11269
- console.log(` ${chalk14.yellow("\u2022")} ${rec}`);
11482
+ console.log(` ${chalk15.yellow("\u2022")} ${rec}`);
11270
11483
  }
11271
11484
  } else {
11272
- console.log(chalk14.green(" \u2713 Project looks well-configured!"));
11485
+ console.log(chalk15.green(" \u2713 Project looks well-configured!"));
11273
11486
  }
11274
11487
  console.log();
11275
- console.log(chalk14.gray(" Run 'lynxp wizard' to generate AI IDE configuration"));
11488
+ console.log(chalk15.gray(" Run 'lynxp wizard' to generate AI IDE configuration"));
11276
11489
  console.log();
11277
11490
  }
11278
11491
 
11279
11492
  // src/commands/convert.ts
11280
- import chalk15 from "chalk";
11281
- import { readFile as readFile8, writeFile as writeFile4, access as access5 } from "fs/promises";
11282
- import { join as join8, basename as basename2, resolve as resolve2, dirname as dirname4 } from "path";
11493
+ import chalk16 from "chalk";
11494
+ import { readFile as readFile9, writeFile as writeFile5, access as access6 } from "fs/promises";
11495
+ import { basename as basename2, resolve as resolve2, dirname as dirname5 } from "path";
11283
11496
  import ora12 from "ora";
11284
11497
 
11285
11498
  // src/utils/convert-format.ts
11286
- var isCommandTarget = (target) => target.includes("-command") || target.includes("-prompt") || target.includes("-workflow");
11499
+ import { access as access5 } from "fs/promises";
11500
+ import { join as join9 } from "path";
11501
+
11502
+ // ../packages/shared/src/rules-format.ts
11503
+ function yamlString(value) {
11504
+ return JSON.stringify(value);
11505
+ }
11506
+ var cursorFrontmatter = (description) => [`description: ${yamlString(description)}`, "alwaysApply: true"];
11507
+ var PLATFORM_FRONTMATTER = {
11508
+ cursor: cursorFrontmatter,
11509
+ firebender: cursorFrontmatter,
11510
+ // Firebender reads Cursor-style .mdc rules
11511
+ kiro: () => ["inclusion: always"],
11512
+ augment: (description) => ["type: always_apply", `description: ${yamlString(description)}`]
11513
+ };
11514
+ var FRONTMATTER_PATTERN = /^---\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n)+/;
11515
+ function frontmatterLines(platform2, description) {
11516
+ const keys = PLATFORM_FRONTMATTER[platform2];
11517
+ return keys ? ["---", ...keys(description), "---", ""] : [];
11518
+ }
11287
11519
  function splitFrontmatter(content) {
11288
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/);
11289
- if (!match) return { frontmatter: null, body: content };
11290
- return { frontmatter: match[1], body: content.slice(match[0].length).replace(/^\s*\n/, "") };
11291
- }
11292
- function parseMarkdownConfig(content) {
11293
- const config2 = {};
11294
- const sections = content.split(/^##\s+/m);
11295
- for (const section of sections) {
11296
- const lines = section.trim().split("\n");
11297
- if (lines.length === 0) continue;
11298
- const title = lines[0].toLowerCase().trim();
11299
- const body2 = lines.slice(1).join("\n").trim();
11300
- config2[title] = body2;
11301
- }
11302
- config2._raw = content;
11520
+ const match = content.match(FRONTMATTER_PATTERN);
11521
+ if (!match) return { frontmatter: "", body: content };
11522
+ return { frontmatter: match[0], body: content.slice(match[0].length) };
11523
+ }
11524
+ function adaptRulesContent(content, fromPlatform, toPlatform, description) {
11303
11525
  const { frontmatter, body } = splitFrontmatter(content);
11304
- config2._body = body;
11305
- if (frontmatter !== null) config2._frontmatter = frontmatter;
11306
- return config2;
11307
- }
11308
- var DEFAULT_MDC_FRONTMATTER = `description: "AI coding rules"
11309
- globs: ["**/*"]
11310
- alwaysApply: true`;
11311
- function generateTargetContent(config2, targetPlatform) {
11312
- const rawContent = config2._body ?? config2._raw ?? "";
11313
- const sourceFrontmatter = config2._frontmatter;
11314
- const mdcFrontmatter = sourceFrontmatter && /^(alwaysApply|globs)\s*:/m.test(sourceFrontmatter) ? sourceFrontmatter : DEFAULT_MDC_FRONTMATTER;
11315
- if (isCommandTarget(targetPlatform)) {
11316
- return config2._raw || "";
11317
- }
11318
- switch (targetPlatform) {
11319
- case "cursor":
11320
- case "firebender":
11321
- return `---
11322
- ${mdcFrontmatter}
11323
- ---
11324
-
11325
- ${rawContent}`;
11326
- case "kiro":
11327
- return `---
11328
- inclusion: always
11329
- ---
11330
-
11331
- ${rawContent}`;
11332
- case "augment":
11333
- return `---
11334
- type: always_apply
11335
- ---
11336
-
11337
- ${rawContent}`;
11338
- case "cursor_legacy":
11339
- return rawContent.replace(/^#\s+/gm, "").replace(/^##\s+/gm, "\n").replace(/^###\s+/gm, "").trim();
11340
- case "windsurf":
11341
- case "cline":
11342
- case "goose":
11343
- case "trae":
11344
- return rawContent;
11345
- case "tabnine":
11346
- return `# Tabnine configuration
11347
- # Converted from AI IDE configuration
11348
- instructions: |
11349
- ${rawContent.split("\n").map((line) => ` ${line}`).join("\n")}
11350
- `;
11351
- case "void":
11352
- case "continue":
11353
- case "cody":
11354
- case "codegpt":
11355
- case "supermaven":
11356
- return JSON.stringify({ instructions: rawContent }, null, 2) + "\n";
11357
- case "copilot":
11358
- return `# GitHub Copilot Instructions
11359
-
11360
- ${rawContent}
11361
- `;
11362
- case "agents":
11363
- case "universal":
11364
- case "claude":
11365
- case "codex":
11366
- case "antigravity":
11367
- case "gemini-cli":
11368
- case "zed":
11369
- case "amazonq":
11370
- case "junie":
11371
- case "warp":
11372
- case "openhands":
11373
- case "crush":
11374
- case "aider":
11375
- case "opencode":
11376
- case "firebase":
11377
- case "roocode":
11378
- case "kilocode":
11379
- default:
11380
- return rawContent;
11381
- }
11526
+ const target = PLATFORM_FRONTMATTER[toPlatform];
11527
+ if (fromPlatform === toPlatform && (frontmatter || !target)) return content;
11528
+ if (frontmatter && target && PLATFORM_FRONTMATTER[fromPlatform] === target) return content;
11529
+ const lines = frontmatterLines(toPlatform, description);
11530
+ return lines.length ? `${lines.join("\n")}
11531
+ ${body}` : body;
11382
11532
  }
11383
11533
 
11384
- // src/commands/convert.ts
11534
+ // src/utils/convert-format.ts
11535
+ var isCommandTarget = (target) => target.includes("-command") || target.includes("-prompt") || target.includes("-workflow");
11536
+ var RULES_DESCRIPTION = "AI rules for this project";
11537
+ function isStructuredPlatform(platform2) {
11538
+ const format = getPlatform(platform2)?.format;
11539
+ return format === "json" || format === "yaml";
11540
+ }
11541
+ function platformForPath(filePath) {
11542
+ const normalized = filePath.replace(/\\/g, "/").toLowerCase();
11543
+ const rules = PLATFORMS.filter((p) => !p.isCommand);
11544
+ const inFolder2 = rules.find((p) => p.rulesDirectory && `/${normalized}`.includes(`/${p.rulesDirectory.toLowerCase()}`));
11545
+ if (inFolder2) return inFolder2.id;
11546
+ const file = rules.find((p) => {
11547
+ const own = p.file.toLowerCase();
11548
+ return normalized === own || normalized.endsWith(`/${own}`);
11549
+ });
11550
+ if (file) return file.id;
11551
+ return normalized.endsWith(".mdc") ? "cursor" : void 0;
11552
+ }
11553
+ function convertContent(content, sourcePlatform, targetPlatform) {
11554
+ if (isCommandTarget(targetPlatform)) return content;
11555
+ return adaptRulesContent(content, sourcePlatform, targetPlatform, RULES_DESCRIPTION);
11556
+ }
11385
11557
  var SOURCE_FILES = {
11386
11558
  "agents.md": "agents",
11387
11559
  "claude.md": "claude",
@@ -11393,8 +11565,33 @@ var SOURCE_FILES = {
11393
11565
  "copilot-instructions.md": "copilot",
11394
11566
  ".windsurfrules": "windsurf",
11395
11567
  ".clinerules": "cline",
11396
- ".aider.conf.yml": "aider"
11568
+ // Real case: auto-detect looks the name up as is, and Linux disks are case-sensitive
11569
+ "CONVENTIONS.md": "aider"
11397
11570
  };
11571
+ var sourceFilePlatform = (name) => Object.entries(SOURCE_FILES).find(([file]) => file.toLowerCase() === name.toLowerCase())?.[1];
11572
+ async function detectSourceFile(cwd) {
11573
+ for (const [pattern, platform2] of Object.entries(SOURCE_FILES)) {
11574
+ try {
11575
+ const fullPath = join9(cwd, pattern);
11576
+ await access5(fullPath);
11577
+ return { path: fullPath, platform: platform2 };
11578
+ } catch {
11579
+ }
11580
+ }
11581
+ const uppercaseVariants = ["AGENTS.md", "CLAUDE.md"];
11582
+ for (const variant of uppercaseVariants) {
11583
+ try {
11584
+ const fullPath = join9(cwd, variant);
11585
+ await access5(fullPath);
11586
+ const platform2 = variant.toLowerCase().replace(".md", "");
11587
+ return { path: fullPath, platform: platform2 };
11588
+ } catch {
11589
+ }
11590
+ }
11591
+ return null;
11592
+ }
11593
+
11594
+ // src/commands/convert.ts
11398
11595
  var TARGET_FILES = {
11399
11596
  ...PLATFORM_FILES2,
11400
11597
  cursor_legacy: ".cursorrules",
@@ -11446,27 +11643,6 @@ var COMMAND_DIRS = {
11446
11643
  ...Object.fromEntries(COMMANDS.map((c) => [c.directory, c.id])),
11447
11644
  ".copilot/prompts": "copilot-prompt"
11448
11645
  };
11449
- async function detectSourceFile(cwd) {
11450
- for (const [pattern, platform2] of Object.entries(SOURCE_FILES)) {
11451
- try {
11452
- const fullPath = join8(cwd, pattern);
11453
- await access5(fullPath);
11454
- return { path: fullPath, platform: platform2 };
11455
- } catch {
11456
- }
11457
- }
11458
- const uppercaseVariants = ["AGENTS.md", "CLAUDE.md"];
11459
- for (const variant of uppercaseVariants) {
11460
- try {
11461
- const fullPath = join8(cwd, variant);
11462
- await access5(fullPath);
11463
- const platform2 = variant.toLowerCase().replace(".md", "");
11464
- return { path: fullPath, platform: platform2 };
11465
- } catch {
11466
- }
11467
- }
11468
- return null;
11469
- }
11470
11646
  function detectCommandPlatform(sourcePath) {
11471
11647
  const normalized = sourcePath.replace(/\\/g, "/").toLowerCase();
11472
11648
  for (const [dir, platform2] of Object.entries(COMMAND_DIRS)) {
@@ -11479,8 +11655,8 @@ function detectCommandPlatform(sourcePath) {
11479
11655
  async function convertCommand(first, second, options) {
11480
11656
  const [source, target] = second === void 0 ? [void 0, first] : [first, second];
11481
11657
  console.log();
11482
- console.log(chalk15.cyan.bold(" \u{1F504} LynxPrompt Convert"));
11483
- console.log(chalk15.gray(" Convert AI IDE configuration between formats"));
11658
+ console.log(chalk16.cyan.bold(" \u{1F504} LynxPrompt Convert"));
11659
+ console.log(chalk16.gray(" Convert AI IDE configuration between formats"));
11484
11660
  console.log();
11485
11661
  const cwd = process.cwd();
11486
11662
  let sourcePath;
@@ -11491,27 +11667,26 @@ async function convertCommand(first, second, options) {
11491
11667
  if (cmdPlatform) {
11492
11668
  sourcePlatform = cmdPlatform;
11493
11669
  } else {
11494
- const sourceBasename = basename2(source).toLowerCase();
11495
- sourcePlatform = SOURCE_FILES[sourceBasename] || "unknown";
11670
+ sourcePlatform = platformForPath(source) || sourceFilePlatform(basename2(source)) || "unknown";
11496
11671
  }
11497
11672
  } else {
11498
11673
  const detected = await detectSourceFile(cwd);
11499
11674
  if (!detected) {
11500
- console.log(chalk15.red(" \u2717 No AI configuration file found in current directory"));
11675
+ console.log(chalk16.red(" \u2717 No AI configuration file found in current directory"));
11501
11676
  console.log();
11502
- console.log(chalk15.gray(" Supported source files:"));
11677
+ console.log(chalk16.gray(" Supported source files:"));
11503
11678
  for (const file of Object.keys(SOURCE_FILES)) {
11504
- console.log(chalk15.gray(` \u2022 ${file}`));
11679
+ console.log(chalk16.gray(` \u2022 ${file}`));
11505
11680
  }
11506
11681
  console.log();
11507
- console.log(chalk15.gray(" Command directories (for slash commands):"));
11682
+ console.log(chalk16.gray(" Command directories (for slash commands):"));
11508
11683
  for (const dir of Object.keys(COMMAND_DIRS)) {
11509
- console.log(chalk15.gray(` \u2022 ${dir}/*.md`));
11684
+ console.log(chalk16.gray(` \u2022 ${dir}/*.md`));
11510
11685
  }
11511
11686
  console.log();
11512
- console.log(chalk15.gray(" Usage: lynxp convert <source> <target>"));
11513
- console.log(chalk15.gray(" Example: lynxp convert AGENTS.md cursor"));
11514
- console.log(chalk15.gray(" Example: lynxp convert .cursor/commands/deploy.md claude-command"));
11687
+ console.log(chalk16.gray(" Usage: lynxp convert <source> <target>"));
11688
+ console.log(chalk16.gray(" Example: lynxp convert AGENTS.md cursor"));
11689
+ console.log(chalk16.gray(" Example: lynxp convert .cursor/commands/deploy.md claude-command"));
11515
11690
  process.exit(1);
11516
11691
  }
11517
11692
  sourcePath = detected.path;
@@ -11520,27 +11695,33 @@ async function convertCommand(first, second, options) {
11520
11695
  const targetLower = target.toLowerCase();
11521
11696
  const normalizedTarget = TARGET_FILES[targetLower] ? targetLower : targetLower.replace(/-/g, "_");
11522
11697
  if (!TARGET_FILES[normalizedTarget]) {
11523
- console.log(chalk15.red(` \u2717 Unknown target format: ${target}`));
11698
+ console.log(chalk16.red(` \u2717 Unknown target format: ${target}`));
11524
11699
  console.log();
11525
- console.log(chalk15.gray(" Supported target formats:"));
11700
+ console.log(chalk16.gray(" Supported target formats:"));
11526
11701
  for (const [key, name] of Object.entries(PLATFORM_NAMES)) {
11527
- console.log(chalk15.gray(` \u2022 ${key.padEnd(15)} \u2192 ${name}`));
11702
+ if (isStructuredPlatform(key)) continue;
11703
+ console.log(chalk16.gray(` \u2022 ${key.padEnd(15)} \u2192 ${name}`));
11528
11704
  }
11529
11705
  process.exit(1);
11530
11706
  }
11707
+ const structured = [sourcePlatform, normalizedTarget].find(isStructuredPlatform);
11708
+ if (structured) {
11709
+ console.log(chalk16.red(` \u2717 ${PLATFORM_NAMES[structured] || structured} uses a JSON/YAML config, not a rules file, so it cannot be converted`));
11710
+ console.log(chalk16.gray(` Run 'lynxp wizard' and pick ${PLATFORM_NAMES[structured] || structured} to generate one`));
11711
+ process.exit(1);
11712
+ }
11531
11713
  let sourceContent;
11532
11714
  try {
11533
- sourceContent = await readFile8(sourcePath, "utf-8");
11715
+ sourceContent = await readFile9(sourcePath, "utf-8");
11534
11716
  } catch {
11535
- console.log(chalk15.red(` \u2717 Could not read source file: ${sourcePath}`));
11717
+ console.log(chalk16.red(` \u2717 Could not read source file: ${sourcePath}`));
11536
11718
  process.exit(1);
11537
11719
  }
11538
- console.log(chalk15.white(` Source: ${basename2(sourcePath)} (${PLATFORM_NAMES[sourcePlatform] || sourcePlatform})`));
11539
- console.log(chalk15.white(` Target: ${PLATFORM_NAMES[normalizedTarget]}`));
11720
+ console.log(chalk16.white(` Source: ${basename2(sourcePath)} (${PLATFORM_NAMES[sourcePlatform] || sourcePlatform})`));
11721
+ console.log(chalk16.white(` Target: ${PLATFORM_NAMES[normalizedTarget]}`));
11540
11722
  console.log();
11541
11723
  const spinner = ora12("Converting configuration...").start();
11542
- const config2 = parseMarkdownConfig(sourceContent);
11543
- const targetContent = generateTargetContent(config2, normalizedTarget);
11724
+ const targetContent = convertContent(sourceContent, sourcePlatform, normalizedTarget);
11544
11725
  spinner.stop();
11545
11726
  let outputFilename = options.output || TARGET_FILES[normalizedTarget];
11546
11727
  const targetCommand = COMMANDS.find((c) => c.id === normalizedTarget);
@@ -11550,35 +11731,35 @@ async function convertCommand(first, second, options) {
11550
11731
  }
11551
11732
  const outputPath = resolve2(cwd, outputFilename);
11552
11733
  try {
11553
- await access5(outputPath);
11734
+ await access6(outputPath);
11554
11735
  if (!options.force) {
11555
- console.log(chalk15.yellow(` \u26A0\uFE0F File already exists: ${outputFilename}`));
11556
- console.log(chalk15.gray(" Use --force to overwrite"));
11736
+ console.log(chalk16.yellow(` \u26A0\uFE0F File already exists: ${outputFilename}`));
11737
+ console.log(chalk16.gray(" Use --force to overwrite"));
11557
11738
  process.exit(1);
11558
11739
  }
11559
11740
  } catch {
11560
11741
  }
11561
11742
  try {
11562
- const { mkdir: mkdir4 } = await import("fs/promises");
11563
- const outputDir = dirname4(outputPath);
11743
+ const { mkdir: mkdir5 } = await import("fs/promises");
11744
+ const outputDir = dirname5(outputPath);
11564
11745
  if (outputDir !== cwd) {
11565
- await mkdir4(outputDir, { recursive: true });
11746
+ await mkdir5(outputDir, { recursive: true });
11566
11747
  }
11567
- await writeFile4(outputPath, targetContent, "utf-8");
11568
- console.log(chalk15.green(` \u2713 Converted to ${outputFilename}`));
11748
+ await writeFile5(outputPath, targetContent, "utf-8");
11749
+ console.log(chalk16.green(` \u2713 Converted to ${outputFilename}`));
11569
11750
  console.log();
11570
- console.log(chalk15.gray(` Lines: ${targetContent.split("\n").length}`));
11571
- console.log(chalk15.gray(` Size: ${targetContent.length} bytes`));
11751
+ console.log(chalk16.gray(` Lines: ${targetContent.split("\n").length}`));
11752
+ console.log(chalk16.gray(` Size: ${targetContent.length} bytes`));
11572
11753
  console.log();
11573
11754
  } catch (error) {
11574
- console.log(chalk15.red(` \u2717 Could not write output: ${error instanceof Error ? error.message : "unknown error"}`));
11755
+ console.log(chalk16.red(` \u2717 Could not write output: ${error instanceof Error ? error.message : "unknown error"}`));
11575
11756
  process.exit(1);
11576
11757
  }
11577
11758
  }
11578
11759
 
11579
11760
  // src/commands/merge.ts
11580
- import chalk16 from "chalk";
11581
- import { readFile as readFile9, writeFile as writeFile5, access as access6 } from "fs/promises";
11761
+ import chalk17 from "chalk";
11762
+ import { readFile as readFile10, writeFile as writeFile6, access as access7 } from "fs/promises";
11582
11763
  import { basename as basename3, resolve as resolve3 } from "path";
11583
11764
  import ora13 from "ora";
11584
11765
  import prompts5 from "prompts";
@@ -11675,43 +11856,43 @@ ${s.content.trim()}`).join("\n\n");
11675
11856
  // src/commands/merge.ts
11676
11857
  async function mergeCommand(files, options) {
11677
11858
  console.log();
11678
- console.log(chalk16.cyan.bold(" \u{1F500} LynxPrompt Merge"));
11679
- console.log(chalk16.gray(" Merge multiple AI IDE configuration files"));
11859
+ console.log(chalk17.cyan.bold(" \u{1F500} LynxPrompt Merge"));
11860
+ console.log(chalk17.gray(" Merge multiple AI IDE configuration files"));
11680
11861
  console.log();
11681
11862
  if (files.length < 2) {
11682
- console.log(chalk16.red(" \u2717 Please provide at least 2 files to merge"));
11863
+ console.log(chalk17.red(" \u2717 Please provide at least 2 files to merge"));
11683
11864
  console.log();
11684
- console.log(chalk16.gray(" Usage: lynxp merge <file1> <file2> [...files]"));
11685
- console.log(chalk16.gray(" Example: lynxp merge AGENTS.md team-rules.md --output merged.md"));
11865
+ console.log(chalk17.gray(" Usage: lynxp merge <file1> <file2> [...files]"));
11866
+ console.log(chalk17.gray(" Example: lynxp merge AGENTS.md team-rules.md --output merged.md"));
11686
11867
  console.log();
11687
- console.log(chalk16.gray(" Options:"));
11688
- console.log(chalk16.gray(" --output <file> Output filename (default: merged.md)"));
11689
- console.log(chalk16.gray(" --strategy <type> Merge strategy: concat, sections, smart (default: smart)"));
11690
- console.log(chalk16.gray(" --force Overwrite existing output file"));
11691
- console.log(chalk16.gray(" --interactive Review and select sections to include"));
11868
+ console.log(chalk17.gray(" Options:"));
11869
+ console.log(chalk17.gray(" --output <file> Output filename (default: merged.md)"));
11870
+ console.log(chalk17.gray(" --strategy <type> Merge strategy: concat, sections, smart (default: smart)"));
11871
+ console.log(chalk17.gray(" --force Overwrite existing output file"));
11872
+ console.log(chalk17.gray(" --interactive Review and select sections to include"));
11692
11873
  process.exit(1);
11693
11874
  }
11694
11875
  const cwd = process.cwd();
11695
11876
  const strategy = options.strategy || "smart";
11696
- console.log(chalk16.white(` Files to merge: ${files.length}`));
11697
- console.log(chalk16.white(` Strategy: ${strategy}`));
11877
+ console.log(chalk17.white(` Files to merge: ${files.length}`));
11878
+ console.log(chalk17.white(` Strategy: ${strategy}`));
11698
11879
  console.log();
11699
11880
  const allSections = [];
11700
11881
  for (const file of files) {
11701
11882
  const filePath = resolve3(cwd, file);
11702
11883
  try {
11703
- await access6(filePath);
11884
+ await access7(filePath);
11704
11885
  } catch {
11705
- console.log(chalk16.red(` \u2717 File not found: ${file}`));
11886
+ console.log(chalk17.red(` \u2717 File not found: ${file}`));
11706
11887
  process.exit(1);
11707
11888
  }
11708
11889
  try {
11709
- const content = await readFile9(filePath, "utf-8");
11890
+ const content = await readFile10(filePath, "utf-8");
11710
11891
  const sections = parseMarkdownSections(content, basename3(file));
11711
11892
  allSections.push(sections);
11712
- console.log(chalk16.gray(` \u2713 Read ${file} (${sections.length} sections)`));
11893
+ console.log(chalk17.gray(` \u2713 Read ${file} (${sections.length} sections)`));
11713
11894
  } catch (error) {
11714
- console.log(chalk16.red(` \u2717 Could not read ${file}: ${error instanceof Error ? error.message : "unknown"}`));
11895
+ console.log(chalk17.red(` \u2717 Could not read ${file}: ${error instanceof Error ? error.message : "unknown"}`));
11715
11896
  process.exit(1);
11716
11897
  }
11717
11898
  }
@@ -11734,7 +11915,7 @@ async function mergeCommand(files, options) {
11734
11915
  hint: "- Space to toggle, Enter to confirm"
11735
11916
  });
11736
11917
  if (!response.sections || response.sections.length === 0) {
11737
- console.log(chalk16.yellow(" No sections selected, aborting."));
11918
+ console.log(chalk17.yellow(" No sections selected, aborting."));
11738
11919
  process.exit(0);
11739
11920
  }
11740
11921
  const selectedSections = response.sections.map((i) => flatSections[i]);
@@ -11757,34 +11938,34 @@ ${mergedContent}
11757
11938
  const outputFilename = options.output || "merged.md";
11758
11939
  const outputPath = resolve3(cwd, outputFilename);
11759
11940
  try {
11760
- await access6(outputPath);
11941
+ await access7(outputPath);
11761
11942
  if (!options.force) {
11762
- console.log(chalk16.yellow(` \u26A0\uFE0F File already exists: ${outputFilename}`));
11763
- console.log(chalk16.gray(" Use --force to overwrite"));
11943
+ console.log(chalk17.yellow(` \u26A0\uFE0F File already exists: ${outputFilename}`));
11944
+ console.log(chalk17.gray(" Use --force to overwrite"));
11764
11945
  process.exit(1);
11765
11946
  }
11766
11947
  } catch {
11767
11948
  }
11768
11949
  try {
11769
- await writeFile5(outputPath, finalContent, "utf-8");
11770
- console.log(chalk16.green(` \u2713 Merged to ${outputFilename}`));
11950
+ await writeFile6(outputPath, finalContent, "utf-8");
11951
+ console.log(chalk17.green(` \u2713 Merged to ${outputFilename}`));
11771
11952
  console.log();
11772
- console.log(chalk16.gray(` Sources: ${files.length} files`));
11773
- console.log(chalk16.gray(` Lines: ${finalContent.split("\n").length}`));
11774
- console.log(chalk16.gray(` Size: ${finalContent.length} bytes`));
11953
+ console.log(chalk17.gray(` Sources: ${files.length} files`));
11954
+ console.log(chalk17.gray(` Lines: ${finalContent.split("\n").length}`));
11955
+ console.log(chalk17.gray(` Size: ${finalContent.length} bytes`));
11775
11956
  console.log();
11776
11957
  } catch (error) {
11777
- console.log(chalk16.red(` \u2717 Could not write output: ${error instanceof Error ? error.message : "unknown error"}`));
11958
+ console.log(chalk17.red(` \u2717 Could not write output: ${error instanceof Error ? error.message : "unknown error"}`));
11778
11959
  process.exit(1);
11779
11960
  }
11780
11961
  }
11781
11962
 
11782
11963
  // src/commands/import.ts
11783
- import chalk17 from "chalk";
11964
+ import chalk18 from "chalk";
11784
11965
  import prompts6 from "prompts";
11785
11966
  import ora14 from "ora";
11786
- import { readFile as readFile10, access as access7, readdir as readdir3 } from "fs/promises";
11787
- import { join as join9, relative as relative3, dirname as dirname5, basename as basename4, resolve as resolve4 } from "path";
11967
+ import { readFile as readFile11, access as access8, readdir as readdir3 } from "fs/promises";
11968
+ import { join as join10, relative as relative3, dirname as dirname6, basename as basename4, resolve as resolve4 } from "path";
11788
11969
  var CONFIG_FILE_PATTERNS = [
11789
11970
  "AGENTS.md",
11790
11971
  "CLAUDE.md",
@@ -11801,7 +11982,7 @@ async function scanDirectory(rootPath, options = {}) {
11801
11982
  try {
11802
11983
  const entries = await readdir3(dir, { withFileTypes: true });
11803
11984
  for (const entry of entries) {
11804
- const fullPath = join9(dir, entry.name);
11985
+ const fullPath = join10(dir, entry.name);
11805
11986
  if (entry.isDirectory()) {
11806
11987
  const skipDirs = [
11807
11988
  "node_modules",
@@ -11827,13 +12008,13 @@ async function scanDirectory(rootPath, options = {}) {
11827
12008
  } else if (entry.isFile()) {
11828
12009
  if (patterns.includes(entry.name)) {
11829
12010
  try {
11830
- const content = await readFile10(fullPath, "utf-8");
12011
+ const content = await readFile11(fullPath, "utf-8");
11831
12012
  const relativePath = relative3(rootPath, fullPath);
11832
12013
  files.push({
11833
12014
  path: fullPath,
11834
12015
  relativePath,
11835
12016
  depth,
11836
- name: extractProjectName(content, dirname5(fullPath)),
12017
+ name: extractProjectName(content, dirname6(fullPath)),
11837
12018
  content,
11838
12019
  sections: parseMarkdownSections2(content)
11839
12020
  });
@@ -11900,13 +12081,13 @@ function buildHierarchy(files, _rootPath) {
11900
12081
  const potentialRoots = sorted.filter((f) => f.depth <= 1);
11901
12082
  if (potentialRoots.length === 0 && files.length > 0) {
11902
12083
  return files.map((f) => ({
11903
- rootPath: dirname5(f.path),
12084
+ rootPath: dirname6(f.path),
11904
12085
  root: f,
11905
12086
  children: []
11906
12087
  }));
11907
12088
  }
11908
12089
  for (const root of potentialRoots) {
11909
- const rootDir = dirname5(root.path);
12090
+ const rootDir = dirname6(root.path);
11910
12091
  const children = files.filter((f) => {
11911
12092
  if (f === root) return false;
11912
12093
  return f.path.startsWith(rootDir + "/") && f.depth > root.depth;
@@ -11924,7 +12105,7 @@ function buildHierarchy(files, _rootPath) {
11924
12105
  const orphans = files.filter((f) => !assignedPaths.has(f.path));
11925
12106
  for (const orphan of orphans) {
11926
12107
  hierarchies.push({
11927
- rootPath: dirname5(orphan.path),
12108
+ rootPath: dirname6(orphan.path),
11928
12109
  root: orphan,
11929
12110
  children: []
11930
12111
  });
@@ -11937,33 +12118,33 @@ function displayResults(result, options) {
11937
12118
  return;
11938
12119
  }
11939
12120
  console.log();
11940
- console.log(chalk17.cyan.bold(" \u{1F4E5} Import Results"));
12121
+ console.log(chalk18.cyan.bold(" \u{1F4E5} Import Results"));
11941
12122
  console.log();
11942
12123
  if (result.totalFound === 0) {
11943
- console.log(chalk17.yellow(" No AGENTS.md or compatible files found."));
11944
- console.log(chalk17.gray(" Try running from your project root, or use --pattern to specify custom filenames."));
12124
+ console.log(chalk18.yellow(" No AGENTS.md or compatible files found."));
12125
+ console.log(chalk18.gray(" Try running from your project root, or use --pattern to specify custom filenames."));
11945
12126
  return;
11946
12127
  }
11947
- console.log(chalk17.green(` Found ${result.totalFound} configuration file(s)`));
12128
+ console.log(chalk18.green(` Found ${result.totalFound} configuration file(s)`));
11948
12129
  console.log();
11949
12130
  for (const hierarchy of result.hierarchy) {
11950
12131
  const isMonorepo = hierarchy.children.length > 0;
11951
12132
  if (hierarchy.root) {
11952
12133
  const icon = isMonorepo ? "\u{1F3E2}" : "\u{1F4C4}";
11953
- const typeLabel = isMonorepo ? chalk17.magenta("[Monorepo Root]") : chalk17.blue("[Standalone]");
11954
- console.log(` ${icon} ${chalk17.white.bold(hierarchy.root.name)} ${typeLabel}`);
11955
- console.log(chalk17.gray(` ${hierarchy.root.relativePath}`));
12134
+ const typeLabel = isMonorepo ? chalk18.magenta("[Monorepo Root]") : chalk18.blue("[Standalone]");
12135
+ console.log(` ${icon} ${chalk18.white.bold(hierarchy.root.name)} ${typeLabel}`);
12136
+ console.log(chalk18.gray(` ${hierarchy.root.relativePath}`));
11956
12137
  if (options.verbose && hierarchy.root.sections.length > 0) {
11957
12138
  const sectionNames = hierarchy.root.sections.slice(0, 5).map((s) => s.title);
11958
- console.log(chalk17.gray(` Sections: ${sectionNames.join(", ")}${hierarchy.root.sections.length > 5 ? "..." : ""}`));
12139
+ console.log(chalk18.gray(` Sections: ${sectionNames.join(", ")}${hierarchy.root.sections.length > 5 ? "..." : ""}`));
11959
12140
  }
11960
12141
  }
11961
12142
  for (const child of hierarchy.children) {
11962
- console.log(` \u2514\u2500 \u{1F4C4} ${chalk17.white(child.name)}`);
11963
- console.log(chalk17.gray(` ${child.relativePath}`));
12143
+ console.log(` \u2514\u2500 \u{1F4C4} ${chalk18.white(child.name)}`);
12144
+ console.log(chalk18.gray(` ${child.relativePath}`));
11964
12145
  if (options.verbose && child.sections.length > 0) {
11965
12146
  const sectionNames = child.sections.slice(0, 3).map((s) => s.title);
11966
- console.log(chalk17.gray(` Sections: ${sectionNames.join(", ")}${child.sections.length > 3 ? "..." : ""}`));
12147
+ console.log(chalk18.gray(` Sections: ${sectionNames.join(", ")}${child.sections.length > 3 ? "..." : ""}`));
11967
12148
  }
11968
12149
  }
11969
12150
  console.log();
@@ -11971,16 +12152,16 @@ function displayResults(result, options) {
11971
12152
  const monorepoCount = result.hierarchy.filter((h) => h.children.length > 0).length;
11972
12153
  const standaloneCount = result.hierarchy.filter((h) => h.children.length === 0).length;
11973
12154
  if (monorepoCount > 0) {
11974
- console.log(chalk17.cyan(` \u{1F4CA} ${monorepoCount} monorepo(s) detected with hierarchical configs`));
12155
+ console.log(chalk18.cyan(` \u{1F4CA} ${monorepoCount} monorepo(s) detected with hierarchical configs`));
11975
12156
  }
11976
12157
  if (standaloneCount > 0) {
11977
- console.log(chalk17.cyan(` \u{1F4CA} ${standaloneCount} standalone config(s)`));
12158
+ console.log(chalk18.cyan(` \u{1F4CA} ${standaloneCount} standalone config(s)`));
11978
12159
  }
11979
12160
  if (result.errors.length > 0) {
11980
12161
  console.log();
11981
- console.log(chalk17.yellow(" \u26A0\uFE0F Warnings:"));
12162
+ console.log(chalk18.yellow(" \u26A0\uFE0F Warnings:"));
11982
12163
  for (const error of result.errors) {
11983
- console.log(chalk17.gray(` ${error}`));
12164
+ console.log(chalk18.gray(` ${error}`));
11984
12165
  }
11985
12166
  }
11986
12167
  }
@@ -11988,15 +12169,15 @@ async function importCommand(path3 = ".", options) {
11988
12169
  const json = Boolean(options.json);
11989
12170
  if (!json) {
11990
12171
  console.log();
11991
- console.log(chalk17.cyan.bold(" \u{1F4E5} LynxPrompt Import"));
11992
- console.log(chalk17.gray(" Scan and import AGENTS.md files and AI commands from your repository"));
12172
+ console.log(chalk18.cyan.bold(" \u{1F4E5} LynxPrompt Import"));
12173
+ console.log(chalk18.gray(" Scan and import AGENTS.md files and AI commands from your repository"));
11993
12174
  console.log();
11994
12175
  }
11995
12176
  const rootPath = resolve4(process.cwd(), path3);
11996
12177
  try {
11997
- await access7(rootPath);
12178
+ await access8(rootPath);
11998
12179
  } catch {
11999
- console.error(chalk17.red(` \u2717 Path not found: ${rootPath}`));
12180
+ console.error(chalk18.red(` \u2717 Path not found: ${rootPath}`));
12000
12181
  process.exit(1);
12001
12182
  }
12002
12183
  const spinner = ora14({ text: "Scanning for configuration files and commands...", isSilent: json }).start();
@@ -12011,10 +12192,10 @@ async function importCommand(path3 = ".", options) {
12011
12192
  }
12012
12193
  spinner.warn("No configuration files or commands found");
12013
12194
  console.log();
12014
- console.log(chalk17.gray(" Looking for:"));
12015
- console.log(chalk17.gray(" \u2022 Rules: AGENTS.md, CLAUDE.md, .cursorrules, .windsurfrules"));
12016
- console.log(chalk17.gray(" \u2022 Commands: .cursor/commands/*.md, .claude/commands/*.md"));
12017
- console.log(chalk17.gray(" Try specifying a different path or use --pattern for custom filenames"));
12195
+ console.log(chalk18.gray(" Looking for:"));
12196
+ console.log(chalk18.gray(" \u2022 Rules: AGENTS.md, CLAUDE.md, .cursorrules, .windsurfrules"));
12197
+ console.log(chalk18.gray(" \u2022 Commands: .cursor/commands/*.md, .claude/commands/*.md"));
12198
+ console.log(chalk18.gray(" Try specifying a different path or use --pattern for custom filenames"));
12018
12199
  return;
12019
12200
  }
12020
12201
  if (json) spinner.stop();
@@ -12031,31 +12212,31 @@ async function importCommand(path3 = ".", options) {
12031
12212
  if (json) return;
12032
12213
  if (commands.length > 0) {
12033
12214
  console.log();
12034
- console.log(chalk17.cyan.bold(" \u26A1 AI Agent Commands"));
12215
+ console.log(chalk18.cyan.bold(" \u26A1 AI Agent Commands"));
12035
12216
  console.log();
12036
12217
  const cursorCommands = commands.filter((c) => c.type === "cursor-command");
12037
12218
  const claudeCommands = commands.filter((c) => c.type === "claude-command");
12038
12219
  if (cursorCommands.length > 0) {
12039
- console.log(chalk17.blue(` Cursor Commands (${cursorCommands.length}):`));
12220
+ console.log(chalk18.blue(` Cursor Commands (${cursorCommands.length}):`));
12040
12221
  for (const cmd of cursorCommands) {
12041
- console.log(chalk17.gray(` \u26A1 ${cmd.name}`));
12042
- console.log(chalk17.gray(` ${relative3(rootPath, cmd.path)}`));
12222
+ console.log(chalk18.gray(` \u26A1 ${cmd.name}`));
12223
+ console.log(chalk18.gray(` ${relative3(rootPath, cmd.path)}`));
12043
12224
  }
12044
12225
  console.log();
12045
12226
  }
12046
12227
  if (claudeCommands.length > 0) {
12047
- console.log(chalk17.yellow(` Claude Commands (${claudeCommands.length}):`));
12228
+ console.log(chalk18.yellow(` Claude Commands (${claudeCommands.length}):`));
12048
12229
  for (const cmd of claudeCommands) {
12049
- console.log(chalk17.gray(` \u{1F9E0} ${cmd.name}`));
12050
- console.log(chalk17.gray(` ${relative3(rootPath, cmd.path)}`));
12230
+ console.log(chalk18.gray(` \u{1F9E0} ${cmd.name}`));
12231
+ console.log(chalk18.gray(` ${relative3(rootPath, cmd.path)}`));
12051
12232
  }
12052
12233
  console.log();
12053
12234
  }
12054
- console.log(chalk17.cyan(" \u{1F4A1} Push commands with: lynxp push .cursor/commands/my-command.md"));
12235
+ console.log(chalk18.cyan(" \u{1F4A1} Push commands with: lynxp push .cursor/commands/my-command.md"));
12055
12236
  }
12056
12237
  if (options.dryRun) {
12057
- console.log(chalk17.yellow(" \u{1F4CB} Dry run complete - no changes made"));
12058
- console.log(chalk17.gray(" Remove --dry-run to proceed with import"));
12238
+ console.log(chalk18.yellow(" \u{1F4CB} Dry run complete - no changes made"));
12239
+ console.log(chalk18.gray(" Remove --dry-run to proceed with import"));
12059
12240
  return;
12060
12241
  }
12061
12242
  if (!options.json) {
@@ -12074,15 +12255,15 @@ async function importCommand(path3 = ".", options) {
12074
12255
  });
12075
12256
  switch (action) {
12076
12257
  case "convert":
12077
- console.log(chalk17.cyan("\n \u{1F4A1} Use 'lynxp convert <file> agents' to convert individual files"));
12078
- console.log(chalk17.cyan(" or 'lynxp merge <files...>' to combine multiple configs\n"));
12258
+ console.log(chalk18.cyan("\n \u{1F4A1} Use 'lynxp convert <file> agents' to convert individual files"));
12259
+ console.log(chalk18.cyan(" or 'lynxp merge <files...>' to combine multiple configs\n"));
12079
12260
  break;
12080
12261
  case "save":
12081
12262
  await saveHierarchyInfo(rootPath, result);
12082
12263
  break;
12083
12264
  case "push":
12084
- console.log(chalk17.cyan("\n \u{1F4A1} Use 'lynxp push <file>' to push files individually"));
12085
- console.log(chalk17.cyan(" Requires login: 'lynxp login'\n"));
12265
+ console.log(chalk18.cyan("\n \u{1F4A1} Use 'lynxp push <file>' to push files individually"));
12266
+ console.log(chalk18.cyan(" Requires login: 'lynxp login'\n"));
12086
12267
  break;
12087
12268
  default:
12088
12269
  break;
@@ -12090,15 +12271,15 @@ async function importCommand(path3 = ".", options) {
12090
12271
  }
12091
12272
  } catch (error) {
12092
12273
  spinner.fail("Import failed");
12093
- console.error(chalk17.red(` Error: ${error instanceof Error ? error.message : "Unknown error"}`));
12274
+ console.error(chalk18.red(` Error: ${error instanceof Error ? error.message : "Unknown error"}`));
12094
12275
  process.exit(1);
12095
12276
  }
12096
12277
  }
12097
12278
  async function saveHierarchyInfo(rootPath, result) {
12098
- const { writeFile: writeFile6, mkdir: mkdir4 } = await import("fs/promises");
12099
- const configDir = join9(rootPath, ".lynxprompt");
12279
+ const { writeFile: writeFile7, mkdir: mkdir5 } = await import("fs/promises");
12280
+ const configDir = join10(rootPath, ".lynxprompt");
12100
12281
  try {
12101
- await mkdir4(configDir, { recursive: true });
12282
+ await mkdir5(configDir, { recursive: true });
12102
12283
  const hierarchyInfo = {
12103
12284
  scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
12104
12285
  rootPath,
@@ -12114,25 +12295,25 @@ async function saveHierarchyInfo(rootPath, result) {
12114
12295
  }))
12115
12296
  }))
12116
12297
  };
12117
- await writeFile6(
12118
- join9(configDir, "hierarchy.json"),
12298
+ await writeFile7(
12299
+ join10(configDir, "hierarchy.json"),
12119
12300
  JSON.stringify(hierarchyInfo, null, 2),
12120
12301
  "utf-8"
12121
12302
  );
12122
- console.log(chalk17.green("\n \u2713 Hierarchy saved to .lynxprompt/hierarchy.json"));
12123
- console.log(chalk17.gray(" The wizard will use this to understand your monorepo structure"));
12303
+ console.log(chalk18.green("\n \u2713 Hierarchy saved to .lynxprompt/hierarchy.json"));
12304
+ console.log(chalk18.gray(" The wizard will use this to understand your monorepo structure"));
12124
12305
  } catch (error) {
12125
- console.error(chalk17.red(` \u2717 Failed to save hierarchy: ${error instanceof Error ? error.message : "Unknown"}`));
12306
+ console.error(chalk18.red(` \u2717 Failed to save hierarchy: ${error instanceof Error ? error.message : "Unknown"}`));
12126
12307
  }
12127
12308
  }
12128
12309
 
12129
12310
  // src/commands/hierarchies.ts
12130
- import chalk18 from "chalk";
12311
+ import chalk19 from "chalk";
12131
12312
  import ora15 from "ora";
12132
12313
  async function hierarchiesCommand(options) {
12133
12314
  if (!isAuthenticated()) {
12134
- console.log(chalk18.yellow("You need to be logged in to view hierarchies."));
12135
- console.log(chalk18.gray("Run 'lynxp login' to authenticate."));
12315
+ console.log(chalk19.yellow("You need to be logged in to view hierarchies."));
12316
+ console.log(chalk19.gray("Run 'lynxp login' to authenticate."));
12136
12317
  process.exit(1);
12137
12318
  }
12138
12319
  const spinner = ora15("Fetching hierarchies...").start();
@@ -12148,32 +12329,32 @@ async function hierarchiesCommand(options) {
12148
12329
  const { hierarchies, total } = response;
12149
12330
  if (hierarchies.length === 0) {
12150
12331
  console.log();
12151
- console.log(chalk18.yellow("No hierarchies found."));
12332
+ console.log(chalk19.yellow("No hierarchies found."));
12152
12333
  console.log();
12153
- console.log(chalk18.gray("Hierarchies are created automatically when you push AGENTS.md files from a repository."));
12154
- console.log(chalk18.gray("Run 'lynxp push AGENTS.md' in a git repository to create a hierarchy."));
12334
+ console.log(chalk19.gray("Hierarchies are created automatically when you push AGENTS.md files from a repository."));
12335
+ console.log(chalk19.gray("Run 'lynxp push AGENTS.md' in a git repository to create a hierarchy."));
12155
12336
  console.log();
12156
12337
  return;
12157
12338
  }
12158
12339
  console.log();
12159
- console.log(chalk18.cyan(`\u{1F4C1} Your Hierarchies (${total} total)`));
12340
+ console.log(chalk19.cyan(`\u{1F4C1} Your Hierarchies (${total} total)`));
12160
12341
  console.log();
12161
12342
  for (const hierarchy of hierarchies) {
12162
- console.log(chalk18.bold(` ${hierarchy.name}`));
12163
- console.log(chalk18.gray(` ID: ${hierarchy.id}`));
12343
+ console.log(chalk19.bold(` ${hierarchy.name}`));
12344
+ console.log(chalk19.gray(` ID: ${hierarchy.id}`));
12164
12345
  if (hierarchy.description) {
12165
- console.log(chalk18.gray(` ${hierarchy.description}`));
12346
+ console.log(chalk19.gray(` ${hierarchy.description}`));
12166
12347
  }
12167
- console.log(chalk18.gray(` Blueprints: ${hierarchy.blueprint_count || 0}`));
12168
- console.log(chalk18.gray(` Repository: ${hierarchy.repository_root.slice(0, 16)}...`));
12348
+ console.log(chalk19.gray(` Blueprints: ${hierarchy.blueprint_count || 0}`));
12349
+ console.log(chalk19.gray(` Repository: ${hierarchy.repository_root.slice(0, 16)}...`));
12169
12350
  console.log();
12170
12351
  }
12171
- console.log(chalk18.gray("\u2500".repeat(50)));
12352
+ console.log(chalk19.gray("\u2500".repeat(50)));
12172
12353
  console.log();
12173
- console.log(chalk18.gray("Tips:"));
12174
- console.log(chalk18.gray(` \u2022 Pull entire hierarchy: lynxp pull <hierarchy_id>`));
12175
- console.log(chalk18.gray(` \u2022 Preview a hierarchy: lynxp pull <hierarchy_id> --preview`));
12176
- console.log(chalk18.gray(` \u2022 Push local changes: lynxp push --all`));
12354
+ console.log(chalk19.gray("Tips:"));
12355
+ console.log(chalk19.gray(` \u2022 Pull entire hierarchy: lynxp pull <hierarchy_id>`));
12356
+ console.log(chalk19.gray(` \u2022 Preview a hierarchy: lynxp pull <hierarchy_id> --preview`));
12357
+ console.log(chalk19.gray(` \u2022 Push local changes: lynxp push --all`));
12177
12358
  console.log();
12178
12359
  } catch (error) {
12179
12360
  spinner.fail("Failed to fetch hierarchies");
@@ -12182,46 +12363,46 @@ async function hierarchiesCommand(options) {
12182
12363
  }
12183
12364
  function handleError2(error) {
12184
12365
  if (error instanceof ApiRequestError) {
12185
- console.error(chalk18.red(`Error: ${error.message}`));
12366
+ console.error(chalk19.red(`Error: ${error.message}`));
12186
12367
  if (error.statusCode === 401) {
12187
- console.error(chalk18.gray("Your session may have expired. Run 'lynxp login' to re-authenticate."));
12368
+ console.error(chalk19.gray("Your session may have expired. Run 'lynxp login' to re-authenticate."));
12188
12369
  } else if (error.statusCode === 403) {
12189
- console.error(chalk18.gray("You don't have permission to access hierarchies."));
12370
+ console.error(chalk19.gray("You don't have permission to access hierarchies."));
12190
12371
  }
12191
12372
  } else {
12192
- console.error(chalk18.red("An unexpected error occurred."));
12373
+ console.error(chalk19.red("An unexpected error occurred."));
12193
12374
  }
12194
12375
  process.exit(1);
12195
12376
  }
12196
12377
 
12197
12378
  // src/commands/config.ts
12198
- import chalk19 from "chalk";
12379
+ import chalk20 from "chalk";
12199
12380
  function printLoginState() {
12200
12381
  if (isAuthenticated()) {
12201
12382
  const email = getUser()?.email;
12202
- console.log(chalk19.gray(` Logged in${email ? ` as ${email}` : ""} on this instance.`));
12383
+ console.log(chalk20.gray(` Logged in${email ? ` as ${email}` : ""} on this instance.`));
12203
12384
  } else {
12204
- console.log(chalk19.gray(" Run 'lynxp login' to authenticate with this instance."));
12385
+ console.log(chalk20.gray(" Run 'lynxp login' to authenticate with this instance."));
12205
12386
  }
12206
12387
  }
12207
12388
  async function configCommand(action, valueArg) {
12208
12389
  if (!action || action === "show") {
12209
12390
  console.log();
12210
- console.log(chalk19.cyan("\u2699\uFE0F LynxPrompt CLI Configuration"));
12391
+ console.log(chalk20.cyan("\u2699\uFE0F LynxPrompt CLI Configuration"));
12211
12392
  console.log();
12212
12393
  console.log(
12213
- chalk19.white(" API URL: ") + chalk19.green(getApiUrl())
12394
+ chalk20.white(" API URL: ") + chalk20.green(getApiUrl())
12214
12395
  );
12215
12396
  const loggedIn = isAuthenticated();
12216
12397
  console.log(
12217
- chalk19.white(" Login: ") + (loggedIn ? chalk19.green(getUser()?.email ?? "token set") : chalk19.gray("not logged in"))
12398
+ chalk20.white(" Login: ") + (loggedIn ? chalk20.green(getUser()?.email ?? "token set") : chalk20.gray("not logged in"))
12218
12399
  );
12219
12400
  console.log(
12220
- chalk19.white(" Config: ") + chalk19.gray(getConfigPath())
12401
+ chalk20.white(" Config: ") + chalk20.gray(getConfigPath())
12221
12402
  );
12222
12403
  if (process.env.LYNXPROMPT_API_URL) {
12223
12404
  console.log(
12224
- chalk19.gray(
12405
+ chalk20.gray(
12225
12406
  " (API URL overridden by LYNXPROMPT_API_URL env var)"
12226
12407
  )
12227
12408
  );
@@ -12232,20 +12413,20 @@ async function configCommand(action, valueArg) {
12232
12413
  if (action === "set-url") {
12233
12414
  if (!valueArg) {
12234
12415
  console.error(
12235
- chalk19.red("Usage: lynxp config set-url <url>")
12416
+ chalk20.red("Usage: lynxp config set-url <url>")
12236
12417
  );
12237
12418
  process.exit(1);
12238
12419
  }
12239
12420
  try {
12240
12421
  new URL(valueArg);
12241
12422
  } catch {
12242
- console.error(chalk19.red(`Invalid URL: ${valueArg}`));
12423
+ console.error(chalk20.red(`Invalid URL: ${valueArg}`));
12243
12424
  process.exit(1);
12244
12425
  }
12245
12426
  const clean = valueArg.replace(/\/+$/, "");
12246
12427
  setApiUrl(clean);
12247
12428
  console.log(
12248
- chalk19.green("\u2713") + ` API URL set to ${chalk19.cyan(clean)}`
12429
+ chalk20.green("\u2713") + ` API URL set to ${chalk20.cyan(clean)}`
12249
12430
  );
12250
12431
  printLoginState();
12251
12432
  return;
@@ -12253,7 +12434,7 @@ async function configCommand(action, valueArg) {
12253
12434
  if (action === "reset-url") {
12254
12435
  const url = resetApiUrl();
12255
12436
  console.log(
12256
- chalk19.green("\u2713") + " API URL reset to " + chalk19.cyan(url)
12437
+ chalk20.green("\u2713") + " API URL reset to " + chalk20.cyan(url)
12257
12438
  );
12258
12439
  printLoginState();
12259
12440
  return;
@@ -12262,13 +12443,13 @@ async function configCommand(action, valueArg) {
12262
12443
  console.log(getConfigPath());
12263
12444
  return;
12264
12445
  }
12265
- console.error(chalk19.red(`Unknown config action: ${action}`));
12266
- console.error(chalk19.gray("Available: show, set-url <url>, reset-url, path"));
12446
+ console.error(chalk20.red(`Unknown config action: ${action}`));
12447
+ console.error(chalk20.gray("Available: show, set-url <url>, reset-url, path"));
12267
12448
  process.exit(1);
12268
12449
  }
12269
12450
 
12270
12451
  // src/index.ts
12271
- var CLI_VERSION2 = "2.1.39";
12452
+ var CLI_VERSION2 = "2.1.40";
12272
12453
  var program = new Command();
12273
12454
  program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
12274
12455
  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);
@@ -12278,7 +12459,7 @@ program.command("convert <source> [target]").description("Convert AI config betw
12278
12459
  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);
12279
12460
  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("-v, --verbose", "Show detailed section information").option("-j, --json", "Output as JSON").action(importCommand);
12280
12461
  program.command("status").description("Show current AI configuration and tracked blueprints").action(statusCommand);
12281
- 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);
12462
+ 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").option("--vars <values>", "Fill [[VARIABLES]]: VAR1=value1,VAR2=value2 (others get their defaults)").action(pullCommand);
12282
12463
  program.command("search <query>").description("Search public blueprints in the marketplace").option("-l, --limit <number>", "Number of results", "20").action(searchCommand);
12283
12464
  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);
12284
12465
  program.command("push [file]").description("Push local file to LynxPrompt cloud as a blueprint").option("-a, --all", "Scan recursively and push ALL AI config files (40+ types)").option("-n, --name <name>", "Blueprint name").option("-d, --description <desc>", "Blueprint description").option("-v, --visibility <vis>", "Visibility: PRIVATE, TEAM, or PUBLIC (default: PRIVATE)").option("-t, --tags <tags>", "Tags (comma-separated)").option("-y, --yes", "Skip prompts").option("-f, --force", "Force push (overwrite remote changes)").option("--allow-sensitive", "Publish public content even if it looks like it holds secrets").action(pushCommand);
@@ -12286,6 +12467,7 @@ program.command("hierarchies").description("List your blueprint hierarchies (mon
12286
12467
  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);
12287
12468
  program.command("unlink [file]").description("Disconnect a local file from its cloud blueprint").action(unlinkCommand);
12288
12469
  program.command("diff [file-or-id]").description("Compare tracked files with their cloud blueprints").option("--local", "Compare .lynxprompt/rules/ with exported files").action(diffCommand);
12470
+ program.command("sync [file]").description("Pull cloud changes and push local ones for tracked files; conflicts go to <file>.remote").option("--dry-run", "Show what would change without writing or pushing").action(syncCommand);
12289
12471
  program.command("login").description("Authenticate with LynxPrompt (opens browser)").action(loginCommand);
12290
12472
  program.command("logout").description("Log out and remove stored credentials").action(logoutCommand);
12291
12473
  program.command("whoami").description("Show current authenticated user").action(whoamiCommand);
@@ -12293,51 +12475,53 @@ program.command("config [action] [value]").description("View or change CLI setti
12293
12475
  program.addHelpText(
12294
12476
  "beforeAll",
12295
12477
  `
12296
- ${chalk20.cyan("\u{1F431} LynxPrompt CLI")} ${chalk20.gray("(also available as: lynxp)")}
12297
- ${chalk20.gray("Generate AI IDE configuration files from your terminal")}
12478
+ ${chalk21.cyan("\u{1F431} LynxPrompt CLI")} ${chalk21.gray("(also available as: lynxp)")}
12479
+ ${chalk21.gray("Generate AI IDE configuration files from your terminal")}
12298
12480
  `
12299
12481
  );
12300
12482
  program.addHelpText(
12301
12483
  "after",
12302
12484
  `
12303
- ${chalk20.cyan("Quick Start:")}
12304
- ${chalk20.white("$ lynxp wizard")} ${chalk20.gray("Generate config interactively")}
12305
- ${chalk20.white("$ lynxp wizard -y")} ${chalk20.gray("Generate AGENTS.md with defaults")}
12306
- ${chalk20.white("$ lynxp wizard -f cursor")} ${chalk20.gray("Generate .cursor/rules/")}
12307
- ${chalk20.white("$ lynxp wizard --blueprint")} ${chalk20.gray("Generate with [[VAR|default]] placeholders")}
12308
-
12309
- ${chalk20.cyan("Analysis & Tools:")}
12310
- ${chalk20.white("$ lynxp analyze")} ${chalk20.gray("Analyze project tech stack")}
12311
- ${chalk20.white("$ lynxp analyze -r <url>")} ${chalk20.gray("Analyze remote repository")}
12312
- ${chalk20.white("$ lynxp import")} ${chalk20.gray("Scan repo for AGENTS.md files")}
12313
- ${chalk20.white("$ lynxp import --dry-run")} ${chalk20.gray("Preview monorepo hierarchy")}
12314
- ${chalk20.white("$ lynxp convert AGENTS.md cursor")} ${chalk20.gray("Convert to Cursor format")}
12315
- ${chalk20.white("$ lynxp merge a.md b.md -o out.md")} ${chalk20.gray("Merge multiple configs")}
12316
-
12317
- ${chalk20.cyan("Marketplace:")}
12318
- ${chalk20.white("$ lynxp search nextjs")} ${chalk20.gray("Search blueprints")}
12319
- ${chalk20.white("$ lynxp pull bp_abc123")} ${chalk20.gray("Download and track a blueprint")}
12320
- ${chalk20.white("$ lynxp pull ha_xyz789")} ${chalk20.gray("Download entire hierarchy")}
12321
- ${chalk20.white("$ lynxp push")} ${chalk20.gray("Push local file to cloud")}
12322
- ${chalk20.white("$ lynxp push --all")} ${chalk20.gray("Push ALL config files recursively")}
12323
- ${chalk20.white("$ lynxp hierarchies")} ${chalk20.gray("List your hierarchies")}
12324
- ${chalk20.white("$ lynxp link --list")} ${chalk20.gray("Show tracked blueprints")}
12325
-
12326
- ${chalk20.cyan("Blueprint Tracking:")}
12327
- ${chalk20.white("$ lynxp link AGENTS.md bp_xyz")} ${chalk20.gray("Link existing file to blueprint")}
12328
- ${chalk20.white("$ lynxp unlink AGENTS.md")} ${chalk20.gray("Disconnect from cloud")}
12329
- ${chalk20.white("$ lynxp diff bp_abc123")} ${chalk20.gray("Show changes vs cloud version")}
12330
-
12331
- ${chalk20.cyan("CI/CD:")}
12332
- ${chalk20.white("$ lynxp check --ci")} ${chalk20.gray("Validate config (exit code)")}
12333
-
12334
- ${chalk20.cyan("Configuration:")}
12335
- ${chalk20.white("$ lynxp config")} ${chalk20.gray("Show current settings")}
12336
- ${chalk20.white("$ lynxp config set-url <url>")} ${chalk20.gray("Point CLI to a self-hosted instance")}
12337
- ${chalk20.white("$ lynxp config reset-url")} ${chalk20.gray("Reset to https://lynxprompt.com")}
12338
- ${chalk20.white("$ lynxp config path")} ${chalk20.gray("Show config file location")}
12339
-
12340
- ${chalk20.gray("Docs: https://lynxprompt.com/docs/cli")}
12485
+ ${chalk21.cyan("Quick Start:")}
12486
+ ${chalk21.white("$ lynxp wizard")} ${chalk21.gray("Generate config interactively")}
12487
+ ${chalk21.white("$ lynxp wizard -y")} ${chalk21.gray("Generate AGENTS.md with defaults")}
12488
+ ${chalk21.white("$ lynxp wizard -f cursor")} ${chalk21.gray("Generate .cursor/rules/")}
12489
+ ${chalk21.white("$ lynxp wizard --blueprint")} ${chalk21.gray("Generate with [[VAR|default]] placeholders")}
12490
+
12491
+ ${chalk21.cyan("Analysis & Tools:")}
12492
+ ${chalk21.white("$ lynxp analyze")} ${chalk21.gray("Analyze project tech stack")}
12493
+ ${chalk21.white("$ lynxp analyze -r <url>")} ${chalk21.gray("Analyze remote repository")}
12494
+ ${chalk21.white("$ lynxp import")} ${chalk21.gray("Scan repo for AGENTS.md files")}
12495
+ ${chalk21.white("$ lynxp import --dry-run")} ${chalk21.gray("Preview monorepo hierarchy")}
12496
+ ${chalk21.white("$ lynxp convert AGENTS.md cursor")} ${chalk21.gray("Convert to Cursor format")}
12497
+ ${chalk21.white("$ lynxp merge a.md b.md -o out.md")} ${chalk21.gray("Merge multiple configs")}
12498
+
12499
+ ${chalk21.cyan("Marketplace:")}
12500
+ ${chalk21.white("$ lynxp search nextjs")} ${chalk21.gray("Search blueprints")}
12501
+ ${chalk21.white("$ lynxp pull bp_abc123")} ${chalk21.gray("Download and track a blueprint")}
12502
+ ${chalk21.white("$ lynxp pull ha_xyz789")} ${chalk21.gray("Download entire hierarchy")}
12503
+ ${chalk21.white("$ lynxp push")} ${chalk21.gray("Push local file to cloud")}
12504
+ ${chalk21.white("$ lynxp push --all")} ${chalk21.gray("Push ALL config files recursively")}
12505
+ ${chalk21.white("$ lynxp hierarchies")} ${chalk21.gray("List your hierarchies")}
12506
+ ${chalk21.white("$ lynxp link --list")} ${chalk21.gray("Show tracked blueprints")}
12507
+
12508
+ ${chalk21.cyan("Blueprint Tracking:")}
12509
+ ${chalk21.white("$ lynxp link AGENTS.md bp_xyz")} ${chalk21.gray("Link existing file to blueprint")}
12510
+ ${chalk21.white("$ lynxp unlink AGENTS.md")} ${chalk21.gray("Disconnect from cloud")}
12511
+ ${chalk21.white("$ lynxp diff bp_abc123")} ${chalk21.gray("Show changes vs cloud version")}
12512
+ ${chalk21.white("$ lynxp sync")} ${chalk21.gray("Pull cloud changes, push local ones")}
12513
+ ${chalk21.white("$ lynxp pull bp_x --vars A=1")} ${chalk21.gray("Download with [[A]] filled in")}
12514
+
12515
+ ${chalk21.cyan("CI/CD:")}
12516
+ ${chalk21.white("$ lynxp check --ci")} ${chalk21.gray("Validate config (exit code)")}
12517
+
12518
+ ${chalk21.cyan("Configuration:")}
12519
+ ${chalk21.white("$ lynxp config")} ${chalk21.gray("Show current settings")}
12520
+ ${chalk21.white("$ lynxp config set-url <url>")} ${chalk21.gray("Point CLI to a self-hosted instance")}
12521
+ ${chalk21.white("$ lynxp config reset-url")} ${chalk21.gray("Reset to https://lynxprompt.com")}
12522
+ ${chalk21.white("$ lynxp config path")} ${chalk21.gray("Show config file location")}
12523
+
12524
+ ${chalk21.gray("Docs: https://lynxprompt.com/docs/cli")}
12341
12525
  `
12342
12526
  );
12343
12527
  program.parse();