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