@jvittechs/jai1-cli 0.1.92 → 0.1.93
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/cli.js +542 -443
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
|
|
|
33
33
|
// package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@jvittechs/jai1-cli",
|
|
36
|
-
version: "0.1.
|
|
36
|
+
version: "0.1.93",
|
|
37
37
|
description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
|
|
38
38
|
type: "module",
|
|
39
39
|
bin: {
|
|
@@ -772,6 +772,316 @@ import { Box as Box2, Text as Text3, useInput, useApp } from "ink";
|
|
|
772
772
|
import Spinner from "ink-spinner";
|
|
773
773
|
import TextInput from "ink-text-input";
|
|
774
774
|
|
|
775
|
+
// src/services/migrate-ide.service.ts
|
|
776
|
+
import { promises as fs4 } from "fs";
|
|
777
|
+
import path from "path";
|
|
778
|
+
import matter from "gray-matter";
|
|
779
|
+
|
|
780
|
+
// src/constants/ide-migration-configs.ts
|
|
781
|
+
var IDE_MIGRATION_CONFIGS = {
|
|
782
|
+
cursor: {
|
|
783
|
+
id: "cursor",
|
|
784
|
+
name: "Cursor",
|
|
785
|
+
icon: "\u{1F52E}",
|
|
786
|
+
basePath: ".cursor",
|
|
787
|
+
rulesPath: "rules",
|
|
788
|
+
workflowsPath: null,
|
|
789
|
+
commandsPath: "commands",
|
|
790
|
+
fileExtension: ".mdc",
|
|
791
|
+
generateFrontmatter: (opts) => {
|
|
792
|
+
const lines = ["---"];
|
|
793
|
+
if (opts.description) {
|
|
794
|
+
lines.push(`description: ${opts.description}`);
|
|
795
|
+
}
|
|
796
|
+
if (opts.globs && opts.globs.length > 0) {
|
|
797
|
+
lines.push(`globs: ${opts.globs.join(", ")}`);
|
|
798
|
+
}
|
|
799
|
+
lines.push(`alwaysApply: ${opts.alwaysApply}`);
|
|
800
|
+
lines.push("---");
|
|
801
|
+
return lines.join("\n");
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
windsurf: {
|
|
805
|
+
id: "windsurf",
|
|
806
|
+
name: "Windsurf",
|
|
807
|
+
icon: "\u{1F3C4}",
|
|
808
|
+
basePath: ".windsurf",
|
|
809
|
+
rulesPath: "rules",
|
|
810
|
+
workflowsPath: "workflows",
|
|
811
|
+
commandsPath: null,
|
|
812
|
+
fileExtension: ".md",
|
|
813
|
+
generateFrontmatter: (opts) => {
|
|
814
|
+
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
815
|
+
return `---
|
|
816
|
+
trigger: ${trigger}
|
|
817
|
+
---`;
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
antigravity: {
|
|
821
|
+
id: "antigravity",
|
|
822
|
+
name: "Antigravity",
|
|
823
|
+
icon: "\u{1F680}",
|
|
824
|
+
basePath: ".agent",
|
|
825
|
+
rulesPath: "rules",
|
|
826
|
+
workflowsPath: "workflows",
|
|
827
|
+
commandsPath: null,
|
|
828
|
+
fileExtension: ".md",
|
|
829
|
+
generateFrontmatter: (opts) => {
|
|
830
|
+
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
831
|
+
return `---
|
|
832
|
+
trigger: ${trigger}
|
|
833
|
+
---`;
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
claudecode: {
|
|
837
|
+
id: "claudecode",
|
|
838
|
+
name: "Claude Code",
|
|
839
|
+
icon: "\u{1F916}",
|
|
840
|
+
basePath: ".claude",
|
|
841
|
+
rulesPath: "rules",
|
|
842
|
+
workflowsPath: null,
|
|
843
|
+
commandsPath: "commands",
|
|
844
|
+
fileExtension: ".md",
|
|
845
|
+
generateFrontmatter: (opts) => {
|
|
846
|
+
const lines = ["---"];
|
|
847
|
+
if (opts.description) {
|
|
848
|
+
lines.push(`description: ${opts.description}`);
|
|
849
|
+
}
|
|
850
|
+
if (opts.globs && opts.globs.length > 0) {
|
|
851
|
+
lines.push(`paths: ${opts.globs.join(", ")}`);
|
|
852
|
+
}
|
|
853
|
+
lines.push("---");
|
|
854
|
+
return lines.join("\n");
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
opencode: {
|
|
858
|
+
id: "opencode",
|
|
859
|
+
name: "OpenCode",
|
|
860
|
+
icon: "\u{1F4BB}",
|
|
861
|
+
basePath: ".opencode",
|
|
862
|
+
rulesPath: "rules",
|
|
863
|
+
workflowsPath: "workflows",
|
|
864
|
+
commandsPath: null,
|
|
865
|
+
fileExtension: ".md",
|
|
866
|
+
generateFrontmatter: (opts) => {
|
|
867
|
+
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
868
|
+
return `---
|
|
869
|
+
trigger: ${trigger}
|
|
870
|
+
---`;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
function getMigrationIDEs() {
|
|
875
|
+
return Object.keys(IDE_MIGRATION_CONFIGS);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// src/services/migrate-ide.service.ts
|
|
879
|
+
var MigrateIdeService = class {
|
|
880
|
+
projectPath;
|
|
881
|
+
jai1Path;
|
|
882
|
+
constructor(projectPath = process.cwd()) {
|
|
883
|
+
this.projectPath = projectPath;
|
|
884
|
+
this.jai1Path = path.join(projectPath, ".jai1");
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Scan .jai1/ directory for content
|
|
888
|
+
*/
|
|
889
|
+
async scanJai1Content() {
|
|
890
|
+
const manualRules = await this.scanContentType("rules");
|
|
891
|
+
const presetRules = await this.scanRulePreset();
|
|
892
|
+
const rules = [...presetRules, ...manualRules];
|
|
893
|
+
const workflows = await this.scanContentType("workflows");
|
|
894
|
+
const commands = [];
|
|
895
|
+
return {
|
|
896
|
+
rules,
|
|
897
|
+
workflows,
|
|
898
|
+
commands,
|
|
899
|
+
totalCount: rules.length + workflows.length + commands.length
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Scan .jai1/rule-preset/ directory for rule preset files
|
|
904
|
+
*/
|
|
905
|
+
async scanRulePreset() {
|
|
906
|
+
const items = [];
|
|
907
|
+
const presetDir = path.join(this.jai1Path, "rule-preset");
|
|
908
|
+
try {
|
|
909
|
+
await fs4.access(presetDir);
|
|
910
|
+
} catch {
|
|
911
|
+
return items;
|
|
912
|
+
}
|
|
913
|
+
const files = await fs4.readdir(presetDir);
|
|
914
|
+
for (const file of files) {
|
|
915
|
+
if (!file.endsWith(".mdc")) continue;
|
|
916
|
+
const filepath = path.join(presetDir, file);
|
|
917
|
+
const stat = await fs4.stat(filepath);
|
|
918
|
+
if (!stat.isFile()) continue;
|
|
919
|
+
const content = await fs4.readFile(filepath, "utf-8");
|
|
920
|
+
let frontmatter = {};
|
|
921
|
+
try {
|
|
922
|
+
const { data } = matter(content);
|
|
923
|
+
frontmatter = data;
|
|
924
|
+
} catch {
|
|
925
|
+
}
|
|
926
|
+
items.push({
|
|
927
|
+
type: "rules",
|
|
928
|
+
name: path.basename(file, ".mdc"),
|
|
929
|
+
filepath,
|
|
930
|
+
relativePath: path.relative(this.projectPath, filepath),
|
|
931
|
+
description: frontmatter.description,
|
|
932
|
+
globs: this.extractGlobs(frontmatter),
|
|
933
|
+
alwaysApply: this.extractAlwaysApply(frontmatter)
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
return items;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Scan a specific content type
|
|
940
|
+
*/
|
|
941
|
+
async scanContentType(type) {
|
|
942
|
+
const items = [];
|
|
943
|
+
const dirPath = path.join(this.jai1Path, type);
|
|
944
|
+
try {
|
|
945
|
+
await fs4.access(dirPath);
|
|
946
|
+
} catch {
|
|
947
|
+
return items;
|
|
948
|
+
}
|
|
949
|
+
const files = await fs4.readdir(dirPath);
|
|
950
|
+
for (const file of files) {
|
|
951
|
+
if (!file.endsWith(".md")) continue;
|
|
952
|
+
const filepath = path.join(dirPath, file);
|
|
953
|
+
const stat = await fs4.stat(filepath);
|
|
954
|
+
if (!stat.isFile()) continue;
|
|
955
|
+
const content = await fs4.readFile(filepath, "utf-8");
|
|
956
|
+
const { data: frontmatter } = matter(content);
|
|
957
|
+
items.push({
|
|
958
|
+
type,
|
|
959
|
+
name: path.basename(file, ".md"),
|
|
960
|
+
filepath,
|
|
961
|
+
relativePath: path.relative(this.projectPath, filepath),
|
|
962
|
+
description: frontmatter.description,
|
|
963
|
+
globs: this.extractGlobs(frontmatter),
|
|
964
|
+
alwaysApply: this.extractAlwaysApply(frontmatter)
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return items;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Generate stub file content with @ reference
|
|
971
|
+
*/
|
|
972
|
+
generateStubContent(ide, sourceItem) {
|
|
973
|
+
const config = IDE_MIGRATION_CONFIGS[ide];
|
|
974
|
+
if (!config) throw new Error(`Unknown IDE: ${ide}`);
|
|
975
|
+
const frontmatter = config.generateFrontmatter({
|
|
976
|
+
description: sourceItem.description,
|
|
977
|
+
globs: sourceItem.globs,
|
|
978
|
+
alwaysApply: sourceItem.alwaysApply,
|
|
979
|
+
sourceFile: sourceItem.relativePath
|
|
980
|
+
});
|
|
981
|
+
const reference = `@${sourceItem.relativePath}`;
|
|
982
|
+
if (frontmatter) {
|
|
983
|
+
return `${frontmatter}
|
|
984
|
+
|
|
985
|
+
${reference}
|
|
986
|
+
`;
|
|
987
|
+
}
|
|
988
|
+
return `${reference}
|
|
989
|
+
`;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Migrate content to specific IDEs
|
|
993
|
+
*/
|
|
994
|
+
async migrate(ides, contentTypes, content, onProgress) {
|
|
995
|
+
const results = [];
|
|
996
|
+
for (const ide of ides) {
|
|
997
|
+
const config = IDE_MIGRATION_CONFIGS[ide];
|
|
998
|
+
if (!config) continue;
|
|
999
|
+
for (const type of contentTypes) {
|
|
1000
|
+
const items = type === "rules" ? content.rules : type === "workflows" ? content.workflows : content.commands;
|
|
1001
|
+
for (const item of items) {
|
|
1002
|
+
const result = await this.migrateItem(ide, config, item);
|
|
1003
|
+
results.push(result);
|
|
1004
|
+
onProgress?.(result);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
return results;
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Migrate a single item
|
|
1012
|
+
*/
|
|
1013
|
+
async migrateItem(ide, config, item) {
|
|
1014
|
+
try {
|
|
1015
|
+
const targetPath = this.getTargetPath(config, item);
|
|
1016
|
+
if (!targetPath) {
|
|
1017
|
+
return {
|
|
1018
|
+
source: item,
|
|
1019
|
+
targetIDE: ide,
|
|
1020
|
+
targetPath: "",
|
|
1021
|
+
status: "skipped",
|
|
1022
|
+
error: `IDE ${config.id} does not support ${item.type}`
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
const targetDir = path.dirname(targetPath);
|
|
1026
|
+
await fs4.mkdir(targetDir, { recursive: true });
|
|
1027
|
+
let status = "created";
|
|
1028
|
+
try {
|
|
1029
|
+
await fs4.access(targetPath);
|
|
1030
|
+
status = "updated";
|
|
1031
|
+
} catch {
|
|
1032
|
+
}
|
|
1033
|
+
const stubContent = this.generateStubContent(ide, item);
|
|
1034
|
+
await fs4.writeFile(targetPath, stubContent, "utf-8");
|
|
1035
|
+
return {
|
|
1036
|
+
source: item,
|
|
1037
|
+
targetIDE: ide,
|
|
1038
|
+
targetPath,
|
|
1039
|
+
status
|
|
1040
|
+
};
|
|
1041
|
+
} catch (error) {
|
|
1042
|
+
return {
|
|
1043
|
+
source: item,
|
|
1044
|
+
targetIDE: ide,
|
|
1045
|
+
targetPath: "",
|
|
1046
|
+
status: "error",
|
|
1047
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Get target file path for an item
|
|
1053
|
+
*/
|
|
1054
|
+
getTargetPath(config, item) {
|
|
1055
|
+
let contentPath = null;
|
|
1056
|
+
switch (item.type) {
|
|
1057
|
+
case "rules":
|
|
1058
|
+
contentPath = config.rulesPath;
|
|
1059
|
+
break;
|
|
1060
|
+
case "workflows":
|
|
1061
|
+
contentPath = config.workflowsPath ?? config.commandsPath;
|
|
1062
|
+
break;
|
|
1063
|
+
case "commands":
|
|
1064
|
+
contentPath = config.commandsPath;
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
if (!contentPath) {
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
const filename = `${item.name}${config.fileExtension}`;
|
|
1071
|
+
return path.join(this.projectPath, config.basePath, contentPath, filename);
|
|
1072
|
+
}
|
|
1073
|
+
// Helper methods
|
|
1074
|
+
extractGlobs(frontmatter) {
|
|
1075
|
+
const globs = frontmatter.globs;
|
|
1076
|
+
if (typeof globs === "string") return [globs];
|
|
1077
|
+
if (Array.isArray(globs)) return globs;
|
|
1078
|
+
return void 0;
|
|
1079
|
+
}
|
|
1080
|
+
extractAlwaysApply(frontmatter) {
|
|
1081
|
+
return frontmatter.alwaysApply === true || frontmatter.trigger === "always" || frontmatter.trigger === "always_on";
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
|
|
775
1085
|
// src/ui/shared/ProgressBar.tsx
|
|
776
1086
|
import React from "react";
|
|
777
1087
|
import { Box, Text } from "ink";
|
|
@@ -888,11 +1198,15 @@ var UnifiedApplyApp = ({
|
|
|
888
1198
|
const [selectedPackageIndex, setSelectedPackageIndex] = useState(0);
|
|
889
1199
|
const [installProgress, setInstallProgress] = useState([]);
|
|
890
1200
|
const [installStats, setInstallStats] = useState({ total: 0, completed: 0, added: 0, updated: 0, failed: 0 });
|
|
1201
|
+
const [availableIdes, setAvailableIdes] = useState([]);
|
|
1202
|
+
const [selectedIdes, setSelectedIdes] = useState(/* @__PURE__ */ new Set());
|
|
1203
|
+
const [ideCursorIndex, setIdeCursorIndex] = useState(0);
|
|
1204
|
+
const [syncProgress, setSyncProgress] = useState([]);
|
|
1205
|
+
const [syncStats, setSyncStats] = useState({ total: 0, completed: 0, created: 0, updated: 0, skipped: 0, errors: 0 });
|
|
891
1206
|
const service = new ComponentsService();
|
|
892
1207
|
useEffect(() => {
|
|
893
1208
|
const loadData = async () => {
|
|
894
1209
|
try {
|
|
895
|
-
setLoading(true);
|
|
896
1210
|
const [comps, tagList, installed] = await Promise.all([
|
|
897
1211
|
service.list(config),
|
|
898
1212
|
service.listTags(config),
|
|
@@ -901,28 +1215,71 @@ var UnifiedApplyApp = ({
|
|
|
901
1215
|
setComponents(comps);
|
|
902
1216
|
setTags(tagList);
|
|
903
1217
|
setInstalledPaths(new Set(Object.keys(installed)));
|
|
1218
|
+
setLoading(false);
|
|
904
1219
|
} catch (err) {
|
|
905
|
-
setError(err instanceof Error ? err.message : "Failed to load
|
|
906
|
-
} finally {
|
|
1220
|
+
setError(err instanceof Error ? err.message : "Failed to load");
|
|
907
1221
|
setLoading(false);
|
|
908
1222
|
}
|
|
909
1223
|
};
|
|
910
1224
|
loadData();
|
|
1225
|
+
setAvailableIdes(getMigrationIDEs());
|
|
911
1226
|
}, []);
|
|
912
1227
|
const filteredComponents = useMemo(() => {
|
|
913
1228
|
if (!searchQuery.trim()) return components;
|
|
914
1229
|
const query = searchQuery.toLowerCase();
|
|
915
1230
|
return components.filter(
|
|
916
|
-
(c) => c.filepath.toLowerCase().includes(query) || c.
|
|
1231
|
+
(c) => c.filepath.toLowerCase().includes(query) || c.tags?.some((t) => t.toLowerCase().includes(query))
|
|
917
1232
|
);
|
|
918
1233
|
}, [components, searchQuery]);
|
|
919
1234
|
useInput((input4, key) => {
|
|
920
|
-
if (viewState === "
|
|
1235
|
+
if (viewState === "done") {
|
|
921
1236
|
if (key.return || input4 === "q" || key.escape) {
|
|
922
1237
|
onExit();
|
|
923
1238
|
}
|
|
924
1239
|
return;
|
|
925
1240
|
}
|
|
1241
|
+
if (viewState === "summary") {
|
|
1242
|
+
if (key.return) {
|
|
1243
|
+
setViewState("ide-sync");
|
|
1244
|
+
} else if (input4 === "s" || input4 === "q" || key.escape) {
|
|
1245
|
+
onExit();
|
|
1246
|
+
}
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
if (viewState === "ide-sync") {
|
|
1250
|
+
if (key.upArrow) {
|
|
1251
|
+
setIdeCursorIndex((prev) => Math.max(0, prev - 1));
|
|
1252
|
+
} else if (key.downArrow) {
|
|
1253
|
+
setIdeCursorIndex((prev) => Math.min(availableIdes.length - 1, prev + 1));
|
|
1254
|
+
} else if (input4 === " ") {
|
|
1255
|
+
const ide = availableIdes[ideCursorIndex];
|
|
1256
|
+
if (ide) {
|
|
1257
|
+
setSelectedIdes((prev) => {
|
|
1258
|
+
const next = new Set(prev);
|
|
1259
|
+
if (next.has(ide)) {
|
|
1260
|
+
next.delete(ide);
|
|
1261
|
+
} else {
|
|
1262
|
+
next.add(ide);
|
|
1263
|
+
}
|
|
1264
|
+
return next;
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
} else if (input4 === "a") {
|
|
1268
|
+
setSelectedIdes(new Set(availableIdes));
|
|
1269
|
+
} else if (input4 === "c") {
|
|
1270
|
+
setSelectedIdes(/* @__PURE__ */ new Set());
|
|
1271
|
+
} else if (key.return) {
|
|
1272
|
+
if (selectedIdes.size > 0) {
|
|
1273
|
+
handleIdeSync();
|
|
1274
|
+
}
|
|
1275
|
+
} else if (input4 === "s" || input4 === "q" || key.escape) {
|
|
1276
|
+
onExit();
|
|
1277
|
+
}
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
if (viewState === "syncing") {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
926
1283
|
if (viewState === "installing") {
|
|
927
1284
|
return;
|
|
928
1285
|
}
|
|
@@ -1037,6 +1394,44 @@ var UnifiedApplyApp = ({
|
|
|
1037
1394
|
}
|
|
1038
1395
|
setViewState("summary");
|
|
1039
1396
|
};
|
|
1397
|
+
const handleIdeSync = async () => {
|
|
1398
|
+
setViewState("syncing");
|
|
1399
|
+
const migrateService = new MigrateIdeService();
|
|
1400
|
+
const content = await migrateService.scanJai1Content();
|
|
1401
|
+
if (content.totalCount === 0) {
|
|
1402
|
+
setSyncStats({ total: 0, completed: 0, created: 0, updated: 0, skipped: 0, errors: 0 });
|
|
1403
|
+
setViewState("done");
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
const selectedIdeList = Array.from(selectedIdes);
|
|
1407
|
+
const contentTypes = ["rules", "workflows"];
|
|
1408
|
+
const totalItems = contentTypes.reduce((sum, type) => {
|
|
1409
|
+
return sum + (type === "rules" ? content.rules.length : type === "workflows" ? content.workflows.length : content.commands.length);
|
|
1410
|
+
}, 0);
|
|
1411
|
+
const totalFiles = totalItems * selectedIdeList.length;
|
|
1412
|
+
setSyncStats({ total: totalFiles, completed: 0, created: 0, updated: 0, skipped: 0, errors: 0 });
|
|
1413
|
+
let created = 0, updated = 0, skipped = 0, errors = 0;
|
|
1414
|
+
let completed = 0;
|
|
1415
|
+
const results = await migrateService.migrate(
|
|
1416
|
+
selectedIdeList,
|
|
1417
|
+
contentTypes,
|
|
1418
|
+
content,
|
|
1419
|
+
(result) => {
|
|
1420
|
+
completed++;
|
|
1421
|
+
if (result.status === "created") created++;
|
|
1422
|
+
else if (result.status === "updated") updated++;
|
|
1423
|
+
else if (result.status === "skipped") skipped++;
|
|
1424
|
+
else if (result.status === "error") errors++;
|
|
1425
|
+
setSyncProgress((prev) => [...prev.slice(-7), {
|
|
1426
|
+
targetPath: result.targetPath || result.source.relativePath,
|
|
1427
|
+
status: result.status === "error" ? "error" : "success",
|
|
1428
|
+
error: result.error
|
|
1429
|
+
}]);
|
|
1430
|
+
setSyncStats({ total: totalFiles, completed, created, updated, skipped, errors });
|
|
1431
|
+
}
|
|
1432
|
+
);
|
|
1433
|
+
setViewState("done");
|
|
1434
|
+
};
|
|
1040
1435
|
if (loading) {
|
|
1041
1436
|
return /* @__PURE__ */ React3.createElement(Box2, { padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, /* @__PURE__ */ React3.createElement(Spinner, { type: "dots" }), " \u0110ang t\u1EA3i components..."));
|
|
1042
1437
|
}
|
|
@@ -1047,7 +1442,21 @@ var UnifiedApplyApp = ({
|
|
|
1047
1442
|
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F4E6} Installing Components")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(ProgressBar, { current: installStats.completed, total: installStats.total, width: 50 })), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1, height: 10 }, installProgress.slice(-8).map((item) => /* @__PURE__ */ React3.createElement(Box2, { key: item.filepath }, /* @__PURE__ */ React3.createElement(StatusIcon, { status: item.status === "success" ? "success" : item.status === "error" ? "error" : item.status === "downloading" ? "loading" : "pending" }), /* @__PURE__ */ React3.createElement(Text3, null, " ", item.filepath), item.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red", dimColor: true }, " (", item.error, ")")))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4CA} ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added, " added"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated, " updated"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed, " failed"))));
|
|
1048
1443
|
}
|
|
1049
1444
|
if (viewState === "summary") {
|
|
1050
|
-
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "\u2705 Installation Complete!")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, installStats.total, " components processed:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added), " newly added"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated), " updated"), installStats.failed > 0 && /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed), " failed")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4C1} Location: ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, process.cwd(), "/.jai1"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "
|
|
1445
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "\u2705 Installation Complete!")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, installStats.total, " components processed:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added), " newly added"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated), " updated"), installStats.failed > 0 && /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed), " failed")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4C1} Location: ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, process.cwd(), "/.jai1"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "yellow" }, "\u{1F4E6} Next Step: Sync to IDE(s)?"), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Sync .jai1/ content to your IDE directories (rules, workflows)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[Enter] Select IDE(s) to sync \xB7 [S/Q] Skip and exit")));
|
|
1446
|
+
}
|
|
1447
|
+
if (viewState === "ide-sync") {
|
|
1448
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F504} Select IDE(s) to Sync")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Sync .jai1/ content (rules, workflows) to IDE-specific directories")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1 }, availableIdes.map((ide, i) => {
|
|
1449
|
+
const ideConfig = IDE_MIGRATION_CONFIGS[ide];
|
|
1450
|
+
const isCursor = i === ideCursorIndex;
|
|
1451
|
+
const isChecked = selectedIdes.has(ide);
|
|
1452
|
+
return /* @__PURE__ */ React3.createElement(Box2, { key: ide }, /* @__PURE__ */ React3.createElement(Text3, { color: isCursor ? "cyan" : "white" }, isCursor ? "\u276F " : " ", isChecked ? "[\u2713]" : "[ ]", " ", ideConfig.icon, " ", ideConfig.name));
|
|
1453
|
+
})), selectedIdes.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "Selected: ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, selectedIdes.size), " IDE(s)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[\u2191\u2193] Navigate \xB7 [\u2423] Toggle \xB7 [A] Select all \xB7 [C] Clear \xB7 [Enter] Sync \xB7 [S/Q] Skip")));
|
|
1454
|
+
}
|
|
1455
|
+
if (viewState === "syncing") {
|
|
1456
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F504} Syncing to IDE(s)")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(ProgressBar, { current: syncStats.completed, total: syncStats.total, width: 50 })), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1, height: 10 }, syncProgress.slice(-8).map((item, idx) => /* @__PURE__ */ React3.createElement(Box2, { key: `${item.targetPath}-${idx}` }, /* @__PURE__ */ React3.createElement(StatusIcon, { status: item.status === "success" ? "success" : item.status === "error" ? "error" : item.status === "syncing" ? "loading" : "pending" }), /* @__PURE__ */ React3.createElement(Text3, null, " ", item.targetPath), item.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red", dimColor: true }, " (", item.error, ")")))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4CA} ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, syncStats.created, " created"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, syncStats.updated, " updated"), syncStats.skipped > 0 && /* @__PURE__ */ React3.createElement(React3.Fragment, null, " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, syncStats.skipped, " skipped")), syncStats.errors > 0 && /* @__PURE__ */ React3.createElement(React3.Fragment, null, " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, syncStats.errors, " errors")))));
|
|
1457
|
+
}
|
|
1458
|
+
if (viewState === "done") {
|
|
1459
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "\u{1F389} All Done!")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "\u{1F4E6} Components Applied:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added), " added, ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated), " updated"), syncStats.total > 0 && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Text3, null, " "), /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "\u{1F504} IDE Sync:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, syncStats.created), " created, ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, syncStats.updated), " updated"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 Synced to: ", Array.from(selectedIdes).map((ide) => IDE_MIGRATION_CONFIGS[ide].name).join(", ")))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4C1} Framework: ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, process.cwd(), "/.jai1"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Press Enter or Q to exit")));
|
|
1051
1460
|
}
|
|
1052
1461
|
const visibleComponents = filteredComponents.slice(0, 12);
|
|
1053
1462
|
const hasMore = filteredComponents.length > 12;
|
|
@@ -1155,6 +1564,8 @@ async function nonInteractiveApply(config, items, options) {
|
|
|
1155
1564
|
console.log(`
|
|
1156
1565
|
\u2705 Complete: ${added} added, ${updated} updated, ${skipped} skipped`);
|
|
1157
1566
|
console.log(`\u{1F4C1} Location: ${targetDir}`);
|
|
1567
|
+
console.log(`
|
|
1568
|
+
\u{1F4A1} Next step: Run "jai1 ide sync" to sync content to your IDE(s)`);
|
|
1158
1569
|
}
|
|
1159
1570
|
|
|
1160
1571
|
// src/commands/update.ts
|
|
@@ -1624,9 +2035,9 @@ var DetailView = ({ item, scrollPosition: initialScroll, onBack }) => {
|
|
|
1624
2035
|
};
|
|
1625
2036
|
|
|
1626
2037
|
// src/services/context-scanner.service.ts
|
|
1627
|
-
import { promises as
|
|
1628
|
-
import
|
|
1629
|
-
import
|
|
2038
|
+
import { promises as fs5 } from "fs";
|
|
2039
|
+
import path2 from "path";
|
|
2040
|
+
import matter2 from "gray-matter";
|
|
1630
2041
|
|
|
1631
2042
|
// src/constants/ide-configs.ts
|
|
1632
2043
|
var IDE_CONFIGS = {
|
|
@@ -1789,8 +2200,8 @@ var ContextScannerService = class {
|
|
|
1789
2200
|
if (!relativePath) return [];
|
|
1790
2201
|
let dirPath;
|
|
1791
2202
|
if (ide === "jai1") {
|
|
1792
|
-
const jai1Path =
|
|
1793
|
-
const frameworkPath =
|
|
2203
|
+
const jai1Path = path2.join(this.projectPath, ".jai1", relativePath);
|
|
2204
|
+
const frameworkPath = path2.join(this.projectPath, "packages/jai1-framework", relativePath);
|
|
1794
2205
|
if (await this.pathExists(jai1Path)) {
|
|
1795
2206
|
dirPath = jai1Path;
|
|
1796
2207
|
} else if (await this.pathExists(frameworkPath)) {
|
|
@@ -1799,9 +2210,9 @@ var ContextScannerService = class {
|
|
|
1799
2210
|
return [];
|
|
1800
2211
|
}
|
|
1801
2212
|
} else {
|
|
1802
|
-
dirPath =
|
|
2213
|
+
dirPath = path2.join(this.projectPath, config.basePath, relativePath);
|
|
1803
2214
|
try {
|
|
1804
|
-
await
|
|
2215
|
+
await fs5.access(dirPath);
|
|
1805
2216
|
} catch {
|
|
1806
2217
|
return [];
|
|
1807
2218
|
}
|
|
@@ -1812,10 +2223,10 @@ var ContextScannerService = class {
|
|
|
1812
2223
|
const skillItems = await this.scanSkills(dirPath, ide);
|
|
1813
2224
|
items.push(...skillItems);
|
|
1814
2225
|
} else {
|
|
1815
|
-
const files = await
|
|
2226
|
+
const files = await fs5.readdir(dirPath);
|
|
1816
2227
|
for (const file of files) {
|
|
1817
|
-
const filepath =
|
|
1818
|
-
const stat = await
|
|
2228
|
+
const filepath = path2.join(dirPath, file);
|
|
2229
|
+
const stat = await fs5.stat(filepath);
|
|
1819
2230
|
if (!stat.isFile()) continue;
|
|
1820
2231
|
const matchesExtension = extensions.some((ext) => file.endsWith(ext));
|
|
1821
2232
|
if (!matchesExtension) continue;
|
|
@@ -1835,20 +2246,20 @@ var ContextScannerService = class {
|
|
|
1835
2246
|
async scanSkills(skillsDir, ide) {
|
|
1836
2247
|
const items = [];
|
|
1837
2248
|
try {
|
|
1838
|
-
const entries = await
|
|
2249
|
+
const entries = await fs5.readdir(skillsDir, { withFileTypes: true });
|
|
1839
2250
|
for (const entry of entries) {
|
|
1840
2251
|
if (!entry.isDirectory()) continue;
|
|
1841
|
-
const skillPath =
|
|
1842
|
-
const skillFilePath =
|
|
2252
|
+
const skillPath = path2.join(skillsDir, entry.name);
|
|
2253
|
+
const skillFilePath = path2.join(skillPath, "SKILL.md");
|
|
1843
2254
|
try {
|
|
1844
|
-
await
|
|
2255
|
+
await fs5.access(skillFilePath);
|
|
1845
2256
|
} catch {
|
|
1846
2257
|
continue;
|
|
1847
2258
|
}
|
|
1848
2259
|
const item = await this.parseContextItem(skillFilePath, ide, "skills");
|
|
1849
|
-
item.hasScripts = await this.pathExists(
|
|
1850
|
-
item.hasReferences = await this.pathExists(
|
|
1851
|
-
item.hasAssets = await this.pathExists(
|
|
2260
|
+
item.hasScripts = await this.pathExists(path2.join(skillPath, "scripts"));
|
|
2261
|
+
item.hasReferences = await this.pathExists(path2.join(skillPath, "references"));
|
|
2262
|
+
item.hasAssets = await this.pathExists(path2.join(skillPath, "assets"));
|
|
1852
2263
|
items.push(item);
|
|
1853
2264
|
}
|
|
1854
2265
|
} catch (error) {
|
|
@@ -1860,9 +2271,9 @@ var ContextScannerService = class {
|
|
|
1860
2271
|
* Parse a context item from file
|
|
1861
2272
|
*/
|
|
1862
2273
|
async parseContextItem(filepath, ide, type) {
|
|
1863
|
-
const content = await
|
|
1864
|
-
const stat = await
|
|
1865
|
-
const { data: frontmatter, content: bodyContent } =
|
|
2274
|
+
const content = await fs5.readFile(filepath, "utf-8");
|
|
2275
|
+
const stat = await fs5.stat(filepath);
|
|
2276
|
+
const { data: frontmatter, content: bodyContent } = matter2(content);
|
|
1866
2277
|
const config = IDE_CONFIGS[ide];
|
|
1867
2278
|
const description = frontmatter[config.frontmatterSchema.descriptionField];
|
|
1868
2279
|
let globs;
|
|
@@ -1878,9 +2289,9 @@ var ContextScannerService = class {
|
|
|
1878
2289
|
globs = triggerValue;
|
|
1879
2290
|
}
|
|
1880
2291
|
const { previewLines, lineCount } = this.extractPreview(bodyContent, 20);
|
|
1881
|
-
const relativePath =
|
|
1882
|
-
const id = `${ide}-${type}-${
|
|
1883
|
-
const name = frontmatter.name ||
|
|
2292
|
+
const relativePath = path2.relative(this.projectPath, filepath);
|
|
2293
|
+
const id = `${ide}-${type}-${path2.basename(filepath, path2.extname(filepath))}`;
|
|
2294
|
+
const name = frontmatter.name || path2.basename(filepath, path2.extname(filepath));
|
|
1884
2295
|
return {
|
|
1885
2296
|
id,
|
|
1886
2297
|
ide,
|
|
@@ -1916,13 +2327,13 @@ var ContextScannerService = class {
|
|
|
1916
2327
|
for (const ide of getAllIDEs()) {
|
|
1917
2328
|
const config = IDE_CONFIGS[ide];
|
|
1918
2329
|
if (ide === "jai1") {
|
|
1919
|
-
const jai1Path =
|
|
1920
|
-
const frameworkPath =
|
|
2330
|
+
const jai1Path = path2.join(this.projectPath, ".jai1");
|
|
2331
|
+
const frameworkPath = path2.join(this.projectPath, "packages/jai1-framework");
|
|
1921
2332
|
if (await this.pathExists(jai1Path) || await this.pathExists(frameworkPath)) {
|
|
1922
2333
|
ides.push(ide);
|
|
1923
2334
|
}
|
|
1924
2335
|
} else {
|
|
1925
|
-
const idePath =
|
|
2336
|
+
const idePath = path2.join(this.projectPath, config.basePath);
|
|
1926
2337
|
if (await this.pathExists(idePath)) {
|
|
1927
2338
|
ides.push(ide);
|
|
1928
2339
|
}
|
|
@@ -1935,7 +2346,7 @@ var ContextScannerService = class {
|
|
|
1935
2346
|
*/
|
|
1936
2347
|
async pathExists(filepath) {
|
|
1937
2348
|
try {
|
|
1938
|
-
await
|
|
2349
|
+
await fs5.access(filepath);
|
|
1939
2350
|
return true;
|
|
1940
2351
|
} catch {
|
|
1941
2352
|
return false;
|
|
@@ -2163,8 +2574,8 @@ async function printStats() {
|
|
|
2163
2574
|
// src/commands/ide/setup.ts
|
|
2164
2575
|
import { Command as Command7 } from "commander";
|
|
2165
2576
|
import { checkbox, confirm as confirm2, select } from "@inquirer/prompts";
|
|
2166
|
-
import
|
|
2167
|
-
import
|
|
2577
|
+
import fs6 from "fs/promises";
|
|
2578
|
+
import path3 from "path";
|
|
2168
2579
|
import { existsSync } from "fs";
|
|
2169
2580
|
var PERFORMANCE_GROUPS = {
|
|
2170
2581
|
telemetry: {
|
|
@@ -2358,432 +2769,120 @@ async function interactiveMode() {
|
|
|
2358
2769
|
const allGroups = Object.keys(PERFORMANCE_GROUPS);
|
|
2359
2770
|
await applyGroups(allGroups, "enable");
|
|
2360
2771
|
} else if (action === "reset") {
|
|
2361
|
-
await resetSettings([]);
|
|
2362
|
-
} else {
|
|
2363
|
-
await selectGroupsToApply(action);
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
async function selectGroupsToApply(action) {
|
|
2367
|
-
const choices = Object.entries(PERFORMANCE_GROUPS).map(([key, group]) => ({
|
|
2368
|
-
name: `${group.name} - ${group.description}`,
|
|
2369
|
-
value: key
|
|
2370
|
-
}));
|
|
2371
|
-
try {
|
|
2372
|
-
const selectedGroups = await checkbox({
|
|
2373
|
-
message: `Select groups to ${action} (SPACE to select, ENTER to confirm):`,
|
|
2374
|
-
choices
|
|
2375
|
-
});
|
|
2376
|
-
if (selectedGroups.length === 0) {
|
|
2377
|
-
console.log("\n\u26A0\uFE0F No groups selected!");
|
|
2378
|
-
console.log(" \u{1F4A1} Tip: Press SPACE to select at least 1 group before pressing ENTER.");
|
|
2379
|
-
return;
|
|
2380
|
-
}
|
|
2381
|
-
await applyGroups(selectedGroups, action);
|
|
2382
|
-
} catch {
|
|
2383
|
-
console.log("\n\u274C Operation cancelled.");
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
async function applyGroups(groupKeys, action) {
|
|
2387
|
-
const vscodeDir = path2.join(process.cwd(), ".vscode");
|
|
2388
|
-
const settingsPath = path2.join(vscodeDir, "settings.json");
|
|
2389
|
-
const invalidGroups = groupKeys.filter((key) => !PERFORMANCE_GROUPS[key]);
|
|
2390
|
-
if (invalidGroups.length > 0) {
|
|
2391
|
-
console.log(`
|
|
2392
|
-
\u274C Invalid groups: ${invalidGroups.join(", ")}`);
|
|
2393
|
-
console.log(' \u{1F4A1} Run "jai1 ide setup list" to see available groups.');
|
|
2394
|
-
return;
|
|
2395
|
-
}
|
|
2396
|
-
if (!existsSync(vscodeDir)) {
|
|
2397
|
-
await fs5.mkdir(vscodeDir, { recursive: true });
|
|
2398
|
-
console.log("\u{1F4C1} Created .vscode/ directory");
|
|
2399
|
-
}
|
|
2400
|
-
let currentSettings = {};
|
|
2401
|
-
if (existsSync(settingsPath)) {
|
|
2402
|
-
try {
|
|
2403
|
-
const content = await fs5.readFile(settingsPath, "utf-8");
|
|
2404
|
-
currentSettings = JSON.parse(content);
|
|
2405
|
-
console.log("\u{1F4C4} Read current settings from settings.json");
|
|
2406
|
-
} catch {
|
|
2407
|
-
console.warn("\u26A0\uFE0F Cannot read settings.json (may contain comments).");
|
|
2408
|
-
const confirmOverwrite = await confirm2({
|
|
2409
|
-
message: "Overwrite current settings.json file?",
|
|
2410
|
-
default: false
|
|
2411
|
-
});
|
|
2412
|
-
if (!confirmOverwrite) {
|
|
2413
|
-
console.log("\u274C Operation cancelled.");
|
|
2414
|
-
return;
|
|
2415
|
-
}
|
|
2416
|
-
currentSettings = {};
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
const newSettings = { ...currentSettings };
|
|
2420
|
-
console.log(`
|
|
2421
|
-
\u{1F4DD} ${action === "enable" ? "Enabling" : "Disabling"} groups:
|
|
2422
|
-
`);
|
|
2423
|
-
for (const key of groupKeys) {
|
|
2424
|
-
const group = PERFORMANCE_GROUPS[key];
|
|
2425
|
-
console.log(` ${action === "enable" ? "\u2713" : "\u2717"} ${group.name}`);
|
|
2426
|
-
if (action === "enable") {
|
|
2427
|
-
for (const [settingKey, settingValue] of Object.entries(group.settings)) {
|
|
2428
|
-
if (typeof settingValue === "object" && settingValue !== null && !Array.isArray(settingValue) && typeof newSettings[settingKey] === "object" && newSettings[settingKey] !== null) {
|
|
2429
|
-
newSettings[settingKey] = {
|
|
2430
|
-
...newSettings[settingKey],
|
|
2431
|
-
...settingValue
|
|
2432
|
-
};
|
|
2433
|
-
} else {
|
|
2434
|
-
newSettings[settingKey] = settingValue;
|
|
2435
|
-
}
|
|
2436
|
-
}
|
|
2437
|
-
} else {
|
|
2438
|
-
for (const settingKey of Object.keys(group.settings)) {
|
|
2439
|
-
delete newSettings[settingKey];
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
await fs5.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
|
2444
|
-
console.log(`
|
|
2445
|
-
\u2705 Updated IDE settings at: ${settingsPath}`);
|
|
2446
|
-
console.log("\u{1F4A1} Tip: Restart your IDE to apply changes.");
|
|
2447
|
-
}
|
|
2448
|
-
async function resetSettings(groupKeys) {
|
|
2449
|
-
const vscodeDir = path2.join(process.cwd(), ".vscode");
|
|
2450
|
-
const settingsPath = path2.join(vscodeDir, "settings.json");
|
|
2451
|
-
if (!existsSync(settingsPath)) {
|
|
2452
|
-
console.log("\n\u26A0\uFE0F No settings.json file found");
|
|
2453
|
-
return;
|
|
2454
|
-
}
|
|
2455
|
-
const confirmReset = await confirm2({
|
|
2456
|
-
message: groupKeys.length === 0 ? "Reset ALL settings to default (delete entire file)?" : `Reset groups: ${groupKeys.join(", ")}?`,
|
|
2457
|
-
default: false
|
|
2458
|
-
});
|
|
2459
|
-
if (!confirmReset) {
|
|
2460
|
-
console.log("\u274C Operation cancelled.");
|
|
2461
|
-
return;
|
|
2462
|
-
}
|
|
2463
|
-
if (groupKeys.length === 0) {
|
|
2464
|
-
await fs5.unlink(settingsPath);
|
|
2465
|
-
console.log("\n\u2705 Deleted settings.json file");
|
|
2466
|
-
} else {
|
|
2467
|
-
await applyGroups(groupKeys, "disable");
|
|
2468
|
-
}
|
|
2469
|
-
console.log("\u{1F4A1} Tip: Restart your IDE to apply changes.");
|
|
2470
|
-
}
|
|
2471
|
-
|
|
2472
|
-
// src/commands/ide/sync.ts
|
|
2473
|
-
import { Command as Command8 } from "commander";
|
|
2474
|
-
import { checkbox as checkbox2, confirm as confirm3 } from "@inquirer/prompts";
|
|
2475
|
-
|
|
2476
|
-
// src/services/migrate-ide.service.ts
|
|
2477
|
-
import { promises as fs6 } from "fs";
|
|
2478
|
-
import path3 from "path";
|
|
2479
|
-
import matter2 from "gray-matter";
|
|
2480
|
-
|
|
2481
|
-
// src/constants/ide-migration-configs.ts
|
|
2482
|
-
var IDE_MIGRATION_CONFIGS = {
|
|
2483
|
-
cursor: {
|
|
2484
|
-
id: "cursor",
|
|
2485
|
-
name: "Cursor",
|
|
2486
|
-
icon: "\u{1F52E}",
|
|
2487
|
-
basePath: ".cursor",
|
|
2488
|
-
rulesPath: "rules",
|
|
2489
|
-
workflowsPath: null,
|
|
2490
|
-
commandsPath: "commands",
|
|
2491
|
-
fileExtension: ".mdc",
|
|
2492
|
-
generateFrontmatter: (opts) => {
|
|
2493
|
-
const lines = ["---"];
|
|
2494
|
-
if (opts.description) {
|
|
2495
|
-
lines.push(`description: ${opts.description}`);
|
|
2496
|
-
}
|
|
2497
|
-
if (opts.globs && opts.globs.length > 0) {
|
|
2498
|
-
lines.push(`globs: ${opts.globs.join(", ")}`);
|
|
2499
|
-
}
|
|
2500
|
-
lines.push(`alwaysApply: ${opts.alwaysApply}`);
|
|
2501
|
-
lines.push("---");
|
|
2502
|
-
return lines.join("\n");
|
|
2503
|
-
}
|
|
2504
|
-
},
|
|
2505
|
-
windsurf: {
|
|
2506
|
-
id: "windsurf",
|
|
2507
|
-
name: "Windsurf",
|
|
2508
|
-
icon: "\u{1F3C4}",
|
|
2509
|
-
basePath: ".windsurf",
|
|
2510
|
-
rulesPath: "rules",
|
|
2511
|
-
workflowsPath: "workflows",
|
|
2512
|
-
commandsPath: null,
|
|
2513
|
-
fileExtension: ".md",
|
|
2514
|
-
generateFrontmatter: (opts) => {
|
|
2515
|
-
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
2516
|
-
return `---
|
|
2517
|
-
trigger: ${trigger}
|
|
2518
|
-
---`;
|
|
2519
|
-
}
|
|
2520
|
-
},
|
|
2521
|
-
antigravity: {
|
|
2522
|
-
id: "antigravity",
|
|
2523
|
-
name: "Antigravity",
|
|
2524
|
-
icon: "\u{1F680}",
|
|
2525
|
-
basePath: ".agent",
|
|
2526
|
-
rulesPath: "rules",
|
|
2527
|
-
workflowsPath: "workflows",
|
|
2528
|
-
commandsPath: null,
|
|
2529
|
-
fileExtension: ".md",
|
|
2530
|
-
generateFrontmatter: (opts) => {
|
|
2531
|
-
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
2532
|
-
return `---
|
|
2533
|
-
trigger: ${trigger}
|
|
2534
|
-
---`;
|
|
2535
|
-
}
|
|
2536
|
-
},
|
|
2537
|
-
claudecode: {
|
|
2538
|
-
id: "claudecode",
|
|
2539
|
-
name: "Claude Code",
|
|
2540
|
-
icon: "\u{1F916}",
|
|
2541
|
-
basePath: ".claude",
|
|
2542
|
-
rulesPath: "rules",
|
|
2543
|
-
workflowsPath: null,
|
|
2544
|
-
commandsPath: "commands",
|
|
2545
|
-
fileExtension: ".md",
|
|
2546
|
-
generateFrontmatter: (opts) => {
|
|
2547
|
-
const lines = ["---"];
|
|
2548
|
-
if (opts.description) {
|
|
2549
|
-
lines.push(`description: ${opts.description}`);
|
|
2550
|
-
}
|
|
2551
|
-
if (opts.globs && opts.globs.length > 0) {
|
|
2552
|
-
lines.push(`paths: ${opts.globs.join(", ")}`);
|
|
2553
|
-
}
|
|
2554
|
-
lines.push("---");
|
|
2555
|
-
return lines.join("\n");
|
|
2556
|
-
}
|
|
2557
|
-
},
|
|
2558
|
-
opencode: {
|
|
2559
|
-
id: "opencode",
|
|
2560
|
-
name: "OpenCode",
|
|
2561
|
-
icon: "\u{1F4BB}",
|
|
2562
|
-
basePath: ".opencode",
|
|
2563
|
-
rulesPath: "rules",
|
|
2564
|
-
workflowsPath: "workflows",
|
|
2565
|
-
commandsPath: null,
|
|
2566
|
-
fileExtension: ".md",
|
|
2567
|
-
generateFrontmatter: (opts) => {
|
|
2568
|
-
const trigger = opts.alwaysApply ? "always" : "glob";
|
|
2569
|
-
return `---
|
|
2570
|
-
trigger: ${trigger}
|
|
2571
|
-
---`;
|
|
2572
|
-
}
|
|
2772
|
+
await resetSettings([]);
|
|
2773
|
+
} else {
|
|
2774
|
+
await selectGroupsToApply(action);
|
|
2573
2775
|
}
|
|
2574
|
-
};
|
|
2575
|
-
function getMigrationIDEs() {
|
|
2576
|
-
return Object.keys(IDE_MIGRATION_CONFIGS);
|
|
2577
2776
|
}
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2777
|
+
async function selectGroupsToApply(action) {
|
|
2778
|
+
const choices = Object.entries(PERFORMANCE_GROUPS).map(([key, group]) => ({
|
|
2779
|
+
name: `${group.name} - ${group.description}`,
|
|
2780
|
+
value: key
|
|
2781
|
+
}));
|
|
2782
|
+
try {
|
|
2783
|
+
const selectedGroups = await checkbox({
|
|
2784
|
+
message: `Select groups to ${action} (SPACE to select, ENTER to confirm):`,
|
|
2785
|
+
choices
|
|
2786
|
+
});
|
|
2787
|
+
if (selectedGroups.length === 0) {
|
|
2788
|
+
console.log("\n\u26A0\uFE0F No groups selected!");
|
|
2789
|
+
console.log(" \u{1F4A1} Tip: Press SPACE to select at least 1 group before pressing ENTER.");
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
await applyGroups(selectedGroups, action);
|
|
2793
|
+
} catch {
|
|
2794
|
+
console.log("\n\u274C Operation cancelled.");
|
|
2586
2795
|
}
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
return
|
|
2597
|
-
rules,
|
|
2598
|
-
workflows,
|
|
2599
|
-
commands,
|
|
2600
|
-
totalCount: rules.length + workflows.length + commands.length
|
|
2601
|
-
};
|
|
2796
|
+
}
|
|
2797
|
+
async function applyGroups(groupKeys, action) {
|
|
2798
|
+
const vscodeDir = path3.join(process.cwd(), ".vscode");
|
|
2799
|
+
const settingsPath = path3.join(vscodeDir, "settings.json");
|
|
2800
|
+
const invalidGroups = groupKeys.filter((key) => !PERFORMANCE_GROUPS[key]);
|
|
2801
|
+
if (invalidGroups.length > 0) {
|
|
2802
|
+
console.log(`
|
|
2803
|
+
\u274C Invalid groups: ${invalidGroups.join(", ")}`);
|
|
2804
|
+
console.log(' \u{1F4A1} Run "jai1 ide setup list" to see available groups.');
|
|
2805
|
+
return;
|
|
2602
2806
|
}
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
async scanRulePreset() {
|
|
2607
|
-
const items = [];
|
|
2608
|
-
const presetDir = path3.join(this.jai1Path, "rule-preset");
|
|
2609
|
-
try {
|
|
2610
|
-
await fs6.access(presetDir);
|
|
2611
|
-
} catch {
|
|
2612
|
-
return items;
|
|
2613
|
-
}
|
|
2614
|
-
const files = await fs6.readdir(presetDir);
|
|
2615
|
-
for (const file of files) {
|
|
2616
|
-
if (!file.endsWith(".mdc")) continue;
|
|
2617
|
-
const filepath = path3.join(presetDir, file);
|
|
2618
|
-
const stat = await fs6.stat(filepath);
|
|
2619
|
-
if (!stat.isFile()) continue;
|
|
2620
|
-
const content = await fs6.readFile(filepath, "utf-8");
|
|
2621
|
-
let frontmatter = {};
|
|
2622
|
-
try {
|
|
2623
|
-
const { data } = matter2(content);
|
|
2624
|
-
frontmatter = data;
|
|
2625
|
-
} catch {
|
|
2626
|
-
}
|
|
2627
|
-
items.push({
|
|
2628
|
-
type: "rules",
|
|
2629
|
-
name: path3.basename(file, ".mdc"),
|
|
2630
|
-
filepath,
|
|
2631
|
-
relativePath: path3.relative(this.projectPath, filepath),
|
|
2632
|
-
description: frontmatter.description,
|
|
2633
|
-
globs: this.extractGlobs(frontmatter),
|
|
2634
|
-
alwaysApply: this.extractAlwaysApply(frontmatter)
|
|
2635
|
-
});
|
|
2636
|
-
}
|
|
2637
|
-
return items;
|
|
2807
|
+
if (!existsSync(vscodeDir)) {
|
|
2808
|
+
await fs6.mkdir(vscodeDir, { recursive: true });
|
|
2809
|
+
console.log("\u{1F4C1} Created .vscode/ directory");
|
|
2638
2810
|
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
*/
|
|
2642
|
-
async scanContentType(type) {
|
|
2643
|
-
const items = [];
|
|
2644
|
-
const dirPath = path3.join(this.jai1Path, type);
|
|
2811
|
+
let currentSettings = {};
|
|
2812
|
+
if (existsSync(settingsPath)) {
|
|
2645
2813
|
try {
|
|
2646
|
-
await fs6.
|
|
2814
|
+
const content = await fs6.readFile(settingsPath, "utf-8");
|
|
2815
|
+
currentSettings = JSON.parse(content);
|
|
2816
|
+
console.log("\u{1F4C4} Read current settings from settings.json");
|
|
2647
2817
|
} catch {
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
if (!file.endsWith(".md")) continue;
|
|
2653
|
-
const filepath = path3.join(dirPath, file);
|
|
2654
|
-
const stat = await fs6.stat(filepath);
|
|
2655
|
-
if (!stat.isFile()) continue;
|
|
2656
|
-
const content = await fs6.readFile(filepath, "utf-8");
|
|
2657
|
-
const { data: frontmatter } = matter2(content);
|
|
2658
|
-
items.push({
|
|
2659
|
-
type,
|
|
2660
|
-
name: path3.basename(file, ".md"),
|
|
2661
|
-
filepath,
|
|
2662
|
-
relativePath: path3.relative(this.projectPath, filepath),
|
|
2663
|
-
description: frontmatter.description,
|
|
2664
|
-
globs: this.extractGlobs(frontmatter),
|
|
2665
|
-
alwaysApply: this.extractAlwaysApply(frontmatter)
|
|
2818
|
+
console.warn("\u26A0\uFE0F Cannot read settings.json (may contain comments).");
|
|
2819
|
+
const confirmOverwrite = await confirm2({
|
|
2820
|
+
message: "Overwrite current settings.json file?",
|
|
2821
|
+
default: false
|
|
2666
2822
|
});
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
/**
|
|
2671
|
-
* Generate stub file content with @ reference
|
|
2672
|
-
*/
|
|
2673
|
-
generateStubContent(ide, sourceItem) {
|
|
2674
|
-
const config = IDE_MIGRATION_CONFIGS[ide];
|
|
2675
|
-
if (!config) throw new Error(`Unknown IDE: ${ide}`);
|
|
2676
|
-
const frontmatter = config.generateFrontmatter({
|
|
2677
|
-
description: sourceItem.description,
|
|
2678
|
-
globs: sourceItem.globs,
|
|
2679
|
-
alwaysApply: sourceItem.alwaysApply,
|
|
2680
|
-
sourceFile: sourceItem.relativePath
|
|
2681
|
-
});
|
|
2682
|
-
const reference = `@${sourceItem.relativePath}`;
|
|
2683
|
-
if (frontmatter) {
|
|
2684
|
-
return `${frontmatter}
|
|
2685
|
-
|
|
2686
|
-
${reference}
|
|
2687
|
-
`;
|
|
2688
|
-
}
|
|
2689
|
-
return `${reference}
|
|
2690
|
-
`;
|
|
2691
|
-
}
|
|
2692
|
-
/**
|
|
2693
|
-
* Migrate content to specific IDEs
|
|
2694
|
-
*/
|
|
2695
|
-
async migrate(ides, contentTypes, content, onProgress) {
|
|
2696
|
-
const results = [];
|
|
2697
|
-
for (const ide of ides) {
|
|
2698
|
-
const config = IDE_MIGRATION_CONFIGS[ide];
|
|
2699
|
-
if (!config) continue;
|
|
2700
|
-
for (const type of contentTypes) {
|
|
2701
|
-
const items = type === "rules" ? content.rules : type === "workflows" ? content.workflows : content.commands;
|
|
2702
|
-
for (const item of items) {
|
|
2703
|
-
const result = await this.migrateItem(ide, config, item);
|
|
2704
|
-
results.push(result);
|
|
2705
|
-
onProgress?.(result);
|
|
2706
|
-
}
|
|
2823
|
+
if (!confirmOverwrite) {
|
|
2824
|
+
console.log("\u274C Operation cancelled.");
|
|
2825
|
+
return;
|
|
2707
2826
|
}
|
|
2827
|
+
currentSettings = {};
|
|
2708
2828
|
}
|
|
2709
|
-
return results;
|
|
2710
2829
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2830
|
+
const newSettings = { ...currentSettings };
|
|
2831
|
+
console.log(`
|
|
2832
|
+
\u{1F4DD} ${action === "enable" ? "Enabling" : "Disabling"} groups:
|
|
2833
|
+
`);
|
|
2834
|
+
for (const key of groupKeys) {
|
|
2835
|
+
const group = PERFORMANCE_GROUPS[key];
|
|
2836
|
+
console.log(` ${action === "enable" ? "\u2713" : "\u2717"} ${group.name}`);
|
|
2837
|
+
if (action === "enable") {
|
|
2838
|
+
for (const [settingKey, settingValue] of Object.entries(group.settings)) {
|
|
2839
|
+
if (typeof settingValue === "object" && settingValue !== null && !Array.isArray(settingValue) && typeof newSettings[settingKey] === "object" && newSettings[settingKey] !== null) {
|
|
2840
|
+
newSettings[settingKey] = {
|
|
2841
|
+
...newSettings[settingKey],
|
|
2842
|
+
...settingValue
|
|
2843
|
+
};
|
|
2844
|
+
} else {
|
|
2845
|
+
newSettings[settingKey] = settingValue;
|
|
2846
|
+
}
|
|
2725
2847
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
try {
|
|
2730
|
-
await fs6.access(targetPath);
|
|
2731
|
-
status = "updated";
|
|
2732
|
-
} catch {
|
|
2848
|
+
} else {
|
|
2849
|
+
for (const settingKey of Object.keys(group.settings)) {
|
|
2850
|
+
delete newSettings[settingKey];
|
|
2733
2851
|
}
|
|
2734
|
-
const stubContent = this.generateStubContent(ide, item);
|
|
2735
|
-
await fs6.writeFile(targetPath, stubContent, "utf-8");
|
|
2736
|
-
return {
|
|
2737
|
-
source: item,
|
|
2738
|
-
targetIDE: ide,
|
|
2739
|
-
targetPath,
|
|
2740
|
-
status
|
|
2741
|
-
};
|
|
2742
|
-
} catch (error) {
|
|
2743
|
-
return {
|
|
2744
|
-
source: item,
|
|
2745
|
-
targetIDE: ide,
|
|
2746
|
-
targetPath: "",
|
|
2747
|
-
status: "error",
|
|
2748
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
2749
|
-
};
|
|
2750
2852
|
}
|
|
2751
2853
|
}
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
break;
|
|
2764
|
-
case "commands":
|
|
2765
|
-
contentPath = config.commandsPath;
|
|
2766
|
-
break;
|
|
2767
|
-
}
|
|
2768
|
-
if (!contentPath) {
|
|
2769
|
-
return null;
|
|
2770
|
-
}
|
|
2771
|
-
const filename = `${item.name}${config.fileExtension}`;
|
|
2772
|
-
return path3.join(this.projectPath, config.basePath, contentPath, filename);
|
|
2854
|
+
await fs6.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
|
2855
|
+
console.log(`
|
|
2856
|
+
\u2705 Updated IDE settings at: ${settingsPath}`);
|
|
2857
|
+
console.log("\u{1F4A1} Tip: Restart your IDE to apply changes.");
|
|
2858
|
+
}
|
|
2859
|
+
async function resetSettings(groupKeys) {
|
|
2860
|
+
const vscodeDir = path3.join(process.cwd(), ".vscode");
|
|
2861
|
+
const settingsPath = path3.join(vscodeDir, "settings.json");
|
|
2862
|
+
if (!existsSync(settingsPath)) {
|
|
2863
|
+
console.log("\n\u26A0\uFE0F No settings.json file found");
|
|
2864
|
+
return;
|
|
2773
2865
|
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2866
|
+
const confirmReset = await confirm2({
|
|
2867
|
+
message: groupKeys.length === 0 ? "Reset ALL settings to default (delete entire file)?" : `Reset groups: ${groupKeys.join(", ")}?`,
|
|
2868
|
+
default: false
|
|
2869
|
+
});
|
|
2870
|
+
if (!confirmReset) {
|
|
2871
|
+
console.log("\u274C Operation cancelled.");
|
|
2872
|
+
return;
|
|
2780
2873
|
}
|
|
2781
|
-
|
|
2782
|
-
|
|
2874
|
+
if (groupKeys.length === 0) {
|
|
2875
|
+
await fs6.unlink(settingsPath);
|
|
2876
|
+
console.log("\n\u2705 Deleted settings.json file");
|
|
2877
|
+
} else {
|
|
2878
|
+
await applyGroups(groupKeys, "disable");
|
|
2783
2879
|
}
|
|
2784
|
-
};
|
|
2880
|
+
console.log("\u{1F4A1} Tip: Restart your IDE to apply changes.");
|
|
2881
|
+
}
|
|
2785
2882
|
|
|
2786
2883
|
// src/commands/ide/sync.ts
|
|
2884
|
+
import { Command as Command8 } from "commander";
|
|
2885
|
+
import { checkbox as checkbox2, confirm as confirm3 } from "@inquirer/prompts";
|
|
2787
2886
|
function createSyncSubcommand() {
|
|
2788
2887
|
const cmd = new Command8("sync").description("Sync .jai1 content to IDE directories (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
|
|
2789
2888
|
await runSync(options);
|
|
@@ -5662,7 +5761,7 @@ function createImageDeleteCommand() {
|
|
|
5662
5761
|
|
|
5663
5762
|
// src/commands/image/index.ts
|
|
5664
5763
|
function createImageCommand() {
|
|
5665
|
-
const cmd = new Command20("image").description("Image generation commands");
|
|
5764
|
+
const cmd = new Command20("image").description("Image generation commands (Coming Soon)");
|
|
5666
5765
|
cmd.addCommand(createImageGenCommand());
|
|
5667
5766
|
cmd.addCommand(createImageListCommand());
|
|
5668
5767
|
cmd.addCommand(createImageInfoCommand());
|