set-prompt 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { Command } from "commander";
5
5
  import chalk8 from "chalk";
6
6
  import figlet from "figlet";
7
7
  import fs6 from "fs";
8
- import path6 from "path";
8
+ import path5 from "path";
9
9
  import { fileURLToPath } from "url";
10
10
 
11
11
  // src/commands/install-command.ts
@@ -27,20 +27,28 @@ var ROO_DIR = path.join(os.homedir(), ".roo");
27
27
  var ROO_BACKUP_DIR = path.join(ROO_DIR, "SET_PROMPT_BACKUP");
28
28
  var OPENCLAW_DIR = path.join(os.homedir(), ".openclaw", "workspace");
29
29
  var OPENCLAW_BACKUP_DIR = path.join(OPENCLAW_DIR, "SET_PROMPT_BACKUP");
30
+ var ANTIGRAVITY_DIR = path.join(os.homedir(), ".gemini", "antigravity");
31
+ var ANTIGRAVITY_BACKUP_DIR = path.join(ANTIGRAVITY_DIR, "SET_PROMPT_BACKUP");
32
+ var CODEX_DIR = path.join(os.homedir(), ".codex");
33
+ var CODEX_BACKUP_DIR = path.join(CODEX_DIR, "SET_PROMPT_BACKUP");
34
+ var CURSOR_DIR = path.join(HOME_DIR, "cursor");
35
+ var CURSOR_PLUGIN_DIR = path.join(os.homedir(), ".cursor", "plugins", "local", "set-prompt");
30
36
  var PROMPT_DIR_NAMES = ["skills", "commands", "hooks", "agents"];
31
37
  var AGENT_PROMPT_DIRS = {
32
38
  ["claudecode" /* CLAUDECODE */]: ["skills", "commands", "hooks", "agents"],
33
39
  ["roocode" /* ROOCODE */]: ["skills", "commands"],
34
40
  ["openclaw" /* OPENCLAW */]: ["skills"],
35
41
  ["codex" /* CODEX */]: ["skills", "commands"],
36
- ["antigravity" /* ANTIGRAVITY */]: ["skills", "commands"]
42
+ ["antigravity" /* ANTIGRAVITY */]: ["skills"],
43
+ ["cursor" /* CURSOR */]: ["skills", "agents", "rules"]
37
44
  };
38
45
  var ALL_AGENTS = [
39
46
  { name: "Claude Code", value: "claudecode" /* CLAUDECODE */ },
40
47
  { name: "RooCode", value: "roocode" /* ROOCODE */ },
41
48
  { name: "OpenClaw", value: "openclaw" /* OPENCLAW */ },
42
49
  { name: "Codex", value: "codex" /* CODEX */ },
43
- { name: "Antigravity", value: "antigravity" /* ANTIGRAVITY */ }
50
+ { name: "Antigravity", value: "antigravity" /* ANTIGRAVITY */ },
51
+ { name: "Cursor", value: "cursor" /* CURSOR */ }
44
52
  ];
45
53
 
46
54
  // src/_libs/config.ts
@@ -63,10 +71,18 @@ var OpenclawConfigSchema = z.object({
63
71
  backup_path: z.string().nullish().optional()
64
72
  });
65
73
  var CodexConfigSchema = z.object({
66
- path: z.string().nullable()
74
+ path: z.string().nullable(),
75
+ backup_path: z.string().nullish().optional()
67
76
  });
68
77
  var AntigravityConfigSchema = z.object({
69
- path: z.string().nullable()
78
+ path: z.string().nullable(),
79
+ backup_path: z.string().nullish().optional()
80
+ });
81
+ var CursorConfigSchema = z.object({
82
+ path: z.string().nullable(),
83
+ // ~/.set-prompt/cursor (플러그인 파일 구조)
84
+ plugin_dir: z.string().nullable()
85
+ // ~/.cursor/plugins/set-prompt (설치 symlink)
70
86
  });
