set-prompt 0.5.4 → 0.6.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/CHANGELOG.md +24 -0
- package/README.md +27 -4
- package/dist/index.js +793 -383
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk21 from "chalk";
|
|
6
6
|
import figlet from "figlet";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import fs12 from "fs";
|
|
8
|
+
import path11 from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
10
|
|
|
11
11
|
// src/commands/install-command.ts
|
|
12
|
-
import
|
|
12
|
+
import fs4 from "fs";
|
|
13
13
|
import path3 from "path";
|
|
14
|
-
import { spawnSync } from "child_process";
|
|
15
|
-
import
|
|
14
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
15
|
+
import chalk5 from "chalk";
|
|
16
16
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
17
17
|
|
|
18
18
|
// src/_defs/index.ts
|
|
@@ -239,6 +239,8 @@ var ConfigManager = class {
|
|
|
239
239
|
var configManager = new ConfigManager();
|
|
240
240
|
|
|
241
241
|
// src/_libs/index.ts
|
|
242
|
+
import { spawnSync } from "child_process";
|
|
243
|
+
import fs2 from "fs";
|
|
242
244
|
import chalk2 from "chalk";
|
|
243
245
|
var isGitUrl = (source) => source.startsWith("http://") || source.startsWith("https://") || source.startsWith("git@") || source.startsWith("ssh://") || source.endsWith(".git") && (source.startsWith("http") || source.startsWith("git@") || source.startsWith("ssh://"));
|
|
244
246
|
var resolveRepoPath = () => {
|
|
@@ -249,11 +251,71 @@ var resolveRepoPath = () => {
|
|
|
249
251
|
}
|
|
250
252
|
return configManager.repo_path;
|
|
251
253
|
};
|
|
254
|
+
var isOnPath = (bin) => {
|
|
255
|
+
const probeCmd = process.platform === "win32" ? "where" : "which";
|
|
256
|
+
const probe = spawnSync(probeCmd, [bin], { stdio: "ignore" });
|
|
257
|
+
return probe.status === 0;
|
|
258
|
+
};
|
|
259
|
+
var firstExistingPath = (candidates) => {
|
|
260
|
+
for (const candidate of candidates) {
|
|
261
|
+
if (candidate != null && candidate !== "" && fs2.existsSync(candidate)) return candidate;
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/_libs/repo.ts
|
|
267
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
268
|
+
import chalk3 from "chalk";
|
|
269
|
+
var parsePorcelainLine = (line) => {
|
|
270
|
+
if (line.length < 4) return null;
|
|
271
|
+
const status = line.slice(0, 2);
|
|
272
|
+
let name = line.slice(3);
|
|
273
|
+
const arrowIdx = name.indexOf(" -> ");
|
|
274
|
+
if (arrowIdx >= 0) name = name.slice(arrowIdx + 4);
|
|
275
|
+
if (name.startsWith('"') && name.endsWith('"')) name = name.slice(1, -1);
|
|
276
|
+
if (status.includes("?")) return { kind: "?", name };
|
|
277
|
+
if (status.includes("D")) return { kind: "D", name };
|
|
278
|
+
if (status.includes("R")) return { kind: "R", name };
|
|
279
|
+
if (status.includes("A")) return { kind: "A", name };
|
|
280
|
+
if (status.includes("M")) return { kind: "M", name };
|
|
281
|
+
return null;
|
|
282
|
+
};
|
|
283
|
+
var pickVerb = (files) => {
|
|
284
|
+
const allAdded = files.every((f) => f.kind === "A" || f.kind === "?");
|
|
285
|
+
const allDeleted = files.every((f) => f.kind === "D");
|
|
286
|
+
if (allAdded) return "add";
|
|
287
|
+
if (allDeleted) return "remove";
|
|
288
|
+
return "update";
|
|
289
|
+
};
|
|
290
|
+
var generateCommitMessage = (repoPath) => {
|
|
291
|
+
const result = spawnSync2("git", ["status", "--porcelain", "--untracked-files=all"], {
|
|
292
|
+
cwd: repoPath,
|
|
293
|
+
encoding: "utf8"
|
|
294
|
+
});
|
|
295
|
+
if (result.status !== 0) return null;
|
|
296
|
+
const files = result.stdout.split("\n").map(parsePorcelainLine).filter((f) => f !== null);
|
|
297
|
+
if (files.length === 0) return null;
|
|
298
|
+
const verb = pickVerb(files);
|
|
299
|
+
const noun = files.length === 1 ? "file" : "files";
|
|
300
|
+
const subject = `${verb} ${files.length} ${noun}`;
|
|
301
|
+
const body = files.map((f) => `- ${f.name}`).join("\n");
|
|
302
|
+
return `${subject}
|
|
303
|
+
|
|
304
|
+
${body}`;
|
|
305
|
+
};
|
|
306
|
+
var printSaveHint = (repoPath) => {
|
|
307
|
+
const generated = generateCommitMessage(repoPath);
|
|
308
|
+
if (generated == null) return;
|
|
309
|
+
const subject = generated.split("\n")[0];
|
|
310
|
+
console.log(chalk3.yellow("\nUncommitted changes detected."));
|
|
311
|
+
console.log(chalk3.dim(` Pending: ${subject}`));
|
|
312
|
+
console.log(chalk3.cyan(" Tip: run `sppt repo save` to commit and push."));
|
|
313
|
+
};
|
|
252
314
|
|
|
253
315
|
// src/commands/scaffold-command.ts
|
|
254
|
-
import
|
|
316
|
+
import fs3 from "fs";
|
|
255
317
|
import path2 from "path";
|
|
256
|
-
import
|
|
318
|
+
import chalk4 from "chalk";
|
|
257
319
|
import { confirm } from "@inquirer/prompts";
|
|
258
320
|
|
|
259
321
|
// src/_libs/templates.ts
|
|
@@ -299,8 +361,23 @@ set-prompt scaffold .
|
|
|
299
361
|
set-prompt install https://github.com/you/my-prompts
|
|
300
362
|
set-prompt link
|
|
301
363
|
|
|
302
|
-
#
|
|
303
|
-
set-prompt
|
|
364
|
+
# Inspect current state (branch, ahead/behind, changed files)
|
|
365
|
+
set-prompt repo status
|
|
366
|
+
|
|
367
|
+
# Pull latest changes from remote
|
|
368
|
+
set-prompt repo pull
|
|
369
|
+
|
|
370
|
+
# Commit + push local edits in one step (auto-generates message if -m omitted)
|
|
371
|
+
set-prompt repo save -m "update skills"
|
|
372
|
+
set-prompt repo save
|
|
373
|
+
|
|
374
|
+
# Or commit and push separately
|
|
375
|
+
set-prompt repo commit -m "update skills"
|
|
376
|
+
set-prompt repo push
|
|
377
|
+
|
|
378
|
+
# Jump into the repo or open it in an editor
|
|
379
|
+
cd "$(set-prompt repo path)"
|
|
380
|
+
set-prompt repo open --code
|
|
304
381
|
\`\`\`
|
|
305
382
|
|
|
306
383
|
## Frontmatter Reference
|
|
@@ -650,43 +727,86 @@ echo '{"permission":"deny","user_message":"Blocked by policy","agent_message":"N
|
|
|
650
727
|
`;
|
|
651
728
|
|
|
652
729
|
// src/commands/scaffold-command.ts
|
|
730
|
+
var validateClaudePluginManifest = (data) => {
|
|
731
|
+
const issues = [];
|
|
732
|
+
if (typeof data !== "object" || data === null) return ["root must be a JSON object"];
|
|
733
|
+
const obj = data;
|
|
734
|
+
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
735
|
+
issues.push('"name" is required and must be a non-empty string');
|
|
736
|
+
}
|
|
737
|
+
return issues;
|
|
738
|
+
};
|
|
739
|
+
var validateCodexPluginManifest = (data) => {
|
|
740
|
+
const issues = [];
|
|
741
|
+
if (typeof data !== "object" || data === null) return ["root must be a JSON object"];
|
|
742
|
+
const obj = data;
|
|
743
|
+
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
744
|
+
issues.push('"name" is required and must be a non-empty string');
|
|
745
|
+
}
|
|
746
|
+
if (typeof obj.skills !== "string" || obj.skills.length === 0) {
|
|
747
|
+
issues.push('"skills" is required and must be a string path (e.g. "./skills/")');
|
|
748
|
+
}
|
|
749
|
+
if (typeof obj.mcpServers !== "string" || obj.mcpServers.length === 0) {
|
|
750
|
+
issues.push('"mcpServers" is required and must be a string path (e.g. "./.mcp.json")');
|
|
751
|
+
}
|
|
752
|
+
if (typeof obj.apps !== "string" || obj.apps.length === 0) {
|
|
753
|
+
issues.push('"apps" is required and must be a string path (e.g. "./.app.json")');
|
|
754
|
+
}
|
|
755
|
+
return issues;
|
|
756
|
+
};
|
|
757
|
+
var ensureManifest = (jsonPath, metaDir, validate, defaultData, label) => {
|
|
758
|
+
if (fs3.existsSync(jsonPath)) {
|
|
759
|
+
try {
|
|
760
|
+
const parsed = JSON.parse(fs3.readFileSync(jsonPath, "utf-8"));
|
|
761
|
+
const issues = validate(parsed);
|
|
762
|
+
if (issues.length === 0) return "valid";
|
|
763
|
+
console.warn(chalk4.yellow(` \u26A0 ${label} has issues \u2014 keeping existing file:`));
|
|
764
|
+
for (const issue of issues) console.warn(chalk4.dim(` ${issue}`));
|
|
765
|
+
return "invalid";
|
|
766
|
+
} catch (ex) {
|
|
767
|
+
console.warn(chalk4.yellow(` \u26A0 ${label} failed to parse: ${ex.message} \u2014 keeping existing file`));
|
|
768
|
+
return "invalid";
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
fs3.mkdirSync(metaDir, { recursive: true });
|
|
772
|
+
fs3.writeFileSync(jsonPath, JSON.stringify(defaultData, null, 4), { encoding: "utf-8" });
|
|
773
|
+
return "created";
|
|
774
|
+
};
|
|
653
775
|
var ensureClaudePluginManifest = (repoPath) => {
|
|
654
776
|
const metaDir = path2.join(repoPath, ".claude-plugin");
|
|
655
777
|
const jsonPath = path2.join(metaDir, "plugin.json");
|
|
656
|
-
|
|
657
|
-
fs2.writeFileSync(jsonPath, JSON.stringify({
|
|
778
|
+
return ensureManifest(jsonPath, metaDir, validateClaudePluginManifest, {
|
|
658
779
|
name: PLUGIN_NAME,
|
|
659
780
|
version: "1.0.0",
|
|
660
781
|
description: "Managed by set-prompt"
|
|
661
|
-
},
|
|
782
|
+
}, ".claude-plugin/plugin.json");
|
|
662
783
|
};
|
|
663
784
|
var ensureCodexPluginManifest = (repoPath) => {
|
|
664
785
|
const metaDir = path2.join(repoPath, ".codex-plugin");
|
|
665
786
|
const jsonPath = path2.join(metaDir, "plugin.json");
|
|
666
|
-
|
|
667
|
-
fs2.writeFileSync(jsonPath, JSON.stringify({
|
|
787
|
+
return ensureManifest(jsonPath, metaDir, validateCodexPluginManifest, {
|
|
668
788
|
name: PLUGIN_NAME,
|
|
669
789
|
version: "1.0.0",
|
|
670
790
|
description: "Managed by set-prompt",
|
|
671
791
|
skills: "./skills/",
|
|
672
792
|
mcpServers: "./.mcp.json",
|
|
673
793
|
apps: "./.app.json"
|
|
674
|
-
},
|
|
794
|
+
}, ".codex-plugin/plugin.json");
|
|
675
795
|
};
|
|
676
796
|
var ensureMcpJson = (repoPath) => {
|
|
677
797
|
const mcpJsonPath = path2.join(repoPath, ".mcp.json");
|
|
678
|
-
if (
|
|
798
|
+
if (fs3.existsSync(mcpJsonPath)) {
|
|
679
799
|
return false;
|
|
680
800
|
}
|
|
681
|
-
|
|
801
|
+
fs3.writeFileSync(mcpJsonPath, JSON.stringify({ mcpServers: {} }, null, 4), { encoding: "utf-8" });
|
|
682
802
|
return true;
|
|
683
803
|
};
|
|
684
804
|
var ensureAppJson = (repoPath) => {
|
|
685
805
|
const appJsonPath = path2.join(repoPath, ".app.json");
|
|
686
|
-
if (
|
|
806
|
+
if (fs3.existsSync(appJsonPath)) {
|
|
687
807
|
return false;
|
|
688
808
|
}
|
|
689
|
-
|
|
809
|
+
fs3.writeFileSync(appJsonPath, JSON.stringify({ apps: {} }, null, 4), { encoding: "utf-8" });
|
|
690
810
|
return true;
|
|
691
811
|
};
|
|
692
812
|
var scaffoldCommand = async (localPath) => {
|
|
@@ -698,15 +818,15 @@ var scaffoldCommand = async (localPath) => {
|
|
|
698
818
|
if (configManager.repo_path != null) {
|
|
699
819
|
targetPath = configManager.repo_path;
|
|
700
820
|
} else {
|
|
701
|
-
console.error(
|
|
821
|
+
console.error(chalk4.red("No path provided and no repo registered. Please provide a path."));
|
|
702
822
|
process.exit(1);
|
|
703
823
|
}
|
|
704
824
|
}
|
|
705
|
-
if (
|
|
706
|
-
console.error(
|
|
825
|
+
if (fs3.existsSync(targetPath) === false || fs3.statSync(targetPath).isDirectory() === false) {
|
|
826
|
+
console.error(chalk4.red(`Invalid directory path: '${targetPath}'`));
|
|
707
827
|
process.exit(1);
|
|
708
828
|
}
|
|
709
|
-
console.log(
|
|
829
|
+
console.log(chalk4.dim(`Scaffolding: ${targetPath}
|
|
710
830
|
`));
|
|
711
831
|
const writeGuide = await confirm({
|
|
712
832
|
message: "Generate SET_PROMPT_GUIDE.md? (reference doc for writing prompts)",
|
|
@@ -714,32 +834,36 @@ var scaffoldCommand = async (localPath) => {
|
|
|
714
834
|
});
|
|
715
835
|
if (writeGuide) {
|
|
716
836
|
const guideMdPath = path2.join(targetPath, "SET_PROMPT_GUIDE.md");
|
|
717
|
-
|
|
718
|
-
console.log(`${TAB}${
|
|
837
|
+
fs3.writeFileSync(guideMdPath, SET_PROMPT_GUIDE, { encoding: "utf-8", flag: "w" });
|
|
838
|
+
console.log(`${TAB}${chalk4.green("\u2713")} SET_PROMPT_GUIDE.md`);
|
|
719
839
|
}
|
|
720
840
|
for (const dirName of PROMPT_DIR_NAMES) {
|
|
721
841
|
const dirPath = path2.join(targetPath, dirName);
|
|
722
|
-
if (
|
|
723
|
-
console.log(`${TAB}${
|
|
842
|
+
if (fs3.existsSync(dirPath)) {
|
|
843
|
+
console.log(`${TAB}${chalk4.dim("\u2713")} ${dirName}/`);
|
|
724
844
|
} else {
|
|
725
|
-
|
|
726
|
-
console.log(`${TAB}${
|
|
845
|
+
fs3.mkdirSync(dirPath, { recursive: true });
|
|
846
|
+
console.log(`${TAB}${chalk4.green("+")} ${dirName}/`);
|
|
727
847
|
}
|
|
728
848
|
const gitkeepPath = path2.join(dirPath, ".gitkeep");
|
|
729
|
-
if (!
|
|
730
|
-
|
|
849
|
+
if (!fs3.existsSync(gitkeepPath)) {
|
|
850
|
+
fs3.writeFileSync(gitkeepPath, "", { encoding: "utf-8" });
|
|
731
851
|
}
|
|
732
852
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
console.log(`${TAB}${
|
|
738
|
-
console.log(`${TAB}${
|
|
739
|
-
console.log(
|
|
853
|
+
const symFor = (r) => r === "created" ? chalk4.green("+") : r === "valid" ? chalk4.dim("\u2713") : chalk4.yellow("\u26A0");
|
|
854
|
+
const claudeResult = ensureClaudePluginManifest(targetPath);
|
|
855
|
+
console.log(`${TAB}${symFor(claudeResult)} .claude-plugin/plugin.json`);
|
|
856
|
+
const codexResult = ensureCodexPluginManifest(targetPath);
|
|
857
|
+
console.log(`${TAB}${symFor(codexResult)} .codex-plugin/plugin.json`);
|
|
858
|
+
console.log(`${TAB}${ensureMcpJson(targetPath) ? chalk4.green("+") : chalk4.dim("\u2713")} .mcp.json`);
|
|
859
|
+
console.log(`${TAB}${ensureAppJson(targetPath) ? chalk4.green("+") : chalk4.dim("\u2713")} .app.json`);
|
|
860
|
+
console.log(chalk4.green("\nScaffold complete."));
|
|
861
|
+
if (configManager.repo_path != null && path2.resolve(targetPath) === path2.resolve(configManager.repo_path)) {
|
|
862
|
+
printSaveHint(targetPath);
|
|
863
|
+
}
|
|
740
864
|
return true;
|
|
741
865
|
} catch (ex) {
|
|
742
|
-
console.error(
|
|
866
|
+
console.error(chalk4.red(`Failed to scaffold repo structure: ${ex.message}`), ex);
|
|
743
867
|
throw ex;
|
|
744
868
|
}
|
|
745
869
|
};
|
|
@@ -748,86 +872,87 @@ var scaffoldCommand = async (localPath) => {
|
|
|
748
872
|
var cloneRepo = async (remoteUrl) => {
|
|
749
873
|
const localPath = path3.join(HOME_DIR, "repo");
|
|
750
874
|
let backupPath = null;
|
|
751
|
-
if (
|
|
875
|
+
if (fs4.existsSync(localPath) == true) {
|
|
752
876
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
753
877
|
backupPath = path3.join(HOME_DIR, `repo.bak.${timestamp}`);
|
|
754
878
|
try {
|
|
755
|
-
|
|
756
|
-
console.log(
|
|
879
|
+
fs4.renameSync(localPath, backupPath);
|
|
880
|
+
console.log(chalk5.yellow(" backed up") + chalk5.dim(` existing repo \u2192 ${backupPath}`));
|
|
757
881
|
} catch (ex) {
|
|
758
882
|
if (ex.code === "EPERM") {
|
|
759
|
-
console.error(
|
|
760
|
-
console.log(
|
|
883
|
+
console.error(chalk5.red("\u274C Cannot rename existing repo \u2014 it may be open in another process."));
|
|
884
|
+
console.log(chalk5.dim(` Close any editors or terminals using: ${localPath}`));
|
|
761
885
|
} else {
|
|
762
|
-
console.error(
|
|
886
|
+
console.error(chalk5.red(`\u274C Failed to backup existing repo: ${ex.message}`));
|
|
763
887
|
}
|
|
764
888
|
return false;
|
|
765
889
|
}
|
|
766
890
|
}
|
|
767
|
-
|
|
891
|
+
fs4.mkdirSync(path3.dirname(localPath), { recursive: true });
|
|
768
892
|
console.log(`Cloning ${remoteUrl}...`);
|
|
769
|
-
const result =
|
|
893
|
+
const result = spawnSync3("git", ["clone", remoteUrl, localPath], { stdio: "inherit" });
|
|
770
894
|
if (result.status !== 0) {
|
|
771
895
|
console.log("\u274C Failed to clone. Check the URL and your git credentials.");
|
|
772
896
|
process.exit(1);
|
|
773
897
|
}
|
|
774
898
|
console.log("\u2705 Cloned successfully.");
|
|
775
899
|
if (backupPath != null) {
|
|
776
|
-
|
|
777
|
-
console.log(
|
|
900
|
+
fs4.rmSync(backupPath, { recursive: true, force: true });
|
|
901
|
+
console.log(chalk5.red(" removed") + chalk5.dim(` backup \u2192 ${backupPath}`));
|
|
778
902
|
}
|
|
779
|
-
await scaffoldCommand(localPath
|
|
903
|
+
await scaffoldCommand(localPath);
|
|
780
904
|
configManager.repo_path = localPath;
|
|
781
905
|
configManager.remote_url = remoteUrl;
|
|
782
906
|
if (configManager.save() === false) {
|
|
783
|
-
console.error(
|
|
907
|
+
console.error(chalk5.red("Failed to save config."));
|
|
784
908
|
return false;
|
|
785
909
|
}
|
|
910
|
+
printSaveHint(localPath);
|
|
786
911
|
return true;
|
|
787
912
|
};
|
|
788
913
|
var installCommand = async (target) => {
|
|
789
914
|
try {
|
|
790
915
|
if (isGitUrl(target) === false) {
|
|
791
|
-
console.error(
|
|
792
|
-
console.log(
|
|
916
|
+
console.error(chalk5.red("\u274C Only remote git URLs are supported."));
|
|
917
|
+
console.log(chalk5.dim(" Example: set-prompt install https://github.com/you/my-prompts"));
|
|
793
918
|
process.exit(1);
|
|
794
919
|
}
|
|
795
920
|
const normalizeUrl = (url) => url.replace(/\.git$/, "").toLowerCase();
|
|
796
921
|
if (configManager.repo_path != null) {
|
|
797
922
|
if (normalizeUrl(configManager.remote_url ?? "") === normalizeUrl(target)) {
|
|
798
|
-
console.error(
|
|
799
|
-
console.log(
|
|
923
|
+
console.error(chalk5.red(`\u274C Already installed from the same URL: ${target}`));
|
|
924
|
+
console.log(chalk5.dim(" Use `set-prompt repo pull` to pull the latest changes."));
|
|
800
925
|
return false;
|
|
801
926
|
}
|
|
802
|
-
console.warn(
|
|
927
|
+
console.warn(chalk5.yellow(`\u26A0 Switching repo: ${configManager.remote_url} \u2192 ${target}`));
|
|
803
928
|
const proceed = await confirm2({ message: "Replace existing installation?", default: false });
|
|
804
929
|
if (!proceed) {
|
|
805
|
-
console.log(
|
|
930
|
+
console.log(chalk5.yellow("Cancelled."));
|
|
806
931
|
return false;
|
|
807
932
|
}
|
|
808
933
|
} else {
|
|
809
934
|
const proceed = await confirm2({ message: `Clone and register "${target}"?`, default: true });
|
|
810
935
|
if (!proceed) {
|
|
811
|
-
console.log(
|
|
936
|
+
console.log(chalk5.yellow("Cancelled."));
|
|
812
937
|
return false;
|
|
813
938
|
}
|
|
814
939
|
}
|
|
815
940
|
return await cloneRepo(target);
|
|
816
941
|
} catch (ex) {
|
|
817
|
-
console.error(
|
|
942
|
+
console.error(chalk5.red(`Unexpected error: ${ex.message}`), ex);
|
|
818
943
|
process.exit(1);
|
|
819
944
|
}
|
|
820
945
|
};
|
|
821
946
|
|
|
822
947
|
// src/commands/link-command.ts
|
|
823
|
-
import
|
|
948
|
+
import chalk12 from "chalk";
|
|
824
949
|
import { checkbox } from "@inquirer/prompts";
|
|
825
950
|
|
|
826
951
|
// src/link/claudecode.ts
|
|
827
952
|
import path4 from "path";
|
|
828
|
-
import
|
|
953
|
+
import fs5 from "fs";
|
|
829
954
|
import os2 from "os";
|
|
830
|
-
import
|
|
955
|
+
import chalk6 from "chalk";
|
|
831
956
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
832
957
|
var linkClaudeCode = async () => {
|
|
833
958
|
const repoPath = resolveRepoPath();
|
|
@@ -837,32 +962,32 @@ var linkClaudeCode = async () => {
|
|
|
837
962
|
const buildMarketplace = () => {
|
|
838
963
|
try {
|
|
839
964
|
const marketplaceMetaDir = path4.join(CLAUDE_CODE_DIR, ".claude-plugin");
|
|
840
|
-
|
|
965
|
+
fs5.mkdirSync(marketplaceMetaDir, { recursive: true });
|
|
841
966
|
const marketplaceJson = {
|
|
842
967
|
name: MARKET_NAME,
|
|
843
968
|
owner: { name: os2.userInfo().username },
|
|
844
969
|
metadata: { description: "Managed by set-prompt", version: "1.0.0" },
|
|
845
970
|
plugins: [{ name: PLUGIN_NAME, source: `./plugins/${PLUGIN_NAME}`, description: "Managed by set-prompt" }]
|
|
846
971
|
};
|
|
847
|
-
|
|
972
|
+
fs5.writeFileSync(
|
|
848
973
|
path4.join(marketplaceMetaDir, "marketplace.json"),
|
|
849
974
|
JSON.stringify(marketplaceJson, null, 4),
|
|
850
975
|
"utf-8"
|
|
851
976
|
);
|
|
852
|
-
console.log(
|
|
853
|
-
console.log(
|
|
977
|
+
console.log(chalk6.dim(" \u251C\u2500\u2500 .claude-plugin/"));
|
|
978
|
+
console.log(chalk6.dim(" \u2502 \u2514\u2500\u2500 marketplace.json") + chalk6.green(" \u2713"));
|
|
854
979
|
const pluginLink = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
|
|
855
|
-
|
|
856
|
-
if (
|
|
857
|
-
|
|
980
|
+
fs5.mkdirSync(path4.dirname(pluginLink), { recursive: true });
|
|
981
|
+
if (fs5.existsSync(pluginLink)) {
|
|
982
|
+
fs5.rmSync(pluginLink, { recursive: true, force: true });
|
|
858
983
|
}
|
|
859
984
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
860
|
-
|
|
861
|
-
console.log(
|
|
862
|
-
console.log(
|
|
985
|
+
fs5.symlinkSync(repoPath, pluginLink, symlinkType);
|
|
986
|
+
console.log(chalk6.dim(" \u2514\u2500\u2500 plugins/"));
|
|
987
|
+
console.log(chalk6.dim(` \u2514\u2500\u2500 ${PLUGIN_NAME}/`) + chalk6.dim(` \u2192 ${repoPath}`) + chalk6.green(" \u2713"));
|
|
863
988
|
return true;
|
|
864
989
|
} catch (ex) {
|
|
865
|
-
console.error(
|
|
990
|
+
console.error(chalk6.red(`\u274C Failed to build marketplace structure: ${ex.message}`));
|
|
866
991
|
return false;
|
|
867
992
|
}
|
|
868
993
|
};
|
|
@@ -870,18 +995,18 @@ var linkClaudeCode = async () => {
|
|
|
870
995
|
const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
|
|
871
996
|
try {
|
|
872
997
|
let settings = {};
|
|
873
|
-
if (
|
|
874
|
-
const raw =
|
|
998
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
999
|
+
const raw = fs5.readFileSync(claudeSettingsPath, "utf-8");
|
|
875
1000
|
try {
|
|
876
1001
|
const parsed = JSON.parse(raw);
|
|
877
1002
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
878
1003
|
settings = parsed;
|
|
879
1004
|
} else {
|
|
880
|
-
console.warn(
|
|
1005
|
+
console.warn(chalk6.yellow(" \u26A0 settings.json has unexpected format \u2014 proceeding with caution"));
|
|
881
1006
|
}
|
|
882
1007
|
} catch {
|
|
883
|
-
console.warn(
|
|
884
|
-
console.error(
|
|
1008
|
+
console.warn(chalk6.yellow(" \u26A0 Failed to parse settings.json \u2014 will not overwrite existing file"));
|
|
1009
|
+
console.error(chalk6.red("\u274C Could not register plugin. Please add manually."));
|
|
885
1010
|
return false;
|
|
886
1011
|
}
|
|
887
1012
|
}
|
|
@@ -894,43 +1019,43 @@ var linkClaudeCode = async () => {
|
|
|
894
1019
|
[`${PLUGIN_NAME}@${MARKET_NAME}`]: true
|
|
895
1020
|
};
|
|
896
1021
|
let backupPath = null;
|
|
897
|
-
if (
|
|
1022
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
898
1023
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
899
1024
|
backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
|
|
900
1025
|
try {
|
|
901
|
-
|
|
1026
|
+
fs5.copyFileSync(claudeSettingsPath, backupPath);
|
|
902
1027
|
} catch (ex) {
|
|
903
|
-
console.warn(
|
|
1028
|
+
console.warn(chalk6.yellow(` \u26A0 Could not create backup: ${ex.message}`));
|
|
904
1029
|
backupPath = null;
|
|
905
1030
|
}
|
|
906
1031
|
}
|
|
907
1032
|
try {
|
|
908
|
-
|
|
909
|
-
|
|
1033
|
+
fs5.mkdirSync(path4.dirname(claudeSettingsPath), { recursive: true });
|
|
1034
|
+
fs5.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 4), "utf-8");
|
|
910
1035
|
} catch (ex) {
|
|
911
1036
|
if (backupPath !== null) {
|
|
912
1037
|
try {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
console.warn(
|
|
1038
|
+
fs5.copyFileSync(backupPath, claudeSettingsPath);
|
|
1039
|
+
fs5.unlinkSync(backupPath);
|
|
1040
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
916
1041
|
} catch {
|
|
917
|
-
console.error(
|
|
1042
|
+
console.error(chalk6.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
|
|
918
1043
|
}
|
|
919
1044
|
}
|
|
920
1045
|
throw ex;
|
|
921
1046
|
}
|
|
922
1047
|
if (backupPath !== null) {
|
|
923
1048
|
try {
|
|
924
|
-
|
|
1049
|
+
fs5.unlinkSync(backupPath);
|
|
925
1050
|
} catch {
|
|
926
1051
|
}
|
|
927
1052
|
}
|
|
928
1053
|
console.log(`\u2705 Registered to Claude Code settings.`);
|
|
929
|
-
console.log(
|
|
1054
|
+
console.log(chalk6.dim(` ${claudeSettingsPath}`));
|
|
930
1055
|
return true;
|
|
931
1056
|
} catch (ex) {
|
|
932
|
-
console.error(
|
|
933
|
-
console.log(
|
|
1057
|
+
console.error(chalk6.red(`\u274C Failed to update settings.json: ${ex.message}`));
|
|
1058
|
+
console.log(chalk6.dim(" Please add the plugin manually via Claude Code /plugins."));
|
|
934
1059
|
return false;
|
|
935
1060
|
}
|
|
936
1061
|
};
|
|
@@ -940,9 +1065,9 @@ var linkClaudeCode = async () => {
|
|
|
940
1065
|
const pluginKey = `${PLUGIN_NAME}@${MARKET_NAME}`;
|
|
941
1066
|
try {
|
|
942
1067
|
let data = { version: 2, plugins: {} };
|
|
943
|
-
if (
|
|
1068
|
+
if (fs5.existsSync(installedPluginsPath)) {
|
|
944
1069
|
try {
|
|
945
|
-
data = JSON.parse(
|
|
1070
|
+
data = JSON.parse(fs5.readFileSync(installedPluginsPath, "utf-8"));
|
|
946
1071
|
} catch {
|
|
947
1072
|
}
|
|
948
1073
|
}
|
|
@@ -958,17 +1083,17 @@ var linkClaudeCode = async () => {
|
|
|
958
1083
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
959
1084
|
}
|
|
960
1085
|
];
|
|
961
|
-
|
|
962
|
-
|
|
1086
|
+
fs5.mkdirSync(path4.dirname(installedPluginsPath), { recursive: true });
|
|
1087
|
+
fs5.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 4), "utf-8");
|
|
963
1088
|
console.log(`\u2705 Patched installed_plugins.json \u2192 installPath points to source.`);
|
|
964
|
-
console.log(
|
|
1089
|
+
console.log(chalk6.dim(` ${installPath}`));
|
|
965
1090
|
} catch (ex) {
|
|
966
|
-
console.warn(
|
|
1091
|
+
console.warn(chalk6.yellow(` \u26A0 Could not patch installed_plugins.json: ${ex.message}`));
|
|
967
1092
|
}
|
|
968
1093
|
};
|
|
969
|
-
console.log(
|
|
1094
|
+
console.log(chalk6.green(`
|
|
970
1095
|
Setting up Claude Code plugin...`));
|
|
971
|
-
console.log(
|
|
1096
|
+
console.log(chalk6.dim(CLAUDE_CODE_DIR));
|
|
972
1097
|
const marketplaceOk = buildMarketplace();
|
|
973
1098
|
if (marketplaceOk === false) {
|
|
974
1099
|
return;
|
|
@@ -988,20 +1113,20 @@ var unlinkClaudeCode = async (force = false) => {
|
|
|
988
1113
|
default: false
|
|
989
1114
|
});
|
|
990
1115
|
if (!ok) {
|
|
991
|
-
console.log(
|
|
1116
|
+
console.log(chalk6.yellow("Cancelled."));
|
|
992
1117
|
return;
|
|
993
1118
|
}
|
|
994
1119
|
}
|
|
995
|
-
console.log(
|
|
1120
|
+
console.log(chalk6.red(`
|
|
996
1121
|
Removing Claude Code plugin...`));
|
|
997
|
-
console.log(
|
|
1122
|
+
console.log(chalk6.dim(CLAUDE_CODE_DIR));
|
|
998
1123
|
const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
|
|
999
|
-
if (
|
|
1124
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
1000
1125
|
try {
|
|
1001
1126
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1002
1127
|
const backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
|
|
1003
|
-
|
|
1004
|
-
const settings = JSON.parse(
|
|
1128
|
+
fs5.copyFileSync(claudeSettingsPath, backupPath);
|
|
1129
|
+
const settings = JSON.parse(fs5.readFileSync(claudeSettingsPath, "utf-8"));
|
|
1005
1130
|
if (settings?.extraKnownMarketplaces?.[MARKET_NAME] !== void 0) {
|
|
1006
1131
|
delete settings.extraKnownMarketplaces[MARKET_NAME];
|
|
1007
1132
|
}
|
|
@@ -1009,26 +1134,26 @@ Removing Claude Code plugin...`));
|
|
|
1009
1134
|
delete settings.enabledPlugins[`${PLUGIN_NAME}@${MARKET_NAME}`];
|
|
1010
1135
|
}
|
|
1011
1136
|
try {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
console.log(
|
|
1137
|
+
fs5.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 4), "utf-8");
|
|
1138
|
+
fs5.unlinkSync(backupPath);
|
|
1139
|
+
console.log(chalk6.red(" removed") + chalk6.dim(` set-prompt entries from: ${claudeSettingsPath}`));
|
|
1015
1140
|
} catch (ex) {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
console.warn(
|
|
1141
|
+
fs5.copyFileSync(backupPath, claudeSettingsPath);
|
|
1142
|
+
fs5.unlinkSync(backupPath);
|
|
1143
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1019
1144
|
}
|
|
1020
1145
|
} catch (ex) {
|
|
1021
|
-
console.error(
|
|
1146
|
+
console.error(chalk6.red(` \u274C Failed to clean up settings.json: ${ex.message}`));
|
|
1022
1147
|
}
|
|
1023
1148
|
}
|
|
1024
1149
|
const claudePluginsDir = path4.join(os2.homedir(), ".claude", "plugins");
|
|
1025
1150
|
const installedPluginsPath = path4.join(claudePluginsDir, "installed_plugins.json");
|
|
1026
|
-
if (
|
|
1151
|
+
if (fs5.existsSync(installedPluginsPath)) {
|
|
1027
1152
|
try {
|
|
1028
1153
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1029
1154
|
const backupPath = `${installedPluginsPath}.bak.${timestamp}`;
|
|
1030
|
-
|
|
1031
|
-
const installed = JSON.parse(
|
|
1155
|
+
fs5.copyFileSync(installedPluginsPath, backupPath);
|
|
1156
|
+
const installed = JSON.parse(fs5.readFileSync(installedPluginsPath, "utf-8"));
|
|
1032
1157
|
if (installed?.plugins && typeof installed.plugins === "object") {
|
|
1033
1158
|
for (const key of Object.keys(installed.plugins)) {
|
|
1034
1159
|
if (key.endsWith(`@${MARKET_NAME}`)) {
|
|
@@ -1037,44 +1162,44 @@ Removing Claude Code plugin...`));
|
|
|
1037
1162
|
}
|
|
1038
1163
|
}
|
|
1039
1164
|
try {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
console.log(
|
|
1165
|
+
fs5.writeFileSync(installedPluginsPath, JSON.stringify(installed, null, 4), "utf-8");
|
|
1166
|
+
fs5.unlinkSync(backupPath);
|
|
1167
|
+
console.log(chalk6.red(" removed") + chalk6.dim(` set-prompt entries from: ${installedPluginsPath}`));
|
|
1043
1168
|
} catch (ex) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
console.warn(
|
|
1169
|
+
fs5.copyFileSync(backupPath, installedPluginsPath);
|
|
1170
|
+
fs5.unlinkSync(backupPath);
|
|
1171
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back installed_plugins.json."));
|
|
1047
1172
|
}
|
|
1048
1173
|
} catch (ex) {
|
|
1049
|
-
console.error(
|
|
1174
|
+
console.error(chalk6.red(` \u274C Failed to clean up installed_plugins.json: ${ex.message}`));
|
|
1050
1175
|
}
|
|
1051
1176
|
}
|
|
1052
1177
|
const knownMarketplacesPath = path4.join(claudePluginsDir, "known_marketplaces.json");
|
|
1053
|
-
if (
|
|
1178
|
+
if (fs5.existsSync(knownMarketplacesPath)) {
|
|
1054
1179
|
try {
|
|
1055
1180
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1056
1181
|
const backupPath = `${knownMarketplacesPath}.bak.${timestamp}`;
|
|
1057
|
-
|
|
1058
|
-
const marketplaces = JSON.parse(
|
|
1182
|
+
fs5.copyFileSync(knownMarketplacesPath, backupPath);
|
|
1183
|
+
const marketplaces = JSON.parse(fs5.readFileSync(knownMarketplacesPath, "utf-8"));
|
|
1059
1184
|
if (marketplaces?.[MARKET_NAME] !== void 0) {
|
|
1060
1185
|
delete marketplaces[MARKET_NAME];
|
|
1061
1186
|
}
|
|
1062
1187
|
try {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
console.log(
|
|
1188
|
+
fs5.writeFileSync(knownMarketplacesPath, JSON.stringify(marketplaces, null, 4), "utf-8");
|
|
1189
|
+
fs5.unlinkSync(backupPath);
|
|
1190
|
+
console.log(chalk6.red(" removed") + chalk6.dim(` set-prompt entry from: ${knownMarketplacesPath}`));
|
|
1066
1191
|
} catch (ex) {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
console.warn(
|
|
1192
|
+
fs5.copyFileSync(backupPath, knownMarketplacesPath);
|
|
1193
|
+
fs5.unlinkSync(backupPath);
|
|
1194
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back known_marketplaces.json."));
|
|
1070
1195
|
}
|
|
1071
1196
|
} catch (ex) {
|
|
1072
|
-
console.error(
|
|
1197
|
+
console.error(chalk6.red(` \u274C Failed to clean up known_marketplaces.json: ${ex.message}`));
|
|
1073
1198
|
}
|
|
1074
1199
|
}
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1077
|
-
console.log(
|
|
1200
|
+
if (fs5.existsSync(CLAUDE_CODE_DIR)) {
|
|
1201
|
+
fs5.rmSync(CLAUDE_CODE_DIR, { recursive: true, force: true });
|
|
1202
|
+
console.log(chalk6.red(" removed") + chalk6.dim(`: ${CLAUDE_CODE_DIR}`));
|
|
1078
1203
|
}
|
|
1079
1204
|
configManager.claude_code = null;
|
|
1080
1205
|
configManager.save();
|
|
@@ -1082,8 +1207,8 @@ Removing Claude Code plugin...`));
|
|
|
1082
1207
|
|
|
1083
1208
|
// src/link/roocode.ts
|
|
1084
1209
|
import path5 from "path";
|
|
1085
|
-
import
|
|
1086
|
-
import
|
|
1210
|
+
import fs6 from "fs";
|
|
1211
|
+
import chalk7 from "chalk";
|
|
1087
1212
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
1088
1213
|
import { pathExists } from "fs-extra";
|
|
1089
1214
|
var linkRooCode = async () => {
|
|
@@ -1091,44 +1216,44 @@ var linkRooCode = async () => {
|
|
|
1091
1216
|
if (repoPath == null) {
|
|
1092
1217
|
return;
|
|
1093
1218
|
}
|
|
1094
|
-
console.log(
|
|
1219
|
+
console.log(chalk7.green(`
|
|
1095
1220
|
Setting up RooCode integration...`));
|
|
1096
|
-
console.log(
|
|
1221
|
+
console.log(chalk7.dim(ROO_DIR));
|
|
1097
1222
|
const roocodeDirs = AGENT_PROMPT_DIRS["roocode" /* ROOCODE */];
|
|
1098
1223
|
const backupExistingRooCodeFiles = async () => {
|
|
1099
1224
|
try {
|
|
1100
|
-
|
|
1225
|
+
fs6.mkdirSync(ROO_DIR, { recursive: true });
|
|
1101
1226
|
const dirsToBackup = [];
|
|
1102
1227
|
for (const dir of roocodeDirs) {
|
|
1103
1228
|
const target = path5.join(ROO_DIR, dir);
|
|
1104
|
-
if (
|
|
1229
|
+
if (fs6.existsSync(target) && fs6.lstatSync(target).isSymbolicLink() === false && fs6.readdirSync(target).length > 0) {
|
|
1105
1230
|
dirsToBackup.push(dir);
|
|
1106
1231
|
}
|
|
1107
1232
|
}
|
|
1108
1233
|
if (dirsToBackup.length === 0) {
|
|
1109
1234
|
return true;
|
|
1110
1235
|
}
|
|
1111
|
-
console.log(
|
|
1236
|
+
console.log(chalk7.yellow(`
|
|
1112
1237
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1113
1238
|
for (const dir of dirsToBackup) {
|
|
1114
|
-
console.log(
|
|
1239
|
+
console.log(chalk7.dim(` - ${path5.join(ROO_DIR, dir)}`));
|
|
1115
1240
|
}
|
|
1116
|
-
console.log(
|
|
1241
|
+
console.log(chalk7.yellow(` They will be backed up to: `) + chalk7.dim(ROO_BACKUP_DIR));
|
|
1117
1242
|
const ok = await confirm4({ message: "Back up existing directories?", default: true });
|
|
1118
1243
|
if (!ok) {
|
|
1119
|
-
console.log(
|
|
1244
|
+
console.log(chalk7.yellow("Skipped RooCode linking."));
|
|
1120
1245
|
return false;
|
|
1121
1246
|
}
|
|
1122
|
-
|
|
1247
|
+
fs6.mkdirSync(ROO_BACKUP_DIR, { recursive: true });
|
|
1123
1248
|
for (const dir of dirsToBackup) {
|
|
1124
1249
|
const src = path5.join(ROO_DIR, dir);
|
|
1125
1250
|
const dest = path5.join(ROO_BACKUP_DIR, dir);
|
|
1126
|
-
|
|
1127
|
-
console.log(
|
|
1251
|
+
fs6.renameSync(src, dest);
|
|
1252
|
+
console.log(chalk7.yellow(" backed up") + chalk7.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1128
1253
|
}
|
|
1129
1254
|
return true;
|
|
1130
1255
|
} catch (ex) {
|
|
1131
|
-
console.error(
|
|
1256
|
+
console.error(chalk7.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1132
1257
|
return false;
|
|
1133
1258
|
}
|
|
1134
1259
|
};
|
|
@@ -1141,21 +1266,21 @@ Setting up RooCode integration...`));
|
|
|
1141
1266
|
if (await pathExists(src) === false) {
|
|
1142
1267
|
continue;
|
|
1143
1268
|
}
|
|
1144
|
-
if (
|
|
1145
|
-
|
|
1269
|
+
if (fs6.existsSync(dest)) {
|
|
1270
|
+
fs6.rmSync(dest, { recursive: true, force: true });
|
|
1146
1271
|
}
|
|
1147
1272
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1148
|
-
|
|
1273
|
+
fs6.symlinkSync(src, dest, symlinkType);
|
|
1149
1274
|
linked.push({ dir, src });
|
|
1150
1275
|
}
|
|
1151
1276
|
for (const { dir, src } of linked) {
|
|
1152
1277
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1153
1278
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1154
|
-
console.log(
|
|
1279
|
+
console.log(chalk7.dim(` ${branch} `) + chalk7.bold(`${dir}/`) + chalk7.dim(` \u2192 ${src}`) + chalk7.green(" \u2713"));
|
|
1155
1280
|
}
|
|
1156
1281
|
return true;
|
|
1157
1282
|
} catch (ex) {
|
|
1158
|
-
console.error(
|
|
1283
|
+
console.error(chalk7.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1159
1284
|
return false;
|
|
1160
1285
|
}
|
|
1161
1286
|
};
|
|
@@ -1177,35 +1302,35 @@ var unlinkRooCode = async (force = false) => {
|
|
|
1177
1302
|
default: false
|
|
1178
1303
|
});
|
|
1179
1304
|
if (!ok) {
|
|
1180
|
-
console.log(
|
|
1305
|
+
console.log(chalk7.yellow("Cancelled."));
|
|
1181
1306
|
return;
|
|
1182
1307
|
}
|
|
1183
1308
|
}
|
|
1184
|
-
console.log(
|
|
1309
|
+
console.log(chalk7.red(`
|
|
1185
1310
|
Removing RooCode integration...`));
|
|
1186
|
-
console.log(
|
|
1311
|
+
console.log(chalk7.dim(ROO_DIR));
|
|
1187
1312
|
const backupPath = configManager.roocode?.backup_path ?? ROO_BACKUP_DIR;
|
|
1188
1313
|
for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
|
|
1189
1314
|
const target = path5.join(ROO_DIR, dir);
|
|
1190
|
-
if (
|
|
1191
|
-
|
|
1192
|
-
console.log(
|
|
1315
|
+
if (fs6.existsSync(target) && fs6.lstatSync(target).isSymbolicLink()) {
|
|
1316
|
+
fs6.unlinkSync(target);
|
|
1317
|
+
console.log(chalk7.red(" removed symlink") + chalk7.dim(`: ${target}`));
|
|
1193
1318
|
}
|
|
1194
1319
|
}
|
|
1195
|
-
if (
|
|
1320
|
+
if (fs6.existsSync(backupPath)) {
|
|
1196
1321
|
try {
|
|
1197
1322
|
for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
|
|
1198
1323
|
const src = path5.join(backupPath, dir);
|
|
1199
1324
|
const dest = path5.join(ROO_DIR, dir);
|
|
1200
|
-
if (!
|
|
1325
|
+
if (!fs6.existsSync(src)) {
|
|
1201
1326
|
continue;
|
|
1202
1327
|
}
|
|
1203
|
-
|
|
1204
|
-
console.log(
|
|
1328
|
+
fs6.renameSync(src, dest);
|
|
1329
|
+
console.log(chalk7.green(" restored") + chalk7.dim(`: ${dir}/`));
|
|
1205
1330
|
}
|
|
1206
|
-
|
|
1331
|
+
fs6.rmdirSync(backupPath);
|
|
1207
1332
|
} catch (ex) {
|
|
1208
|
-
console.error(
|
|
1333
|
+
console.error(chalk7.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
|
|
1209
1334
|
}
|
|
1210
1335
|
}
|
|
1211
1336
|
configManager.roocode = null;
|
|
@@ -1214,8 +1339,8 @@ Removing RooCode integration...`));
|
|
|
1214
1339
|
|
|
1215
1340
|
// src/link/openclaw.ts
|
|
1216
1341
|
import path6 from "path";
|
|
1217
|
-
import
|
|
1218
|
-
import
|
|
1342
|
+
import fs7 from "fs";
|
|
1343
|
+
import chalk8 from "chalk";
|
|
1219
1344
|
import { confirm as confirm5 } from "@inquirer/prompts";
|
|
1220
1345
|
import { pathExists as pathExists2 } from "fs-extra";
|
|
1221
1346
|
var linkOpenclaw = async () => {
|
|
@@ -1223,44 +1348,44 @@ var linkOpenclaw = async () => {
|
|
|
1223
1348
|
if (repoPath == null) {
|
|
1224
1349
|
return;
|
|
1225
1350
|
}
|
|
1226
|
-
console.log(
|
|
1351
|
+
console.log(chalk8.green(`
|
|
1227
1352
|
Setting up OpenClaw integration...`));
|
|
1228
|
-
console.log(
|
|
1353
|
+
console.log(chalk8.dim(OPENCLAW_DIR));
|
|
1229
1354
|
const openclawDirs = AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */];
|
|
1230
1355
|
const backupExistingOpenclawFiles = async () => {
|
|
1231
1356
|
try {
|
|
1232
|
-
|
|
1357
|
+
fs7.mkdirSync(OPENCLAW_DIR, { recursive: true });
|
|
1233
1358
|
const dirsToBackup = [];
|
|
1234
1359
|
for (const dir of openclawDirs) {
|
|
1235
1360
|
const target = path6.join(OPENCLAW_DIR, dir);
|
|
1236
|
-
if (
|
|
1361
|
+
if (fs7.existsSync(target) && fs7.lstatSync(target).isSymbolicLink() === false && fs7.readdirSync(target).length > 0) {
|
|
1237
1362
|
dirsToBackup.push(dir);
|
|
1238
1363
|
}
|
|
1239
1364
|
}
|
|
1240
1365
|
if (dirsToBackup.length === 0) {
|
|
1241
1366
|
return true;
|
|
1242
1367
|
}
|
|
1243
|
-
console.log(
|
|
1368
|
+
console.log(chalk8.yellow(`
|
|
1244
1369
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1245
1370
|
for (const dir of dirsToBackup) {
|
|
1246
|
-
console.log(
|
|
1371
|
+
console.log(chalk8.dim(` - ${path6.join(OPENCLAW_DIR, dir)}`));
|
|
1247
1372
|
}
|
|
1248
|
-
console.log(
|
|
1373
|
+
console.log(chalk8.yellow(` They will be backed up to: `) + chalk8.dim(OPENCLAW_BACKUP_DIR));
|
|
1249
1374
|
const ok = await confirm5({ message: "Back up existing directories?", default: true });
|
|
1250
1375
|
if (!ok) {
|
|
1251
|
-
console.log(
|
|
1376
|
+
console.log(chalk8.yellow("Skipped OpenClaw linking."));
|
|
1252
1377
|
return false;
|
|
1253
1378
|
}
|
|
1254
|
-
|
|
1379
|
+
fs7.mkdirSync(OPENCLAW_BACKUP_DIR, { recursive: true });
|
|
1255
1380
|
for (const dir of dirsToBackup) {
|
|
1256
1381
|
const src = path6.join(OPENCLAW_DIR, dir);
|
|
1257
1382
|
const dest = path6.join(OPENCLAW_BACKUP_DIR, dir);
|
|
1258
|
-
|
|
1259
|
-
console.log(
|
|
1383
|
+
fs7.renameSync(src, dest);
|
|
1384
|
+
console.log(chalk8.yellow(" backed up") + chalk8.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1260
1385
|
}
|
|
1261
1386
|
return true;
|
|
1262
1387
|
} catch (ex) {
|
|
1263
|
-
console.error(
|
|
1388
|
+
console.error(chalk8.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1264
1389
|
return false;
|
|
1265
1390
|
}
|
|
1266
1391
|
};
|
|
@@ -1273,21 +1398,21 @@ Setting up OpenClaw integration...`));
|
|
|
1273
1398
|
if (await pathExists2(src) === false) {
|
|
1274
1399
|
continue;
|
|
1275
1400
|
}
|
|
1276
|
-
if (
|
|
1277
|
-
|
|
1401
|
+
if (fs7.existsSync(dest)) {
|
|
1402
|
+
fs7.rmSync(dest, { recursive: true, force: true });
|
|
1278
1403
|
}
|
|
1279
1404
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1280
|
-
|
|
1405
|
+
fs7.symlinkSync(src, dest, symlinkType);
|
|
1281
1406
|
linked.push({ dir, src });
|
|
1282
1407
|
}
|
|
1283
1408
|
for (const { dir, src } of linked) {
|
|
1284
1409
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1285
1410
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1286
|
-
console.log(
|
|
1411
|
+
console.log(chalk8.dim(` ${branch} `) + chalk8.bold(`${dir}/`) + chalk8.dim(` \u2192 ${src}`) + chalk8.green(" \u2713"));
|
|
1287
1412
|
}
|
|
1288
1413
|
return true;
|
|
1289
1414
|
} catch (ex) {
|
|
1290
|
-
console.error(
|
|
1415
|
+
console.error(chalk8.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1291
1416
|
return false;
|
|
1292
1417
|
}
|
|
1293
1418
|
};
|
|
@@ -1309,35 +1434,35 @@ var unlinkOpenclaw = async (force = false) => {
|
|
|
1309
1434
|
default: false
|
|
1310
1435
|
});
|
|
1311
1436
|
if (!ok) {
|
|
1312
|
-
console.log(
|
|
1437
|
+
console.log(chalk8.yellow("Cancelled."));
|
|
1313
1438
|
return;
|
|
1314
1439
|
}
|
|
1315
1440
|
}
|
|
1316
|
-
console.log(
|
|
1441
|
+
console.log(chalk8.red(`
|
|
1317
1442
|
Removing OpenClaw integration...`));
|
|
1318
|
-
console.log(
|
|
1443
|
+
console.log(chalk8.dim(OPENCLAW_DIR));
|
|
1319
1444
|
const backupPath = configManager.openclaw?.backup_path ?? OPENCLAW_BACKUP_DIR;
|
|
1320
1445
|
for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
|
|
1321
1446
|
const target = path6.join(OPENCLAW_DIR, dir);
|
|
1322
|
-
if (
|
|
1323
|
-
|
|
1324
|
-
console.log(
|
|
1447
|
+
if (fs7.existsSync(target) && fs7.lstatSync(target).isSymbolicLink()) {
|
|
1448
|
+
fs7.unlinkSync(target);
|
|
1449
|
+
console.log(chalk8.red(" removed symlink") + chalk8.dim(`: ${target}`));
|
|
1325
1450
|
}
|
|
1326
1451
|
}
|
|
1327
|
-
if (
|
|
1452
|
+
if (fs7.existsSync(backupPath)) {
|
|
1328
1453
|
try {
|
|
1329
1454
|
for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
|
|
1330
1455
|
const src = path6.join(backupPath, dir);
|
|
1331
1456
|
const dest = path6.join(OPENCLAW_DIR, dir);
|
|
1332
|
-
if (!
|
|
1457
|
+
if (!fs7.existsSync(src)) {
|
|
1333
1458
|
continue;
|
|
1334
1459
|
}
|
|
1335
|
-
|
|
1336
|
-
console.log(
|
|
1460
|
+
fs7.renameSync(src, dest);
|
|
1461
|
+
console.log(chalk8.green(" restored") + chalk8.dim(`: ${dir}/`));
|
|
1337
1462
|
}
|
|
1338
|
-
|
|
1463
|
+
fs7.rmdirSync(backupPath);
|
|
1339
1464
|
} catch (ex) {
|
|
1340
|
-
console.error(
|
|
1465
|
+
console.error(chalk8.red(` \u274C Failed to restore OpenClaw backup: ${ex.message}`));
|
|
1341
1466
|
}
|
|
1342
1467
|
}
|
|
1343
1468
|
configManager.openclaw = null;
|
|
@@ -1346,8 +1471,8 @@ Removing OpenClaw integration...`));
|
|
|
1346
1471
|
|
|
1347
1472
|
// src/link/antigravity.ts
|
|
1348
1473
|
import path7 from "path";
|
|
1349
|
-
import
|
|
1350
|
-
import
|
|
1474
|
+
import fs8 from "fs";
|
|
1475
|
+
import chalk9 from "chalk";
|
|
1351
1476
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
1352
1477
|
import { pathExists as pathExists3 } from "fs-extra";
|
|
1353
1478
|
var linkAntigravity = async () => {
|
|
@@ -1355,44 +1480,44 @@ var linkAntigravity = async () => {
|
|
|
1355
1480
|
if (repoPath == null) {
|
|
1356
1481
|
return;
|
|
1357
1482
|
}
|
|
1358
|
-
console.log(
|
|
1483
|
+
console.log(chalk9.green(`
|
|
1359
1484
|
Setting up Antigravity integration...`));
|
|
1360
|
-
console.log(
|
|
1485
|
+
console.log(chalk9.dim(ANTIGRAVITY_DIR));
|
|
1361
1486
|
const antigravityDirs = AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */];
|
|
1362
1487
|
const backupExistingAntigravityFiles = async () => {
|
|
1363
1488
|
try {
|
|
1364
|
-
|
|
1489
|
+
fs8.mkdirSync(ANTIGRAVITY_DIR, { recursive: true });
|
|
1365
1490
|
const dirsToBackup = [];
|
|
1366
1491
|
for (const dir of antigravityDirs) {
|
|
1367
1492
|
const target = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1368
|
-
if (
|
|
1493
|
+
if (fs8.existsSync(target) && fs8.lstatSync(target).isSymbolicLink() === false && fs8.readdirSync(target).length > 0) {
|
|
1369
1494
|
dirsToBackup.push(dir);
|
|
1370
1495
|
}
|
|
1371
1496
|
}
|
|
1372
1497
|
if (dirsToBackup.length === 0) {
|
|
1373
1498
|
return true;
|
|
1374
1499
|
}
|
|
1375
|
-
console.log(
|
|
1500
|
+
console.log(chalk9.yellow(`
|
|
1376
1501
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1377
1502
|
for (const dir of dirsToBackup) {
|
|
1378
|
-
console.log(
|
|
1503
|
+
console.log(chalk9.dim(` - ${path7.join(ANTIGRAVITY_DIR, dir)}`));
|
|
1379
1504
|
}
|
|
1380
|
-
console.log(
|
|
1505
|
+
console.log(chalk9.yellow(` They will be backed up to: `) + chalk9.dim(ANTIGRAVITY_BACKUP_DIR));
|
|
1381
1506
|
const ok = await confirm6({ message: "Back up existing directories?", default: true });
|
|
1382
1507
|
if (!ok) {
|
|
1383
|
-
console.log(
|
|
1508
|
+
console.log(chalk9.yellow("Skipped Antigravity linking."));
|
|
1384
1509
|
return false;
|
|
1385
1510
|
}
|
|
1386
|
-
|
|
1511
|
+
fs8.mkdirSync(ANTIGRAVITY_BACKUP_DIR, { recursive: true });
|
|
1387
1512
|
for (const dir of antigravityDirs) {
|
|
1388
1513
|
const src = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1389
1514
|
const dest = path7.join(ANTIGRAVITY_BACKUP_DIR, dir);
|
|
1390
|
-
|
|
1391
|
-
console.log(
|
|
1515
|
+
fs8.renameSync(src, dest);
|
|
1516
|
+
console.log(chalk9.yellow(" backed up") + chalk9.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1392
1517
|
}
|
|
1393
1518
|
return true;
|
|
1394
1519
|
} catch (ex) {
|
|
1395
|
-
console.error(
|
|
1520
|
+
console.error(chalk9.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1396
1521
|
return false;
|
|
1397
1522
|
}
|
|
1398
1523
|
};
|
|
@@ -1405,21 +1530,21 @@ Setting up Antigravity integration...`));
|
|
|
1405
1530
|
if (await pathExists3(src) === false) {
|
|
1406
1531
|
continue;
|
|
1407
1532
|
}
|
|
1408
|
-
if (
|
|
1409
|
-
|
|
1533
|
+
if (fs8.existsSync(dest)) {
|
|
1534
|
+
fs8.rmSync(dest, { recursive: true, force: true });
|
|
1410
1535
|
}
|
|
1411
1536
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1412
|
-
|
|
1537
|
+
fs8.symlinkSync(src, dest, symlinkType);
|
|
1413
1538
|
linked.push({ dir, src });
|
|
1414
1539
|
}
|
|
1415
1540
|
for (const { dir, src } of linked) {
|
|
1416
1541
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1417
1542
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1418
|
-
console.log(
|
|
1543
|
+
console.log(chalk9.dim(` ${branch} `) + chalk9.bold(`${dir}/`) + chalk9.dim(` \u2192 ${src}`) + chalk9.green(" \u2713"));
|
|
1419
1544
|
}
|
|
1420
1545
|
return true;
|
|
1421
1546
|
} catch (ex) {
|
|
1422
|
-
console.error(
|
|
1547
|
+
console.error(chalk9.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1423
1548
|
return false;
|
|
1424
1549
|
}
|
|
1425
1550
|
};
|
|
@@ -1441,35 +1566,35 @@ var unlinkAntigravity = async (force = false) => {
|
|
|
1441
1566
|
default: false
|
|
1442
1567
|
});
|
|
1443
1568
|
if (!ok) {
|
|
1444
|
-
console.log(
|
|
1569
|
+
console.log(chalk9.yellow("Cancelled."));
|
|
1445
1570
|
return;
|
|
1446
1571
|
}
|
|
1447
1572
|
}
|
|
1448
|
-
console.log(
|
|
1573
|
+
console.log(chalk9.red(`
|
|
1449
1574
|
Removing Antigravity integration...`));
|
|
1450
|
-
console.log(
|
|
1575
|
+
console.log(chalk9.dim(ANTIGRAVITY_DIR));
|
|
1451
1576
|
const backupPath = configManager.antigravity?.backup_path ?? ANTIGRAVITY_BACKUP_DIR;
|
|
1452
1577
|
for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
|
|
1453
1578
|
const target = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1454
|
-
if (
|
|
1455
|
-
|
|
1456
|
-
console.log(
|
|
1579
|
+
if (fs8.existsSync(target) && fs8.lstatSync(target).isSymbolicLink()) {
|
|
1580
|
+
fs8.unlinkSync(target);
|
|
1581
|
+
console.log(chalk9.red(" removed symlink") + chalk9.dim(`: ${target}`));
|
|
1457
1582
|
}
|
|
1458
1583
|
}
|
|
1459
|
-
if (
|
|
1584
|
+
if (fs8.existsSync(backupPath)) {
|
|
1460
1585
|
try {
|
|
1461
1586
|
for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
|
|
1462
1587
|
const src = path7.join(backupPath, dir);
|
|
1463
1588
|
const dest = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1464
|
-
if (!
|
|
1589
|
+
if (!fs8.existsSync(src)) {
|
|
1465
1590
|
continue;
|
|
1466
1591
|
}
|
|
1467
|
-
|
|
1468
|
-
console.log(
|
|
1592
|
+
fs8.renameSync(src, dest);
|
|
1593
|
+
console.log(chalk9.green(" restored") + chalk9.dim(`: ${dir}/`));
|
|
1469
1594
|
}
|
|
1470
|
-
|
|
1595
|
+
fs8.rmdirSync(backupPath);
|
|
1471
1596
|
} catch (ex) {
|
|
1472
|
-
console.error(
|
|
1597
|
+
console.error(chalk9.red(` \u274C Failed to restore Antigravity backup: ${ex.message}`));
|
|
1473
1598
|
}
|
|
1474
1599
|
}
|
|
1475
1600
|
configManager.antigravity = null;
|
|
@@ -1478,9 +1603,9 @@ Removing Antigravity integration...`));
|
|
|
1478
1603
|
|
|
1479
1604
|
// src/link/codex.ts
|
|
1480
1605
|
import path8 from "path";
|
|
1481
|
-
import
|
|
1606
|
+
import fs9 from "fs";
|
|
1482
1607
|
import os3 from "os";
|
|
1483
|
-
import
|
|
1608
|
+
import chalk10 from "chalk";
|
|
1484
1609
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
1485
1610
|
import TOML from "smol-toml";
|
|
1486
1611
|
var CODEX_AGENTS_DIR = path8.join(os3.homedir(), ".agents", "plugins");
|
|
@@ -1502,16 +1627,16 @@ var linkCodex = async () => {
|
|
|
1502
1627
|
interface: { displayName: "Local Repository" },
|
|
1503
1628
|
plugins: []
|
|
1504
1629
|
};
|
|
1505
|
-
if (
|
|
1506
|
-
const raw =
|
|
1630
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1631
|
+
const raw = fs9.readFileSync(marketplacePath, "utf-8");
|
|
1507
1632
|
try {
|
|
1508
1633
|
const parsed = JSON.parse(raw);
|
|
1509
1634
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1510
1635
|
marketplace = parsed;
|
|
1511
1636
|
}
|
|
1512
1637
|
} catch {
|
|
1513
|
-
console.warn(
|
|
1514
|
-
console.error(
|
|
1638
|
+
console.warn(chalk10.yellow(" \u26A0 Failed to parse marketplace.json \u2014 will not overwrite existing file"));
|
|
1639
|
+
console.error(chalk10.red("\u274C Could not register plugin. Please add manually."));
|
|
1515
1640
|
return false;
|
|
1516
1641
|
}
|
|
1517
1642
|
}
|
|
@@ -1534,58 +1659,58 @@ var linkCodex = async () => {
|
|
|
1534
1659
|
category: "Productivity"
|
|
1535
1660
|
});
|
|
1536
1661
|
let backupPath = null;
|
|
1537
|
-
if (
|
|
1662
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1538
1663
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1539
1664
|
backupPath = `${marketplacePath}.bak.${timestamp}`;
|
|
1540
1665
|
try {
|
|
1541
|
-
|
|
1666
|
+
fs9.copyFileSync(marketplacePath, backupPath);
|
|
1542
1667
|
} catch (ex) {
|
|
1543
|
-
console.warn(
|
|
1668
|
+
console.warn(chalk10.yellow(` \u26A0 Could not create backup: ${ex.message}`));
|
|
1544
1669
|
backupPath = null;
|
|
1545
1670
|
}
|
|
1546
1671
|
}
|
|
1547
1672
|
try {
|
|
1548
|
-
|
|
1549
|
-
|
|
1673
|
+
fs9.mkdirSync(path8.dirname(marketplacePath), { recursive: true });
|
|
1674
|
+
fs9.writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 4), "utf-8");
|
|
1550
1675
|
} catch (ex) {
|
|
1551
1676
|
if (backupPath !== null) {
|
|
1552
1677
|
try {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
console.warn(
|
|
1678
|
+
fs9.copyFileSync(backupPath, marketplacePath);
|
|
1679
|
+
fs9.unlinkSync(backupPath);
|
|
1680
|
+
console.warn(chalk10.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1556
1681
|
} catch {
|
|
1557
|
-
console.error(
|
|
1682
|
+
console.error(chalk10.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
|
|
1558
1683
|
}
|
|
1559
1684
|
}
|
|
1560
1685
|
throw ex;
|
|
1561
1686
|
}
|
|
1562
1687
|
if (backupPath !== null) {
|
|
1563
1688
|
try {
|
|
1564
|
-
|
|
1689
|
+
fs9.unlinkSync(backupPath);
|
|
1565
1690
|
} catch {
|
|
1566
1691
|
}
|
|
1567
1692
|
}
|
|
1568
1693
|
console.log(`\u2705 Registered to marketplace.json`);
|
|
1569
|
-
console.log(
|
|
1694
|
+
console.log(chalk10.dim(` ${marketplacePath}`));
|
|
1570
1695
|
return true;
|
|
1571
1696
|
} catch (ex) {
|
|
1572
|
-
console.error(
|
|
1697
|
+
console.error(chalk10.red(`\u274C Failed to update marketplace.json: ${ex.message}`));
|
|
1573
1698
|
return false;
|
|
1574
1699
|
}
|
|
1575
1700
|
};
|
|
1576
1701
|
const patchPluginCache = () => {
|
|
1577
1702
|
const cachePath = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME, PLUGIN_NAME, "1.0.0");
|
|
1578
1703
|
try {
|
|
1579
|
-
|
|
1580
|
-
if (
|
|
1581
|
-
|
|
1704
|
+
fs9.mkdirSync(path8.dirname(cachePath), { recursive: true });
|
|
1705
|
+
if (fs9.existsSync(cachePath)) {
|
|
1706
|
+
fs9.rmSync(cachePath, { recursive: true, force: true });
|
|
1582
1707
|
}
|
|
1583
1708
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1584
|
-
|
|
1709
|
+
fs9.symlinkSync(repoPath, cachePath, symlinkType);
|
|
1585
1710
|
console.log(`\u2705 Patched plugin cache.`);
|
|
1586
|
-
console.log(
|
|
1711
|
+
console.log(chalk10.dim(` ${cachePath}`) + chalk10.dim(" \u2192 ") + chalk10.dim(repoPath));
|
|
1587
1712
|
} catch (ex) {
|
|
1588
|
-
console.warn(
|
|
1713
|
+
console.warn(chalk10.yellow(` \u26A0 Could not patch plugin cache: ${ex.message}`));
|
|
1589
1714
|
}
|
|
1590
1715
|
};
|
|
1591
1716
|
const enableInConfig = () => {
|
|
@@ -1593,22 +1718,22 @@ var linkCodex = async () => {
|
|
|
1593
1718
|
const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
1594
1719
|
try {
|
|
1595
1720
|
let config = {};
|
|
1596
|
-
if (
|
|
1597
|
-
config = TOML.parse(
|
|
1721
|
+
if (fs9.existsSync(configPath)) {
|
|
1722
|
+
config = TOML.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1598
1723
|
}
|
|
1599
1724
|
if (config.plugins == null) {
|
|
1600
1725
|
config.plugins = {};
|
|
1601
1726
|
}
|
|
1602
1727
|
config.plugins[pluginKey] = { enabled: true };
|
|
1603
|
-
|
|
1604
|
-
|
|
1728
|
+
fs9.mkdirSync(path8.dirname(configPath), { recursive: true });
|
|
1729
|
+
fs9.writeFileSync(configPath, TOML.stringify(config), "utf-8");
|
|
1605
1730
|
console.log(`\u2705 Enabled plugin in config.toml`);
|
|
1606
|
-
console.log(
|
|
1731
|
+
console.log(chalk10.dim(` ${configPath}`));
|
|
1607
1732
|
} catch (ex) {
|
|
1608
|
-
console.warn(
|
|
1733
|
+
console.warn(chalk10.yellow(` \u26A0 Could not update config.toml: ${ex.message}`));
|
|
1609
1734
|
}
|
|
1610
1735
|
};
|
|
1611
|
-
console.log(
|
|
1736
|
+
console.log(chalk10.green(`
|
|
1612
1737
|
Setting up Codex plugin...`));
|
|
1613
1738
|
const marketplaceOk = registerToMarketplace();
|
|
1614
1739
|
if (marketplaceOk === false) {
|
|
@@ -1626,55 +1751,55 @@ var unlinkCodex = async (force = false) => {
|
|
|
1626
1751
|
default: false
|
|
1627
1752
|
});
|
|
1628
1753
|
if (!ok) {
|
|
1629
|
-
console.log(
|
|
1754
|
+
console.log(chalk10.yellow("Cancelled."));
|
|
1630
1755
|
return;
|
|
1631
1756
|
}
|
|
1632
1757
|
}
|
|
1633
|
-
console.log(
|
|
1758
|
+
console.log(chalk10.red(`
|
|
1634
1759
|
Removing Codex plugin...`));
|
|
1635
1760
|
const marketplacePath = path8.join(CODEX_AGENTS_DIR, "marketplace.json");
|
|
1636
|
-
if (
|
|
1761
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1637
1762
|
try {
|
|
1638
1763
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1639
1764
|
const backupPath = `${marketplacePath}.bak.${timestamp}`;
|
|
1640
|
-
|
|
1641
|
-
const marketplace = JSON.parse(
|
|
1765
|
+
fs9.copyFileSync(marketplacePath, backupPath);
|
|
1766
|
+
const marketplace = JSON.parse(fs9.readFileSync(marketplacePath, "utf-8"));
|
|
1642
1767
|
if (Array.isArray(marketplace?.plugins)) {
|
|
1643
1768
|
marketplace.plugins = marketplace.plugins.filter(
|
|
1644
1769
|
(p) => p?.name !== PLUGIN_NAME
|
|
1645
1770
|
);
|
|
1646
1771
|
}
|
|
1647
1772
|
try {
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
console.log(
|
|
1773
|
+
fs9.writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 4), "utf-8");
|
|
1774
|
+
fs9.unlinkSync(backupPath);
|
|
1775
|
+
console.log(chalk10.red(" removed") + chalk10.dim(` ${PLUGIN_NAME} from: ${marketplacePath}`));
|
|
1651
1776
|
} catch (ex) {
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
console.warn(
|
|
1777
|
+
fs9.copyFileSync(backupPath, marketplacePath);
|
|
1778
|
+
fs9.unlinkSync(backupPath);
|
|
1779
|
+
console.warn(chalk10.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1655
1780
|
}
|
|
1656
1781
|
} catch (ex) {
|
|
1657
|
-
console.error(
|
|
1782
|
+
console.error(chalk10.red(` \u274C Failed to clean up marketplace.json: ${ex.message}`));
|
|
1658
1783
|
}
|
|
1659
1784
|
}
|
|
1660
1785
|
const configPath = path8.join(os3.homedir(), ".codex", "config.toml");
|
|
1661
|
-
if (
|
|
1786
|
+
if (fs9.existsSync(configPath)) {
|
|
1662
1787
|
try {
|
|
1663
|
-
const config = TOML.parse(
|
|
1788
|
+
const config = TOML.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1664
1789
|
const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
1665
1790
|
if (config.plugins?.[pluginKey] !== void 0) {
|
|
1666
1791
|
delete config.plugins[pluginKey];
|
|
1667
|
-
|
|
1668
|
-
console.log(
|
|
1792
|
+
fs9.writeFileSync(configPath, TOML.stringify(config), "utf-8");
|
|
1793
|
+
console.log(chalk10.red(" removed") + chalk10.dim(` ${pluginKey} from: ${configPath}`));
|
|
1669
1794
|
}
|
|
1670
1795
|
} catch (ex) {
|
|
1671
|
-
console.error(
|
|
1796
|
+
console.error(chalk10.red(` \u274C Failed to clean up config.toml: ${ex.message}`));
|
|
1672
1797
|
}
|
|
1673
1798
|
}
|
|
1674
1799
|
const cacheMarketDir = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME);
|
|
1675
|
-
if (
|
|
1676
|
-
|
|
1677
|
-
console.log(
|
|
1800
|
+
if (fs9.existsSync(cacheMarketDir)) {
|
|
1801
|
+
fs9.rmSync(cacheMarketDir, { recursive: true, force: true });
|
|
1802
|
+
console.log(chalk10.red(" removed") + chalk10.dim(`: ${cacheMarketDir}`));
|
|
1678
1803
|
}
|
|
1679
1804
|
configManager.codex = null;
|
|
1680
1805
|
configManager.save();
|
|
@@ -1682,8 +1807,8 @@ Removing Codex plugin...`));
|
|
|
1682
1807
|
|
|
1683
1808
|
// src/link/cursor.ts
|
|
1684
1809
|
import path9 from "path";
|
|
1685
|
-
import
|
|
1686
|
-
import
|
|
1810
|
+
import fs10 from "fs";
|
|
1811
|
+
import chalk11 from "chalk";
|
|
1687
1812
|
import { confirm as confirm8 } from "@inquirer/prompts";
|
|
1688
1813
|
import { pathExists as pathExists4 } from "fs-extra";
|
|
1689
1814
|
var CURSOR_BACKUP_DIR = path9.join(CURSOR_DIR, "SET_PROMPT_BACKUP");
|
|
@@ -1692,35 +1817,35 @@ var linkCursor = async () => {
|
|
|
1692
1817
|
if (repoPath == null) {
|
|
1693
1818
|
return;
|
|
1694
1819
|
}
|
|
1695
|
-
console.log(
|
|
1820
|
+
console.log(chalk11.green(`
|
|
1696
1821
|
Setting up Cursor integration...`));
|
|
1697
|
-
console.log(
|
|
1822
|
+
console.log(chalk11.dim(CURSOR_DIR));
|
|
1698
1823
|
const cursorDirs = AGENT_PROMPT_DIRS["cursor" /* CURSOR */];
|
|
1699
1824
|
const dirsToBackup = [];
|
|
1700
1825
|
for (const dir of cursorDirs) {
|
|
1701
1826
|
const target = path9.join(CURSOR_DIR, dir);
|
|
1702
|
-
if (
|
|
1827
|
+
if (fs10.existsSync(target) && fs10.lstatSync(target).isSymbolicLink() === false && fs10.readdirSync(target).length > 0) {
|
|
1703
1828
|
dirsToBackup.push(dir);
|
|
1704
1829
|
}
|
|
1705
1830
|
}
|
|
1706
1831
|
if (dirsToBackup.length > 0) {
|
|
1707
|
-
console.log(
|
|
1832
|
+
console.log(chalk11.yellow(`
|
|
1708
1833
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1709
1834
|
for (const dir of dirsToBackup) {
|
|
1710
|
-
console.log(
|
|
1835
|
+
console.log(chalk11.dim(` - ${path9.join(CURSOR_DIR, dir)}`));
|
|
1711
1836
|
}
|
|
1712
|
-
console.log(
|
|
1837
|
+
console.log(chalk11.yellow(` They will be backed up to: `) + chalk11.dim(CURSOR_BACKUP_DIR));
|
|
1713
1838
|
const ok = await confirm8({ message: "Back up existing directories?", default: true });
|
|
1714
1839
|
if (!ok) {
|
|
1715
|
-
console.log(
|
|
1840
|
+
console.log(chalk11.yellow("Skipped Cursor linking."));
|
|
1716
1841
|
return;
|
|
1717
1842
|
}
|
|
1718
|
-
|
|
1843
|
+
fs10.mkdirSync(CURSOR_BACKUP_DIR, { recursive: true });
|
|
1719
1844
|
for (const dir of dirsToBackup) {
|
|
1720
1845
|
const src = path9.join(CURSOR_DIR, dir);
|
|
1721
1846
|
const dest = path9.join(CURSOR_BACKUP_DIR, dir);
|
|
1722
|
-
|
|
1723
|
-
console.log(
|
|
1847
|
+
fs10.renameSync(src, dest);
|
|
1848
|
+
console.log(chalk11.yellow(" backed up") + chalk11.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1724
1849
|
}
|
|
1725
1850
|
}
|
|
1726
1851
|
try {
|
|
@@ -1731,33 +1856,33 @@ Setting up Cursor integration...`));
|
|
|
1731
1856
|
if (await pathExists4(src) === false) {
|
|
1732
1857
|
continue;
|
|
1733
1858
|
}
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1859
|
+
if (fs10.existsSync(dest)) {
|
|
1860
|
+
fs10.rmSync(dest, { recursive: true, force: true });
|
|
1736
1861
|
}
|
|
1737
1862
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1738
|
-
|
|
1863
|
+
fs10.symlinkSync(src, dest, symlinkType);
|
|
1739
1864
|
linked.push({ dir, src });
|
|
1740
1865
|
}
|
|
1741
1866
|
for (const { dir, src } of linked) {
|
|
1742
|
-
console.log(
|
|
1867
|
+
console.log(chalk11.dim(` \u251C\u2500\u2500 `) + chalk11.bold(`${dir}/`) + chalk11.dim(` \u2192 ${src}`) + chalk11.green(" \u2713"));
|
|
1743
1868
|
}
|
|
1744
1869
|
const mcpSrc = path9.join(repoPath, ".mcp.json");
|
|
1745
1870
|
const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
|
|
1746
|
-
if (
|
|
1747
|
-
if (
|
|
1871
|
+
if (fs10.existsSync(mcpSrc)) {
|
|
1872
|
+
if (fs10.existsSync(mcpDest) && fs10.statSync(mcpDest).ino !== fs10.statSync(mcpSrc).ino) {
|
|
1748
1873
|
const mcpBackup = path9.join(CURSOR_BACKUP_DIR, "mcp.json");
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
console.log(
|
|
1874
|
+
fs10.mkdirSync(CURSOR_BACKUP_DIR, { recursive: true });
|
|
1875
|
+
fs10.renameSync(mcpDest, mcpBackup);
|
|
1876
|
+
console.log(chalk11.yellow(" backed up") + chalk11.dim(`: mcp.json \u2192 ${mcpBackup}`));
|
|
1752
1877
|
}
|
|
1753
|
-
if (
|
|
1754
|
-
|
|
1878
|
+
if (fs10.existsSync(mcpDest)) {
|
|
1879
|
+
fs10.unlinkSync(mcpDest);
|
|
1755
1880
|
}
|
|
1756
|
-
|
|
1757
|
-
console.log(
|
|
1881
|
+
fs10.linkSync(mcpSrc, mcpDest);
|
|
1882
|
+
console.log(chalk11.dim(` \u2514\u2500\u2500 `) + chalk11.bold("mcp.json") + chalk11.dim(` \u21D4 ${mcpSrc}`) + chalk11.green(" \u2713"));
|
|
1758
1883
|
}
|
|
1759
1884
|
} catch (ex) {
|
|
1760
|
-
console.error(
|
|
1885
|
+
console.error(chalk11.red(`\u274C Failed to set up Cursor: ${ex.message}`));
|
|
1761
1886
|
return;
|
|
1762
1887
|
}
|
|
1763
1888
|
configManager.cursor = { path: CURSOR_DIR, backup_path: CURSOR_BACKUP_DIR };
|
|
@@ -1770,45 +1895,45 @@ var unlinkCursor = async (force = false) => {
|
|
|
1770
1895
|
default: false
|
|
1771
1896
|
});
|
|
1772
1897
|
if (!ok) {
|
|
1773
|
-
console.log(
|
|
1898
|
+
console.log(chalk11.yellow("Cancelled."));
|
|
1774
1899
|
return;
|
|
1775
1900
|
}
|
|
1776
1901
|
}
|
|
1777
|
-
console.log(
|
|
1902
|
+
console.log(chalk11.red(`
|
|
1778
1903
|
Removing Cursor integration...`));
|
|
1779
|
-
console.log(
|
|
1904
|
+
console.log(chalk11.dim(CURSOR_DIR));
|
|
1780
1905
|
const backupPath = configManager.cursor?.backup_path ?? CURSOR_BACKUP_DIR;
|
|
1781
1906
|
for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
|
|
1782
1907
|
const target = path9.join(CURSOR_DIR, dir);
|
|
1783
|
-
if (
|
|
1784
|
-
|
|
1785
|
-
console.log(
|
|
1908
|
+
if (fs10.existsSync(target) && fs10.lstatSync(target).isSymbolicLink()) {
|
|
1909
|
+
fs10.unlinkSync(target);
|
|
1910
|
+
console.log(chalk11.red(" removed symlink") + chalk11.dim(`: ${target}`));
|
|
1786
1911
|
}
|
|
1787
1912
|
}
|
|
1788
1913
|
const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
|
|
1789
|
-
if (
|
|
1790
|
-
|
|
1791
|
-
console.log(
|
|
1914
|
+
if (fs10.existsSync(mcpDest)) {
|
|
1915
|
+
fs10.unlinkSync(mcpDest);
|
|
1916
|
+
console.log(chalk11.red(" removed") + chalk11.dim(`: ${mcpDest}`));
|
|
1792
1917
|
}
|
|
1793
|
-
if (
|
|
1918
|
+
if (fs10.existsSync(backupPath)) {
|
|
1794
1919
|
try {
|
|
1795
1920
|
for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
|
|
1796
1921
|
const src = path9.join(backupPath, dir);
|
|
1797
1922
|
const dest = path9.join(CURSOR_DIR, dir);
|
|
1798
|
-
if (!
|
|
1923
|
+
if (!fs10.existsSync(src)) {
|
|
1799
1924
|
continue;
|
|
1800
1925
|
}
|
|
1801
|
-
|
|
1802
|
-
console.log(
|
|
1926
|
+
fs10.renameSync(src, dest);
|
|
1927
|
+
console.log(chalk11.green(" restored") + chalk11.dim(`: ${dir}/`));
|
|
1803
1928
|
}
|
|
1804
1929
|
const mcpBackup = path9.join(backupPath, "mcp.json");
|
|
1805
|
-
if (
|
|
1806
|
-
|
|
1807
|
-
console.log(
|
|
1930
|
+
if (fs10.existsSync(mcpBackup)) {
|
|
1931
|
+
fs10.renameSync(mcpBackup, mcpDest);
|
|
1932
|
+
console.log(chalk11.green(" restored") + chalk11.dim(`: mcp.json`));
|
|
1808
1933
|
}
|
|
1809
|
-
|
|
1934
|
+
fs10.rmSync(backupPath, { recursive: true, force: true });
|
|
1810
1935
|
} catch (ex) {
|
|
1811
|
-
console.error(
|
|
1936
|
+
console.error(chalk11.red(` \u274C Failed to restore Cursor backup: ${ex.message}`));
|
|
1812
1937
|
}
|
|
1813
1938
|
}
|
|
1814
1939
|
configManager.cursor = null;
|
|
@@ -1836,7 +1961,7 @@ var linkCommand = async (tool) => {
|
|
|
1836
1961
|
if (tool != null) {
|
|
1837
1962
|
const known = ALL_AGENTS.some((a) => a.value === tool);
|
|
1838
1963
|
if (!known) {
|
|
1839
|
-
console.log(
|
|
1964
|
+
console.log(chalk12.red(`Unknown vendor: ${tool}`));
|
|
1840
1965
|
process.exit(1);
|
|
1841
1966
|
}
|
|
1842
1967
|
await LINK_MAP[tool]();
|
|
@@ -1853,7 +1978,7 @@ var linkCommand = async (tool) => {
|
|
|
1853
1978
|
const selected = await checkbox({
|
|
1854
1979
|
message: "Which AI agent do you want to integrate?",
|
|
1855
1980
|
choices: ALL_AGENTS.map((a) => ({
|
|
1856
|
-
name: prevLinked[a.value] ? `${a.name} ${
|
|
1981
|
+
name: prevLinked[a.value] ? `${a.name} ${chalk12.dim("(applied)")}` : a.name,
|
|
1857
1982
|
value: a.value,
|
|
1858
1983
|
checked: prevLinked[a.value]
|
|
1859
1984
|
}))
|
|
@@ -1862,10 +1987,10 @@ var linkCommand = async (tool) => {
|
|
|
1862
1987
|
const toUnlink = ALL_AGENTS.filter((a) => prevLinked[a.value] && !selected.includes(a.value));
|
|
1863
1988
|
console.log();
|
|
1864
1989
|
if (toLink.length > 0) {
|
|
1865
|
-
console.log(
|
|
1990
|
+
console.log(chalk12.green(" Link ") + chalk12.dim("\u2192 ") + toLink.map((a) => chalk12.bold(a.name)).join(chalk12.dim(", ")));
|
|
1866
1991
|
}
|
|
1867
1992
|
if (toUnlink.length > 0) {
|
|
1868
|
-
console.log(
|
|
1993
|
+
console.log(chalk12.red(" Unlink ") + chalk12.dim("\u2192 ") + toUnlink.map((a) => chalk12.bold(a.name)).join(chalk12.dim(", ")));
|
|
1869
1994
|
}
|
|
1870
1995
|
console.log();
|
|
1871
1996
|
if (toLink.length === 0 && toUnlink.length === 0) {
|
|
@@ -1884,14 +2009,14 @@ var linkCommand = async (tool) => {
|
|
|
1884
2009
|
};
|
|
1885
2010
|
|
|
1886
2011
|
// src/commands/uninstall-command.ts
|
|
1887
|
-
import
|
|
1888
|
-
import
|
|
2012
|
+
import fs11 from "fs";
|
|
2013
|
+
import chalk13 from "chalk";
|
|
1889
2014
|
import { confirm as confirm9 } from "@inquirer/prompts";
|
|
1890
2015
|
var uninstallCommand = async () => {
|
|
1891
2016
|
const targets = [
|
|
1892
|
-
{ label: `Config file ${
|
|
1893
|
-
{ label: `Home dir ${
|
|
1894
|
-
].filter((t) =>
|
|
2017
|
+
{ label: `Config file ${chalk13.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
|
|
2018
|
+
{ label: `Home dir ${chalk13.dim(HOME_DIR)}`, path: HOME_DIR }
|
|
2019
|
+
].filter((t) => fs11.existsSync(t.path));
|
|
1895
2020
|
const hasClaudeCode = configManager.isClaudeCodeEnabled();
|
|
1896
2021
|
const hasRooCode = configManager.isRooCodeEnabled();
|
|
1897
2022
|
const hasOpenclaw = configManager.isOpenclawEnabled();
|
|
@@ -1899,32 +2024,32 @@ var uninstallCommand = async () => {
|
|
|
1899
2024
|
const hasCodex = configManager.isCodexEnabled();
|
|
1900
2025
|
const hasCursor = configManager.isCursorEnabled();
|
|
1901
2026
|
if (targets.length === 0 && !hasClaudeCode && !hasRooCode && !hasOpenclaw && !hasAntigravity && !hasCodex && !hasCursor) {
|
|
1902
|
-
console.log(
|
|
2027
|
+
console.log(chalk13.yellow("Nothing to remove."));
|
|
1903
2028
|
return;
|
|
1904
2029
|
}
|
|
1905
|
-
console.log(
|
|
2030
|
+
console.log(chalk13.red("\nThe following will be removed:"));
|
|
1906
2031
|
targets.forEach((t) => console.log(` ${t.label}`));
|
|
1907
2032
|
if (hasClaudeCode) {
|
|
1908
|
-
console.log(` Claude Code plugin dir ${
|
|
2033
|
+
console.log(` Claude Code plugin dir ${chalk13.dim(CLAUDE_CODE_DIR)}`);
|
|
1909
2034
|
}
|
|
1910
2035
|
if (hasRooCode) {
|
|
1911
|
-
console.log(` RooCode symlinks ${
|
|
2036
|
+
console.log(` RooCode symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1912
2037
|
}
|
|
1913
2038
|
if (hasOpenclaw) {
|
|
1914
|
-
console.log(` OpenClaw symlinks ${
|
|
2039
|
+
console.log(` OpenClaw symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1915
2040
|
}
|
|
1916
2041
|
if (hasAntigravity) {
|
|
1917
|
-
console.log(` Antigravity symlinks ${
|
|
2042
|
+
console.log(` Antigravity symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1918
2043
|
}
|
|
1919
2044
|
if (hasCodex) {
|
|
1920
|
-
console.log(` Codex symlinks ${
|
|
2045
|
+
console.log(` Codex symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1921
2046
|
}
|
|
1922
2047
|
if (hasCursor) {
|
|
1923
|
-
console.log(` Cursor plugin dir ${
|
|
2048
|
+
console.log(` Cursor plugin dir ${chalk13.dim("(symlink will be removed)")}`);
|
|
1924
2049
|
}
|
|
1925
2050
|
const ok = await confirm9({ message: "Proceed?", default: false });
|
|
1926
2051
|
if (!ok) {
|
|
1927
|
-
console.log(
|
|
2052
|
+
console.log(chalk13.yellow("Cancelled."));
|
|
1928
2053
|
return;
|
|
1929
2054
|
}
|
|
1930
2055
|
if (hasClaudeCode) {
|
|
@@ -1946,26 +2071,26 @@ var uninstallCommand = async () => {
|
|
|
1946
2071
|
await unlinkCursor(true);
|
|
1947
2072
|
}
|
|
1948
2073
|
for (const t of targets) {
|
|
1949
|
-
|
|
1950
|
-
console.log(
|
|
2074
|
+
fs11.rmSync(t.path, { recursive: true, force: true });
|
|
2075
|
+
console.log(chalk13.dim(` removed: ${t.path}`));
|
|
1951
2076
|
}
|
|
1952
|
-
console.log(
|
|
2077
|
+
console.log(chalk13.green("\nUninstalled."));
|
|
1953
2078
|
};
|
|
1954
2079
|
|
|
1955
2080
|
// src/commands/status-command.ts
|
|
1956
|
-
import
|
|
2081
|
+
import chalk14 from "chalk";
|
|
1957
2082
|
var statusCommand = () => {
|
|
1958
2083
|
if (configManager.repo_path == null) {
|
|
1959
|
-
console.log(
|
|
1960
|
-
console.log(
|
|
2084
|
+
console.log(chalk14.yellow("\u274C No repo installed."));
|
|
2085
|
+
console.log(chalk14.dim(` Run: set-prompt install <repo-url>`));
|
|
1961
2086
|
return;
|
|
1962
2087
|
}
|
|
1963
|
-
console.log(
|
|
1964
|
-
console.log(`${TAB}path ${
|
|
2088
|
+
console.log(chalk14.bold("\nRepo"));
|
|
2089
|
+
console.log(`${TAB}path ${chalk14.cyan(configManager.repo_path)}`);
|
|
1965
2090
|
if (configManager.remote_url != null) {
|
|
1966
|
-
console.log(`${TAB}remote ${
|
|
2091
|
+
console.log(`${TAB}remote ${chalk14.dim(configManager.remote_url)}`);
|
|
1967
2092
|
}
|
|
1968
|
-
console.log(
|
|
2093
|
+
console.log(chalk14.bold("\nLinked agents"));
|
|
1969
2094
|
for (const agent of ALL_AGENTS) {
|
|
1970
2095
|
let linked = false;
|
|
1971
2096
|
let agentPath = null;
|
|
@@ -1985,78 +2110,363 @@ var statusCommand = () => {
|
|
|
1985
2110
|
linked = configManager.isAntigravityEnabled();
|
|
1986
2111
|
agentPath = configManager.antigravity?.path;
|
|
1987
2112
|
}
|
|
1988
|
-
const label = linked ?
|
|
1989
|
-
const pathStr = linked && agentPath ?
|
|
2113
|
+
const label = linked ? chalk14.green("linked") : chalk14.dim("not linked");
|
|
2114
|
+
const pathStr = linked && agentPath ? chalk14.dim(` \u2192 ${agentPath}`) : "";
|
|
1990
2115
|
console.log(`${TAB}${agent.name.padEnd(12)} ${label}${pathStr}`);
|
|
1991
2116
|
}
|
|
1992
2117
|
console.log("");
|
|
1993
2118
|
};
|
|
1994
2119
|
|
|
1995
|
-
// src/commands/
|
|
1996
|
-
import { spawnSync as
|
|
1997
|
-
import
|
|
1998
|
-
var
|
|
2120
|
+
// src/commands/repo/pull-command.ts
|
|
2121
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
2122
|
+
import chalk15 from "chalk";
|
|
2123
|
+
var repoPullCommand = () => {
|
|
1999
2124
|
const repoPath = configManager.repo_path;
|
|
2000
2125
|
if (repoPath == null) {
|
|
2001
|
-
console.error(
|
|
2002
|
-
console.log(
|
|
2126
|
+
console.error(chalk15.red("\u274C No repo installed."));
|
|
2127
|
+
console.log(chalk15.yellow("Run: set-prompt install <git-url>"));
|
|
2003
2128
|
return;
|
|
2004
2129
|
}
|
|
2005
2130
|
if (configManager.remote_url == null) {
|
|
2006
|
-
console.error(
|
|
2131
|
+
console.error(chalk15.red("\u274C No remote URL registered. Cannot pull."));
|
|
2007
2132
|
return;
|
|
2008
2133
|
}
|
|
2009
|
-
console.log(
|
|
2010
|
-
console.log(
|
|
2011
|
-
const fetch =
|
|
2134
|
+
console.log(chalk15.green("\nPulling prompt repo..."));
|
|
2135
|
+
console.log(chalk15.dim(repoPath));
|
|
2136
|
+
const fetch = spawnSync4("git", ["fetch"], { cwd: repoPath, stdio: "inherit" });
|
|
2012
2137
|
if (fetch.status !== 0) {
|
|
2013
|
-
console.error(
|
|
2138
|
+
console.error(chalk15.red("\u274C git fetch failed."));
|
|
2014
2139
|
return;
|
|
2015
2140
|
}
|
|
2016
|
-
const pull =
|
|
2141
|
+
const pull = spawnSync4("git", ["pull"], { cwd: repoPath, stdio: "inherit" });
|
|
2017
2142
|
if (pull.status !== 0) {
|
|
2018
|
-
console.error(
|
|
2143
|
+
console.error(chalk15.red("\u274C git pull failed."));
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
console.log(chalk15.green("\u2705 Repo pulled."));
|
|
2147
|
+
};
|
|
2148
|
+
|
|
2149
|
+
// src/commands/repo/commit-command.ts
|
|
2150
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
2151
|
+
import chalk16 from "chalk";
|
|
2152
|
+
var repoCommitCommand = (options = {}) => {
|
|
2153
|
+
const repoPath = configManager.repo_path;
|
|
2154
|
+
if (repoPath == null) {
|
|
2155
|
+
console.error(chalk16.red("\u274C No repo installed."));
|
|
2156
|
+
console.log(chalk16.yellow("Run: set-prompt install <git-url>"));
|
|
2157
|
+
return false;
|
|
2158
|
+
}
|
|
2159
|
+
let message = options.message;
|
|
2160
|
+
if (message == null || message.trim() === "") {
|
|
2161
|
+
const generated = generateCommitMessage(repoPath);
|
|
2162
|
+
if (generated == null) {
|
|
2163
|
+
console.error(chalk16.red("\u274C Nothing to commit \u2014 working tree is clean."));
|
|
2164
|
+
return false;
|
|
2165
|
+
}
|
|
2166
|
+
message = generated;
|
|
2167
|
+
const subject = message.split("\n")[0];
|
|
2168
|
+
console.log(chalk16.dim(` (auto-generated: ${subject})`));
|
|
2169
|
+
}
|
|
2170
|
+
console.log(chalk16.green("\nCommitting prompt repo changes..."));
|
|
2171
|
+
console.log(chalk16.dim(repoPath));
|
|
2172
|
+
const add = spawnSync5("git", ["add", "-A"], { cwd: repoPath, stdio: "inherit" });
|
|
2173
|
+
if (add.status !== 0) {
|
|
2174
|
+
console.error(chalk16.red("\u274C git add failed."));
|
|
2175
|
+
return false;
|
|
2176
|
+
}
|
|
2177
|
+
const commit = spawnSync5("git", ["commit", "-m", message], { cwd: repoPath, stdio: "inherit" });
|
|
2178
|
+
if (commit.status !== 0) {
|
|
2179
|
+
console.error(chalk16.red("\u274C git commit failed \u2014 nothing to commit, or commit rejected."));
|
|
2180
|
+
return false;
|
|
2181
|
+
}
|
|
2182
|
+
console.log(chalk16.green("\u2705 Committed."));
|
|
2183
|
+
return true;
|
|
2184
|
+
};
|
|
2185
|
+
|
|
2186
|
+
// src/commands/repo/push-command.ts
|
|
2187
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
2188
|
+
import chalk17 from "chalk";
|
|
2189
|
+
var repoPushCommand = () => {
|
|
2190
|
+
const repoPath = configManager.repo_path;
|
|
2191
|
+
if (repoPath == null) {
|
|
2192
|
+
console.error(chalk17.red("\u274C No repo installed."));
|
|
2193
|
+
console.log(chalk17.yellow("Run: set-prompt install <git-url>"));
|
|
2194
|
+
return false;
|
|
2195
|
+
}
|
|
2196
|
+
if (configManager.remote_url == null) {
|
|
2197
|
+
console.error(chalk17.red("\u274C No remote URL registered. Cannot push."));
|
|
2198
|
+
return false;
|
|
2199
|
+
}
|
|
2200
|
+
console.log(chalk17.green("\nPushing prompt repo..."));
|
|
2201
|
+
console.log(chalk17.dim(repoPath));
|
|
2202
|
+
const push = spawnSync6("git", ["push"], { cwd: repoPath, stdio: "inherit" });
|
|
2203
|
+
if (push.status !== 0) {
|
|
2204
|
+
console.error(chalk17.red("\u274C git push failed."));
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
console.log(chalk17.green("\u2705 Pushed."));
|
|
2208
|
+
return true;
|
|
2209
|
+
};
|
|
2210
|
+
|
|
2211
|
+
// src/commands/repo/save-command.ts
|
|
2212
|
+
var repoSaveCommand = (options = {}) => {
|
|
2213
|
+
const committed = repoCommitCommand({ message: options.message });
|
|
2214
|
+
if (committed === false) return;
|
|
2215
|
+
repoPushCommand();
|
|
2216
|
+
};
|
|
2217
|
+
|
|
2218
|
+
// src/commands/repo/status-command.ts
|
|
2219
|
+
import { spawnSync as spawnSync7 } from "child_process";
|
|
2220
|
+
import chalk18 from "chalk";
|
|
2221
|
+
var parseBranchLine = (line) => {
|
|
2222
|
+
const body = line.replace(/^## /, "");
|
|
2223
|
+
if (body.startsWith("HEAD ") || body.includes("(no branch)")) {
|
|
2224
|
+
return { branch: null, upstream: null, ahead: 0, behind: 0 };
|
|
2225
|
+
}
|
|
2226
|
+
const [refPart, bracketPart] = body.split(/\s+(?=\[)/);
|
|
2227
|
+
const [branch, upstream] = refPart.split("...");
|
|
2228
|
+
let ahead = 0;
|
|
2229
|
+
let behind = 0;
|
|
2230
|
+
if (bracketPart != null) {
|
|
2231
|
+
const inside = bracketPart.replace(/[\[\]]/g, "");
|
|
2232
|
+
for (const piece of inside.split(",").map((s) => s.trim())) {
|
|
2233
|
+
const m = piece.match(/^(ahead|behind) (\d+)$/);
|
|
2234
|
+
if (m == null) continue;
|
|
2235
|
+
if (m[1] === "ahead") ahead = Number(m[2]);
|
|
2236
|
+
if (m[1] === "behind") behind = Number(m[2]);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
return { branch: branch ?? null, upstream: upstream ?? null, ahead, behind };
|
|
2240
|
+
};
|
|
2241
|
+
var parseFileLine = (line) => {
|
|
2242
|
+
if (line.length < 4) return null;
|
|
2243
|
+
const status = line.slice(0, 2);
|
|
2244
|
+
let name = line.slice(3);
|
|
2245
|
+
const arrowIdx = name.indexOf(" -> ");
|
|
2246
|
+
if (arrowIdx >= 0) name = name.slice(arrowIdx + 4);
|
|
2247
|
+
if (name.startsWith('"') && name.endsWith('"')) name = name.slice(1, -1);
|
|
2248
|
+
if (status.includes("?")) return { label: "untracked", color: chalk18.gray, path: name };
|
|
2249
|
+
if (status.includes("D")) return { label: "deleted", color: chalk18.red, path: name };
|
|
2250
|
+
if (status.includes("R")) return { label: "renamed", color: chalk18.cyan, path: name };
|
|
2251
|
+
if (status.includes("A")) return { label: "added", color: chalk18.green, path: name };
|
|
2252
|
+
if (status.includes("M")) return { label: "modified", color: chalk18.yellow, path: name };
|
|
2253
|
+
return null;
|
|
2254
|
+
};
|
|
2255
|
+
var formatUpstream = (info) => {
|
|
2256
|
+
if (info.branch == null) return chalk18.red("(detached HEAD)");
|
|
2257
|
+
if (info.upstream == null) return `${info.branch} ${chalk18.yellow("(no upstream)")}`;
|
|
2258
|
+
const segs = [];
|
|
2259
|
+
if (info.ahead > 0) segs.push(chalk18.green(`ahead ${info.ahead}`));
|
|
2260
|
+
if (info.behind > 0) segs.push(chalk18.red(`behind ${info.behind}`));
|
|
2261
|
+
const trailing = segs.length > 0 ? ` (${segs.join(", ")})` : chalk18.dim(" (up to date)");
|
|
2262
|
+
return `${info.branch} ${chalk18.dim("\u2192")} ${info.upstream}${trailing}`;
|
|
2263
|
+
};
|
|
2264
|
+
var repoStatusCommand = () => {
|
|
2265
|
+
const repoPath = configManager.repo_path;
|
|
2266
|
+
if (repoPath == null) {
|
|
2267
|
+
console.error(chalk18.red("\u274C No repo installed."));
|
|
2268
|
+
console.log(chalk18.yellow("Run: set-prompt install <git-url>"));
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2271
|
+
const result = spawnSync7("git", ["status", "--porcelain=v1", "--branch", "--untracked-files=all"], {
|
|
2272
|
+
cwd: repoPath,
|
|
2273
|
+
encoding: "utf8"
|
|
2274
|
+
});
|
|
2275
|
+
if (result.status !== 0) {
|
|
2276
|
+
console.error(chalk18.red("\u274C git status failed."));
|
|
2277
|
+
if (result.stderr) console.error(chalk18.dim(result.stderr));
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
const lines = result.stdout.split("\n").filter((l) => l.length > 0);
|
|
2281
|
+
const branchLine = lines[0] ?? "## (unknown)";
|
|
2282
|
+
const fileLines = lines.slice(1);
|
|
2283
|
+
const branchInfo = parseBranchLine(branchLine);
|
|
2284
|
+
const changes = fileLines.map(parseFileLine).filter((f) => f !== null);
|
|
2285
|
+
console.log(`${chalk18.cyan("\u{1F4C2}")} ${chalk18.dim(repoPath)}`);
|
|
2286
|
+
console.log(`${chalk18.cyan("\u{1F33F}")} ${formatUpstream(branchInfo)}`);
|
|
2287
|
+
console.log("");
|
|
2288
|
+
if (changes.length === 0) {
|
|
2289
|
+
console.log(chalk18.green("\u2705 Working tree clean"));
|
|
2019
2290
|
return;
|
|
2020
2291
|
}
|
|
2021
|
-
console.log(
|
|
2292
|
+
console.log(chalk18.bold(`\u{1F4DD} Changes (${changes.length}):`));
|
|
2293
|
+
const labelWidth = Math.max(...changes.map((c) => c.label.length));
|
|
2294
|
+
for (const c of changes) {
|
|
2295
|
+
const label = c.color(c.label.padEnd(labelWidth));
|
|
2296
|
+
console.log(` ${label} ${c.path}`);
|
|
2297
|
+
}
|
|
2298
|
+
};
|
|
2299
|
+
|
|
2300
|
+
// src/commands/repo/path-command.ts
|
|
2301
|
+
import chalk19 from "chalk";
|
|
2302
|
+
var repoPathCommand = () => {
|
|
2303
|
+
const repoPath = configManager.repo_path;
|
|
2304
|
+
if (repoPath == null) {
|
|
2305
|
+
console.error(chalk19.red("\u274C No repo installed."));
|
|
2306
|
+
console.error(chalk19.yellow("Run: set-prompt install <git-url>"));
|
|
2307
|
+
process.exitCode = 1;
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
2310
|
+
console.log(repoPath);
|
|
2311
|
+
};
|
|
2312
|
+
|
|
2313
|
+
// src/commands/repo/open-command.ts
|
|
2314
|
+
import { spawn } from "child_process";
|
|
2315
|
+
import path10 from "path";
|
|
2316
|
+
import chalk20 from "chalk";
|
|
2317
|
+
var resolveVscodeTarget = (repoPath) => {
|
|
2318
|
+
if (isOnPath("code") === false) return null;
|
|
2319
|
+
return { bin: "code", args: [repoPath] };
|
|
2320
|
+
};
|
|
2321
|
+
var resolveSourcetreeTarget = (repoPath) => {
|
|
2322
|
+
if (isOnPath("stree")) {
|
|
2323
|
+
return { bin: "stree", args: [repoPath] };
|
|
2324
|
+
}
|
|
2325
|
+
if (process.platform === "win32") {
|
|
2326
|
+
const exe = firstExistingPath([
|
|
2327
|
+
process.env.LOCALAPPDATA && path10.join(process.env.LOCALAPPDATA, "SourceTree", "SourceTree.exe"),
|
|
2328
|
+
process.env["ProgramFiles(x86)"] && path10.join(process.env["ProgramFiles(x86)"], "Atlassian", "SourceTree", "SourceTree.exe"),
|
|
2329
|
+
process.env.ProgramFiles && path10.join(process.env.ProgramFiles, "Atlassian", "SourceTree", "SourceTree.exe")
|
|
2330
|
+
]);
|
|
2331
|
+
if (exe != null) return { bin: exe, args: ["-f", repoPath] };
|
|
2332
|
+
}
|
|
2333
|
+
return null;
|
|
2334
|
+
};
|
|
2335
|
+
var VSCODE_INSTALL_HINT = `Install VSCode CLI: View \u2192 Command Palette \u2192 "Shell Command: Install 'code' command"`;
|
|
2336
|
+
var sourcetreeInstallHint = () => {
|
|
2337
|
+
if (process.platform === "darwin") {
|
|
2338
|
+
return 'Install Sourcetree, then: Sourcetree menu bar \u2192 "Install Command Line Tools"';
|
|
2339
|
+
}
|
|
2340
|
+
if (process.platform === "win32") {
|
|
2341
|
+
return "Install Sourcetree from https://sourcetreeapp.com/ \u2014 this CLI auto-detects it at %LOCALAPPDATA%\\SourceTree";
|
|
2342
|
+
}
|
|
2343
|
+
return "Sourcetree is not available on Linux \u2014 try a native Git GUI instead";
|
|
2344
|
+
};
|
|
2345
|
+
var runLaunch = (label, target) => {
|
|
2346
|
+
console.log(chalk20.green(`Opening in ${label}: ${chalk20.dim(target.args[target.args.length - 1])}`));
|
|
2347
|
+
const child = spawn(target.bin, target.args, { stdio: "ignore", detached: true, shell: true });
|
|
2348
|
+
child.unref();
|
|
2349
|
+
};
|
|
2350
|
+
var repoOpenCommand = (options = {}) => {
|
|
2351
|
+
const repoPath = configManager.repo_path;
|
|
2352
|
+
if (repoPath == null) {
|
|
2353
|
+
console.error(chalk20.red("\u274C No repo installed."));
|
|
2354
|
+
console.log(chalk20.yellow("Run: set-prompt install <git-url>"));
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
if (options.code === true) {
|
|
2358
|
+
const target = resolveVscodeTarget(repoPath);
|
|
2359
|
+
if (target == null) {
|
|
2360
|
+
console.error(chalk20.red("\u274C VSCode CLI (`code`) not found on PATH."));
|
|
2361
|
+
console.log(chalk20.dim(` ${VSCODE_INSTALL_HINT}`));
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
runLaunch("VSCode", target);
|
|
2365
|
+
return;
|
|
2366
|
+
}
|
|
2367
|
+
if (options.stree === true) {
|
|
2368
|
+
const target = resolveSourcetreeTarget(repoPath);
|
|
2369
|
+
if (target == null) {
|
|
2370
|
+
console.error(chalk20.red("\u274C Sourcetree not found."));
|
|
2371
|
+
console.log(chalk20.dim(` ${sourcetreeInstallHint()}`));
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
runLaunch("Sourcetree", target);
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2377
|
+
const platform = process.platform;
|
|
2378
|
+
const opener = platform === "win32" ? "explorer" : platform === "darwin" ? "open" : "xdg-open";
|
|
2379
|
+
console.log(chalk20.green(`Opening: ${chalk20.dim(repoPath)}`));
|
|
2380
|
+
const child = spawn(opener, [repoPath], { stdio: "ignore", detached: true });
|
|
2381
|
+
child.on("error", (ex) => {
|
|
2382
|
+
console.error(chalk20.red(`\u274C Failed to open: ${ex.message}`));
|
|
2383
|
+
});
|
|
2384
|
+
child.unref();
|
|
2022
2385
|
};
|
|
2023
2386
|
|
|
2024
2387
|
// src/index.ts
|
|
2025
2388
|
process.on("SIGINT", () => {
|
|
2026
|
-
console.log(
|
|
2389
|
+
console.log(chalk21.yellow("\nCancelled."));
|
|
2027
2390
|
process.exit(0);
|
|
2028
2391
|
});
|
|
2029
2392
|
process.on("unhandledRejection", (reason) => {
|
|
2030
2393
|
if (reason instanceof Error && reason.name === "ExitPromptError") {
|
|
2031
|
-
console.log(
|
|
2394
|
+
console.log(chalk21.yellow("\nCancelled."));
|
|
2032
2395
|
process.exit(0);
|
|
2033
2396
|
}
|
|
2034
2397
|
throw reason;
|
|
2035
2398
|
});
|
|
2036
|
-
var __dirname =
|
|
2037
|
-
var pkg = JSON.parse(
|
|
2399
|
+
var __dirname = path11.dirname(fileURLToPath(import.meta.url));
|
|
2400
|
+
var pkg = JSON.parse(fs12.readFileSync(path11.join(__dirname, "../package.json"), "utf-8"));
|
|
2038
2401
|
configManager.init();
|
|
2039
2402
|
var program = new Command();
|
|
2040
|
-
var banner =
|
|
2041
|
-
program.name("set-prompt").description(pkg.description).version(pkg.version).addHelpText("beforeAll", banner + "\n"
|
|
2042
|
-
|
|
2043
|
-
});
|
|
2044
|
-
program.command("install").description(`\u{1F4E6} Clone a ${chalk15.cyan("git repo")} into ${chalk15.dim("~/.set-prompt/repo/")} and register it as your prompt source`).argument("<url>", "remote git URL").action(async (source) => {
|
|
2403
|
+
var banner = chalk21.cyan(figlet.textSync("Set-Prompt", { horizontalLayout: "full" }));
|
|
2404
|
+
program.name("set-prompt").description(pkg.description).version(pkg.version).addHelpText("beforeAll", ({ command }) => command === program ? banner + "\n" : "");
|
|
2405
|
+
program.command("install").description(`\u{1F4E6} Clone a ${chalk21.cyan("git repo")} into ${chalk21.dim("~/.set-prompt/repo/")} and register it as your prompt source`).argument("<url>", "remote git URL").action(async (source) => {
|
|
2045
2406
|
await installCommand(source);
|
|
2046
2407
|
});
|
|
2047
|
-
program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${
|
|
2408
|
+
program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${chalk21.cyan("AI agent")} plugin dir ${chalk21.dim("(claudecode | roocode | openclaw | codex | antigravity)")}`).argument("[agent]", `target agent ${chalk21.dim("(omit for interactive selection)")}`).action(async (agent) => {
|
|
2048
2409
|
await linkCommand(agent);
|
|
2049
2410
|
});
|
|
2050
|
-
program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${
|
|
2411
|
+
program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${chalk21.cyan("required directories")} in a prompt repo ${chalk21.dim("(-f to force overwrite)")}`).argument("[path]", `path to repo ${chalk21.dim("(defaults to installed source)")}`).action(async (localPath) => {
|
|
2051
2412
|
await scaffoldCommand(localPath);
|
|
2052
2413
|
});
|
|
2053
|
-
program.command("status").description(`\u{1F4CB} Show registered ${
|
|
2414
|
+
program.command("status").description(`\u{1F4CB} Show registered ${chalk21.cyan("repo")} and which ${chalk21.cyan("agents")} are linked`).action(() => {
|
|
2054
2415
|
statusCommand();
|
|
2055
2416
|
});
|
|
2056
|
-
program.command("
|
|
2057
|
-
|
|
2417
|
+
var repo = program.command("repo").description(`\u{1F5C2}\uFE0F Manage the installed prompt repo ${chalk21.dim("(status | pull | commit | push | save | path | open)")}`);
|
|
2418
|
+
repo.command("status").description(`\u{1F4CB} Show VCS status of the repo ${chalk21.dim("(branch, ahead/behind, changed files)")}`).addHelpText("after", `
|
|
2419
|
+
Example output:
|
|
2420
|
+
\u{1F4C2} ~/.set-prompt/repo
|
|
2421
|
+
\u{1F33F} main \u2192 origin/main (ahead 2)
|
|
2422
|
+
|
|
2423
|
+
\u{1F4DD} Changes (2):
|
|
2424
|
+
modified skills/foo.md
|
|
2425
|
+
untracked draft.md
|
|
2426
|
+
`).action(() => {
|
|
2427
|
+
repoStatusCommand();
|
|
2428
|
+
});
|
|
2429
|
+
repo.command("pull").description(`\u{1F504} Fetch and pull the latest changes from the ${chalk21.cyan("remote repo")}`).action(() => {
|
|
2430
|
+
repoPullCommand();
|
|
2431
|
+
});
|
|
2432
|
+
repo.command("commit").description(`\u{1F4DD} Stage all changes and commit ${chalk21.dim("(auto-generates message if -m omitted; does not push)")}`).option("-m, --message <msg>", "commit message (auto-generated from changed files if omitted)").addHelpText("after", `
|
|
2433
|
+
Examples:
|
|
2434
|
+
$ sppt repo commit -m "edit dbml skill"
|
|
2435
|
+
$ sppt repo commit ${chalk21.dim('# auto-generates "update N files" + file list')}
|
|
2436
|
+
`).action((opts) => {
|
|
2437
|
+
repoCommitCommand({ message: opts.message });
|
|
2438
|
+
});
|
|
2439
|
+
repo.command("push").description(`\u2B06\uFE0F Push local commits to the remote`).action(() => {
|
|
2440
|
+
repoPushCommand();
|
|
2441
|
+
});
|
|
2442
|
+
repo.command("save").description(`\u{1F4BE} Stage + commit + push in one step ${chalk21.dim("(macro for commit \u2192 push; auto-generates message if -m omitted)")}`).option("-m, --message <msg>", "commit message (auto-generated from changed files if omitted)").addHelpText("after", `
|
|
2443
|
+
Examples:
|
|
2444
|
+
$ sppt repo save -m "edit dbml skill"
|
|
2445
|
+
$ sppt repo save ${chalk21.dim("# auto-generates message and pushes")}
|
|
2446
|
+
|
|
2447
|
+
Equivalent to: sppt repo commit && sppt repo push
|
|
2448
|
+
`).action((opts) => {
|
|
2449
|
+
repoSaveCommand({ message: opts.message });
|
|
2450
|
+
});
|
|
2451
|
+
repo.command("path").description(`\u{1F4CD} Print the repo path to stdout ${chalk21.dim("(e.g. cd $(sppt repo path))")}`).addHelpText("after", `
|
|
2452
|
+
Examples:
|
|
2453
|
+
$ sppt repo path
|
|
2454
|
+
${chalk21.dim("/Users/me/.set-prompt/repo")}
|
|
2455
|
+
|
|
2456
|
+
$ cd "$(sppt repo path)" ${chalk21.dim("# jump into the repo")}
|
|
2457
|
+
$ code "$(sppt repo path)" ${chalk21.dim("# open in VSCode")}
|
|
2458
|
+
`).action(() => {
|
|
2459
|
+
repoPathCommand();
|
|
2460
|
+
});
|
|
2461
|
+
repo.command("open").description(`\u{1F4C2} Open the repo in the OS file manager ${chalk21.dim("(--code: VSCode, --stree: Sourcetree)")}`).option("--code", "open with VSCode (`code` CLI)").option("--stree", "open with Sourcetree (`stree` CLI)").addHelpText("after", `
|
|
2462
|
+
Examples:
|
|
2463
|
+
$ sppt repo open ${chalk21.dim("# Explorer / Finder / xdg-open")}
|
|
2464
|
+
$ sppt repo open --code ${chalk21.dim("# open in VSCode")}
|
|
2465
|
+
$ sppt repo open --stree ${chalk21.dim("# open in Sourcetree")}
|
|
2466
|
+
`).action((opts) => {
|
|
2467
|
+
repoOpenCommand({ code: opts.code, stree: opts.stree });
|
|
2058
2468
|
});
|
|
2059
|
-
program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${
|
|
2469
|
+
program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${chalk21.dim("(~/.set-prompt/, plugin dirs, settings entries)")}`).action(async () => {
|
|
2060
2470
|
await uninstallCommand();
|
|
2061
2471
|
});
|
|
2062
2472
|
program.parse(process.argv);
|