set-prompt 0.5.3 → 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 +32 -0
- package/README.md +27 -4
- package/dist/index.js +804 -388
- 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
|
|
@@ -278,9 +340,15 @@ This is a shared prompt repository linked to various AI agents via \`set-prompt
|
|
|
278
340
|
\u251C\u2500\u2500 agents/ # Agent definitions (Claude Code, Cursor)
|
|
279
341
|
\u2502 \u2514\u2500\u2500 <agent-name>/
|
|
280
342
|
\u2502 \u2514\u2500\u2500 AGENT.md
|
|
281
|
-
\
|
|
282
|
-
|
|
283
|
-
|
|
343
|
+
\u251C\u2500\u2500 rules/ # Rule definitions (Cursor)
|
|
344
|
+
\u2502 \u2514\u2500\u2500 <rule-name>/
|
|
345
|
+
\u2502 \u2514\u2500\u2500 RULE.md
|
|
346
|
+
\u251C\u2500\u2500 .mcp.json # MCP server configurations
|
|
347
|
+
\u251C\u2500\u2500 .app.json # Application configurations
|
|
348
|
+
\u251C\u2500\u2500 .claude-plugin/
|
|
349
|
+
\u2502 \u2514\u2500\u2500 plugin.json # Claude Code plugin manifest
|
|
350
|
+
\u2514\u2500\u2500 .codex-plugin/
|
|
351
|
+
\u2514\u2500\u2500 plugin.json # Codex plugin manifest
|
|
284
352
|
\`\`\`
|
|
285
353
|
|
|
286
354
|
## Usage
|
|
@@ -293,8 +361,23 @@ set-prompt scaffold .
|
|
|
293
361
|
set-prompt install https://github.com/you/my-prompts
|
|
294
362
|
set-prompt link
|
|
295
363
|
|
|
296
|
-
#
|
|
297
|
-
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
|
|
298
381
|
\`\`\`
|
|
299
382
|
|
|
300
383
|
## Frontmatter Reference
|
|
@@ -644,43 +727,86 @@ echo '{"permission":"deny","user_message":"Blocked by policy","agent_message":"N
|
|
|
644
727
|
`;
|
|
645
728
|
|
|
646
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
|
+
};
|
|
647
775
|
var ensureClaudePluginManifest = (repoPath) => {
|
|
648
776
|
const metaDir = path2.join(repoPath, ".claude-plugin");
|
|
649
777
|
const jsonPath = path2.join(metaDir, "plugin.json");
|
|
650
|
-
|
|
651
|
-
fs2.writeFileSync(jsonPath, JSON.stringify({
|
|
778
|
+
return ensureManifest(jsonPath, metaDir, validateClaudePluginManifest, {
|
|
652
779
|
name: PLUGIN_NAME,
|
|
653
780
|
version: "1.0.0",
|
|
654
|
-
description:
|
|
655
|
-
},
|
|
781
|
+
description: "Managed by set-prompt"
|
|
782
|
+
}, ".claude-plugin/plugin.json");
|
|
656
783
|
};
|
|
657
784
|
var ensureCodexPluginManifest = (repoPath) => {
|
|
658
785
|
const metaDir = path2.join(repoPath, ".codex-plugin");
|
|
659
786
|
const jsonPath = path2.join(metaDir, "plugin.json");
|
|
660
|
-
|
|
661
|
-
fs2.writeFileSync(jsonPath, JSON.stringify({
|
|
787
|
+
return ensureManifest(jsonPath, metaDir, validateCodexPluginManifest, {
|
|
662
788
|
name: PLUGIN_NAME,
|
|
663
789
|
version: "1.0.0",
|
|
664
|
-
description:
|
|
790
|
+
description: "Managed by set-prompt",
|
|
665
791
|
skills: "./skills/",
|
|
666
792
|
mcpServers: "./.mcp.json",
|
|
667
793
|
apps: "./.app.json"
|
|
668
|
-
},
|
|
794
|
+
}, ".codex-plugin/plugin.json");
|
|
669
795
|
};
|
|
670
796
|
var ensureMcpJson = (repoPath) => {
|
|
671
797
|
const mcpJsonPath = path2.join(repoPath, ".mcp.json");
|
|
672
|
-
if (
|
|
798
|
+
if (fs3.existsSync(mcpJsonPath)) {
|
|
673
799
|
return false;
|
|
674
800
|
}
|
|
675
|
-
|
|
801
|
+
fs3.writeFileSync(mcpJsonPath, JSON.stringify({ mcpServers: {} }, null, 4), { encoding: "utf-8" });
|
|
676
802
|
return true;
|
|
677
803
|
};
|
|
678
804
|
var ensureAppJson = (repoPath) => {
|
|
679
805
|
const appJsonPath = path2.join(repoPath, ".app.json");
|
|
680
|
-
if (
|
|
806
|
+
if (fs3.existsSync(appJsonPath)) {
|
|
681
807
|
return false;
|
|
682
808
|
}
|
|
683
|
-
|
|
809
|
+
fs3.writeFileSync(appJsonPath, JSON.stringify({ apps: {} }, null, 4), { encoding: "utf-8" });
|
|
684
810
|
return true;
|
|
685
811
|
};
|
|
686
812
|
var scaffoldCommand = async (localPath) => {
|
|
@@ -692,15 +818,15 @@ var scaffoldCommand = async (localPath) => {
|
|
|
692
818
|
if (configManager.repo_path != null) {
|
|
693
819
|
targetPath = configManager.repo_path;
|
|
694
820
|
} else {
|
|
695
|
-
console.error(
|
|
821
|
+
console.error(chalk4.red("No path provided and no repo registered. Please provide a path."));
|
|
696
822
|
process.exit(1);
|
|
697
823
|
}
|
|
698
824
|
}
|
|
699
|
-
if (
|
|
700
|
-
console.error(
|
|
825
|
+
if (fs3.existsSync(targetPath) === false || fs3.statSync(targetPath).isDirectory() === false) {
|
|
826
|
+
console.error(chalk4.red(`Invalid directory path: '${targetPath}'`));
|
|
701
827
|
process.exit(1);
|
|
702
828
|
}
|
|
703
|
-
console.log(
|
|
829
|
+
console.log(chalk4.dim(`Scaffolding: ${targetPath}
|
|
704
830
|
`));
|
|
705
831
|
const writeGuide = await confirm({
|
|
706
832
|
message: "Generate SET_PROMPT_GUIDE.md? (reference doc for writing prompts)",
|
|
@@ -708,32 +834,36 @@ var scaffoldCommand = async (localPath) => {
|
|
|
708
834
|
});
|
|
709
835
|
if (writeGuide) {
|
|
710
836
|
const guideMdPath = path2.join(targetPath, "SET_PROMPT_GUIDE.md");
|
|
711
|
-
|
|
712
|
-
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`);
|
|
713
839
|
}
|
|
714
840
|
for (const dirName of PROMPT_DIR_NAMES) {
|
|
715
841
|
const dirPath = path2.join(targetPath, dirName);
|
|
716
|
-
if (
|
|
717
|
-
console.log(`${TAB}${
|
|
842
|
+
if (fs3.existsSync(dirPath)) {
|
|
843
|
+
console.log(`${TAB}${chalk4.dim("\u2713")} ${dirName}/`);
|
|
718
844
|
} else {
|
|
719
|
-
|
|
720
|
-
console.log(`${TAB}${
|
|
845
|
+
fs3.mkdirSync(dirPath, { recursive: true });
|
|
846
|
+
console.log(`${TAB}${chalk4.green("+")} ${dirName}/`);
|
|
721
847
|
}
|
|
722
848
|
const gitkeepPath = path2.join(dirPath, ".gitkeep");
|
|
723
|
-
if (!
|
|
724
|
-
|
|
849
|
+
if (!fs3.existsSync(gitkeepPath)) {
|
|
850
|
+
fs3.writeFileSync(gitkeepPath, "", { encoding: "utf-8" });
|
|
725
851
|
}
|
|
726
852
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
console.log(`${TAB}${
|
|
732
|
-
console.log(`${TAB}${
|
|
733
|
-
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
|
+
}
|
|
734
864
|
return true;
|
|
735
865
|
} catch (ex) {
|
|
736
|
-
console.error(
|
|
866
|
+
console.error(chalk4.red(`Failed to scaffold repo structure: ${ex.message}`), ex);
|
|
737
867
|
throw ex;
|
|
738
868
|
}
|
|
739
869
|
};
|
|
@@ -742,86 +872,87 @@ var scaffoldCommand = async (localPath) => {
|
|
|
742
872
|
var cloneRepo = async (remoteUrl) => {
|
|
743
873
|
const localPath = path3.join(HOME_DIR, "repo");
|
|
744
874
|
let backupPath = null;
|
|
745
|
-
if (
|
|
875
|
+
if (fs4.existsSync(localPath) == true) {
|
|
746
876
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
747
877
|
backupPath = path3.join(HOME_DIR, `repo.bak.${timestamp}`);
|
|
748
878
|
try {
|
|
749
|
-
|
|
750
|
-
console.log(
|
|
879
|
+
fs4.renameSync(localPath, backupPath);
|
|
880
|
+
console.log(chalk5.yellow(" backed up") + chalk5.dim(` existing repo \u2192 ${backupPath}`));
|
|
751
881
|
} catch (ex) {
|
|
752
882
|
if (ex.code === "EPERM") {
|
|
753
|
-
console.error(
|
|
754
|
-
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}`));
|
|
755
885
|
} else {
|
|
756
|
-
console.error(
|
|
886
|
+
console.error(chalk5.red(`\u274C Failed to backup existing repo: ${ex.message}`));
|
|
757
887
|
}
|
|
758
888
|
return false;
|
|
759
889
|
}
|
|
760
890
|
}
|
|
761
|
-
|
|
891
|
+
fs4.mkdirSync(path3.dirname(localPath), { recursive: true });
|
|
762
892
|
console.log(`Cloning ${remoteUrl}...`);
|
|
763
|
-
const result =
|
|
893
|
+
const result = spawnSync3("git", ["clone", remoteUrl, localPath], { stdio: "inherit" });
|
|
764
894
|
if (result.status !== 0) {
|
|
765
895
|
console.log("\u274C Failed to clone. Check the URL and your git credentials.");
|
|
766
896
|
process.exit(1);
|
|
767
897
|
}
|
|
768
898
|
console.log("\u2705 Cloned successfully.");
|
|
769
899
|
if (backupPath != null) {
|
|
770
|
-
|
|
771
|
-
console.log(
|
|
900
|
+
fs4.rmSync(backupPath, { recursive: true, force: true });
|
|
901
|
+
console.log(chalk5.red(" removed") + chalk5.dim(` backup \u2192 ${backupPath}`));
|
|
772
902
|
}
|
|
773
|
-
await scaffoldCommand(localPath
|
|
903
|
+
await scaffoldCommand(localPath);
|
|
774
904
|
configManager.repo_path = localPath;
|
|
775
905
|
configManager.remote_url = remoteUrl;
|
|
776
906
|
if (configManager.save() === false) {
|
|
777
|
-
console.error(
|
|
907
|
+
console.error(chalk5.red("Failed to save config."));
|
|
778
908
|
return false;
|
|
779
909
|
}
|
|
910
|
+
printSaveHint(localPath);
|
|
780
911
|
return true;
|
|
781
912
|
};
|
|
782
913
|
var installCommand = async (target) => {
|
|
783
914
|
try {
|
|
784
915
|
if (isGitUrl(target) === false) {
|
|
785
|
-
console.error(
|
|
786
|
-
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"));
|
|
787
918
|
process.exit(1);
|
|
788
919
|
}
|
|
789
920
|
const normalizeUrl = (url) => url.replace(/\.git$/, "").toLowerCase();
|
|
790
921
|
if (configManager.repo_path != null) {
|
|
791
922
|
if (normalizeUrl(configManager.remote_url ?? "") === normalizeUrl(target)) {
|
|
792
|
-
console.error(
|
|
793
|
-
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."));
|
|
794
925
|
return false;
|
|
795
926
|
}
|
|
796
|
-
console.warn(
|
|
927
|
+
console.warn(chalk5.yellow(`\u26A0 Switching repo: ${configManager.remote_url} \u2192 ${target}`));
|
|
797
928
|
const proceed = await confirm2({ message: "Replace existing installation?", default: false });
|
|
798
929
|
if (!proceed) {
|
|
799
|
-
console.log(
|
|
930
|
+
console.log(chalk5.yellow("Cancelled."));
|
|
800
931
|
return false;
|
|
801
932
|
}
|
|
802
933
|
} else {
|
|
803
934
|
const proceed = await confirm2({ message: `Clone and register "${target}"?`, default: true });
|
|
804
935
|
if (!proceed) {
|
|
805
|
-
console.log(
|
|
936
|
+
console.log(chalk5.yellow("Cancelled."));
|
|
806
937
|
return false;
|
|
807
938
|
}
|
|
808
939
|
}
|
|
809
940
|
return await cloneRepo(target);
|
|
810
941
|
} catch (ex) {
|
|
811
|
-
console.error(
|
|
942
|
+
console.error(chalk5.red(`Unexpected error: ${ex.message}`), ex);
|
|
812
943
|
process.exit(1);
|
|
813
944
|
}
|
|
814
945
|
};
|
|
815
946
|
|
|
816
947
|
// src/commands/link-command.ts
|
|
817
|
-
import
|
|
948
|
+
import chalk12 from "chalk";
|
|
818
949
|
import { checkbox } from "@inquirer/prompts";
|
|
819
950
|
|
|
820
951
|
// src/link/claudecode.ts
|
|
821
952
|
import path4 from "path";
|
|
822
|
-
import
|
|
953
|
+
import fs5 from "fs";
|
|
823
954
|
import os2 from "os";
|
|
824
|
-
import
|
|
955
|
+
import chalk6 from "chalk";
|
|
825
956
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
826
957
|
var linkClaudeCode = async () => {
|
|
827
958
|
const repoPath = resolveRepoPath();
|
|
@@ -831,32 +962,32 @@ var linkClaudeCode = async () => {
|
|
|
831
962
|
const buildMarketplace = () => {
|
|
832
963
|
try {
|
|
833
964
|
const marketplaceMetaDir = path4.join(CLAUDE_CODE_DIR, ".claude-plugin");
|
|
834
|
-
|
|
965
|
+
fs5.mkdirSync(marketplaceMetaDir, { recursive: true });
|
|
835
966
|
const marketplaceJson = {
|
|
836
967
|
name: MARKET_NAME,
|
|
837
968
|
owner: { name: os2.userInfo().username },
|
|
838
969
|
metadata: { description: "Managed by set-prompt", version: "1.0.0" },
|
|
839
970
|
plugins: [{ name: PLUGIN_NAME, source: `./plugins/${PLUGIN_NAME}`, description: "Managed by set-prompt" }]
|
|
840
971
|
};
|
|
841
|
-
|
|
972
|
+
fs5.writeFileSync(
|
|
842
973
|
path4.join(marketplaceMetaDir, "marketplace.json"),
|
|
843
974
|
JSON.stringify(marketplaceJson, null, 4),
|
|
844
975
|
"utf-8"
|
|
845
976
|
);
|
|
846
|
-
console.log(
|
|
847
|
-
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"));
|
|
848
979
|
const pluginLink = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
|
|
849
|
-
|
|
850
|
-
if (
|
|
851
|
-
|
|
980
|
+
fs5.mkdirSync(path4.dirname(pluginLink), { recursive: true });
|
|
981
|
+
if (fs5.existsSync(pluginLink)) {
|
|
982
|
+
fs5.rmSync(pluginLink, { recursive: true, force: true });
|
|
852
983
|
}
|
|
853
984
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
854
|
-
|
|
855
|
-
console.log(
|
|
856
|
-
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"));
|
|
857
988
|
return true;
|
|
858
989
|
} catch (ex) {
|
|
859
|
-
console.error(
|
|
990
|
+
console.error(chalk6.red(`\u274C Failed to build marketplace structure: ${ex.message}`));
|
|
860
991
|
return false;
|
|
861
992
|
}
|
|
862
993
|
};
|
|
@@ -864,18 +995,18 @@ var linkClaudeCode = async () => {
|
|
|
864
995
|
const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
|
|
865
996
|
try {
|
|
866
997
|
let settings = {};
|
|
867
|
-
if (
|
|
868
|
-
const raw =
|
|
998
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
999
|
+
const raw = fs5.readFileSync(claudeSettingsPath, "utf-8");
|
|
869
1000
|
try {
|
|
870
1001
|
const parsed = JSON.parse(raw);
|
|
871
1002
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
872
1003
|
settings = parsed;
|
|
873
1004
|
} else {
|
|
874
|
-
console.warn(
|
|
1005
|
+
console.warn(chalk6.yellow(" \u26A0 settings.json has unexpected format \u2014 proceeding with caution"));
|
|
875
1006
|
}
|
|
876
1007
|
} catch {
|
|
877
|
-
console.warn(
|
|
878
|
-
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."));
|
|
879
1010
|
return false;
|
|
880
1011
|
}
|
|
881
1012
|
}
|
|
@@ -888,43 +1019,43 @@ var linkClaudeCode = async () => {
|
|
|
888
1019
|
[`${PLUGIN_NAME}@${MARKET_NAME}`]: true
|
|
889
1020
|
};
|
|
890
1021
|
let backupPath = null;
|
|
891
|
-
if (
|
|
1022
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
892
1023
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
893
1024
|
backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
|
|
894
1025
|
try {
|
|
895
|
-
|
|
1026
|
+
fs5.copyFileSync(claudeSettingsPath, backupPath);
|
|
896
1027
|
} catch (ex) {
|
|
897
|
-
console.warn(
|
|
1028
|
+
console.warn(chalk6.yellow(` \u26A0 Could not create backup: ${ex.message}`));
|
|
898
1029
|
backupPath = null;
|
|
899
1030
|
}
|
|
900
1031
|
}
|
|
901
1032
|
try {
|
|
902
|
-
|
|
903
|
-
|
|
1033
|
+
fs5.mkdirSync(path4.dirname(claudeSettingsPath), { recursive: true });
|
|
1034
|
+
fs5.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 4), "utf-8");
|
|
904
1035
|
} catch (ex) {
|
|
905
1036
|
if (backupPath !== null) {
|
|
906
1037
|
try {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
console.warn(
|
|
1038
|
+
fs5.copyFileSync(backupPath, claudeSettingsPath);
|
|
1039
|
+
fs5.unlinkSync(backupPath);
|
|
1040
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
910
1041
|
} catch {
|
|
911
|
-
console.error(
|
|
1042
|
+
console.error(chalk6.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
|
|
912
1043
|
}
|
|
913
1044
|
}
|
|
914
1045
|
throw ex;
|
|
915
1046
|
}
|
|
916
1047
|
if (backupPath !== null) {
|
|
917
1048
|
try {
|
|
918
|
-
|
|
1049
|
+
fs5.unlinkSync(backupPath);
|
|
919
1050
|
} catch {
|
|
920
1051
|
}
|
|
921
1052
|
}
|
|
922
1053
|
console.log(`\u2705 Registered to Claude Code settings.`);
|
|
923
|
-
console.log(
|
|
1054
|
+
console.log(chalk6.dim(` ${claudeSettingsPath}`));
|
|
924
1055
|
return true;
|
|
925
1056
|
} catch (ex) {
|
|
926
|
-
console.error(
|
|
927
|
-
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."));
|
|
928
1059
|
return false;
|
|
929
1060
|
}
|
|
930
1061
|
};
|
|
@@ -934,9 +1065,9 @@ var linkClaudeCode = async () => {
|
|
|
934
1065
|
const pluginKey = `${PLUGIN_NAME}@${MARKET_NAME}`;
|
|
935
1066
|
try {
|
|
936
1067
|
let data = { version: 2, plugins: {} };
|
|
937
|
-
if (
|
|
1068
|
+
if (fs5.existsSync(installedPluginsPath)) {
|
|
938
1069
|
try {
|
|
939
|
-
data = JSON.parse(
|
|
1070
|
+
data = JSON.parse(fs5.readFileSync(installedPluginsPath, "utf-8"));
|
|
940
1071
|
} catch {
|
|
941
1072
|
}
|
|
942
1073
|
}
|
|
@@ -952,17 +1083,17 @@ var linkClaudeCode = async () => {
|
|
|
952
1083
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
953
1084
|
}
|
|
954
1085
|
];
|
|
955
|
-
|
|
956
|
-
|
|
1086
|
+
fs5.mkdirSync(path4.dirname(installedPluginsPath), { recursive: true });
|
|
1087
|
+
fs5.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 4), "utf-8");
|
|
957
1088
|
console.log(`\u2705 Patched installed_plugins.json \u2192 installPath points to source.`);
|
|
958
|
-
console.log(
|
|
1089
|
+
console.log(chalk6.dim(` ${installPath}`));
|
|
959
1090
|
} catch (ex) {
|
|
960
|
-
console.warn(
|
|
1091
|
+
console.warn(chalk6.yellow(` \u26A0 Could not patch installed_plugins.json: ${ex.message}`));
|
|
961
1092
|
}
|
|
962
1093
|
};
|
|
963
|
-
console.log(
|
|
1094
|
+
console.log(chalk6.green(`
|
|
964
1095
|
Setting up Claude Code plugin...`));
|
|
965
|
-
console.log(
|
|
1096
|
+
console.log(chalk6.dim(CLAUDE_CODE_DIR));
|
|
966
1097
|
const marketplaceOk = buildMarketplace();
|
|
967
1098
|
if (marketplaceOk === false) {
|
|
968
1099
|
return;
|
|
@@ -982,20 +1113,20 @@ var unlinkClaudeCode = async (force = false) => {
|
|
|
982
1113
|
default: false
|
|
983
1114
|
});
|
|
984
1115
|
if (!ok) {
|
|
985
|
-
console.log(
|
|
1116
|
+
console.log(chalk6.yellow("Cancelled."));
|
|
986
1117
|
return;
|
|
987
1118
|
}
|
|
988
1119
|
}
|
|
989
|
-
console.log(
|
|
1120
|
+
console.log(chalk6.red(`
|
|
990
1121
|
Removing Claude Code plugin...`));
|
|
991
|
-
console.log(
|
|
1122
|
+
console.log(chalk6.dim(CLAUDE_CODE_DIR));
|
|
992
1123
|
const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
|
|
993
|
-
if (
|
|
1124
|
+
if (fs5.existsSync(claudeSettingsPath)) {
|
|
994
1125
|
try {
|
|
995
1126
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
996
1127
|
const backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
|
|
997
|
-
|
|
998
|
-
const settings = JSON.parse(
|
|
1128
|
+
fs5.copyFileSync(claudeSettingsPath, backupPath);
|
|
1129
|
+
const settings = JSON.parse(fs5.readFileSync(claudeSettingsPath, "utf-8"));
|
|
999
1130
|
if (settings?.extraKnownMarketplaces?.[MARKET_NAME] !== void 0) {
|
|
1000
1131
|
delete settings.extraKnownMarketplaces[MARKET_NAME];
|
|
1001
1132
|
}
|
|
@@ -1003,26 +1134,26 @@ Removing Claude Code plugin...`));
|
|
|
1003
1134
|
delete settings.enabledPlugins[`${PLUGIN_NAME}@${MARKET_NAME}`];
|
|
1004
1135
|
}
|
|
1005
1136
|
try {
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
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}`));
|
|
1009
1140
|
} catch (ex) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
console.warn(
|
|
1141
|
+
fs5.copyFileSync(backupPath, claudeSettingsPath);
|
|
1142
|
+
fs5.unlinkSync(backupPath);
|
|
1143
|
+
console.warn(chalk6.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1013
1144
|
}
|
|
1014
1145
|
} catch (ex) {
|
|
1015
|
-
console.error(
|
|
1146
|
+
console.error(chalk6.red(` \u274C Failed to clean up settings.json: ${ex.message}`));
|
|
1016
1147
|
}
|
|
1017
1148
|
}
|
|
1018
1149
|
const claudePluginsDir = path4.join(os2.homedir(), ".claude", "plugins");
|
|
1019
1150
|
const installedPluginsPath = path4.join(claudePluginsDir, "installed_plugins.json");
|
|
1020
|
-
if (
|
|
1151
|
+
if (fs5.existsSync(installedPluginsPath)) {
|
|
1021
1152
|
try {
|
|
1022
1153
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1023
1154
|
const backupPath = `${installedPluginsPath}.bak.${timestamp}`;
|
|
1024
|
-
|
|
1025
|
-
const installed = JSON.parse(
|
|
1155
|
+
fs5.copyFileSync(installedPluginsPath, backupPath);
|
|
1156
|
+
const installed = JSON.parse(fs5.readFileSync(installedPluginsPath, "utf-8"));
|
|
1026
1157
|
if (installed?.plugins && typeof installed.plugins === "object") {
|
|
1027
1158
|
for (const key of Object.keys(installed.plugins)) {
|
|
1028
1159
|
if (key.endsWith(`@${MARKET_NAME}`)) {
|
|
@@ -1031,44 +1162,44 @@ Removing Claude Code plugin...`));
|
|
|
1031
1162
|
}
|
|
1032
1163
|
}
|
|
1033
1164
|
try {
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
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}`));
|
|
1037
1168
|
} catch (ex) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
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."));
|
|
1041
1172
|
}
|
|
1042
1173
|
} catch (ex) {
|
|
1043
|
-
console.error(
|
|
1174
|
+
console.error(chalk6.red(` \u274C Failed to clean up installed_plugins.json: ${ex.message}`));
|
|
1044
1175
|
}
|
|
1045
1176
|
}
|
|
1046
1177
|
const knownMarketplacesPath = path4.join(claudePluginsDir, "known_marketplaces.json");
|
|
1047
|
-
if (
|
|
1178
|
+
if (fs5.existsSync(knownMarketplacesPath)) {
|
|
1048
1179
|
try {
|
|
1049
1180
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1050
1181
|
const backupPath = `${knownMarketplacesPath}.bak.${timestamp}`;
|
|
1051
|
-
|
|
1052
|
-
const marketplaces = JSON.parse(
|
|
1182
|
+
fs5.copyFileSync(knownMarketplacesPath, backupPath);
|
|
1183
|
+
const marketplaces = JSON.parse(fs5.readFileSync(knownMarketplacesPath, "utf-8"));
|
|
1053
1184
|
if (marketplaces?.[MARKET_NAME] !== void 0) {
|
|
1054
1185
|
delete marketplaces[MARKET_NAME];
|
|
1055
1186
|
}
|
|
1056
1187
|
try {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
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}`));
|
|
1060
1191
|
} catch (ex) {
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
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."));
|
|
1064
1195
|
}
|
|
1065
1196
|
} catch (ex) {
|
|
1066
|
-
console.error(
|
|
1197
|
+
console.error(chalk6.red(` \u274C Failed to clean up known_marketplaces.json: ${ex.message}`));
|
|
1067
1198
|
}
|
|
1068
1199
|
}
|
|
1069
|
-
if (
|
|
1070
|
-
|
|
1071
|
-
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}`));
|
|
1072
1203
|
}
|
|
1073
1204
|
configManager.claude_code = null;
|
|
1074
1205
|
configManager.save();
|
|
@@ -1076,8 +1207,8 @@ Removing Claude Code plugin...`));
|
|
|
1076
1207
|
|
|
1077
1208
|
// src/link/roocode.ts
|
|
1078
1209
|
import path5 from "path";
|
|
1079
|
-
import
|
|
1080
|
-
import
|
|
1210
|
+
import fs6 from "fs";
|
|
1211
|
+
import chalk7 from "chalk";
|
|
1081
1212
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
1082
1213
|
import { pathExists } from "fs-extra";
|
|
1083
1214
|
var linkRooCode = async () => {
|
|
@@ -1085,44 +1216,44 @@ var linkRooCode = async () => {
|
|
|
1085
1216
|
if (repoPath == null) {
|
|
1086
1217
|
return;
|
|
1087
1218
|
}
|
|
1088
|
-
console.log(
|
|
1219
|
+
console.log(chalk7.green(`
|
|
1089
1220
|
Setting up RooCode integration...`));
|
|
1090
|
-
console.log(
|
|
1221
|
+
console.log(chalk7.dim(ROO_DIR));
|
|
1091
1222
|
const roocodeDirs = AGENT_PROMPT_DIRS["roocode" /* ROOCODE */];
|
|
1092
1223
|
const backupExistingRooCodeFiles = async () => {
|
|
1093
1224
|
try {
|
|
1094
|
-
|
|
1225
|
+
fs6.mkdirSync(ROO_DIR, { recursive: true });
|
|
1095
1226
|
const dirsToBackup = [];
|
|
1096
1227
|
for (const dir of roocodeDirs) {
|
|
1097
1228
|
const target = path5.join(ROO_DIR, dir);
|
|
1098
|
-
if (
|
|
1229
|
+
if (fs6.existsSync(target) && fs6.lstatSync(target).isSymbolicLink() === false && fs6.readdirSync(target).length > 0) {
|
|
1099
1230
|
dirsToBackup.push(dir);
|
|
1100
1231
|
}
|
|
1101
1232
|
}
|
|
1102
1233
|
if (dirsToBackup.length === 0) {
|
|
1103
1234
|
return true;
|
|
1104
1235
|
}
|
|
1105
|
-
console.log(
|
|
1236
|
+
console.log(chalk7.yellow(`
|
|
1106
1237
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1107
1238
|
for (const dir of dirsToBackup) {
|
|
1108
|
-
console.log(
|
|
1239
|
+
console.log(chalk7.dim(` - ${path5.join(ROO_DIR, dir)}`));
|
|
1109
1240
|
}
|
|
1110
|
-
console.log(
|
|
1241
|
+
console.log(chalk7.yellow(` They will be backed up to: `) + chalk7.dim(ROO_BACKUP_DIR));
|
|
1111
1242
|
const ok = await confirm4({ message: "Back up existing directories?", default: true });
|
|
1112
1243
|
if (!ok) {
|
|
1113
|
-
console.log(
|
|
1244
|
+
console.log(chalk7.yellow("Skipped RooCode linking."));
|
|
1114
1245
|
return false;
|
|
1115
1246
|
}
|
|
1116
|
-
|
|
1247
|
+
fs6.mkdirSync(ROO_BACKUP_DIR, { recursive: true });
|
|
1117
1248
|
for (const dir of dirsToBackup) {
|
|
1118
1249
|
const src = path5.join(ROO_DIR, dir);
|
|
1119
1250
|
const dest = path5.join(ROO_BACKUP_DIR, dir);
|
|
1120
|
-
|
|
1121
|
-
console.log(
|
|
1251
|
+
fs6.renameSync(src, dest);
|
|
1252
|
+
console.log(chalk7.yellow(" backed up") + chalk7.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1122
1253
|
}
|
|
1123
1254
|
return true;
|
|
1124
1255
|
} catch (ex) {
|
|
1125
|
-
console.error(
|
|
1256
|
+
console.error(chalk7.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1126
1257
|
return false;
|
|
1127
1258
|
}
|
|
1128
1259
|
};
|
|
@@ -1135,21 +1266,21 @@ Setting up RooCode integration...`));
|
|
|
1135
1266
|
if (await pathExists(src) === false) {
|
|
1136
1267
|
continue;
|
|
1137
1268
|
}
|
|
1138
|
-
if (
|
|
1139
|
-
|
|
1269
|
+
if (fs6.existsSync(dest)) {
|
|
1270
|
+
fs6.rmSync(dest, { recursive: true, force: true });
|
|
1140
1271
|
}
|
|
1141
1272
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1142
|
-
|
|
1273
|
+
fs6.symlinkSync(src, dest, symlinkType);
|
|
1143
1274
|
linked.push({ dir, src });
|
|
1144
1275
|
}
|
|
1145
1276
|
for (const { dir, src } of linked) {
|
|
1146
1277
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1147
1278
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1148
|
-
console.log(
|
|
1279
|
+
console.log(chalk7.dim(` ${branch} `) + chalk7.bold(`${dir}/`) + chalk7.dim(` \u2192 ${src}`) + chalk7.green(" \u2713"));
|
|
1149
1280
|
}
|
|
1150
1281
|
return true;
|
|
1151
1282
|
} catch (ex) {
|
|
1152
|
-
console.error(
|
|
1283
|
+
console.error(chalk7.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1153
1284
|
return false;
|
|
1154
1285
|
}
|
|
1155
1286
|
};
|
|
@@ -1171,35 +1302,35 @@ var unlinkRooCode = async (force = false) => {
|
|
|
1171
1302
|
default: false
|
|
1172
1303
|
});
|
|
1173
1304
|
if (!ok) {
|
|
1174
|
-
console.log(
|
|
1305
|
+
console.log(chalk7.yellow("Cancelled."));
|
|
1175
1306
|
return;
|
|
1176
1307
|
}
|
|
1177
1308
|
}
|
|
1178
|
-
console.log(
|
|
1309
|
+
console.log(chalk7.red(`
|
|
1179
1310
|
Removing RooCode integration...`));
|
|
1180
|
-
console.log(
|
|
1311
|
+
console.log(chalk7.dim(ROO_DIR));
|
|
1181
1312
|
const backupPath = configManager.roocode?.backup_path ?? ROO_BACKUP_DIR;
|
|
1182
1313
|
for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
|
|
1183
1314
|
const target = path5.join(ROO_DIR, dir);
|
|
1184
|
-
if (
|
|
1185
|
-
|
|
1186
|
-
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}`));
|
|
1187
1318
|
}
|
|
1188
1319
|
}
|
|
1189
|
-
if (
|
|
1320
|
+
if (fs6.existsSync(backupPath)) {
|
|
1190
1321
|
try {
|
|
1191
1322
|
for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
|
|
1192
1323
|
const src = path5.join(backupPath, dir);
|
|
1193
1324
|
const dest = path5.join(ROO_DIR, dir);
|
|
1194
|
-
if (!
|
|
1325
|
+
if (!fs6.existsSync(src)) {
|
|
1195
1326
|
continue;
|
|
1196
1327
|
}
|
|
1197
|
-
|
|
1198
|
-
console.log(
|
|
1328
|
+
fs6.renameSync(src, dest);
|
|
1329
|
+
console.log(chalk7.green(" restored") + chalk7.dim(`: ${dir}/`));
|
|
1199
1330
|
}
|
|
1200
|
-
|
|
1331
|
+
fs6.rmdirSync(backupPath);
|
|
1201
1332
|
} catch (ex) {
|
|
1202
|
-
console.error(
|
|
1333
|
+
console.error(chalk7.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
|
|
1203
1334
|
}
|
|
1204
1335
|
}
|
|
1205
1336
|
configManager.roocode = null;
|
|
@@ -1208,8 +1339,8 @@ Removing RooCode integration...`));
|
|
|
1208
1339
|
|
|
1209
1340
|
// src/link/openclaw.ts
|
|
1210
1341
|
import path6 from "path";
|
|
1211
|
-
import
|
|
1212
|
-
import
|
|
1342
|
+
import fs7 from "fs";
|
|
1343
|
+
import chalk8 from "chalk";
|
|
1213
1344
|
import { confirm as confirm5 } from "@inquirer/prompts";
|
|
1214
1345
|
import { pathExists as pathExists2 } from "fs-extra";
|
|
1215
1346
|
var linkOpenclaw = async () => {
|
|
@@ -1217,44 +1348,44 @@ var linkOpenclaw = async () => {
|
|
|
1217
1348
|
if (repoPath == null) {
|
|
1218
1349
|
return;
|
|
1219
1350
|
}
|
|
1220
|
-
console.log(
|
|
1351
|
+
console.log(chalk8.green(`
|
|
1221
1352
|
Setting up OpenClaw integration...`));
|
|
1222
|
-
console.log(
|
|
1353
|
+
console.log(chalk8.dim(OPENCLAW_DIR));
|
|
1223
1354
|
const openclawDirs = AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */];
|
|
1224
1355
|
const backupExistingOpenclawFiles = async () => {
|
|
1225
1356
|
try {
|
|
1226
|
-
|
|
1357
|
+
fs7.mkdirSync(OPENCLAW_DIR, { recursive: true });
|
|
1227
1358
|
const dirsToBackup = [];
|
|
1228
1359
|
for (const dir of openclawDirs) {
|
|
1229
1360
|
const target = path6.join(OPENCLAW_DIR, dir);
|
|
1230
|
-
if (
|
|
1361
|
+
if (fs7.existsSync(target) && fs7.lstatSync(target).isSymbolicLink() === false && fs7.readdirSync(target).length > 0) {
|
|
1231
1362
|
dirsToBackup.push(dir);
|
|
1232
1363
|
}
|
|
1233
1364
|
}
|
|
1234
1365
|
if (dirsToBackup.length === 0) {
|
|
1235
1366
|
return true;
|
|
1236
1367
|
}
|
|
1237
|
-
console.log(
|
|
1368
|
+
console.log(chalk8.yellow(`
|
|
1238
1369
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1239
1370
|
for (const dir of dirsToBackup) {
|
|
1240
|
-
console.log(
|
|
1371
|
+
console.log(chalk8.dim(` - ${path6.join(OPENCLAW_DIR, dir)}`));
|
|
1241
1372
|
}
|
|
1242
|
-
console.log(
|
|
1373
|
+
console.log(chalk8.yellow(` They will be backed up to: `) + chalk8.dim(OPENCLAW_BACKUP_DIR));
|
|
1243
1374
|
const ok = await confirm5({ message: "Back up existing directories?", default: true });
|
|
1244
1375
|
if (!ok) {
|
|
1245
|
-
console.log(
|
|
1376
|
+
console.log(chalk8.yellow("Skipped OpenClaw linking."));
|
|
1246
1377
|
return false;
|
|
1247
1378
|
}
|
|
1248
|
-
|
|
1379
|
+
fs7.mkdirSync(OPENCLAW_BACKUP_DIR, { recursive: true });
|
|
1249
1380
|
for (const dir of dirsToBackup) {
|
|
1250
1381
|
const src = path6.join(OPENCLAW_DIR, dir);
|
|
1251
1382
|
const dest = path6.join(OPENCLAW_BACKUP_DIR, dir);
|
|
1252
|
-
|
|
1253
|
-
console.log(
|
|
1383
|
+
fs7.renameSync(src, dest);
|
|
1384
|
+
console.log(chalk8.yellow(" backed up") + chalk8.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1254
1385
|
}
|
|
1255
1386
|
return true;
|
|
1256
1387
|
} catch (ex) {
|
|
1257
|
-
console.error(
|
|
1388
|
+
console.error(chalk8.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1258
1389
|
return false;
|
|
1259
1390
|
}
|
|
1260
1391
|
};
|
|
@@ -1267,21 +1398,21 @@ Setting up OpenClaw integration...`));
|
|
|
1267
1398
|
if (await pathExists2(src) === false) {
|
|
1268
1399
|
continue;
|
|
1269
1400
|
}
|
|
1270
|
-
if (
|
|
1271
|
-
|
|
1401
|
+
if (fs7.existsSync(dest)) {
|
|
1402
|
+
fs7.rmSync(dest, { recursive: true, force: true });
|
|
1272
1403
|
}
|
|
1273
1404
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1274
|
-
|
|
1405
|
+
fs7.symlinkSync(src, dest, symlinkType);
|
|
1275
1406
|
linked.push({ dir, src });
|
|
1276
1407
|
}
|
|
1277
1408
|
for (const { dir, src } of linked) {
|
|
1278
1409
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1279
1410
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1280
|
-
console.log(
|
|
1411
|
+
console.log(chalk8.dim(` ${branch} `) + chalk8.bold(`${dir}/`) + chalk8.dim(` \u2192 ${src}`) + chalk8.green(" \u2713"));
|
|
1281
1412
|
}
|
|
1282
1413
|
return true;
|
|
1283
1414
|
} catch (ex) {
|
|
1284
|
-
console.error(
|
|
1415
|
+
console.error(chalk8.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1285
1416
|
return false;
|
|
1286
1417
|
}
|
|
1287
1418
|
};
|
|
@@ -1303,35 +1434,35 @@ var unlinkOpenclaw = async (force = false) => {
|
|
|
1303
1434
|
default: false
|
|
1304
1435
|
});
|
|
1305
1436
|
if (!ok) {
|
|
1306
|
-
console.log(
|
|
1437
|
+
console.log(chalk8.yellow("Cancelled."));
|
|
1307
1438
|
return;
|
|
1308
1439
|
}
|
|
1309
1440
|
}
|
|
1310
|
-
console.log(
|
|
1441
|
+
console.log(chalk8.red(`
|
|
1311
1442
|
Removing OpenClaw integration...`));
|
|
1312
|
-
console.log(
|
|
1443
|
+
console.log(chalk8.dim(OPENCLAW_DIR));
|
|
1313
1444
|
const backupPath = configManager.openclaw?.backup_path ?? OPENCLAW_BACKUP_DIR;
|
|
1314
1445
|
for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
|
|
1315
1446
|
const target = path6.join(OPENCLAW_DIR, dir);
|
|
1316
|
-
if (
|
|
1317
|
-
|
|
1318
|
-
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}`));
|
|
1319
1450
|
}
|
|
1320
1451
|
}
|
|
1321
|
-
if (
|
|
1452
|
+
if (fs7.existsSync(backupPath)) {
|
|
1322
1453
|
try {
|
|
1323
1454
|
for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
|
|
1324
1455
|
const src = path6.join(backupPath, dir);
|
|
1325
1456
|
const dest = path6.join(OPENCLAW_DIR, dir);
|
|
1326
|
-
if (!
|
|
1457
|
+
if (!fs7.existsSync(src)) {
|
|
1327
1458
|
continue;
|
|
1328
1459
|
}
|
|
1329
|
-
|
|
1330
|
-
console.log(
|
|
1460
|
+
fs7.renameSync(src, dest);
|
|
1461
|
+
console.log(chalk8.green(" restored") + chalk8.dim(`: ${dir}/`));
|
|
1331
1462
|
}
|
|
1332
|
-
|
|
1463
|
+
fs7.rmdirSync(backupPath);
|
|
1333
1464
|
} catch (ex) {
|
|
1334
|
-
console.error(
|
|
1465
|
+
console.error(chalk8.red(` \u274C Failed to restore OpenClaw backup: ${ex.message}`));
|
|
1335
1466
|
}
|
|
1336
1467
|
}
|
|
1337
1468
|
configManager.openclaw = null;
|
|
@@ -1340,8 +1471,8 @@ Removing OpenClaw integration...`));
|
|
|
1340
1471
|
|
|
1341
1472
|
// src/link/antigravity.ts
|
|
1342
1473
|
import path7 from "path";
|
|
1343
|
-
import
|
|
1344
|
-
import
|
|
1474
|
+
import fs8 from "fs";
|
|
1475
|
+
import chalk9 from "chalk";
|
|
1345
1476
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
1346
1477
|
import { pathExists as pathExists3 } from "fs-extra";
|
|
1347
1478
|
var linkAntigravity = async () => {
|
|
@@ -1349,44 +1480,44 @@ var linkAntigravity = async () => {
|
|
|
1349
1480
|
if (repoPath == null) {
|
|
1350
1481
|
return;
|
|
1351
1482
|
}
|
|
1352
|
-
console.log(
|
|
1483
|
+
console.log(chalk9.green(`
|
|
1353
1484
|
Setting up Antigravity integration...`));
|
|
1354
|
-
console.log(
|
|
1485
|
+
console.log(chalk9.dim(ANTIGRAVITY_DIR));
|
|
1355
1486
|
const antigravityDirs = AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */];
|
|
1356
1487
|
const backupExistingAntigravityFiles = async () => {
|
|
1357
1488
|
try {
|
|
1358
|
-
|
|
1489
|
+
fs8.mkdirSync(ANTIGRAVITY_DIR, { recursive: true });
|
|
1359
1490
|
const dirsToBackup = [];
|
|
1360
1491
|
for (const dir of antigravityDirs) {
|
|
1361
1492
|
const target = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1362
|
-
if (
|
|
1493
|
+
if (fs8.existsSync(target) && fs8.lstatSync(target).isSymbolicLink() === false && fs8.readdirSync(target).length > 0) {
|
|
1363
1494
|
dirsToBackup.push(dir);
|
|
1364
1495
|
}
|
|
1365
1496
|
}
|
|
1366
1497
|
if (dirsToBackup.length === 0) {
|
|
1367
1498
|
return true;
|
|
1368
1499
|
}
|
|
1369
|
-
console.log(
|
|
1500
|
+
console.log(chalk9.yellow(`
|
|
1370
1501
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1371
1502
|
for (const dir of dirsToBackup) {
|
|
1372
|
-
console.log(
|
|
1503
|
+
console.log(chalk9.dim(` - ${path7.join(ANTIGRAVITY_DIR, dir)}`));
|
|
1373
1504
|
}
|
|
1374
|
-
console.log(
|
|
1505
|
+
console.log(chalk9.yellow(` They will be backed up to: `) + chalk9.dim(ANTIGRAVITY_BACKUP_DIR));
|
|
1375
1506
|
const ok = await confirm6({ message: "Back up existing directories?", default: true });
|
|
1376
1507
|
if (!ok) {
|
|
1377
|
-
console.log(
|
|
1508
|
+
console.log(chalk9.yellow("Skipped Antigravity linking."));
|
|
1378
1509
|
return false;
|
|
1379
1510
|
}
|
|
1380
|
-
|
|
1511
|
+
fs8.mkdirSync(ANTIGRAVITY_BACKUP_DIR, { recursive: true });
|
|
1381
1512
|
for (const dir of antigravityDirs) {
|
|
1382
1513
|
const src = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1383
1514
|
const dest = path7.join(ANTIGRAVITY_BACKUP_DIR, dir);
|
|
1384
|
-
|
|
1385
|
-
console.log(
|
|
1515
|
+
fs8.renameSync(src, dest);
|
|
1516
|
+
console.log(chalk9.yellow(" backed up") + chalk9.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1386
1517
|
}
|
|
1387
1518
|
return true;
|
|
1388
1519
|
} catch (ex) {
|
|
1389
|
-
console.error(
|
|
1520
|
+
console.error(chalk9.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
1390
1521
|
return false;
|
|
1391
1522
|
}
|
|
1392
1523
|
};
|
|
@@ -1399,21 +1530,21 @@ Setting up Antigravity integration...`));
|
|
|
1399
1530
|
if (await pathExists3(src) === false) {
|
|
1400
1531
|
continue;
|
|
1401
1532
|
}
|
|
1402
|
-
if (
|
|
1403
|
-
|
|
1533
|
+
if (fs8.existsSync(dest)) {
|
|
1534
|
+
fs8.rmSync(dest, { recursive: true, force: true });
|
|
1404
1535
|
}
|
|
1405
1536
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1406
|
-
|
|
1537
|
+
fs8.symlinkSync(src, dest, symlinkType);
|
|
1407
1538
|
linked.push({ dir, src });
|
|
1408
1539
|
}
|
|
1409
1540
|
for (const { dir, src } of linked) {
|
|
1410
1541
|
const isLast = linked[linked.length - 1].dir === dir;
|
|
1411
1542
|
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
1412
|
-
console.log(
|
|
1543
|
+
console.log(chalk9.dim(` ${branch} `) + chalk9.bold(`${dir}/`) + chalk9.dim(` \u2192 ${src}`) + chalk9.green(" \u2713"));
|
|
1413
1544
|
}
|
|
1414
1545
|
return true;
|
|
1415
1546
|
} catch (ex) {
|
|
1416
|
-
console.error(
|
|
1547
|
+
console.error(chalk9.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
1417
1548
|
return false;
|
|
1418
1549
|
}
|
|
1419
1550
|
};
|
|
@@ -1435,35 +1566,35 @@ var unlinkAntigravity = async (force = false) => {
|
|
|
1435
1566
|
default: false
|
|
1436
1567
|
});
|
|
1437
1568
|
if (!ok) {
|
|
1438
|
-
console.log(
|
|
1569
|
+
console.log(chalk9.yellow("Cancelled."));
|
|
1439
1570
|
return;
|
|
1440
1571
|
}
|
|
1441
1572
|
}
|
|
1442
|
-
console.log(
|
|
1573
|
+
console.log(chalk9.red(`
|
|
1443
1574
|
Removing Antigravity integration...`));
|
|
1444
|
-
console.log(
|
|
1575
|
+
console.log(chalk9.dim(ANTIGRAVITY_DIR));
|
|
1445
1576
|
const backupPath = configManager.antigravity?.backup_path ?? ANTIGRAVITY_BACKUP_DIR;
|
|
1446
1577
|
for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
|
|
1447
1578
|
const target = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1448
|
-
if (
|
|
1449
|
-
|
|
1450
|
-
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}`));
|
|
1451
1582
|
}
|
|
1452
1583
|
}
|
|
1453
|
-
if (
|
|
1584
|
+
if (fs8.existsSync(backupPath)) {
|
|
1454
1585
|
try {
|
|
1455
1586
|
for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
|
|
1456
1587
|
const src = path7.join(backupPath, dir);
|
|
1457
1588
|
const dest = path7.join(ANTIGRAVITY_DIR, dir);
|
|
1458
|
-
if (!
|
|
1589
|
+
if (!fs8.existsSync(src)) {
|
|
1459
1590
|
continue;
|
|
1460
1591
|
}
|
|
1461
|
-
|
|
1462
|
-
console.log(
|
|
1592
|
+
fs8.renameSync(src, dest);
|
|
1593
|
+
console.log(chalk9.green(" restored") + chalk9.dim(`: ${dir}/`));
|
|
1463
1594
|
}
|
|
1464
|
-
|
|
1595
|
+
fs8.rmdirSync(backupPath);
|
|
1465
1596
|
} catch (ex) {
|
|
1466
|
-
console.error(
|
|
1597
|
+
console.error(chalk9.red(` \u274C Failed to restore Antigravity backup: ${ex.message}`));
|
|
1467
1598
|
}
|
|
1468
1599
|
}
|
|
1469
1600
|
configManager.antigravity = null;
|
|
@@ -1472,9 +1603,9 @@ Removing Antigravity integration...`));
|
|
|
1472
1603
|
|
|
1473
1604
|
// src/link/codex.ts
|
|
1474
1605
|
import path8 from "path";
|
|
1475
|
-
import
|
|
1606
|
+
import fs9 from "fs";
|
|
1476
1607
|
import os3 from "os";
|
|
1477
|
-
import
|
|
1608
|
+
import chalk10 from "chalk";
|
|
1478
1609
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
1479
1610
|
import TOML from "smol-toml";
|
|
1480
1611
|
var CODEX_AGENTS_DIR = path8.join(os3.homedir(), ".agents", "plugins");
|
|
@@ -1496,16 +1627,16 @@ var linkCodex = async () => {
|
|
|
1496
1627
|
interface: { displayName: "Local Repository" },
|
|
1497
1628
|
plugins: []
|
|
1498
1629
|
};
|
|
1499
|
-
if (
|
|
1500
|
-
const raw =
|
|
1630
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1631
|
+
const raw = fs9.readFileSync(marketplacePath, "utf-8");
|
|
1501
1632
|
try {
|
|
1502
1633
|
const parsed = JSON.parse(raw);
|
|
1503
1634
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1504
1635
|
marketplace = parsed;
|
|
1505
1636
|
}
|
|
1506
1637
|
} catch {
|
|
1507
|
-
console.warn(
|
|
1508
|
-
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."));
|
|
1509
1640
|
return false;
|
|
1510
1641
|
}
|
|
1511
1642
|
}
|
|
@@ -1528,58 +1659,58 @@ var linkCodex = async () => {
|
|
|
1528
1659
|
category: "Productivity"
|
|
1529
1660
|
});
|
|
1530
1661
|
let backupPath = null;
|
|
1531
|
-
if (
|
|
1662
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1532
1663
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1533
1664
|
backupPath = `${marketplacePath}.bak.${timestamp}`;
|
|
1534
1665
|
try {
|
|
1535
|
-
|
|
1666
|
+
fs9.copyFileSync(marketplacePath, backupPath);
|
|
1536
1667
|
} catch (ex) {
|
|
1537
|
-
console.warn(
|
|
1668
|
+
console.warn(chalk10.yellow(` \u26A0 Could not create backup: ${ex.message}`));
|
|
1538
1669
|
backupPath = null;
|
|
1539
1670
|
}
|
|
1540
1671
|
}
|
|
1541
1672
|
try {
|
|
1542
|
-
|
|
1543
|
-
|
|
1673
|
+
fs9.mkdirSync(path8.dirname(marketplacePath), { recursive: true });
|
|
1674
|
+
fs9.writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 4), "utf-8");
|
|
1544
1675
|
} catch (ex) {
|
|
1545
1676
|
if (backupPath !== null) {
|
|
1546
1677
|
try {
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
console.warn(
|
|
1678
|
+
fs9.copyFileSync(backupPath, marketplacePath);
|
|
1679
|
+
fs9.unlinkSync(backupPath);
|
|
1680
|
+
console.warn(chalk10.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1550
1681
|
} catch {
|
|
1551
|
-
console.error(
|
|
1682
|
+
console.error(chalk10.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
|
|
1552
1683
|
}
|
|
1553
1684
|
}
|
|
1554
1685
|
throw ex;
|
|
1555
1686
|
}
|
|
1556
1687
|
if (backupPath !== null) {
|
|
1557
1688
|
try {
|
|
1558
|
-
|
|
1689
|
+
fs9.unlinkSync(backupPath);
|
|
1559
1690
|
} catch {
|
|
1560
1691
|
}
|
|
1561
1692
|
}
|
|
1562
1693
|
console.log(`\u2705 Registered to marketplace.json`);
|
|
1563
|
-
console.log(
|
|
1694
|
+
console.log(chalk10.dim(` ${marketplacePath}`));
|
|
1564
1695
|
return true;
|
|
1565
1696
|
} catch (ex) {
|
|
1566
|
-
console.error(
|
|
1697
|
+
console.error(chalk10.red(`\u274C Failed to update marketplace.json: ${ex.message}`));
|
|
1567
1698
|
return false;
|
|
1568
1699
|
}
|
|
1569
1700
|
};
|
|
1570
1701
|
const patchPluginCache = () => {
|
|
1571
1702
|
const cachePath = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME, PLUGIN_NAME, "1.0.0");
|
|
1572
1703
|
try {
|
|
1573
|
-
|
|
1574
|
-
if (
|
|
1575
|
-
|
|
1704
|
+
fs9.mkdirSync(path8.dirname(cachePath), { recursive: true });
|
|
1705
|
+
if (fs9.existsSync(cachePath)) {
|
|
1706
|
+
fs9.rmSync(cachePath, { recursive: true, force: true });
|
|
1576
1707
|
}
|
|
1577
1708
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1578
|
-
|
|
1709
|
+
fs9.symlinkSync(repoPath, cachePath, symlinkType);
|
|
1579
1710
|
console.log(`\u2705 Patched plugin cache.`);
|
|
1580
|
-
console.log(
|
|
1711
|
+
console.log(chalk10.dim(` ${cachePath}`) + chalk10.dim(" \u2192 ") + chalk10.dim(repoPath));
|
|
1581
1712
|
} catch (ex) {
|
|
1582
|
-
console.warn(
|
|
1713
|
+
console.warn(chalk10.yellow(` \u26A0 Could not patch plugin cache: ${ex.message}`));
|
|
1583
1714
|
}
|
|
1584
1715
|
};
|
|
1585
1716
|
const enableInConfig = () => {
|
|
@@ -1587,22 +1718,22 @@ var linkCodex = async () => {
|
|
|
1587
1718
|
const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
1588
1719
|
try {
|
|
1589
1720
|
let config = {};
|
|
1590
|
-
if (
|
|
1591
|
-
config = TOML.parse(
|
|
1721
|
+
if (fs9.existsSync(configPath)) {
|
|
1722
|
+
config = TOML.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1592
1723
|
}
|
|
1593
1724
|
if (config.plugins == null) {
|
|
1594
1725
|
config.plugins = {};
|
|
1595
1726
|
}
|
|
1596
1727
|
config.plugins[pluginKey] = { enabled: true };
|
|
1597
|
-
|
|
1598
|
-
|
|
1728
|
+
fs9.mkdirSync(path8.dirname(configPath), { recursive: true });
|
|
1729
|
+
fs9.writeFileSync(configPath, TOML.stringify(config), "utf-8");
|
|
1599
1730
|
console.log(`\u2705 Enabled plugin in config.toml`);
|
|
1600
|
-
console.log(
|
|
1731
|
+
console.log(chalk10.dim(` ${configPath}`));
|
|
1601
1732
|
} catch (ex) {
|
|
1602
|
-
console.warn(
|
|
1733
|
+
console.warn(chalk10.yellow(` \u26A0 Could not update config.toml: ${ex.message}`));
|
|
1603
1734
|
}
|
|
1604
1735
|
};
|
|
1605
|
-
console.log(
|
|
1736
|
+
console.log(chalk10.green(`
|
|
1606
1737
|
Setting up Codex plugin...`));
|
|
1607
1738
|
const marketplaceOk = registerToMarketplace();
|
|
1608
1739
|
if (marketplaceOk === false) {
|
|
@@ -1620,55 +1751,55 @@ var unlinkCodex = async (force = false) => {
|
|
|
1620
1751
|
default: false
|
|
1621
1752
|
});
|
|
1622
1753
|
if (!ok) {
|
|
1623
|
-
console.log(
|
|
1754
|
+
console.log(chalk10.yellow("Cancelled."));
|
|
1624
1755
|
return;
|
|
1625
1756
|
}
|
|
1626
1757
|
}
|
|
1627
|
-
console.log(
|
|
1758
|
+
console.log(chalk10.red(`
|
|
1628
1759
|
Removing Codex plugin...`));
|
|
1629
1760
|
const marketplacePath = path8.join(CODEX_AGENTS_DIR, "marketplace.json");
|
|
1630
|
-
if (
|
|
1761
|
+
if (fs9.existsSync(marketplacePath)) {
|
|
1631
1762
|
try {
|
|
1632
1763
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1633
1764
|
const backupPath = `${marketplacePath}.bak.${timestamp}`;
|
|
1634
|
-
|
|
1635
|
-
const marketplace = JSON.parse(
|
|
1765
|
+
fs9.copyFileSync(marketplacePath, backupPath);
|
|
1766
|
+
const marketplace = JSON.parse(fs9.readFileSync(marketplacePath, "utf-8"));
|
|
1636
1767
|
if (Array.isArray(marketplace?.plugins)) {
|
|
1637
1768
|
marketplace.plugins = marketplace.plugins.filter(
|
|
1638
1769
|
(p) => p?.name !== PLUGIN_NAME
|
|
1639
1770
|
);
|
|
1640
1771
|
}
|
|
1641
1772
|
try {
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
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}`));
|
|
1645
1776
|
} catch (ex) {
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
console.warn(
|
|
1777
|
+
fs9.copyFileSync(backupPath, marketplacePath);
|
|
1778
|
+
fs9.unlinkSync(backupPath);
|
|
1779
|
+
console.warn(chalk10.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
|
|
1649
1780
|
}
|
|
1650
1781
|
} catch (ex) {
|
|
1651
|
-
console.error(
|
|
1782
|
+
console.error(chalk10.red(` \u274C Failed to clean up marketplace.json: ${ex.message}`));
|
|
1652
1783
|
}
|
|
1653
1784
|
}
|
|
1654
1785
|
const configPath = path8.join(os3.homedir(), ".codex", "config.toml");
|
|
1655
|
-
if (
|
|
1786
|
+
if (fs9.existsSync(configPath)) {
|
|
1656
1787
|
try {
|
|
1657
|
-
const config = TOML.parse(
|
|
1788
|
+
const config = TOML.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1658
1789
|
const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
1659
1790
|
if (config.plugins?.[pluginKey] !== void 0) {
|
|
1660
1791
|
delete config.plugins[pluginKey];
|
|
1661
|
-
|
|
1662
|
-
console.log(
|
|
1792
|
+
fs9.writeFileSync(configPath, TOML.stringify(config), "utf-8");
|
|
1793
|
+
console.log(chalk10.red(" removed") + chalk10.dim(` ${pluginKey} from: ${configPath}`));
|
|
1663
1794
|
}
|
|
1664
1795
|
} catch (ex) {
|
|
1665
|
-
console.error(
|
|
1796
|
+
console.error(chalk10.red(` \u274C Failed to clean up config.toml: ${ex.message}`));
|
|
1666
1797
|
}
|
|
1667
1798
|
}
|
|
1668
1799
|
const cacheMarketDir = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME);
|
|
1669
|
-
if (
|
|
1670
|
-
|
|
1671
|
-
console.log(
|
|
1800
|
+
if (fs9.existsSync(cacheMarketDir)) {
|
|
1801
|
+
fs9.rmSync(cacheMarketDir, { recursive: true, force: true });
|
|
1802
|
+
console.log(chalk10.red(" removed") + chalk10.dim(`: ${cacheMarketDir}`));
|
|
1672
1803
|
}
|
|
1673
1804
|
configManager.codex = null;
|
|
1674
1805
|
configManager.save();
|
|
@@ -1676,8 +1807,8 @@ Removing Codex plugin...`));
|
|
|
1676
1807
|
|
|
1677
1808
|
// src/link/cursor.ts
|
|
1678
1809
|
import path9 from "path";
|
|
1679
|
-
import
|
|
1680
|
-
import
|
|
1810
|
+
import fs10 from "fs";
|
|
1811
|
+
import chalk11 from "chalk";
|
|
1681
1812
|
import { confirm as confirm8 } from "@inquirer/prompts";
|
|
1682
1813
|
import { pathExists as pathExists4 } from "fs-extra";
|
|
1683
1814
|
var CURSOR_BACKUP_DIR = path9.join(CURSOR_DIR, "SET_PROMPT_BACKUP");
|
|
@@ -1686,35 +1817,35 @@ var linkCursor = async () => {
|
|
|
1686
1817
|
if (repoPath == null) {
|
|
1687
1818
|
return;
|
|
1688
1819
|
}
|
|
1689
|
-
console.log(
|
|
1820
|
+
console.log(chalk11.green(`
|
|
1690
1821
|
Setting up Cursor integration...`));
|
|
1691
|
-
console.log(
|
|
1822
|
+
console.log(chalk11.dim(CURSOR_DIR));
|
|
1692
1823
|
const cursorDirs = AGENT_PROMPT_DIRS["cursor" /* CURSOR */];
|
|
1693
1824
|
const dirsToBackup = [];
|
|
1694
1825
|
for (const dir of cursorDirs) {
|
|
1695
1826
|
const target = path9.join(CURSOR_DIR, dir);
|
|
1696
|
-
if (
|
|
1827
|
+
if (fs10.existsSync(target) && fs10.lstatSync(target).isSymbolicLink() === false && fs10.readdirSync(target).length > 0) {
|
|
1697
1828
|
dirsToBackup.push(dir);
|
|
1698
1829
|
}
|
|
1699
1830
|
}
|
|
1700
1831
|
if (dirsToBackup.length > 0) {
|
|
1701
|
-
console.log(
|
|
1832
|
+
console.log(chalk11.yellow(`
|
|
1702
1833
|
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
1703
1834
|
for (const dir of dirsToBackup) {
|
|
1704
|
-
console.log(
|
|
1835
|
+
console.log(chalk11.dim(` - ${path9.join(CURSOR_DIR, dir)}`));
|
|
1705
1836
|
}
|
|
1706
|
-
console.log(
|
|
1837
|
+
console.log(chalk11.yellow(` They will be backed up to: `) + chalk11.dim(CURSOR_BACKUP_DIR));
|
|
1707
1838
|
const ok = await confirm8({ message: "Back up existing directories?", default: true });
|
|
1708
1839
|
if (!ok) {
|
|
1709
|
-
console.log(
|
|
1840
|
+
console.log(chalk11.yellow("Skipped Cursor linking."));
|
|
1710
1841
|
return;
|
|
1711
1842
|
}
|
|
1712
|
-
|
|
1843
|
+
fs10.mkdirSync(CURSOR_BACKUP_DIR, { recursive: true });
|
|
1713
1844
|
for (const dir of dirsToBackup) {
|
|
1714
1845
|
const src = path9.join(CURSOR_DIR, dir);
|
|
1715
1846
|
const dest = path9.join(CURSOR_BACKUP_DIR, dir);
|
|
1716
|
-
|
|
1717
|
-
console.log(
|
|
1847
|
+
fs10.renameSync(src, dest);
|
|
1848
|
+
console.log(chalk11.yellow(" backed up") + chalk11.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
1718
1849
|
}
|
|
1719
1850
|
}
|
|
1720
1851
|
try {
|
|
@@ -1725,33 +1856,33 @@ Setting up Cursor integration...`));
|
|
|
1725
1856
|
if (await pathExists4(src) === false) {
|
|
1726
1857
|
continue;
|
|
1727
1858
|
}
|
|
1728
|
-
if (
|
|
1729
|
-
|
|
1859
|
+
if (fs10.existsSync(dest)) {
|
|
1860
|
+
fs10.rmSync(dest, { recursive: true, force: true });
|
|
1730
1861
|
}
|
|
1731
1862
|
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
1732
|
-
|
|
1863
|
+
fs10.symlinkSync(src, dest, symlinkType);
|
|
1733
1864
|
linked.push({ dir, src });
|
|
1734
1865
|
}
|
|
1735
1866
|
for (const { dir, src } of linked) {
|
|
1736
|
-
console.log(
|
|
1867
|
+
console.log(chalk11.dim(` \u251C\u2500\u2500 `) + chalk11.bold(`${dir}/`) + chalk11.dim(` \u2192 ${src}`) + chalk11.green(" \u2713"));
|
|
1737
1868
|
}
|
|
1738
1869
|
const mcpSrc = path9.join(repoPath, ".mcp.json");
|
|
1739
1870
|
const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
|
|
1740
|
-
if (
|
|
1741
|
-
if (
|
|
1871
|
+
if (fs10.existsSync(mcpSrc)) {
|
|
1872
|
+
if (fs10.existsSync(mcpDest) && fs10.statSync(mcpDest).ino !== fs10.statSync(mcpSrc).ino) {
|
|
1742
1873
|
const mcpBackup = path9.join(CURSOR_BACKUP_DIR, "mcp.json");
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
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}`));
|
|
1746
1877
|
}
|
|
1747
|
-
if (
|
|
1748
|
-
|
|
1878
|
+
if (fs10.existsSync(mcpDest)) {
|
|
1879
|
+
fs10.unlinkSync(mcpDest);
|
|
1749
1880
|
}
|
|
1750
|
-
|
|
1751
|
-
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"));
|
|
1752
1883
|
}
|
|
1753
1884
|
} catch (ex) {
|
|
1754
|
-
console.error(
|
|
1885
|
+
console.error(chalk11.red(`\u274C Failed to set up Cursor: ${ex.message}`));
|
|
1755
1886
|
return;
|
|
1756
1887
|
}
|
|
1757
1888
|
configManager.cursor = { path: CURSOR_DIR, backup_path: CURSOR_BACKUP_DIR };
|
|
@@ -1764,45 +1895,45 @@ var unlinkCursor = async (force = false) => {
|
|
|
1764
1895
|
default: false
|
|
1765
1896
|
});
|
|
1766
1897
|
if (!ok) {
|
|
1767
|
-
console.log(
|
|
1898
|
+
console.log(chalk11.yellow("Cancelled."));
|
|
1768
1899
|
return;
|
|
1769
1900
|
}
|
|
1770
1901
|
}
|
|
1771
|
-
console.log(
|
|
1902
|
+
console.log(chalk11.red(`
|
|
1772
1903
|
Removing Cursor integration...`));
|
|
1773
|
-
console.log(
|
|
1904
|
+
console.log(chalk11.dim(CURSOR_DIR));
|
|
1774
1905
|
const backupPath = configManager.cursor?.backup_path ?? CURSOR_BACKUP_DIR;
|
|
1775
1906
|
for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
|
|
1776
1907
|
const target = path9.join(CURSOR_DIR, dir);
|
|
1777
|
-
if (
|
|
1778
|
-
|
|
1779
|
-
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}`));
|
|
1780
1911
|
}
|
|
1781
1912
|
}
|
|
1782
1913
|
const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
|
|
1783
|
-
if (
|
|
1784
|
-
|
|
1785
|
-
console.log(
|
|
1914
|
+
if (fs10.existsSync(mcpDest)) {
|
|
1915
|
+
fs10.unlinkSync(mcpDest);
|
|
1916
|
+
console.log(chalk11.red(" removed") + chalk11.dim(`: ${mcpDest}`));
|
|
1786
1917
|
}
|
|
1787
|
-
if (
|
|
1918
|
+
if (fs10.existsSync(backupPath)) {
|
|
1788
1919
|
try {
|
|
1789
1920
|
for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
|
|
1790
1921
|
const src = path9.join(backupPath, dir);
|
|
1791
1922
|
const dest = path9.join(CURSOR_DIR, dir);
|
|
1792
|
-
if (!
|
|
1923
|
+
if (!fs10.existsSync(src)) {
|
|
1793
1924
|
continue;
|
|
1794
1925
|
}
|
|
1795
|
-
|
|
1796
|
-
console.log(
|
|
1926
|
+
fs10.renameSync(src, dest);
|
|
1927
|
+
console.log(chalk11.green(" restored") + chalk11.dim(`: ${dir}/`));
|
|
1797
1928
|
}
|
|
1798
1929
|
const mcpBackup = path9.join(backupPath, "mcp.json");
|
|
1799
|
-
if (
|
|
1800
|
-
|
|
1801
|
-
console.log(
|
|
1930
|
+
if (fs10.existsSync(mcpBackup)) {
|
|
1931
|
+
fs10.renameSync(mcpBackup, mcpDest);
|
|
1932
|
+
console.log(chalk11.green(" restored") + chalk11.dim(`: mcp.json`));
|
|
1802
1933
|
}
|
|
1803
|
-
|
|
1934
|
+
fs10.rmSync(backupPath, { recursive: true, force: true });
|
|
1804
1935
|
} catch (ex) {
|
|
1805
|
-
console.error(
|
|
1936
|
+
console.error(chalk11.red(` \u274C Failed to restore Cursor backup: ${ex.message}`));
|
|
1806
1937
|
}
|
|
1807
1938
|
}
|
|
1808
1939
|
configManager.cursor = null;
|
|
@@ -1830,7 +1961,7 @@ var linkCommand = async (tool) => {
|
|
|
1830
1961
|
if (tool != null) {
|
|
1831
1962
|
const known = ALL_AGENTS.some((a) => a.value === tool);
|
|
1832
1963
|
if (!known) {
|
|
1833
|
-
console.log(
|
|
1964
|
+
console.log(chalk12.red(`Unknown vendor: ${tool}`));
|
|
1834
1965
|
process.exit(1);
|
|
1835
1966
|
}
|
|
1836
1967
|
await LINK_MAP[tool]();
|
|
@@ -1847,7 +1978,7 @@ var linkCommand = async (tool) => {
|
|
|
1847
1978
|
const selected = await checkbox({
|
|
1848
1979
|
message: "Which AI agent do you want to integrate?",
|
|
1849
1980
|
choices: ALL_AGENTS.map((a) => ({
|
|
1850
|
-
name: prevLinked[a.value] ? `${a.name} ${
|
|
1981
|
+
name: prevLinked[a.value] ? `${a.name} ${chalk12.dim("(applied)")}` : a.name,
|
|
1851
1982
|
value: a.value,
|
|
1852
1983
|
checked: prevLinked[a.value]
|
|
1853
1984
|
}))
|
|
@@ -1856,10 +1987,10 @@ var linkCommand = async (tool) => {
|
|
|
1856
1987
|
const toUnlink = ALL_AGENTS.filter((a) => prevLinked[a.value] && !selected.includes(a.value));
|
|
1857
1988
|
console.log();
|
|
1858
1989
|
if (toLink.length > 0) {
|
|
1859
|
-
console.log(
|
|
1990
|
+
console.log(chalk12.green(" Link ") + chalk12.dim("\u2192 ") + toLink.map((a) => chalk12.bold(a.name)).join(chalk12.dim(", ")));
|
|
1860
1991
|
}
|
|
1861
1992
|
if (toUnlink.length > 0) {
|
|
1862
|
-
console.log(
|
|
1993
|
+
console.log(chalk12.red(" Unlink ") + chalk12.dim("\u2192 ") + toUnlink.map((a) => chalk12.bold(a.name)).join(chalk12.dim(", ")));
|
|
1863
1994
|
}
|
|
1864
1995
|
console.log();
|
|
1865
1996
|
if (toLink.length === 0 && toUnlink.length === 0) {
|
|
@@ -1878,14 +2009,14 @@ var linkCommand = async (tool) => {
|
|
|
1878
2009
|
};
|
|
1879
2010
|
|
|
1880
2011
|
// src/commands/uninstall-command.ts
|
|
1881
|
-
import
|
|
1882
|
-
import
|
|
2012
|
+
import fs11 from "fs";
|
|
2013
|
+
import chalk13 from "chalk";
|
|
1883
2014
|
import { confirm as confirm9 } from "@inquirer/prompts";
|
|
1884
2015
|
var uninstallCommand = async () => {
|
|
1885
2016
|
const targets = [
|
|
1886
|
-
{ label: `Config file ${
|
|
1887
|
-
{ label: `Home dir ${
|
|
1888
|
-
].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));
|
|
1889
2020
|
const hasClaudeCode = configManager.isClaudeCodeEnabled();
|
|
1890
2021
|
const hasRooCode = configManager.isRooCodeEnabled();
|
|
1891
2022
|
const hasOpenclaw = configManager.isOpenclawEnabled();
|
|
@@ -1893,32 +2024,32 @@ var uninstallCommand = async () => {
|
|
|
1893
2024
|
const hasCodex = configManager.isCodexEnabled();
|
|
1894
2025
|
const hasCursor = configManager.isCursorEnabled();
|
|
1895
2026
|
if (targets.length === 0 && !hasClaudeCode && !hasRooCode && !hasOpenclaw && !hasAntigravity && !hasCodex && !hasCursor) {
|
|
1896
|
-
console.log(
|
|
2027
|
+
console.log(chalk13.yellow("Nothing to remove."));
|
|
1897
2028
|
return;
|
|
1898
2029
|
}
|
|
1899
|
-
console.log(
|
|
2030
|
+
console.log(chalk13.red("\nThe following will be removed:"));
|
|
1900
2031
|
targets.forEach((t) => console.log(` ${t.label}`));
|
|
1901
2032
|
if (hasClaudeCode) {
|
|
1902
|
-
console.log(` Claude Code plugin dir ${
|
|
2033
|
+
console.log(` Claude Code plugin dir ${chalk13.dim(CLAUDE_CODE_DIR)}`);
|
|
1903
2034
|
}
|
|
1904
2035
|
if (hasRooCode) {
|
|
1905
|
-
console.log(` RooCode symlinks ${
|
|
2036
|
+
console.log(` RooCode symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1906
2037
|
}
|
|
1907
2038
|
if (hasOpenclaw) {
|
|
1908
|
-
console.log(` OpenClaw symlinks ${
|
|
2039
|
+
console.log(` OpenClaw symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1909
2040
|
}
|
|
1910
2041
|
if (hasAntigravity) {
|
|
1911
|
-
console.log(` Antigravity symlinks ${
|
|
2042
|
+
console.log(` Antigravity symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1912
2043
|
}
|
|
1913
2044
|
if (hasCodex) {
|
|
1914
|
-
console.log(` Codex symlinks ${
|
|
2045
|
+
console.log(` Codex symlinks ${chalk13.dim("(backup will be restored)")}`);
|
|
1915
2046
|
}
|
|
1916
2047
|
if (hasCursor) {
|
|
1917
|
-
console.log(` Cursor plugin dir ${
|
|
2048
|
+
console.log(` Cursor plugin dir ${chalk13.dim("(symlink will be removed)")}`);
|
|
1918
2049
|
}
|
|
1919
2050
|
const ok = await confirm9({ message: "Proceed?", default: false });
|
|
1920
2051
|
if (!ok) {
|
|
1921
|
-
console.log(
|
|
2052
|
+
console.log(chalk13.yellow("Cancelled."));
|
|
1922
2053
|
return;
|
|
1923
2054
|
}
|
|
1924
2055
|
if (hasClaudeCode) {
|
|
@@ -1940,26 +2071,26 @@ var uninstallCommand = async () => {
|
|
|
1940
2071
|
await unlinkCursor(true);
|
|
1941
2072
|
}
|
|
1942
2073
|
for (const t of targets) {
|
|
1943
|
-
|
|
1944
|
-
console.log(
|
|
2074
|
+
fs11.rmSync(t.path, { recursive: true, force: true });
|
|
2075
|
+
console.log(chalk13.dim(` removed: ${t.path}`));
|
|
1945
2076
|
}
|
|
1946
|
-
console.log(
|
|
2077
|
+
console.log(chalk13.green("\nUninstalled."));
|
|
1947
2078
|
};
|
|
1948
2079
|
|
|
1949
2080
|
// src/commands/status-command.ts
|
|
1950
|
-
import
|
|
2081
|
+
import chalk14 from "chalk";
|
|
1951
2082
|
var statusCommand = () => {
|
|
1952
2083
|
if (configManager.repo_path == null) {
|
|
1953
|
-
console.log(
|
|
1954
|
-
console.log(
|
|
2084
|
+
console.log(chalk14.yellow("\u274C No repo installed."));
|
|
2085
|
+
console.log(chalk14.dim(` Run: set-prompt install <repo-url>`));
|
|
1955
2086
|
return;
|
|
1956
2087
|
}
|
|
1957
|
-
console.log(
|
|
1958
|
-
console.log(`${TAB}path ${
|
|
2088
|
+
console.log(chalk14.bold("\nRepo"));
|
|
2089
|
+
console.log(`${TAB}path ${chalk14.cyan(configManager.repo_path)}`);
|
|
1959
2090
|
if (configManager.remote_url != null) {
|
|
1960
|
-
console.log(`${TAB}remote ${
|
|
2091
|
+
console.log(`${TAB}remote ${chalk14.dim(configManager.remote_url)}`);
|
|
1961
2092
|
}
|
|
1962
|
-
console.log(
|
|
2093
|
+
console.log(chalk14.bold("\nLinked agents"));
|
|
1963
2094
|
for (const agent of ALL_AGENTS) {
|
|
1964
2095
|
let linked = false;
|
|
1965
2096
|
let agentPath = null;
|
|
@@ -1979,78 +2110,363 @@ var statusCommand = () => {
|
|
|
1979
2110
|
linked = configManager.isAntigravityEnabled();
|
|
1980
2111
|
agentPath = configManager.antigravity?.path;
|
|
1981
2112
|
}
|
|
1982
|
-
const label = linked ?
|
|
1983
|
-
const pathStr = linked && agentPath ?
|
|
2113
|
+
const label = linked ? chalk14.green("linked") : chalk14.dim("not linked");
|
|
2114
|
+
const pathStr = linked && agentPath ? chalk14.dim(` \u2192 ${agentPath}`) : "";
|
|
1984
2115
|
console.log(`${TAB}${agent.name.padEnd(12)} ${label}${pathStr}`);
|
|
1985
2116
|
}
|
|
1986
2117
|
console.log("");
|
|
1987
2118
|
};
|
|
1988
2119
|
|
|
1989
|
-
// src/commands/
|
|
1990
|
-
import { spawnSync as
|
|
1991
|
-
import
|
|
1992
|
-
var
|
|
2120
|
+
// src/commands/repo/pull-command.ts
|
|
2121
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
2122
|
+
import chalk15 from "chalk";
|
|
2123
|
+
var repoPullCommand = () => {
|
|
1993
2124
|
const repoPath = configManager.repo_path;
|
|
1994
2125
|
if (repoPath == null) {
|
|
1995
|
-
console.error(
|
|
1996
|
-
console.log(
|
|
2126
|
+
console.error(chalk15.red("\u274C No repo installed."));
|
|
2127
|
+
console.log(chalk15.yellow("Run: set-prompt install <git-url>"));
|
|
1997
2128
|
return;
|
|
1998
2129
|
}
|
|
1999
2130
|
if (configManager.remote_url == null) {
|
|
2000
|
-
console.error(
|
|
2131
|
+
console.error(chalk15.red("\u274C No remote URL registered. Cannot pull."));
|
|
2001
2132
|
return;
|
|
2002
2133
|
}
|
|
2003
|
-
console.log(
|
|
2004
|
-
console.log(
|
|
2005
|
-
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" });
|
|
2006
2137
|
if (fetch.status !== 0) {
|
|
2007
|
-
console.error(
|
|
2138
|
+
console.error(chalk15.red("\u274C git fetch failed."));
|
|
2008
2139
|
return;
|
|
2009
2140
|
}
|
|
2010
|
-
const pull =
|
|
2141
|
+
const pull = spawnSync4("git", ["pull"], { cwd: repoPath, stdio: "inherit" });
|
|
2011
2142
|
if (pull.status !== 0) {
|
|
2012
|
-
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"));
|
|
2013
2290
|
return;
|
|
2014
2291
|
}
|
|
2015
|
-
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();
|
|
2016
2385
|
};
|
|
2017
2386
|
|
|
2018
2387
|
// src/index.ts
|
|
2019
2388
|
process.on("SIGINT", () => {
|
|
2020
|
-
console.log(
|
|
2389
|
+
console.log(chalk21.yellow("\nCancelled."));
|
|
2021
2390
|
process.exit(0);
|
|
2022
2391
|
});
|
|
2023
2392
|
process.on("unhandledRejection", (reason) => {
|
|
2024
2393
|
if (reason instanceof Error && reason.name === "ExitPromptError") {
|
|
2025
|
-
console.log(
|
|
2394
|
+
console.log(chalk21.yellow("\nCancelled."));
|
|
2026
2395
|
process.exit(0);
|
|
2027
2396
|
}
|
|
2028
2397
|
throw reason;
|
|
2029
2398
|
});
|
|
2030
|
-
var __dirname =
|
|
2031
|
-
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"));
|
|
2032
2401
|
configManager.init();
|
|
2033
2402
|
var program = new Command();
|
|
2034
|
-
var banner =
|
|
2035
|
-
program.name("set-prompt").description(pkg.description).version(pkg.version).addHelpText("beforeAll", banner + "\n"
|
|
2036
|
-
|
|
2037
|
-
});
|
|
2038
|
-
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) => {
|
|
2039
2406
|
await installCommand(source);
|
|
2040
2407
|
});
|
|
2041
|
-
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) => {
|
|
2042
2409
|
await linkCommand(agent);
|
|
2043
2410
|
});
|
|
2044
|
-
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) => {
|
|
2045
2412
|
await scaffoldCommand(localPath);
|
|
2046
2413
|
});
|
|
2047
|
-
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(() => {
|
|
2048
2415
|
statusCommand();
|
|
2049
2416
|
});
|
|
2050
|
-
program.command("
|
|
2051
|
-
|
|
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 });
|
|
2052
2468
|
});
|
|
2053
|
-
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 () => {
|
|
2054
2470
|
await uninstallCommand();
|
|
2055
2471
|
});
|
|
2056
2472
|
program.parse(process.argv);
|