71
87
  var GlobalConfigSchema = z.object({
72
88
  repo_path: z.string(),
@@ -75,7 +91,8 @@ var GlobalConfigSchema = z.object({
75
91
  roocode: RoocodeConfigSchema.nullable(),
76
92
  openclaw: OpenclawConfigSchema.nullable(),
77
93
  codex: CodexConfigSchema.nullish().optional(),
78
- antigravity: AntigravityConfigSchema.nullish().optional()
94
+ antigravity: AntigravityConfigSchema.nullish().optional(),
95
+ cursor: CursorConfigSchema.nullish().optional()
79
96
  });
80
97
 
81
98
  // src/_libs/config.ts
@@ -88,6 +105,7 @@ var ConfigManager = class {
88
105
  this._openclaw = null;
89
106
  this._codex = null;
90
107
  this._antigravity = null;
108
+ this._cursor = null;
91
109
  }
92
110
  get repo_path() {
93
111
  return this._repo_path;
@@ -110,6 +128,9 @@ var ConfigManager = class {
110
128
  get antigravity() {
111
129
  return this._antigravity;
112
130
  }
131
+ get cursor() {
132
+ return this._cursor;
133
+ }
113
134
  set repo_path(v) {
114
135
  this._repo_path = v;
115
136
  }
@@ -131,10 +152,13 @@ var ConfigManager = class {
131
152
  set antigravity(v) {
132
153
  this._antigravity = v;
133
154
  }
155
+ set cursor(v) {
156
+ this._cursor = v;
157
+ }
134
158
  init() {
135
159
  this._loadFromDisk();
136
160
  if (this._repo_path != null) {
137
- console.log(chalk.dim(`Config loaded from ${CONFIG_PATH}`));
161
+ console.log(chalk.green(`Config loaded`) + chalk.dim(` from ${CONFIG_PATH}`));
138
162
  }
139
163
  }
140
164
  save() {
@@ -151,7 +175,8 @@ var ConfigManager = class {
151
175
  roocode: this._roocode,
152
176
  openclaw: this._openclaw,
153
177
  codex: this._codex,
154
- antigravity: this._antigravity
178
+ antigravity: this._antigravity,
179
+ cursor: this._cursor
155
180
  }, null, 4);
156
181
  fs.writeFileSync(CONFIG_PATH, configStr, "utf-8");
157
182
  console.log(chalk.green(`Config saved`) + chalk.dim(` \u2192 ${CONFIG_PATH}`));
@@ -185,6 +210,9 @@ var ConfigManager = class {
185
210
  isAntigravityEnabled() {
186
211
  return this._antigravity != null;
187
212
  }
213
+ isCursorEnabled() {
214
+ return this._cursor != null;
215
+ }
188
216
  _assign(config) {
189
217
  this._repo_path = config.repo_path;
190
218
  this._remote_url = config.remote_url;
@@ -193,6 +221,7 @@ var ConfigManager = class {
193
221
  this._openclaw = config.openclaw;
194
222
  this._codex = config.codex ?? null;
195
223
  this._antigravity = config.antigravity ?? null;
224
+ this._cursor = config.cursor ?? null;
196
225
  }
197
226
  _loadFromDisk() {
198
227
  if (fs.existsSync(CONFIG_PATH) === false) {
@@ -282,15 +311,20 @@ customInstructions: "Additional behavior guidelines..."
282
311
 
283
312
  # OpenClaw
284
313
  homepage: "https://github.com/you/my-skill"
285
- metadata: {"openclaw":{"emoji":"\u{1F527}","os":["darwin","linux"]}}
314
+ user-invocable: true
315
+ disable-model-invocation: false
316
+ metadata: {"os":["darwin","linux"],"requires":{"bins":["git"],"env":["MY_API_KEY"]}}
317
+
318
+ # Antigravity
319
+ name: my-skill
320
+ description: "What this skill does and when to use it"
286
321
  ---
287
322
  \`\`\`
288
323
 
289
324
  | Field | Required | Platform | Description |
290
325
  |-------|----------|----------|-------------|
291
- | \`name\` | Yes | All | Display name. Claude Code: lowercase, numbers, hyphens only (max 64 chars). RooCode: emoji allowed. |
326
+ | \`name\` | Yes | All | Display name. Claude Code: lowercase, numbers, hyphens only (max 64 chars). RooCode: emoji allowed. Antigravity: optional, defaults to folder name. |
292
327
  | \`description\` | Yes | All | What it does and when to use it. Claude uses this to decide auto-loading. |
293
- | \`disable-model-invocation\` | No | CC, OpenClaw | \`true\` = prevent auto-loading, manual \`/name\` only. (default: \`false\`) |
294
328
  | \`allowed-tools\` | No | Claude Code | Tools Claude can use without asking. e.g. \`Read\` \`Write\` \`Edit\` \`Bash\` \`Grep\` \`Glob\` |
295
329
  | \`model\` | No | Claude Code | Model to use when active. \`sonnet\` or \`haiku\` |
296
330
  | \`context\` | No | Claude Code | \`fork\` = run in a forked subagent context |
@@ -301,15 +335,14 @@ metadata: {"openclaw":{"emoji":"\u{1F527}","os":["darwin","linux"]}}
301
335
  | \`groups\` | Yes | RooCode | Tool permissions: \`read\` \`edit\` \`command\` \`mcp\` \`browser\` |
302
336
  | \`whenToUse\` | No | RooCode | Guide for auto mode selection |
303
337
  | \`customInstructions\` | No | RooCode | Additional behavior guidelines |
304
- | \`homepage\` | No | OpenClaw | Website URL shown in the Skills UI |
305
- | \`metadata\` | No | OpenClaw | Single-line JSON for platform gating. e.g. \`os\`, \`requires.bins\`, \`requires.env\` |
306
-
307
- RooCode file-restricted edit example:
308
- \`\`\`yaml
309
- groups:
310
- - read
311
- - [edit, {fileRegex: '\\.(md|ts)$', description: "Markdown and TS only"}]
312
- \`\`\`
338
+ | \`groups\` (restricted) | No | RooCode | Restrict edit to file patterns: \`[edit, {fileRegex: '\\.(md|ts)$', description: "..."}]\` |
339
+ | \`metadata\` | No | OpenClaw | Single-line JSON for platform gating: \`os\` (platform filter), \`requires.bins\` (required binaries), \`requires.env\` (required env vars) |
340
+ | \`homepage\` | No | OpenClaw | URL shown as "Website" in the macOS Skills UI. Also settable via \`metadata.openclaw.homepage\`. |
341
+ | \`user-invocable\` | No | OpenClaw | \`false\` = hidden from \`/\` menu. (default: \`true\`) |
342
+ | \`disable-model-invocation\` | No | CC, OpenClaw | \`true\` = skill excluded from model prompt, still available via user invocation. (default: \`false\`) |
343
+ | \`command-dispatch\` | No | OpenClaw | \`"tool"\` = bypass model, dispatch directly to a tool |
344
+ | \`command-tool\` | No | OpenClaw | Tool to invoke when \`command-dispatch: "tool"\` |
345
+ | \`command-arg-mode\` | No | OpenClaw | How arguments are forwarded to the tool. (default: \`"raw"\`) |
313
346
 
314
347
  ---
315
348
 
@@ -360,9 +393,6 @@ command-tool: "Bash"
360
393
  | \`context\` | No | Claude Code | \`fork\` = run in a forked subagent context |
361
394
  | \`agent\` | No | Claude Code | Subagent type when \`context: fork\`. e.g. \`general-purpose\` \`Explore\` \`Plan\` |
362
395
  | \`hooks\` | No | Claude Code | Lifecycle hooks for pre/post processing. |
363
- | \`command-dispatch\` | No | OpenClaw | \`"tool"\` = bypass model, dispatch directly to a tool |
364
- | \`command-tool\` | No | OpenClaw | Tool to invoke when \`command-dispatch: "tool"\` |
365
- | \`command-arg-mode\` | No | OpenClaw | How arguments are forwarded to the tool. (default: \`"raw"\`) |
366
396
 
367
397
  ---
368
398
 
@@ -527,18 +557,23 @@ var scaffoldCommand = async (localPath, options = {}) => {
527
557
  }
528
558
  const created = [];
529
559
  const guideMdPath = path2.join(targetPath, "SET_PROMPT_GUIDE.md");
530
- if (options.force === true || fs2.existsSync(guideMdPath) === false) {
531
- fs2.writeFileSync(guideMdPath, SET_PROMPT_GUIDE, { encoding: "utf-8", flag: "w" });
532
- created.push(" SET_PROMPT_GUIDE.md");
533
- }
560
+ fs2.writeFileSync(guideMdPath, SET_PROMPT_GUIDE, { encoding: "utf-8", flag: "w" });
561
+ created.push(" SET_PROMPT_GUIDE.md");
534
562
  for (const dirName of PROMPT_DIR_NAMES) {
535
563
  const dirPath = path2.join(targetPath, dirName);
536
564
  if (fs2.existsSync(dirPath)) {
537
565
  console.warn(chalk2.yellow(`Directory already exists: '${dirName}' (skipping)`));
538
- continue;
566
+ } else {
567
+ fs2.mkdirSync(dirPath, { recursive: true });
568
+ created.push(` ${dirName}/`);
569
+ }
570
+ const gitkeepPath = path2.join(dirPath, ".gitkeep");
571
+ if (!fs2.existsSync(gitkeepPath)) {
572
+ fs2.writeFileSync(gitkeepPath, "", { encoding: "utf-8" });
573
+ if (!created.includes(` ${dirName}/`)) {
574
+ created.push(` ${dirName}/.gitkeep`);
575
+ }
539
576
  }
540
- fs2.mkdirSync(dirPath, { recursive: true });
541
- created.push(` ${dirName}/`);
542
577
  }
543
578
  if (created.length > 0) {
544
579
  console.log(chalk2.green("Created:"));
@@ -554,21 +589,23 @@ var scaffoldCommand = async (localPath, options = {}) => {
554
589
 
555
590
  // src/commands/install-command.ts
556
591
  var cloneRepo = async (remoteUrl) => {
557
- const proceed = await confirm2({
558
- message: `Clone and register "${remoteUrl}"?`,
559
- default: true
560
- });
561
- if (proceed == false) {
562
- console.log(chalk3.yellow("Cancelled."));
563
- return false;
564
- }
565
592
  const localPath = path3.join(HOME_DIR, "repo");
593
+ let backupPath = null;
566
594
  if (fs3.existsSync(localPath) == true) {
567
- console.warn(chalk3.yellow(`Existing repo found. Backing up before proceeding.`));
568
595
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
569
- const backupPath = path3.join(HOME_DIR, `repo.bak.${timestamp}`);
570
- fs3.renameSync(localPath, backupPath);
571
- console.log(chalk3.dim(` Backed up to: ${backupPath}`));
596
+ backupPath = path3.join(HOME_DIR, `repo.bak.${timestamp}`);
597
+ try {
598
+ fs3.renameSync(localPath, backupPath);
599
+ console.log(chalk3.yellow(" backed up") + chalk3.dim(` existing repo \u2192 ${backupPath}`));
600
+ } catch (ex) {
601
+ if (ex.code === "EPERM") {
602
+ console.error(chalk3.red("\u274C Cannot rename existing repo \u2014 it may be open in another process."));
603
+ console.log(chalk3.dim(` Close any editors or terminals using: ${localPath}`));
604
+ } else {
605
+ console.error(chalk3.red(`\u274C Failed to backup existing repo: ${ex.message}`));
606
+ }
607
+ return false;
608
+ }
572
609
  }
573
610
  fs3.mkdirSync(path3.dirname(localPath), { recursive: true });
574
611
  console.log(`Cloning ${remoteUrl}...`);
@@ -578,6 +615,10 @@ var cloneRepo = async (remoteUrl) => {
578
615
  process.exit(1);
579
616
  }
580
617
  console.log("\u2705 Cloned successfully.");
618
+ if (backupPath != null) {
619
+ fs3.rmSync(backupPath, { recursive: true, force: true });
620
+ console.log(chalk3.red(" removed") + chalk3.dim(` backup \u2192 ${backupPath}`));
621
+ }
581
622
  await scaffoldCommand(localPath, { force: true });
582
623
  configManager.repo_path = localPath;
583
624
  configManager.remote_url = remoteUrl;
@@ -594,6 +635,26 @@ var installCommand = async (target) => {
594
635
  console.log(chalk3.dim(" Example: set-prompt install https://github.com/you/my-prompts"));
595
636
  process.exit(1);
596
637
  }
638
+ const normalizeUrl = (url) => url.replace(/\.git$/, "").toLowerCase();
639
+ if (configManager.repo_path != null) {
640
+ if (normalizeUrl(configManager.remote_url ?? "") === normalizeUrl(target)) {
641
+ console.error(chalk3.red(`\u274C Already installed from the same URL: ${target}`));
642
+ console.log(chalk3.dim(" Use `set-prompt update` to pull the latest changes."));
643
+ return false;
644
+ }
645
+ console.warn(chalk3.yellow(`\u26A0 Switching repo: ${configManager.remote_url} \u2192 ${target}`));
646
+ const proceed = await confirm2({ message: "Replace existing installation?", default: false });
647
+ if (!proceed) {
648
+ console.log(chalk3.yellow("Cancelled."));
649
+ return false;
650
+ }
651
+ } else {
652
+ const proceed = await confirm2({ message: `Clone and register "${target}"?`, default: true });
653
+ if (!proceed) {
654
+ console.log(chalk3.yellow("Cancelled."));
655
+ return false;
656
+ }
657
+ }
597
658
  return await cloneRepo(target);
598
659
  } catch (ex) {
599
660
  console.error(chalk3.red(`Unexpected error: ${ex.message}`), ex);
@@ -606,7 +667,7 @@ import path4 from "path";
606
667
  import fs4 from "fs";
607
668
  import os2 from "os";
608
669
  import chalk4 from "chalk";
609
- import { checkbox } from "@inquirer/prompts";
670
+ import { confirm as confirm3, checkbox } from "@inquirer/prompts";
610
671
  import { pathExists } from "fs-extra";
611
672
  var resolveRepoPath = () => {
612
673
  if (configManager.repo_path == null) {
@@ -616,7 +677,8 @@ var resolveRepoPath = () => {
616
677
  }
617
678
  return configManager.repo_path;
618
679
  };
619
- var PLUGIN_NAME = "set-prompt";
680
+ var MARKET_NAME = "set-prompt";
681
+ var PLUGIN_NAME = "sppt";
620
682
  var linkClaudeCode = async () => {
621
683
  const repoPath = resolveRepoPath();
622
684
  if (repoPath == null) {
@@ -628,7 +690,7 @@ var linkClaudeCode = async () => {
628
690
  const marketplaceMetaDir = path4.join(CLAUDE_CODE_DIR, ".claude-plugin");
629
691
  fs4.mkdirSync(marketplaceMetaDir, { recursive: true });
630
692
  const marketplaceJson = {
631
- name: PLUGIN_NAME,
693
+ name: MARKET_NAME,
632
694
  owner: { name: os2.userInfo().username },
633
695
  metadata: { description: "Managed by set-prompt", version: "1.0.0" },
634
696
  plugins: [{ name: PLUGIN_NAME, source: `./plugins/${PLUGIN_NAME}`, description: "Managed by set-prompt" }]
@@ -705,11 +767,11 @@ var linkClaudeCode = async () => {
705
767
  }
706
768
  settings.extraKnownMarketplaces = {
707
769
  ...settings.extraKnownMarketplaces,
708
- [PLUGIN_NAME]: { source: { source: "directory", path: CLAUDE_CODE_DIR } }
770
+ [MARKET_NAME]: { source: { source: "directory", path: CLAUDE_CODE_DIR } }
709
771
  };
710
772
  settings.enabledPlugins = {
711
773
  ...settings.enabledPlugins,
712
- [`${PLUGIN_NAME}@${PLUGIN_NAME}`]: true
774
+ [`${PLUGIN_NAME}@${MARKET_NAME}`]: true
713
775
  };
714
776
  let backupPath = null;
715
777
  if (fs4.existsSync(claudeSettingsPath)) {
@@ -752,6 +814,38 @@ var linkClaudeCode = async () => {
752
814
  return false;
753
815
  }
754
816
  };
817
+ const patchInstalledPlugins = () => {
818
+ const installPath = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
819
+ const installedPluginsPath = path4.join(os2.homedir(), ".claude", "plugins", "installed_plugins.json");
820
+ const pluginKey = `${PLUGIN_NAME}@${MARKET_NAME}`;
821
+ try {
822
+ let data = { version: 2, plugins: {} };
823
+ if (fs4.existsSync(installedPluginsPath)) {
824
+ try {
825
+ data = JSON.parse(fs4.readFileSync(installedPluginsPath, "utf-8"));
826
+ } catch {
827
+ }
828
+ }
829
+ if (data.plugins == null) {
830
+ data.plugins = {};
831
+ }
832
+ data.plugins[pluginKey] = [
833
+ {
834
+ scope: "user",
835
+ installPath,
836
+ version: "1.0.0",
837
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
838
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
839
+ }
840
+ ];
841
+ fs4.mkdirSync(path4.dirname(installedPluginsPath), { recursive: true });
842
+ fs4.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 2), "utf-8");
843
+ console.log(`\u2705 Patched installed_plugins.json \u2192 installPath points to source.`);
844
+ console.log(chalk4.dim(` ${installPath}`));
845
+ } catch (ex) {
846
+ console.warn(chalk4.yellow(` \u26A0 Could not patch installed_plugins.json: ${ex.message}`));
847
+ }
848
+ };
755
849
  console.log(chalk4.green(`
756
850
  Setting up Claude Code plugin...`));
757
851
  console.log(chalk4.dim(CLAUDE_CODE_DIR));
@@ -763,6 +857,7 @@ Setting up Claude Code plugin...`));
763
857
  if (settingsOk === false) {
764
858
  return;
765
859
  }
860
+ patchInstalledPlugins();
766
861
  configManager.claude_code = { path: CLAUDE_CODE_DIR };
767
862
  configManager.save();
768
863
  };
@@ -781,19 +876,30 @@ Setting up RooCode integration...`));
781
876
  const dirsToBackup = [];
782
877
  for (const dir of roocodeDirs) {
783
878
  const target = path4.join(ROO_DIR, dir);
784
- if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false) {
879
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false && fs4.readdirSync(target).length > 0) {
785
880
  dirsToBackup.push(dir);
786
881
  }
787
882
  }
788
883
  if (dirsToBackup.length === 0) {
789
884
  return true;
790
885
  }
886
+ console.log(chalk4.yellow(`
887
+ \u26A0 The following existing directories will be replaced by symlinks:`));
888
+ for (const dir of dirsToBackup) {
889
+ console.log(chalk4.dim(` - ${path4.join(ROO_DIR, dir)}`));
890
+ }
891
+ console.log(chalk4.yellow(` They will be backed up to: `) + chalk4.dim(ROO_BACKUP_DIR));
892
+ const ok = await confirm3({ message: "Back up existing directories?", default: true });
893
+ if (!ok) {
894
+ console.log(chalk4.yellow("Skipped RooCode linking."));
895
+ return false;
896
+ }
791
897
  fs4.mkdirSync(ROO_BACKUP_DIR, { recursive: true });
792
898
  for (const dir of dirsToBackup) {
793
899
  const src = path4.join(ROO_DIR, dir);
794
900
  const dest = path4.join(ROO_BACKUP_DIR, dir);
795
901
  fs4.renameSync(src, dest);
796
- console.log(chalk4.dim(` backed up: ${dir}/ \u2192 ${dest}`));
902
+ console.log(chalk4.yellow(" backed up") + chalk4.dim(`: ${dir}/ \u2192 ${dest}`));
797
903
  }
798
904
  return true;
799
905
  } catch (ex) {
@@ -854,19 +960,30 @@ Setting up OpenClaw integration...`));
854
960
  const dirsToBackup = [];
855
961
  for (const dir of openclawDirs) {
856
962
  const target = path4.join(OPENCLAW_DIR, dir);
857
- if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false) {
963
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false && fs4.readdirSync(target).length > 0) {
858
964
  dirsToBackup.push(dir);
859
965
  }
860
966
  }
861
967
  if (dirsToBackup.length === 0) {
862
968
  return true;
863
969
  }
970
+ console.log(chalk4.yellow(`
971
+ \u26A0 The following existing directories will be replaced by symlinks:`));
972
+ for (const dir of dirsToBackup) {
973
+ console.log(chalk4.dim(` - ${path4.join(OPENCLAW_DIR, dir)}`));
974
+ }
975
+ console.log(chalk4.yellow(` They will be backed up to: `) + chalk4.dim(OPENCLAW_BACKUP_DIR));
976
+ const ok = await confirm3({ message: "Back up existing directories?", default: true });
977
+ if (!ok) {
978
+ console.log(chalk4.yellow("Skipped OpenClaw linking."));
979
+ return false;
980
+ }
864
981
  fs4.mkdirSync(OPENCLAW_BACKUP_DIR, { recursive: true });
865
982
  for (const dir of dirsToBackup) {
866
983
  const src = path4.join(OPENCLAW_DIR, dir);
867
984
  const dest = path4.join(OPENCLAW_BACKUP_DIR, dir);
868
985
  fs4.renameSync(src, dest);
869
- console.log(chalk4.dim(` backed up: ${dir}/ \u2192 ${dest}`));
986
+ console.log(chalk4.yellow(" backed up") + chalk4.dim(`: ${dir}/ \u2192 ${dest}`));
870
987
  }
871
988
  return true;
872
989
  } catch (ex) {
@@ -912,219 +1029,615 @@ Setting up OpenClaw integration...`));
912
1029
  configManager.openclaw = { path: OPENCLAW_DIR, backup_path: OPENCLAW_BACKUP_DIR };
913
1030
  configManager.save();
914
1031
  };
915
- var linkCodex = async () => {
916
- if (resolveRepoPath() == null) {
917
- return;
918
- }
919
- console.log(chalk4.yellow("Codex integration is not yet implemented."));
920
- };
921
1032
  var linkAntigravity = async () => {
922
- if (resolveRepoPath() == null) {
1033
+ const repoPath = resolveRepoPath();
1034
+ if (repoPath == null) {
923
1035
  return;
924
1036
  }
925
- console.log(chalk4.yellow("Antigravity integration is not yet implemented."));
926
- };
927
- var linkCommand = async (tool) => {
928
- if (tool != null) {
929
- const known = ALL_AGENTS.some((a) => a.value === tool);
930
- if (known === false) {
931
- console.log(chalk4.red(`Unknown vendor: ${tool}`));
932
- process.exit(1);
1037
+ console.log(chalk4.green(`
1038
+ Setting up Antigravity integration...`));
1039
+ console.log(chalk4.dim(ANTIGRAVITY_DIR));
1040
+ const antigravityDirs = AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */];
1041
+ const backupExistingAntigravityFiles = async () => {
1042
+ try {
1043
+ fs4.mkdirSync(ANTIGRAVITY_DIR, { recursive: true });
1044
+ const dirsToBackup = [];
1045
+ for (const dir of antigravityDirs) {
1046
+ const target = path4.join(ANTIGRAVITY_DIR, dir);
1047
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false && fs4.readdirSync(target).length > 0) {
1048
+ dirsToBackup.push(dir);
1049
+ }
1050
+ }
1051
+ if (dirsToBackup.length === 0) {
1052
+ return true;
1053
+ }
1054
+ console.log(chalk4.yellow(`
1055
+ \u26A0 The following existing directories will be replaced by symlinks:`));
1056
+ for (const dir of dirsToBackup) {
1057
+ console.log(chalk4.dim(` - ${path4.join(ANTIGRAVITY_DIR, dir)}`));
1058
+ }
1059
+ console.log(chalk4.yellow(` They will be backed up to: `) + chalk4.dim(ANTIGRAVITY_BACKUP_DIR));
1060
+ const ok = await confirm3({ message: "Back up existing directories?", default: true });
1061
+ if (!ok) {
1062
+ console.log(chalk4.yellow("Skipped Antigravity linking."));
1063
+ return false;
1064
+ }
1065
+ fs4.mkdirSync(ANTIGRAVITY_BACKUP_DIR, { recursive: true });
1066
+ for (const dir of antigravityDirs) {
1067
+ const src = path4.join(ANTIGRAVITY_DIR, dir);
1068
+ const dest = path4.join(ANTIGRAVITY_BACKUP_DIR, dir);
1069
+ fs4.renameSync(src, dest);
1070
+ console.log(chalk4.yellow(" backed up") + chalk4.dim(`: ${dir}/ \u2192 ${dest}`));
1071
+ }
1072
+ return true;
1073
+ } catch (ex) {
1074
+ console.error(chalk4.red(`\u274C Failed to backup existing directories: ${ex.message}`));
1075
+ return false;
933
1076
  }
934
- if (tool === "claudecode" /* CLAUDECODE */) {
935
- await linkClaudeCode();
936
- } else if (tool === "roocode" /* ROOCODE */) {
937
- await linkRooCode();
938
- } else if (tool === "openclaw" /* OPENCLAW */) {
939
- await linkOpenclaw();
940
- } else if (tool === "codex" /* CODEX */) {
941
- await linkCodex();
942
- } else if (tool === "antigravity" /* ANTIGRAVITY */) {
943
- await linkAntigravity();
1077
+ };
1078
+ const setAntigravityAssets = async () => {
1079
+ try {
1080
+ const linked = [];
1081
+ for (const dir of antigravityDirs) {
1082
+ const src = path4.join(repoPath, dir);
1083
+ const dest = path4.join(ANTIGRAVITY_DIR, dir);
1084
+ if (await pathExists(src) === false) {
1085
+ continue;
1086
+ }
1087
+ if (fs4.existsSync(dest)) {
1088
+ fs4.rmSync(dest, { recursive: true, force: true });
1089
+ }
1090
+ const symlinkType = process.platform === "win32" ? "junction" : "dir";
1091
+ fs4.symlinkSync(src, dest, symlinkType);
1092
+ linked.push({ dir, src });
1093
+ }
1094
+ for (const { dir, src } of linked) {
1095
+ const isLast = linked[linked.length - 1].dir === dir;
1096
+ const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
1097
+ console.log(chalk4.dim(` ${branch} `) + chalk4.bold(`${dir}/`) + chalk4.dim(` \u2192 ${src}`) + chalk4.green(" \u2713"));
1098
+ }
1099
+ return true;
1100
+ } catch (ex) {
1101
+ console.error(chalk4.red(`\u274C Failed to create symlinks: ${ex.message}`));
1102
+ return false;
944
1103
  }
1104
+ };
1105
+ const backupOk = await backupExistingAntigravityFiles();
1106
+ if (backupOk === false) {
945
1107
  return;
946
1108
  }
947
- const selected = await checkbox({
948
- message: "Which AI agent do you want to integrate?",
949
- choices: ALL_AGENTS.map((a) => {
950
- const applied = a.value === "claudecode" /* CLAUDECODE */ ? configManager.isClaudeCodeEnabled() : a.value === "roocode" /* ROOCODE */ ? configManager.isRooCodeEnabled() : a.value === "openclaw" /* OPENCLAW */ ? configManager.isOpenclawEnabled() : a.value === "codex" /* CODEX */ ? configManager.isCodexEnabled() : a.value === "antigravity" /* ANTIGRAVITY */ ? configManager.isAntigravityEnabled() : false;
951
- return {
952
- name: applied ? `${a.name} ${chalk4.dim("(applied)")}` : a.name,
953
- value: a.value,
954
- checked: applied
955
- };
956
- })
957
- });
958
- for (const a of selected) {
959
- if (a === "claudecode" /* CLAUDECODE */) {
960
- await linkClaudeCode();
961
- } else if (a === "roocode" /* ROOCODE */) {
962
- await linkRooCode();
963
- } else if (a === "openclaw" /* OPENCLAW */) {
964
- await linkOpenclaw();
965
- } else if (a === "codex" /* CODEX */) {
966
- await linkCodex();
967
- } else if (a === "antigravity" /* ANTIGRAVITY */) {
968
- await linkAntigravity();
969
- }
1109
+ const linkOk = await setAntigravityAssets();
1110
+ if (linkOk === false) {
1111
+ return;
970
1112
  }
1113
+ configManager.antigravity = { path: ANTIGRAVITY_DIR, backup_path: ANTIGRAVITY_BACKUP_DIR };
1114
+ configManager.save();
971
1115
  };
972
-
973
- // src/commands/uninstall-command.ts
974
- import fs5 from "fs";
975
- import path5 from "path";
976
- import os3 from "os";
977
- import chalk5 from "chalk";
978
- import { confirm as confirm4 } from "@inquirer/prompts";
979
- var PLUGIN_NAME2 = "set-prompt";
980
- var rollbackClaudeCode = () => {
981
- const claudeSettingsPath = path5.join(os3.homedir(), ".claude", "settings.json");
982
- if (fs5.existsSync(claudeSettingsPath) === false) {
1116
+ var linkCodex = async () => {
1117
+ console.error(chalk4.red("\u274C Codex integration is not available in this version."));
1118
+ return;
1119
+ };
1120
+ var linkCursor = async () => {
1121
+ const repoPath = resolveRepoPath();
1122
+ if (repoPath == null) {
983
1123
  return;
984
1124
  }
985
- try {
986
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
987
- const backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
1125
+ const CURSOR_LOCAL_DIR = "local";
1126
+ const CURSOR_PLUGIN_NAME = "set-prompt";
1127
+ const setCursorAssets = async () => {
988
1128
  try {
989
- fs5.copyFileSync(claudeSettingsPath, backupPath);
1129
+ const marketplaceMetaDir = path4.join(CURSOR_DIR, ".cursor-plugin");
1130
+ fs4.mkdirSync(marketplaceMetaDir, { recursive: true });
1131
+ const marketplaceJson = {
1132
+ name: CURSOR_PLUGIN_NAME,
1133
+ owner: { name: os2.userInfo().username },
1134
+ metadata: { description: "Managed by set-prompt" },
1135
+ plugins: [{ name: CURSOR_PLUGIN_NAME, source: `./plugins/${CURSOR_LOCAL_DIR}/${CURSOR_PLUGIN_NAME}`, description: "Managed by set-prompt" }]
1136
+ };
1137
+ fs4.writeFileSync(
1138
+ path4.join(marketplaceMetaDir, "marketplace.json"),
1139
+ JSON.stringify(marketplaceJson, null, 2),
1140
+ "utf-8"
1141
+ );
1142
+ console.log(chalk4.dim(" \u251C\u2500\u2500 .cursor-plugin/"));
1143
+ console.log(chalk4.dim(" \u2502 \u2514\u2500\u2500 marketplace.json") + chalk4.green(" \u2713"));
1144
+ const pluginDir = path4.join(CURSOR_DIR, "plugins", CURSOR_LOCAL_DIR, CURSOR_PLUGIN_NAME);
1145
+ const pluginMetaDir = path4.join(pluginDir, ".cursor-plugin");
1146
+ fs4.mkdirSync(pluginMetaDir, { recursive: true });
1147
+ const cursorDirs = AGENT_PROMPT_DIRS["cursor" /* CURSOR */];
1148
+ const pluginJson = {
1149
+ name: CURSOR_PLUGIN_NAME,
1150
+ displayName: "set-prompt",
1151
+ version: "1.0.0",
1152
+ description: "Managed by set-prompt"
1153
+ };
1154
+ for (const dir of cursorDirs) {
1155
+ pluginJson[dir] = `./${dir}/`;
1156
+ }
1157
+ fs4.writeFileSync(
1158
+ path4.join(pluginMetaDir, "plugin.json"),
1159
+ JSON.stringify(pluginJson, null, 2),
1160
+ "utf-8"
1161
+ );
1162
+ console.log(chalk4.dim(" \u2514\u2500\u2500 plugins/"));
1163
+ console.log(chalk4.dim(` \u2514\u2500\u2500 ${CURSOR_PLUGIN_NAME}/`));
1164
+ console.log(chalk4.dim(" \u251C\u2500\u2500 .cursor-plugin/"));
1165
+ console.log(chalk4.dim(" \u2502 \u2514\u2500\u2500 plugin.json") + chalk4.green(" \u2713"));
1166
+ const linked = [];
1167
+ for (const dir of cursorDirs) {
1168
+ const src = path4.join(repoPath, dir);
1169
+ const dest = path4.join(pluginDir, dir);
1170
+ if (await pathExists(src) === false) {
1171
+ continue;
1172
+ }
1173
+ if (fs4.existsSync(dest)) {
1174
+ fs4.rmSync(dest, { recursive: true, force: true });
1175
+ }
1176
+ const symlinkType2 = process.platform === "win32" ? "junction" : "dir";
1177
+ fs4.symlinkSync(src, dest, symlinkType2);
1178
+ linked.push({ dir, src });
1179
+ }
1180
+ for (const { dir, src } of linked) {
1181
+ const isLast = linked[linked.length - 1].dir === dir;
1182
+ const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
1183
+ console.log(chalk4.dim(` ${branch} `) + chalk4.bold(`${dir}/`) + chalk4.dim(` \u2192 ${src}`) + chalk4.green(" \u2713"));
1184
+ }
1185
+ fs4.rmSync(CURSOR_PLUGIN_DIR, { recursive: true, force: true });
1186
+ fs4.mkdirSync(path4.dirname(CURSOR_PLUGIN_DIR), { recursive: true });
1187
+ const symlinkType = process.platform === "win32" ? "junction" : "dir";
1188
+ fs4.symlinkSync(pluginDir, CURSOR_PLUGIN_DIR, symlinkType);
1189
+ console.log(chalk4.green(`
1190
+ \u2705 Installed to Cursor plugins.`));
1191
+ console.log(chalk4.dim(` ${CURSOR_PLUGIN_DIR}`));
1192
+ return true;
990
1193
  } catch (ex) {
991
- console.warn(chalk5.yellow(` \u26A0 Could not create backup: ${ex.message} \u2014 skipping cleanup`));
1194
+ console.error(chalk4.red(`\u274C Failed to build Cursor plugin structure: ${ex.message}`));
1195
+ return false;
1196
+ }
1197
+ };
1198
+ console.log(chalk4.green(`
1199
+ Setting up Cursor plugin...`));
1200
+ console.log(chalk4.dim(CURSOR_DIR));
1201
+ const structureOk = await setCursorAssets();
1202
+ if (structureOk === false) {
1203
+ return;
1204
+ }
1205
+ configManager.cursor = { path: CURSOR_DIR, plugin_dir: CURSOR_PLUGIN_DIR };
1206
+ configManager.save();
1207
+ };
1208
+ var unlinkClaudeCode = async (force = false) => {
1209
+ if (!force) {
1210
+ const ok = await confirm3({
1211
+ message: `Remove Claude Code plugin dir (${CLAUDE_CODE_DIR}) and settings entries?`,
1212
+ default: false
1213
+ });
1214
+ if (!ok) {
1215
+ console.log(chalk4.yellow("Cancelled."));
992
1216
  return;
993
1217
  }
994
- const raw = fs5.readFileSync(claudeSettingsPath, "utf-8");
995
- let settings;
1218
+ }
1219
+ console.log(chalk4.red(`
1220
+ Removing Claude Code plugin...`));
1221
+ console.log(chalk4.dim(CLAUDE_CODE_DIR));
1222
+ const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
1223
+ if (fs4.existsSync(claudeSettingsPath)) {
996
1224
  try {
997
- const parsed = JSON.parse(raw);
998
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
999
- console.warn(chalk5.yellow(" \u26A0 settings.json has unexpected format \u2014 skipping cleanup"));
1000
- fs5.unlinkSync(backupPath);
1001
- return;
1225
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1226
+ const backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
1227
+ fs4.copyFileSync(claudeSettingsPath, backupPath);
1228
+ const settings = JSON.parse(fs4.readFileSync(claudeSettingsPath, "utf-8"));
1229
+ if (settings?.extraKnownMarketplaces?.[MARKET_NAME] !== void 0) {
1230
+ delete settings.extraKnownMarketplaces[MARKET_NAME];
1002
1231
  }
1003
- settings = parsed;
1004
- } catch {
1005
- console.warn(chalk5.yellow(" \u26A0 Failed to parse settings.json \u2014 skipping cleanup"));
1006
- fs5.unlinkSync(backupPath);
1007
- return;
1008
- }
1009
- if (settings.extraKnownMarketplaces?.[PLUGIN_NAME2] !== void 0) {
1010
- delete settings.extraKnownMarketplaces[PLUGIN_NAME2];
1011
- }
1012
- if (settings.enabledPlugins?.[`${PLUGIN_NAME2}@${PLUGIN_NAME2}`] !== void 0) {
1013
- delete settings.enabledPlugins[`${PLUGIN_NAME2}@${PLUGIN_NAME2}`];
1232
+ if (settings?.enabledPlugins?.[`${PLUGIN_NAME}@${MARKET_NAME}`] !== void 0) {
1233
+ delete settings.enabledPlugins[`${PLUGIN_NAME}@${MARKET_NAME}`];
1234
+ }
1235
+ try {
1236
+ fs4.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
1237
+ fs4.unlinkSync(backupPath);
1238
+ console.log(chalk4.red(" removed") + chalk4.dim(` set-prompt entries from: ${claudeSettingsPath}`));
1239
+ } catch (ex) {
1240
+ fs4.copyFileSync(backupPath, claudeSettingsPath);
1241
+ fs4.unlinkSync(backupPath);
1242
+ console.warn(chalk4.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
1243
+ }
1244
+ } catch (ex) {
1245
+ console.error(chalk4.red(` \u274C Failed to clean up settings.json: ${ex.message}`));
1014
1246
  }
1247
+ }
1248
+ const claudePluginsDir = path4.join(os2.homedir(), ".claude", "plugins");
1249
+ const installedPluginsPath = path4.join(claudePluginsDir, "installed_plugins.json");
1250
+ if (fs4.existsSync(installedPluginsPath)) {
1015
1251
  try {
1016
- fs5.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
1017
- } catch (ex) {
1252
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1253
+ const backupPath = `${installedPluginsPath}.bak.${timestamp}`;
1254
+ fs4.copyFileSync(installedPluginsPath, backupPath);
1255
+ const installed = JSON.parse(fs4.readFileSync(installedPluginsPath, "utf-8"));
1256
+ if (installed?.plugins && typeof installed.plugins === "object") {
1257
+ for (const key of Object.keys(installed.plugins)) {
1258
+ if (key.endsWith(`@${MARKET_NAME}`)) {
1259
+ delete installed.plugins[key];
1260
+ }
1261
+ }
1262
+ }
1018
1263
  try {
1019
- fs5.copyFileSync(backupPath, claudeSettingsPath);
1020
- fs5.unlinkSync(backupPath);
1021
- console.warn(chalk5.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
1022
- } catch {
1023
- console.error(chalk5.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
1264
+ fs4.writeFileSync(installedPluginsPath, JSON.stringify(installed, null, 2), "utf-8");
1265
+ fs4.unlinkSync(backupPath);
1266
+ console.log(chalk4.red(" removed") + chalk4.dim(` set-prompt entries from: ${installedPluginsPath}`));
1267
+ } catch (ex) {
1268
+ fs4.copyFileSync(backupPath, installedPluginsPath);
1269
+ fs4.unlinkSync(backupPath);
1270
+ console.warn(chalk4.yellow(" \u26A0 Write failed \u2014 rolled back installed_plugins.json."));
1024
1271
  }
1025
- throw ex;
1272
+ } catch (ex) {
1273
+ console.error(chalk4.red(` \u274C Failed to clean up installed_plugins.json: ${ex.message}`));
1026
1274
  }
1275
+ }
1276
+ const knownMarketplacesPath = path4.join(claudePluginsDir, "known_marketplaces.json");
1277
+ if (fs4.existsSync(knownMarketplacesPath)) {
1027
1278
  try {
1028
- fs5.unlinkSync(backupPath);
1029
- } catch {
1279
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1280
+ const backupPath = `${knownMarketplacesPath}.bak.${timestamp}`;
1281
+ fs4.copyFileSync(knownMarketplacesPath, backupPath);
1282
+ const marketplaces = JSON.parse(fs4.readFileSync(knownMarketplacesPath, "utf-8"));
1283
+ if (marketplaces?.[MARKET_NAME] !== void 0) {
1284
+ delete marketplaces[MARKET_NAME];
1285
+ }
1286
+ try {
1287
+ fs4.writeFileSync(knownMarketplacesPath, JSON.stringify(marketplaces, null, 2), "utf-8");
1288
+ fs4.unlinkSync(backupPath);
1289
+ console.log(chalk4.red(" removed") + chalk4.dim(` set-prompt entry from: ${knownMarketplacesPath}`));
1290
+ } catch (ex) {
1291
+ fs4.copyFileSync(backupPath, knownMarketplacesPath);
1292
+ fs4.unlinkSync(backupPath);
1293
+ console.warn(chalk4.yellow(" \u26A0 Write failed \u2014 rolled back known_marketplaces.json."));
1294
+ }
1295
+ } catch (ex) {
1296
+ console.error(chalk4.red(` \u274C Failed to clean up known_marketplaces.json: ${ex.message}`));
1030
1297
  }
1031
- console.log(chalk5.dim(` removed set-prompt entries from: ${claudeSettingsPath}`));
1032
- } catch (ex) {
1033
- console.error(chalk5.red(` \u274C Failed to clean up settings.json: ${ex.message}`));
1034
1298
  }
1299
+ if (fs4.existsSync(CLAUDE_CODE_DIR)) {
1300
+ fs4.rmSync(CLAUDE_CODE_DIR, { recursive: true, force: true });
1301
+ console.log(chalk4.red(" removed") + chalk4.dim(`: ${CLAUDE_CODE_DIR}`));
1302
+ }
1303
+ configManager.claude_code = null;
1304
+ configManager.save();
1035
1305
  };
1036
- var rollbackRooCode = () => {
1306
+ var unlinkRooCode = async (force = false) => {
1307
+ if (!force) {
1308
+ const ok = await confirm3({
1309
+ message: `Remove RooCode symlinks from ${ROO_DIR}?`,
1310
+ default: false
1311
+ });
1312
+ if (!ok) {
1313
+ console.log(chalk4.yellow("Cancelled."));
1314
+ return;
1315
+ }
1316
+ }
1317
+ console.log(chalk4.red(`
1318
+ Removing RooCode integration...`));
1319
+ console.log(chalk4.dim(ROO_DIR));
1037
1320
  const backupPath = configManager.roocode?.backup_path ?? ROO_BACKUP_DIR;
1038
1321
  for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
1039
- const target = path5.join(ROO_DIR, dir);
1040
- if (fs5.existsSync(target) && fs5.lstatSync(target).isSymbolicLink()) {
1041
- fs5.unlinkSync(target);
1042
- console.log(chalk5.dim(` removed symlink: ${target}`));
1322
+ const target = path4.join(ROO_DIR, dir);
1323
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink()) {
1324
+ fs4.unlinkSync(target);
1325
+ console.log(chalk4.red(" removed symlink") + chalk4.dim(`: ${target}`));
1043
1326
  }
1044
1327
  }
1045
- if (fs5.existsSync(backupPath) === false) {
1046
- return;
1047
- }
1048
- try {
1049
- for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
1050
- const src = path5.join(backupPath, dir);
1051
- const dest = path5.join(ROO_DIR, dir);
1052
- if (fs5.existsSync(src) === false) {
1053
- continue;
1328
+ if (fs4.existsSync(backupPath)) {
1329
+ try {
1330
+ for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
1331
+ const src = path4.join(backupPath, dir);
1332
+ const dest = path4.join(ROO_DIR, dir);
1333
+ if (!fs4.existsSync(src)) {
1334
+ continue;
1335
+ }
1336
+ fs4.renameSync(src, dest);
1337
+ console.log(chalk4.green(" restored") + chalk4.dim(`: ${dir}/`));
1054
1338
  }
1055
- fs5.renameSync(src, dest);
1056
- console.log(chalk5.dim(` restored: ${dir}/`));
1339
+ fs4.rmdirSync(backupPath);
1340
+ } catch (ex) {
1341
+ console.error(chalk4.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
1057
1342
  }
1058
- fs5.rmdirSync(backupPath);
1059
- } catch (ex) {
1060
- console.error(chalk5.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
1061
1343
  }
1344
+ configManager.roocode = null;
1345
+ configManager.save();
1062
1346
  };
1063
- var rollbackOpenclaw = () => {
1347
+ var unlinkOpenclaw = async (force = false) => {
1348
+ if (!force) {
1349
+ const ok = await confirm3({
1350
+ message: `Remove OpenClaw symlinks from ${OPENCLAW_DIR}?`,
1351
+ default: false
1352
+ });
1353
+ if (!ok) {
1354
+ console.log(chalk4.yellow("Cancelled."));
1355
+ return;
1356
+ }
1357
+ }
1358
+ console.log(chalk4.red(`
1359
+ Removing OpenClaw integration...`));
1360
+ console.log(chalk4.dim(OPENCLAW_DIR));
1064
1361
  const backupPath = configManager.openclaw?.backup_path ?? OPENCLAW_BACKUP_DIR;
1065
1362
  for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
1066
- const target = path5.join(OPENCLAW_DIR, dir);
1067
- if (fs5.existsSync(target) && fs5.lstatSync(target).isSymbolicLink()) {
1068
- fs5.unlinkSync(target);
1069
- console.log(chalk5.dim(` removed symlink: ${target}`));
1363
+ const target = path4.join(OPENCLAW_DIR, dir);
1364
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink()) {
1365
+ fs4.unlinkSync(target);
1366
+ console.log(chalk4.red(" removed symlink") + chalk4.dim(`: ${target}`));
1070
1367
  }
1071
1368
  }
1072
- if (fs5.existsSync(backupPath) === false) {
1369
+ if (fs4.existsSync(backupPath)) {
1370
+ try {
1371
+ for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
1372
+ const src = path4.join(backupPath, dir);
1373
+ const dest = path4.join(OPENCLAW_DIR, dir);
1374
+ if (!fs4.existsSync(src)) {
1375
+ continue;
1376
+ }
1377
+ fs4.renameSync(src, dest);
1378
+ console.log(chalk4.green(" restored") + chalk4.dim(`: ${dir}/`));
1379
+ }
1380
+ fs4.rmdirSync(backupPath);
1381
+ } catch (ex) {
1382
+ console.error(chalk4.red(` \u274C Failed to restore OpenClaw backup: ${ex.message}`));
1383
+ }
1384
+ }
1385
+ configManager.openclaw = null;
1386
+ configManager.save();
1387
+ };
1388
+ var unlinkAntigravity = async (force = false) => {
1389
+ if (!force) {
1390
+ const ok = await confirm3({
1391
+ message: `Remove Antigravity symlinks from ${ANTIGRAVITY_DIR}?`,
1392
+ default: false
1393
+ });
1394
+ if (!ok) {
1395
+ console.log(chalk4.yellow("Cancelled."));
1396
+ return;
1397
+ }
1398
+ }
1399
+ console.log(chalk4.red(`
1400
+ Removing Antigravity integration...`));
1401
+ console.log(chalk4.dim(ANTIGRAVITY_DIR));
1402
+ const backupPath = configManager.antigravity?.backup_path ?? ANTIGRAVITY_BACKUP_DIR;
1403
+ for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
1404
+ const target = path4.join(ANTIGRAVITY_DIR, dir);
1405
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink()) {
1406
+ fs4.unlinkSync(target);
1407
+ console.log(chalk4.red(" removed symlink") + chalk4.dim(`: ${target}`));
1408
+ }
1409
+ }
1410
+ if (fs4.existsSync(backupPath)) {
1411
+ try {
1412
+ for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
1413
+ const src = path4.join(backupPath, dir);
1414
+ const dest = path4.join(ANTIGRAVITY_DIR, dir);
1415
+ if (!fs4.existsSync(src)) {
1416
+ continue;
1417
+ }
1418
+ fs4.renameSync(src, dest);
1419
+ console.log(chalk4.green(" restored") + chalk4.dim(`: ${dir}/`));
1420
+ }
1421
+ fs4.rmdirSync(backupPath);
1422
+ } catch (ex) {
1423
+ console.error(chalk4.red(` \u274C Failed to restore Antigravity backup: ${ex.message}`));
1424
+ }
1425
+ }
1426
+ configManager.antigravity = null;
1427
+ configManager.save();
1428
+ };
1429
+ var unlinkCodex = async (force = false) => {
1430
+ if (!force) {
1431
+ const ok = await confirm3({
1432
+ message: `Remove Codex symlinks from ${CODEX_DIR}?`,
1433
+ default: false
1434
+ });
1435
+ if (!ok) {
1436
+ console.log(chalk4.yellow("Cancelled."));
1437
+ return;
1438
+ }
1439
+ }
1440
+ console.log(chalk4.red(`
1441
+ Removing Codex integration...`));
1442
+ console.log(chalk4.dim(CODEX_DIR));
1443
+ const backupPath = configManager.codex?.backup_path ?? CODEX_BACKUP_DIR;
1444
+ for (const dir of AGENT_PROMPT_DIRS["codex" /* CODEX */]) {
1445
+ const target = path4.join(CODEX_DIR, dir);
1446
+ if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink()) {
1447
+ fs4.unlinkSync(target);
1448
+ console.log(chalk4.red(" removed symlink") + chalk4.dim(`: ${target}`));
1449
+ }
1450
+ }
1451
+ if (fs4.existsSync(backupPath)) {
1452
+ try {
1453
+ for (const dir of AGENT_PROMPT_DIRS["codex" /* CODEX */]) {
1454
+ const src = path4.join(backupPath, dir);
1455
+ const dest = path4.join(CODEX_DIR, dir);
1456
+ if (!fs4.existsSync(src)) {
1457
+ continue;
1458
+ }
1459
+ fs4.renameSync(src, dest);
1460
+ console.log(chalk4.green(" restored") + chalk4.dim(`: ${dir}/`));
1461
+ }
1462
+ fs4.rmdirSync(backupPath);
1463
+ } catch (ex) {
1464
+ console.error(chalk4.red(` \u274C Failed to restore Codex backup: ${ex.message}`));
1465
+ }
1466
+ }
1467
+ configManager.codex = null;
1468
+ configManager.save();
1469
+ };
1470
+ var unlinkCursor = async (force = false) => {
1471
+ if (!force) {
1472
+ const ok = await confirm3({
1473
+ message: `Remove Cursor plugin dir (${CURSOR_PLUGIN_DIR}) and plugin structure?`,
1474
+ default: false
1475
+ });
1476
+ if (!ok) {
1477
+ console.log(chalk4.yellow("Cancelled."));
1478
+ return;
1479
+ }
1480
+ }
1481
+ console.log(chalk4.red(`
1482
+ Removing Cursor plugin...`));
1483
+ console.log(chalk4.dim(CURSOR_PLUGIN_DIR));
1484
+ fs4.rmSync(CURSOR_PLUGIN_DIR, { recursive: true, force: true });
1485
+ console.log(chalk4.red(" removed") + chalk4.dim(`: ${CURSOR_PLUGIN_DIR}`));
1486
+ if (fs4.existsSync(CURSOR_DIR)) {
1487
+ fs4.rmSync(CURSOR_DIR, { recursive: true, force: true });
1488
+ console.log(chalk4.red(" removed") + chalk4.dim(`: ${CURSOR_DIR}`));
1489
+ }
1490
+ configManager.cursor = null;
1491
+ configManager.save();
1492
+ };
1493
+ var linkCommand = async (tool) => {
1494
+ if (tool != null) {
1495
+ const known = ALL_AGENTS.some((a) => a.value === tool);
1496
+ if (!known) {
1497
+ console.log(chalk4.red(`Unknown vendor: ${tool}`));
1498
+ process.exit(1);
1499
+ }
1500
+ if (tool === "claudecode" /* CLAUDECODE */) {
1501
+ await linkClaudeCode();
1502
+ } else if (tool === "roocode" /* ROOCODE */) {
1503
+ await linkRooCode();
1504
+ } else if (tool === "openclaw" /* OPENCLAW */) {
1505
+ await linkOpenclaw();
1506
+ } else if (tool === "codex" /* CODEX */) {
1507
+ await linkCodex();
1508
+ } else if (tool === "antigravity" /* ANTIGRAVITY */) {
1509
+ await linkAntigravity();
1510
+ } else if (tool === "cursor" /* CURSOR */) {
1511
+ await linkCursor();
1512
+ }
1073
1513
  return;
1074
1514
  }
1075
- try {
1076
- for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
1077
- const src = path5.join(backupPath, dir);
1078
- const dest = path5.join(OPENCLAW_DIR, dir);
1079
- if (fs5.existsSync(src) === false) {
1080
- continue;
1515
+ const prevLinked = {
1516
+ ["claudecode" /* CLAUDECODE */]: configManager.isClaudeCodeEnabled(),
1517
+ ["roocode" /* ROOCODE */]: configManager.isRooCodeEnabled(),
1518
+ ["openclaw" /* OPENCLAW */]: configManager.isOpenclawEnabled(),
1519
+ ["codex" /* CODEX */]: configManager.isCodexEnabled(),
1520
+ ["antigravity" /* ANTIGRAVITY */]: configManager.isAntigravityEnabled(),
1521
+ ["cursor" /* CURSOR */]: configManager.isCursorEnabled()
1522
+ };
1523
+ const selected = await checkbox({
1524
+ message: "Which AI agent do you want to integrate?",
1525
+ choices: ALL_AGENTS.map((a) => ({
1526
+ name: prevLinked[a.value] ? `${a.name} ${chalk4.dim("(applied)")}` : a.name,
1527
+ value: a.value,
1528
+ checked: prevLinked[a.value]
1529
+ }))
1530
+ });
1531
+ const toLink = ALL_AGENTS.filter((a) => !prevLinked[a.value] && selected.includes(a.value));
1532
+ const toUnlink = ALL_AGENTS.filter((a) => prevLinked[a.value] && !selected.includes(a.value));
1533
+ console.log();
1534
+ if (toLink.length > 0) {
1535
+ console.log(chalk4.green(" Link ") + chalk4.dim("\u2192 ") + toLink.map((a) => chalk4.bold(a.name)).join(chalk4.dim(", ")));
1536
+ }
1537
+ if (toUnlink.length > 0) {
1538
+ console.log(chalk4.red(" Unlink ") + chalk4.dim("\u2192 ") + toUnlink.map((a) => chalk4.bold(a.name)).join(chalk4.dim(", ")));
1539
+ }
1540
+ console.log();
1541
+ if (toLink.length === 0 && toUnlink.length === 0) {
1542
+ return;
1543
+ }
1544
+ for (const a of ALL_AGENTS) {
1545
+ const was = prevLinked[a.value];
1546
+ const now = selected.includes(a.value);
1547
+ if (!was && now) {
1548
+ if (a.value === "claudecode" /* CLAUDECODE */) {
1549
+ await linkClaudeCode();
1550
+ } else if (a.value === "roocode" /* ROOCODE */) {
1551
+ await linkRooCode();
1552
+ } else if (a.value === "openclaw" /* OPENCLAW */) {
1553
+ await linkOpenclaw();
1554
+ } else if (a.value === "codex" /* CODEX */) {
1555
+ await linkCodex();
1556
+ } else if (a.value === "antigravity" /* ANTIGRAVITY */) {
1557
+ await linkAntigravity();
1558
+ } else if (a.value === "cursor" /* CURSOR */) {
1559
+ await linkCursor();
1560
+ }
1561
+ }
1562
+ if (was && !now) {
1563
+ if (a.value === "claudecode" /* CLAUDECODE */) {
1564
+ await unlinkClaudeCode(true);
1565
+ } else if (a.value === "roocode" /* ROOCODE */) {
1566
+ await unlinkRooCode(true);
1567
+ } else if (a.value === "openclaw" /* OPENCLAW */) {
1568
+ await unlinkOpenclaw(true);
1569
+ } else if (a.value === "codex" /* CODEX */) {
1570
+ await unlinkCodex(true);
1571
+ } else if (a.value === "antigravity" /* ANTIGRAVITY */) {
1572
+ await unlinkAntigravity(true);
1573
+ } else if (a.value === "cursor" /* CURSOR */) {
1574
+ await unlinkCursor(true);
1081
1575
  }
1082
- fs5.renameSync(src, dest);
1083
- console.log(chalk5.dim(` restored: ${dir}/`));
1084
1576
  }
1085
- fs5.rmdirSync(backupPath);
1086
- } catch (ex) {
1087
- console.error(chalk5.red(` \u274C Failed to restore OpenClaw backup: ${ex.message}`));
1088
1577
  }
1089
1578
  };
1579
+
1580
+ // src/commands/uninstall-command.ts
1581
+ import fs5 from "fs";
1582
+ import chalk5 from "chalk";
1583
+ import { confirm as confirm4 } from "@inquirer/prompts";
1090
1584
  var uninstallCommand = async () => {
1091
1585
  const targets = [
1092
- { label: `Claude Code plugin dir ${chalk5.dim(CLAUDE_CODE_DIR)}`, path: CLAUDE_CODE_DIR },
1093
- { label: `Config file ${chalk5.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
1094
- { label: `Home dir ${chalk5.dim(HOME_DIR)}`, path: HOME_DIR }
1586
+ { label: `Config file ${chalk5.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
1587
+ { label: `Home dir ${chalk5.dim(HOME_DIR)}`, path: HOME_DIR }
1095
1588
  ].filter((t) => fs5.existsSync(t.path));
1096
- const hasClaudeCodeSettings = configManager.isClaudeCodeEnabled();
1589
+ const hasClaudeCode = configManager.isClaudeCodeEnabled();
1097
1590
  const hasRooCode = configManager.isRooCodeEnabled();
1098
1591
  const hasOpenclaw = configManager.isOpenclawEnabled();
1099
- if (targets.length === 0 && hasClaudeCodeSettings === false && hasRooCode === false && hasOpenclaw === false) {
1592
+ const hasAntigravity = configManager.isAntigravityEnabled();
1593
+ const hasCodex = configManager.isCodexEnabled();
1594
+ const hasCursor = configManager.isCursorEnabled();
1595
+ if (targets.length === 0 && !hasClaudeCode && !hasRooCode && !hasOpenclaw && !hasAntigravity && !hasCodex && !hasCursor) {
1100
1596
  console.log(chalk5.yellow("Nothing to remove."));
1101
1597
  return;
1102
1598
  }
1103
1599
  console.log(chalk5.red("\nThe following will be removed:"));
1104
1600
  targets.forEach((t) => console.log(` ${t.label}`));
1105
- if (hasClaudeCodeSettings) {
1106
- const claudeSettingsPath = path5.join(os3.homedir(), ".claude", "settings.json");
1107
- console.log(` set-prompt entries in ${chalk5.dim(claudeSettingsPath)}`);
1601
+ if (hasClaudeCode) {
1602
+ console.log(` Claude Code plugin dir ${chalk5.dim(CLAUDE_CODE_DIR)}`);
1108
1603
  }
1109
1604
  if (hasRooCode) {
1110
- console.log(` RooCode symlinks in ${chalk5.dim(ROO_DIR)} ${chalk5.dim("(backup will be restored)")}`);
1605
+ console.log(` RooCode symlinks ${chalk5.dim("(backup will be restored)")}`);
1111
1606
  }
1112
1607
  if (hasOpenclaw) {
1113
- console.log(` OpenClaw symlinks in ${chalk5.dim(OPENCLAW_DIR)} ${chalk5.dim("(backup will be restored)")}`);
1608
+ console.log(` OpenClaw symlinks ${chalk5.dim("(backup will be restored)")}`);
1609
+ }
1610
+ if (hasAntigravity) {
1611
+ console.log(` Antigravity symlinks ${chalk5.dim("(backup will be restored)")}`);
1612
+ }
1613
+ if (hasCodex) {
1614
+ console.log(` Codex symlinks ${chalk5.dim("(backup will be restored)")}`);
1615
+ }
1616
+ if (hasCursor) {
1617
+ console.log(` Cursor plugin dir ${chalk5.dim("(symlink will be removed)")}`);
1114
1618
  }
1115
1619
  const ok = await confirm4({ message: "Proceed?", default: false });
1116
- if (ok === false) {
1620
+ if (!ok) {
1117
1621
  console.log(chalk5.yellow("Cancelled."));
1118
1622
  return;
1119
1623
  }
1120
- if (hasClaudeCodeSettings) {
1121
- rollbackClaudeCode();
1624
+ if (hasClaudeCode) {
1625
+ await unlinkClaudeCode(true);
1122
1626
  }
1123
1627
  if (hasRooCode) {
1124
- rollbackRooCode();
1628
+ await unlinkRooCode(true);
1125
1629
  }
1126
1630
  if (hasOpenclaw) {
1127
- rollbackOpenclaw();
1631
+ await unlinkOpenclaw(true);
1632
+ }
1633
+ if (hasAntigravity) {
1634
+ await unlinkAntigravity(true);
1635
+ }
1636
+ if (hasCodex) {
1637
+ await unlinkCodex(true);
1638
+ }
1639
+ if (hasCursor) {
1640
+ await unlinkCursor(true);
1128
1641
  }
1129
1642
  for (const t of targets) {
1130
1643
  fs5.rmSync(t.path, { recursive: true, force: true });
@@ -1214,8 +1727,8 @@ process.on("unhandledRejection", (reason) => {
1214
1727
  }
1215
1728
  throw reason;
1216
1729
  });
1217
- var __dirname = path6.dirname(fileURLToPath(import.meta.url));
1218
- var pkg = JSON.parse(fs6.readFileSync(path6.join(__dirname, "../package.json"), "utf-8"));
1730
+ var __dirname = path5.dirname(fileURLToPath(import.meta.url));
1731
+ var pkg = JSON.parse(fs6.readFileSync(path5.join(__dirname, "../package.json"), "utf-8"));
1219
1732
  configManager.init();
1220
1733
  var program = new Command();
1221
1734
  var banner = chalk8.cyan(figlet.textSync("Set-Prompt", { horizontalLayout: "full" }));