set-prompt 0.4.0 → 0.5.2

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +131 -100
  2. package/README.md +136 -104
  3. package/dist/index.js +957 -657
  4. package/package.json +10 -3
package/dist/index.js CHANGED
@@ -2,23 +2,25 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk8 from "chalk";
5
+ import chalk15 from "chalk";
6
6
  import figlet from "figlet";
7
- import fs6 from "fs";
8
- import path5 from "path";
7
+ import fs11 from "fs";
8
+ import path10 from "path";
9
9
  import { fileURLToPath } from "url";
10
10
 
11
11
  // src/commands/install-command.ts
12
12
  import fs3 from "fs";
13
13
  import path3 from "path";
14
14
  import { spawnSync } from "child_process";
15
- import chalk3 from "chalk";
15
+ import chalk4 from "chalk";
16
16
  import { confirm as confirm2 } from "@inquirer/prompts";
17
17
 
18
18
  // src/_defs/index.ts
19
19
  import path from "path";
20
20
  import os from "os";
21
21
  var TAB = ` `;
22
+ var MARKET_NAME = "set-prompt";
23
+ var PLUGIN_NAME = "sppt";
22
24
  var HOME_DIR = path.join(os.homedir(), ".set-prompt");
23
25
  var CONFIG_PATH = path.join(HOME_DIR, "config.json");
24
26
  var REPO_DIR = path.join(HOME_DIR, "repo");
@@ -29,18 +31,17 @@ var OPENCLAW_DIR = path.join(os.homedir(), ".openclaw", "workspace");
29
31
  var OPENCLAW_BACKUP_DIR = path.join(OPENCLAW_DIR, "SET_PROMPT_BACKUP");
30
32
  var ANTIGRAVITY_DIR = path.join(os.homedir(), ".gemini", "antigravity");
31
33
  var ANTIGRAVITY_BACKUP_DIR = path.join(ANTIGRAVITY_DIR, "SET_PROMPT_BACKUP");
32
- var CODEX_DIR = path.join(os.homedir(), ".codex");
34
+ var CODEX_DIR = path.join(HOME_DIR, "codex");
33
35
  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");
36
- var PROMPT_DIR_NAMES = ["skills", "commands", "hooks", "agents"];
36
+ var CURSOR_DIR = path.join(os.homedir(), ".cursor");
37
+ var PROMPT_DIR_NAMES = ["skills", "commands", "hooks", "agents", "rules"];
37
38
  var AGENT_PROMPT_DIRS = {
38
39
  ["claudecode" /* CLAUDECODE */]: ["skills", "commands", "hooks", "agents"],
39
40
  ["roocode" /* ROOCODE */]: ["skills", "commands"],
40
41
  ["openclaw" /* OPENCLAW */]: ["skills"],
41
- ["codex" /* CODEX */]: ["skills", "commands"],
42
+ ["codex" /* CODEX */]: ["skills"],
42
43
  ["antigravity" /* ANTIGRAVITY */]: ["skills"],
43
- ["cursor" /* CURSOR */]: ["skills", "agents", "rules"]
44
+ ["cursor" /* CURSOR */]: ["skills", "agents", "commands", "hooks"]
44
45
  };
45
46
  var ALL_AGENTS = [
46
47
  { name: "Claude Code", value: "claudecode" /* CLAUDECODE */ },
@@ -80,9 +81,7 @@ var AntigravityConfigSchema = z.object({
80
81
  });
81
82
  var CursorConfigSchema = z.object({
82
83
  path: z.string().nullable(),
83
- // ~/.set-prompt/cursor (플러그인 파일 구조)
84
- plugin_dir: z.string().nullable()
85
- // ~/.cursor/plugins/set-prompt (설치 symlink)
84
+ backup_path: z.string().nullish().optional()
86
85
  });
87
86
  var GlobalConfigSchema = z.object({
88
87
  repo_path: z.string(),
@@ -240,23 +239,33 @@ var ConfigManager = class {
240
239
  var configManager = new ConfigManager();
241
240
 
242
241
  // src/_libs/index.ts
242
+ import chalk2 from "chalk";
243
243
  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
+ var resolveRepoPath = () => {
245
+ if (configManager.repo_path == null) {
246
+ console.error(chalk2.red("\u274C No repo installed."));
247
+ console.log(chalk2.yellow("Run: set-prompt install <git-url>"));
248
+ return null;
249
+ }
250
+ return configManager.repo_path;
251
+ };
244
252
 
245
253
  // src/commands/scaffold-command.ts
246
254
  import fs2 from "fs";
247
255
  import path2 from "path";
248
- import chalk2 from "chalk";
256
+ import chalk3 from "chalk";
249
257
  import { confirm } from "@inquirer/prompts";
250
258
 
251
259
  // src/_libs/templates.ts
252
260
  var SET_PROMPT_GUIDE = `# Set Prompt Repository Guide
253
261
 
254
- > Managed by [set-prompt](https://github.com/alkemic-studio/set-prompt)
262
+ > Managed by [set-prompt](https://github.com/juncha9/set-prompt)
263
+
264
+ This is a shared prompt repository linked to various AI agents via \`set-prompt link\`. When writing or editing prompts in this repository, refer to the structure below and the frontmatter reference for each platform's conventions.
255
265
 
256
266
  ## Structure
257
267
 
258
268
  \`\`\`
259
- \u251C\u2500\u2500 set-prompt.toml # Repository configuration
260
269
  \u251C\u2500\u2500 skills/
261
270
  \u2502 \u2514\u2500\u2500 <skill-name>/
262
271
  \u2502 \u251C\u2500\u2500 SKILL.md # Platform-specific frontmatter + prompt content
@@ -265,10 +274,27 @@ var SET_PROMPT_GUIDE = `# Set Prompt Repository Guide
265
274
  \u2502 \u2514\u2500\u2500 <command-name>/
266
275
  \u2502 \u251C\u2500\u2500 COMMAND.md # Platform-specific frontmatter + prompt content
267
276
  \u2502 \u2514\u2500\u2500 ... # Supporting files
268
- \u251C\u2500\u2500 hooks/ # Lifecycle shell hooks
269
- \u2514\u2500\u2500 agents/ # Agent definitions (Claude Code)
270
- \u2514\u2500\u2500 <agent-name>/
271
- \u2514\u2500\u2500 AGENT.md
277
+ \u251C\u2500\u2500 hooks/ # Lifecycle shell hooks (Claude Code)
278
+ \u251C\u2500\u2500 agents/ # Agent definitions (Claude Code, Cursor)
279
+ \u2502 \u2514\u2500\u2500 <agent-name>/
280
+ \u2502 \u2514\u2500\u2500 AGENT.md
281
+ \u2514\u2500\u2500 rules/ # Rule definitions (Cursor)
282
+ \u2514\u2500\u2500 <rule-name>/
283
+ \u2514\u2500\u2500 RULE.md
284
+ \`\`\`
285
+
286
+ ## Usage
287
+
288
+ \`\`\`bash
289
+ # Scaffold this repo's directory structure
290
+ set-prompt scaffold .
291
+
292
+ # Install from remote and link to AI tools
293
+ set-prompt install https://github.com/you/my-prompts
294
+ set-prompt link
295
+
296
+ # Pull latest changes
297
+ set-prompt update
272
298
  \`\`\`
273
299
 
274
300
  ## Frontmatter Reference
@@ -318,6 +344,15 @@ metadata: {"os":["darwin","linux"],"requires":{"bins":["git"],"env":["MY_API_KEY
318
344
  # Antigravity
319
345
  name: my-skill
320
346
  description: "What this skill does and when to use it"
347
+
348
+ # Cursor
349
+ name: "my-skill"
350
+ description: "What this skill does and when to use it"
351
+ license: "MIT"
352
+ compatibility: "Requires Node.js 18+"
353
+ metadata:
354
+ category: "development"
355
+ disable-model-invocation: false
321
356
  ---
322
357
  \`\`\`
323
358
 
@@ -339,10 +374,13 @@ description: "What this skill does and when to use it"
339
374
  | \`metadata\` | No | OpenClaw | Single-line JSON for platform gating: \`os\` (platform filter), \`requires.bins\` (required binaries), \`requires.env\` (required env vars) |
340
375
  | \`homepage\` | No | OpenClaw | URL shown as "Website" in the macOS Skills UI. Also settable via \`metadata.openclaw.homepage\`. |
341
376
  | \`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\`) |
377
+ | \`disable-model-invocation\` | No | Claude Code, OpenClaw, Cursor | \`true\` = skill only included when explicitly invoked via \`/skill-name\`. (default: \`false\`) |
343
378
  | \`command-dispatch\` | No | OpenClaw | \`"tool"\` = bypass model, dispatch directly to a tool |
344
379
  | \`command-tool\` | No | OpenClaw | Tool to invoke when \`command-dispatch: "tool"\` |
345
380
  | \`command-arg-mode\` | No | OpenClaw | How arguments are forwarded to the tool. (default: \`"raw"\`) |
381
+ | \`license\` | No | Cursor | License name or reference to a bundled license file. |
382
+ | \`compatibility\` | No | Cursor | Environment requirements (system packages, network access, etc.) |
383
+ | \`metadata\` | No | Cursor | Arbitrary key-value mapping for additional metadata. |
346
384
 
347
385
  ---
348
386
 
@@ -386,7 +424,7 @@ command-tool: "Bash"
386
424
  |-------|----------|----------|-------------|
387
425
  | \`name\` | No | All | Display name \u2014 lowercase, numbers, hyphens only (max 64 chars). Defaults to directory name. |
388
426
  | \`description\` | Yes | All | Shown in \`/\` menu. Claude uses this to decide auto-loading. |
389
- | \`user-invocable\` | No | CC, OpenClaw | \`false\` = hidden from \`/\` menu, background knowledge only. (default: \`true\`) |
427
+ | \`user-invocable\` | No | Claude Code, OpenClaw | \`false\` = hidden from \`/\` menu, background knowledge only. (default: \`true\`) |
390
428
  | \`allowed-tools\` | No | Claude Code | Tools Claude can use without asking. e.g. \`Read\` \`Write\` \`Edit\` \`Bash\` \`Grep\` \`Glob\` |
391
429
  | \`argument-hint\` | No | Claude Code | Hint shown during autocomplete. e.g. \`[issue-number]\` |
392
430
  | \`model\` | No | Claude Code | Model to use when active. \`sonnet\` or \`haiku\` |
@@ -398,10 +436,11 @@ command-tool: "Bash"
398
436
 
399
437
  ### Agents
400
438
 
401
- Custom subagent definitions loaded by Claude Code.
439
+ Custom subagent definitions loaded by Claude Code and Cursor.
402
440
 
403
441
  \`\`\`yaml
404
442
  ---
443
+ # Claude Code
405
444
  name: "my-agent"
406
445
  description: "What this agent does and when to use it"
407
446
  allowed-tools:
@@ -409,37 +448,87 @@ allowed-tools:
409
448
  - Bash
410
449
  model: sonnet
411
450
  context: fork
451
+
452
+ # Cursor
453
+ name: "my-agent"
454
+ description: "What this agent does and when to use it"
455
+ model: inherit
456
+ readonly: false
457
+ is_background: false
458
+ ---
459
+ \`\`\`
460
+
461
+ | Field | Required | Platform | Description |
462
+ |-------|----------|----------|-------------|
463
+ | \`name\` | Yes | All | Display name. Claude Code: lowercase, numbers, hyphens only (max 64 chars). Cursor: defaults to folder name. |
464
+ | \`description\` | Yes | All | When and how to use this agent. Used to decide when to spawn/delegate. |
465
+ | \`allowed-tools\` | No | Claude Code | Tools this agent can use without asking |
466
+ | \`model\` | No | All | Claude Code: \`sonnet\` or \`haiku\`. Cursor: \`fast\`, \`inherit\`, or a specific model ID. |
467
+ | \`context\` | No | Claude Code | \`fork\` = run in isolated subagent context |
468
+ | \`readonly\` | No | Cursor | \`true\` = sub-agent runs with restricted write permissions (no file edits or state-changing shell commands). (default: \`false\`) |
469
+ | \`is_background\` | No | Cursor | \`true\` = sub-agent runs in background without blocking parent. (default: \`false\`) |
470
+
471
+ ---
472
+
473
+ ### Rules
474
+
475
+ System-level instructions for the AI agent. Cursor only. Rules are markdown files (\`.md\` or \`.mdc\`) stored in \`.cursor/rules/\`. When a rule is active, its content is prepended to the model context.
476
+
477
+ \`\`\`yaml
478
+ ---
479
+ description: "When and how this rule should be applied"
480
+ globs:
481
+ - "**/*.ts"
482
+ - "**/*.tsx"
483
+ alwaysApply: false
412
484
  ---
485
+
486
+ Use \`@filename\` to reference files instead of copying content.
413
487
  \`\`\`
414
488
 
489
+ **Activation Types**
490
+
491
+ | Type | \`alwaysApply\` | \`globs\` | \`description\` | Behavior |
492
+ |------|:-----------:|:-----:|:-----------:|----------|
493
+ | Always | \`true\` | ignored | optional | Included in every conversation |
494
+ | Auto Attached | \`false\` | set | optional | Included when open files match glob patterns |
495
+ | Agent Requested | \`false\` | empty | set | AI decides based on description relevance |
496
+ | Manual | \`false\` | empty | empty | Invoked via \`@rule-name\` mention only |
497
+
415
498
  | Field | Required | Description |
416
499
  |-------|----------|-------------|
417
- | \`name\` | Yes | Display name \u2014 lowercase, numbers, hyphens only (max 64 chars) |
418
- | \`description\` | Yes | When and how to use this agent. Claude uses this to decide when to spawn it. |
419
- | \`allowed-tools\` | No | Tools this agent can use without asking |
420
- | \`model\` | No | Model override. \`sonnet\` or \`haiku\` |
421
- | \`context\` | No | \`fork\` = run in isolated subagent context |
500
+ | \`description\` | No | Describes the rule's purpose. Used by AI to decide relevance (Agent Requested type). |
501
+ | \`globs\` | No | File patterns for auto-attachment. e.g. \`["**/*.ts", "src/components/**"]\` |
502
+ | \`alwaysApply\` | No | \`true\` = always included regardless of context. (default: \`false\`) |
503
+
504
+ **Priority**: Team Rules > Project Rules (\`.cursor/rules/\`) > User Rules (Cursor Settings) > \`AGENTS.md\`
505
+
506
+ **Best practices**: Keep rules under 500 lines. Reference files with \`@filename\` instead of copying. Be specific \u2014 avoid duplicating what linters or the agent already knows.
422
507
 
423
508
  ---
424
509
 
425
510
  ### Hooks
426
511
 
427
- Lifecycle shell commands (or LLM prompts) that fire at specific points. Hooks in skill/command frontmatter are scoped to that component \u2014 active while it runs, removed when it finishes.
512
+ Lifecycle scripts that fire at specific points in the agent loop. Both Claude Code and Cursor support hooks, but with different configuration formats and event models.
513
+
514
+ #### Claude Code Hooks
515
+
516
+ Defined in YAML frontmatter within skill/command files. Scoped to that component \u2014 active while it runs, removed when it finishes.
428
517
 
429
518
  \`\`\`yaml
430
519
  hooks:
431
520
  PreToolUse:
432
- - matcher: "Bash" # regex matched against tool name
521
+ - matcher: "Bash"
433
522
  hooks:
434
523
  - type: command
435
524
  command: ".claude/hooks/validate.sh"
436
- timeout: 30 # seconds (default: 600)
525
+ timeout: 30
437
526
  PostToolUse:
438
527
  - matcher: "Write|Edit"
439
528
  hooks:
440
529
  - type: command
441
530
  command: "npm run lint"
442
- async: true # run in background, non-blocking
531
+ async: true
443
532
  Stop:
444
533
  - hooks:
445
534
  - type: prompt
@@ -455,12 +544,10 @@ hooks:
455
544
  | \`PostToolUseFailure\` | tool name | No | After a tool fails |
456
545
  | \`UserPromptSubmit\` | \u2014 | Yes | When user submits a prompt |
457
546
  | \`SessionStart\` | \`startup\` \\| \`resume\` \\| \`clear\` \\| \`compact\` | No | Session begins |
458
- | \`Stop\` | \u2014 | Yes | Claude finishes responding |
547
+ | \`Stop\` | \u2014 | Yes | Agent finishes responding |
459
548
  | \`Notification\` | \`permission_prompt\` \\| \`idle_prompt\` | No | Notification fires |
460
549
  | \`SubagentStart\` / \`SubagentStop\` | agent type | No / Yes | Subagent spawned / finished |
461
550
 
462
- Full event list: [hooks reference](https://code.claude.com/docs/en/hooks)
463
-
464
551
  **Handler fields**
465
552
 
466
553
  | Field | Type | Description |
@@ -469,57 +556,134 @@ Full event list: [hooks reference](https://code.claude.com/docs/en/hooks)
469
556
  | \`command\` | command only | Shell command to execute. Receives hook JSON on stdin |
470
557
  | \`prompt\` | prompt/agent | Prompt text. Use \`$ARGUMENTS\` for the hook JSON input |
471
558
  | \`timeout\` | all | Seconds before cancel. Defaults: 600 / 30 / 60 |
472
- | \`async\` | command only | \`true\` = run in background, cannot block Claude |
559
+ | \`async\` | command only | \`true\` = run in background, cannot block |
473
560
  | \`once\` | command only | \`true\` = run once per session then remove (skills only) |
474
561
 
475
- **Decision control** (command hooks)
562
+ Full event list: [Claude Code hooks reference](https://code.claude.com/docs/en/hooks)
476
563
 
477
- Exit \`0\` = allow. Exit \`2\` = block (stderr is fed to Claude as the reason). Print JSON to stdout for richer control:
564
+ ---
478
565
 
479
- \`\`\`bash
480
- # PreToolUse: deny via JSON
481
- echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"reason"}}'
566
+ #### Cursor Hooks
567
+
568
+ Defined in \`hooks.json\` \u2014 not in frontmatter. Project-level (\`.cursor/hooks.json\`) or user-level (\`~/.cursor/hooks.json\`). Supports both command-based and prompt-based (LLM evaluation) handlers.
482
569
 
483
- # Stop/PostToolUse: block via JSON
484
- echo '{"decision":"block","reason":"Tests must pass first"}'
570
+ \`\`\`json
571
+ {
572
+ "version": 1,
573
+ "hooks": {
574
+ "afterFileEdit": [{ "command": ".cursor/hooks/format.sh" }],
575
+ "beforeShellExecution": [
576
+ { "command": ".cursor/hooks/approve.sh", "matcher": "curl|wget", "timeout": 30 }
577
+ ],
578
+ "stop": [{ "command": ".cursor/hooks/audit.sh", "loop_limit": 10 }],
579
+ "beforeReadFile": [{ "command": ".cursor/hooks/redact.sh", "failClosed": true }],
580
+ "preToolUse": [
581
+ { "type": "prompt", "prompt": "Is this tool call safe?", "matcher": "Shell" }
582
+ ]
583
+ }
584
+ }
485
585
  \`\`\`
486
586
 
487
- ## Usage
587
+ **Agent Events**
488
588
 
489
- \`\`\`bash
490
- # Scaffold this repo's directory structure
491
- set-prompt scaffold .
589
+ | Event | Matcher | Can Block | When it fires |
590
+ |-------|---------|:---------:|---------------|
591
+ | \`sessionStart\` | \u2014 | No | New conversation created |
592
+ | \`sessionEnd\` | \u2014 | No | Conversation ends |
593
+ | \`preToolUse\` | tool type | Yes | Before any tool runs |
594
+ | \`postToolUse\` | tool type | No | After a tool succeeds |
595
+ | \`postToolUseFailure\` | tool type | No | After a tool fails/times out |
596
+ | \`subagentStart\` | agent type | Yes | Before sub-agent spawns |
597
+ | \`subagentStop\` | agent type | Yes\\* | Sub-agent completes (\\*followup_message) |
598
+ | \`beforeShellExecution\` | command text | Yes | Before shell command runs |
599
+ | \`afterShellExecution\` | \u2014 | No | After shell command completes |
600
+ | \`beforeMCPExecution\` | \u2014 | Yes | Before MCP tool runs |
601
+ | \`afterMCPExecution\` | \u2014 | No | After MCP tool completes |
602
+ | \`beforeReadFile\` | tool type | Yes | Before file read |
603
+ | \`afterFileEdit\` | tool type | No | After file is edited |
604
+ | \`beforeSubmitPrompt\` | \u2014 | Yes | Before prompt sent to backend |
605
+ | \`preCompact\` | \u2014 | No | Before context compaction (observe only) |
606
+ | \`stop\` | \u2014 | Yes\\* | Agent loop ends (\\*followup_message) |
607
+ | \`afterAgentResponse\` | \u2014 | No | After assistant message |
608
+ | \`afterAgentThought\` | \u2014 | No | After thinking block |
492
609
 
493
- # Install from remote and link to AI tools
494
- set-prompt install https://github.com/you/my-prompts
495
- set-prompt link
610
+ **Tab Events** (inline autocomplete only)
496
611
 
497
- # Pull latest changes
498
- set-prompt update
612
+ | Event | When it fires |
613
+ |-------|---------------|
614
+ | \`beforeTabFileRead\` | Before Tab reads a file |
615
+ | \`afterTabFileEdit\` | After Tab edits a file |
616
+
617
+ **Handler fields**
618
+
619
+ | Field | Type | Default | Description |
620
+ |-------|------|---------|-------------|
621
+ | \`command\` | string | required | Script path or shell command |
622
+ | \`type\` | string | \`"command"\` | \`"command"\` or \`"prompt"\` (LLM evaluation) |
623
+ | \`timeout\` | number | platform default | Execution timeout in seconds |
624
+ | \`matcher\` | string | \u2014 | Regex filter for when the hook fires |
625
+ | \`loop_limit\` | number\\|null | \`5\` | Max auto-followups for stop/subagentStop. \`null\` = unlimited |
626
+ | \`failClosed\` | boolean | \`false\` | \`true\` = block on hook failure instead of fail-open |
627
+
628
+ Full event list: [Cursor hooks reference](https://cursor.com/docs/hooks)
629
+
630
+ ---
631
+
632
+ **Decision control** (both platforms)
633
+
634
+ Exit \`0\` = allow. Exit \`2\` = block. Claude Code reads stderr as the reason. Cursor uses JSON stdout:
635
+
636
+ \`\`\`bash
637
+ # Claude Code: deny via JSON
638
+ echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"reason"}}'
639
+
640
+ # Cursor: deny via JSON
641
+ echo '{"permission":"deny","user_message":"Blocked by policy","agent_message":"Not allowed"}'
499
642
  \`\`\`
643
+
500
644
  `;
501
645
 
502
646
  // src/commands/scaffold-command.ts
503
- var REQUIRED_DIRS = ["skills", "commands"];
504
- var OPTIONAL_DIRS = ["hooks", "agents"];
505
- var printStructure = async (localPath) => {
506
- let valid = true;
507
- for (const dir of REQUIRED_DIRS) {
508
- const exists = fs2.existsSync(path2.join(localPath, dir));
509
- if (exists) {
510
- console.log(`${TAB}\u2705 ${dir}/`);
511
- } else {
512
- console.log(`${TAB}\u274C ${dir}/ ${chalk2.red("(missing)")}`);
513
- valid = false;
514
- }
647
+ var ensureClaudePluginManifest = (repoPath) => {
648
+ const metaDir = path2.join(repoPath, ".claude-plugin");
649
+ const jsonPath = path2.join(metaDir, "plugin.json");
650
+ fs2.mkdirSync(metaDir, { recursive: true });
651
+ fs2.writeFileSync(jsonPath, JSON.stringify({
652
+ name: PLUGIN_NAME,
653
+ version: "1.0.0",
654
+ description: `Managed by set-prompt \u2014 ${repoPath}`
655
+ }, null, 4), { encoding: "utf-8" });
656
+ };
657
+ var ensureCodexPluginManifest = (repoPath) => {
658
+ const metaDir = path2.join(repoPath, ".codex-plugin");
659
+ const jsonPath = path2.join(metaDir, "plugin.json");
660
+ fs2.mkdirSync(metaDir, { recursive: true });
661
+ fs2.writeFileSync(jsonPath, JSON.stringify({
662
+ name: PLUGIN_NAME,
663
+ version: "1.0.0",
664
+ description: `Managed by set-prompt \u2014 ${repoPath}`,
665
+ skills: "./skills/",
666
+ mcpServers: "./mcp.json",
667
+ apps: "./.app.json"
668
+ }, null, 4), { encoding: "utf-8" });
669
+ };
670
+ var ensureMcpJson = (repoPath) => {
671
+ const mcpJsonPath = path2.join(repoPath, "mcp.json");
672
+ if (fs2.existsSync(mcpJsonPath)) {
673
+ return false;
515
674
  }
516
- for (const dir of OPTIONAL_DIRS) {
517
- const exists = fs2.existsSync(path2.join(localPath, dir));
518
- console.log(`${TAB}${chalk2.dim(exists ? "\u2713" : "\u25CB")} ${dir}/ ${exists ? "" : chalk2.dim("(optional)")}`);
675
+ fs2.writeFileSync(mcpJsonPath, JSON.stringify({ mcpServers: {} }, null, 4), { encoding: "utf-8" });
676
+ return true;
677
+ };
678
+ var ensureAppJson = (repoPath) => {
679
+ const appJsonPath = path2.join(repoPath, ".app.json");
680
+ if (fs2.existsSync(appJsonPath)) {
681
+ return false;
519
682
  }
520
- return valid;
683
+ fs2.writeFileSync(appJsonPath, JSON.stringify({ apps: {} }, null, 4), { encoding: "utf-8" });
684
+ return true;
521
685
  };
522
- var scaffoldCommand = async (localPath, options = {}) => {
686
+ var scaffoldCommand = async (localPath) => {
523
687
  try {
524
688
  let targetPath = null;
525
689
  if (localPath != null) {
@@ -528,61 +692,48 @@ var scaffoldCommand = async (localPath, options = {}) => {
528
692
  if (configManager.repo_path != null) {
529
693
  targetPath = configManager.repo_path;
530
694
  } else {
531
- console.error(chalk2.red("No path provided and no repo registered. Please provide a path."));
695
+ console.error(chalk3.red("No path provided and no repo registered. Please provide a path."));
532
696
  process.exit(1);
533
697
  }
534
698
  }
535
699
  if (fs2.existsSync(targetPath) === false || fs2.statSync(targetPath).isDirectory() === false) {
536
- console.error(chalk2.red(`Invalid directory path: '${targetPath}'`));
700
+ console.error(chalk3.red(`Invalid directory path: '${targetPath}'`));
537
701
  process.exit(1);
538
702
  }
539
- if (options.force !== true) {
540
- console.log(chalk2.dim(`Checking repo structure at: ${targetPath}`));
541
- }
542
- const valid = options.force === true ? false : await printStructure(targetPath);
543
- if (valid) {
544
- console.log(chalk2.green("Repo structure is valid."));
545
- return true;
546
- }
547
- if (!valid) {
548
- if (options.force !== true) {
549
- const proceed = await confirm({
550
- message: "Some directories are missing. Scaffold them now?",
551
- default: true
552
- });
553
- if (proceed === false) {
554
- console.log(chalk2.yellow("Scaffold skipped."));
555
- return false;
556
- }
557
- }
558
- const created = [];
703
+ console.log(chalk3.dim(`Scaffolding: ${targetPath}
704
+ `));
705
+ const writeGuide = await confirm({
706
+ message: "Generate SET_PROMPT_GUIDE.md? (reference doc for writing prompts)",
707
+ default: true
708
+ });
709
+ if (writeGuide) {
559
710
  const guideMdPath = path2.join(targetPath, "SET_PROMPT_GUIDE.md");
560
711
  fs2.writeFileSync(guideMdPath, SET_PROMPT_GUIDE, { encoding: "utf-8", flag: "w" });
561
- created.push(" SET_PROMPT_GUIDE.md");
562
- for (const dirName of PROMPT_DIR_NAMES) {
563
- const dirPath = path2.join(targetPath, dirName);
564
- if (fs2.existsSync(dirPath)) {
565
- console.warn(chalk2.yellow(`Directory already exists: '${dirName}' (skipping)`));
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
- }
576
- }
712
+ console.log(`${TAB}${chalk3.green("\u2713")} SET_PROMPT_GUIDE.md`);
713
+ }
714
+ for (const dirName of PROMPT_DIR_NAMES) {
715
+ const dirPath = path2.join(targetPath, dirName);
716
+ if (fs2.existsSync(dirPath)) {
717
+ console.log(`${TAB}${chalk3.dim("\u2713")} ${dirName}/`);
718
+ } else {
719
+ fs2.mkdirSync(dirPath, { recursive: true });
720
+ console.log(`${TAB}${chalk3.green("+")} ${dirName}/`);
577
721
  }
578
- if (created.length > 0) {
579
- console.log(chalk2.green("Created:"));
580
- created.forEach((line) => console.log(line));
722
+ const gitkeepPath = path2.join(dirPath, ".gitkeep");
723
+ if (!fs2.existsSync(gitkeepPath)) {
724
+ fs2.writeFileSync(gitkeepPath, "", { encoding: "utf-8" });
581
725
  }
582
726
  }
727
+ ensureClaudePluginManifest(targetPath);
728
+ console.log(`${TAB}${chalk3.green("\u2713")} .claude-plugin/plugin.json`);
729
+ ensureCodexPluginManifest(targetPath);
730
+ console.log(`${TAB}${chalk3.green("\u2713")} .codex-plugin/plugin.json`);
731
+ console.log(`${TAB}${ensureMcpJson(targetPath) ? chalk3.green("+") : chalk3.dim("\u2713")} mcp.json`);
732
+ console.log(`${TAB}${ensureAppJson(targetPath) ? chalk3.green("+") : chalk3.dim("\u2713")} .app.json`);
733
+ console.log(chalk3.green("\nScaffold complete."));
583
734
  return true;
584
735
  } catch (ex) {
585
- console.error(chalk2.red(`Failed to scaffold repo structure: ${ex.message}`), ex);
736
+ console.error(chalk3.red(`Failed to scaffold repo structure: ${ex.message}`), ex);
586
737
  throw ex;
587
738
  }
588
739
  };
@@ -596,13 +747,13 @@ var cloneRepo = async (remoteUrl) => {
596
747
  backupPath = path3.join(HOME_DIR, `repo.bak.${timestamp}`);
597
748
  try {
598
749
  fs3.renameSync(localPath, backupPath);
599
- console.log(chalk3.yellow(" backed up") + chalk3.dim(` existing repo \u2192 ${backupPath}`));
750
+ console.log(chalk4.yellow(" backed up") + chalk4.dim(` existing repo \u2192 ${backupPath}`));
600
751
  } catch (ex) {
601
752
  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}`));
753
+ console.error(chalk4.red("\u274C Cannot rename existing repo \u2014 it may be open in another process."));
754
+ console.log(chalk4.dim(` Close any editors or terminals using: ${localPath}`));
604
755
  } else {
605
- console.error(chalk3.red(`\u274C Failed to backup existing repo: ${ex.message}`));
756
+ console.error(chalk4.red(`\u274C Failed to backup existing repo: ${ex.message}`));
606
757
  }
607
758
  return false;
608
759
  }
@@ -617,13 +768,13 @@ var cloneRepo = async (remoteUrl) => {
617
768
  console.log("\u2705 Cloned successfully.");
618
769
  if (backupPath != null) {
619
770
  fs3.rmSync(backupPath, { recursive: true, force: true });
620
- console.log(chalk3.red(" removed") + chalk3.dim(` backup \u2192 ${backupPath}`));
771
+ console.log(chalk4.red(" removed") + chalk4.dim(` backup \u2192 ${backupPath}`));
621
772
  }
622
773
  await scaffoldCommand(localPath, { force: true });
623
774
  configManager.repo_path = localPath;
624
775
  configManager.remote_url = remoteUrl;
625
776
  if (configManager.save() === false) {
626
- console.error(chalk3.red("Failed to save config."));
777
+ console.error(chalk4.red("Failed to save config."));
627
778
  return false;
628
779
  }
629
780
  return true;
@@ -631,62 +782,54 @@ var cloneRepo = async (remoteUrl) => {
631
782
  var installCommand = async (target) => {
632
783
  try {
633
784
  if (isGitUrl(target) === false) {
634
- console.error(chalk3.red("\u274C Only remote git URLs are supported."));
635
- console.log(chalk3.dim(" Example: set-prompt install https://github.com/you/my-prompts"));
785
+ console.error(chalk4.red("\u274C Only remote git URLs are supported."));
786
+ console.log(chalk4.dim(" Example: set-prompt install https://github.com/you/my-prompts"));
636
787
  process.exit(1);
637
788
  }
638
789
  const normalizeUrl = (url) => url.replace(/\.git$/, "").toLowerCase();
639
790
  if (configManager.repo_path != null) {
640
791
  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."));
792
+ console.error(chalk4.red(`\u274C Already installed from the same URL: ${target}`));
793
+ console.log(chalk4.dim(" Use `set-prompt update` to pull the latest changes."));
643
794
  return false;
644
795
  }
645
- console.warn(chalk3.yellow(`\u26A0 Switching repo: ${configManager.remote_url} \u2192 ${target}`));
796
+ console.warn(chalk4.yellow(`\u26A0 Switching repo: ${configManager.remote_url} \u2192 ${target}`));
646
797
  const proceed = await confirm2({ message: "Replace existing installation?", default: false });
647
798
  if (!proceed) {
648
- console.log(chalk3.yellow("Cancelled."));
799
+ console.log(chalk4.yellow("Cancelled."));
649
800
  return false;
650
801
  }
651
802
  } else {
652
803
  const proceed = await confirm2({ message: `Clone and register "${target}"?`, default: true });
653
804
  if (!proceed) {
654
- console.log(chalk3.yellow("Cancelled."));
805
+ console.log(chalk4.yellow("Cancelled."));
655
806
  return false;
656
807
  }
657
808
  }
658
809
  return await cloneRepo(target);
659
810
  } catch (ex) {
660
- console.error(chalk3.red(`Unexpected error: ${ex.message}`), ex);
811
+ console.error(chalk4.red(`Unexpected error: ${ex.message}`), ex);
661
812
  process.exit(1);
662
813
  }
663
814
  };
664
815
 
665
816
  // src/commands/link-command.ts
817
+ import chalk11 from "chalk";
818
+ import { checkbox } from "@inquirer/prompts";
819
+
820
+ // src/link/claudecode.ts
666
821
  import path4 from "path";
667
822
  import fs4 from "fs";
668
823
  import os2 from "os";
669
- import chalk4 from "chalk";
670
- import { confirm as confirm3, checkbox } from "@inquirer/prompts";
671
- import { pathExists } from "fs-extra";
672
- var resolveRepoPath = () => {
673
- if (configManager.repo_path == null) {
674
- console.error(chalk4.red("\u274C No repo installed."));
675
- console.log(chalk4.yellow("Run: set-prompt install <git-url>"));
676
- return null;
677
- }
678
- return configManager.repo_path;
679
- };
680
- var MARKET_NAME = "set-prompt";
681
- var PLUGIN_NAME = "sppt";
824
+ import chalk5 from "chalk";
825
+ import { confirm as confirm3 } from "@inquirer/prompts";
682
826
  var linkClaudeCode = async () => {
683
827
  const repoPath = resolveRepoPath();
684
828
  if (repoPath == null) {
685
829
  return;
686
830
  }
687
- const setClaudeCodeAssets = async () => {
831
+ const buildMarketplace = () => {
688
832
  try {
689
- fs4.mkdirSync(CLAUDE_CODE_DIR, { recursive: true });
690
833
  const marketplaceMetaDir = path4.join(CLAUDE_CODE_DIR, ".claude-plugin");
691
834
  fs4.mkdirSync(marketplaceMetaDir, { recursive: true });
692
835
  const marketplaceJson = {
@@ -697,52 +840,23 @@ var linkClaudeCode = async () => {
697
840
  };
698
841
  fs4.writeFileSync(
699
842
  path4.join(marketplaceMetaDir, "marketplace.json"),
700
- JSON.stringify(marketplaceJson, null, 2),
701
- "utf-8"
702
- );
703
- console.log(chalk4.dim(" \u251C\u2500\u2500 .claude-plugin/"));
704
- console.log(chalk4.dim(" \u2502 \u2514\u2500\u2500 marketplace.json") + chalk4.green(" \u2713"));
705
- const pluginDir = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
706
- fs4.mkdirSync(pluginDir, { recursive: true });
707
- console.log(chalk4.dim(" \u2514\u2500\u2500 plugins/"));
708
- console.log(chalk4.dim(` \u2514\u2500\u2500 ${PLUGIN_NAME}/`));
709
- const pluginMetaDir = path4.join(pluginDir, ".claude-plugin");
710
- fs4.mkdirSync(pluginMetaDir, { recursive: true });
711
- const pluginJson = {
712
- name: PLUGIN_NAME,
713
- version: "1.0.0",
714
- description: "Managed by set-prompt",
715
- author: { name: path4.basename(repoPath) }
716
- };
717
- fs4.writeFileSync(
718
- path4.join(pluginMetaDir, "plugin.json"),
719
- JSON.stringify(pluginJson, null, 2),
843
+ JSON.stringify(marketplaceJson, null, 4),
720
844
  "utf-8"
721
845
  );
722
- console.log(chalk4.dim(" \u251C\u2500\u2500 .claude-plugin/"));
723
- console.log(chalk4.dim(" \u2502 \u2514\u2500\u2500 plugin.json") + chalk4.green(" \u2713"));
724
- const linked = [];
725
- for (const dir of AGENT_PROMPT_DIRS["claudecode" /* CLAUDECODE */]) {
726
- const src = path4.join(repoPath, dir);
727
- const dest = path4.join(pluginDir, dir);
728
- if (await pathExists(src) === false) {
729
- continue;
730
- }
731
- if (fs4.existsSync(dest)) {
732
- fs4.rmSync(dest, { recursive: true, force: true });
733
- }
734
- const symlinkType = process.platform === "win32" ? "junction" : "dir";
735
- fs4.symlinkSync(src, dest, symlinkType);
736
- linked.push({ dir, src });
737
- }
738
- for (const { dir, src } of linked) {
739
- const isLast = linked[linked.length - 1].dir === dir;
740
- const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
741
- console.log(chalk4.dim(` ${branch} `) + chalk4.bold(`${dir}/`) + chalk4.dim(` \u2192 ${src}`) + chalk4.green(" \u2713"));
846
+ console.log(chalk5.dim(" \u251C\u2500\u2500 .claude-plugin/"));
847
+ console.log(chalk5.dim(" \u2502 \u2514\u2500\u2500 marketplace.json") + chalk5.green(" \u2713"));
848
+ const pluginLink = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
849
+ fs4.mkdirSync(path4.dirname(pluginLink), { recursive: true });
850
+ if (fs4.existsSync(pluginLink)) {
851
+ fs4.rmSync(pluginLink, { recursive: true, force: true });
742
852
  }
853
+ const symlinkType = process.platform === "win32" ? "junction" : "dir";
854
+ fs4.symlinkSync(repoPath, pluginLink, symlinkType);
855
+ console.log(chalk5.dim(" \u2514\u2500\u2500 plugins/"));
856
+ console.log(chalk5.dim(` \u2514\u2500\u2500 ${PLUGIN_NAME}/`) + chalk5.dim(` \u2192 ${repoPath}`) + chalk5.green(" \u2713"));
743
857
  return true;
744
858
  } catch (ex) {
745
- console.error(chalk4.red(`\u274C Failed to build plugin structure: ${ex.message}`));
859
+ console.error(chalk5.red(`\u274C Failed to build marketplace structure: ${ex.message}`));
746
860
  return false;
747
861
  }
748
862
  };
@@ -757,11 +871,11 @@ var linkClaudeCode = async () => {
757
871
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
758
872
  settings = parsed;
759
873
  } else {
760
- console.warn(chalk4.yellow(" \u26A0 settings.json has unexpected format \u2014 proceeding with caution"));
874
+ console.warn(chalk5.yellow(" \u26A0 settings.json has unexpected format \u2014 proceeding with caution"));
761
875
  }
762
876
  } catch {
763
- console.warn(chalk4.yellow(" \u26A0 Failed to parse settings.json \u2014 will not overwrite existing file"));
764
- console.error(chalk4.red("\u274C Could not register plugin. Please add manually."));
877
+ console.warn(chalk5.yellow(" \u26A0 Failed to parse settings.json \u2014 will not overwrite existing file"));
878
+ console.error(chalk5.red("\u274C Could not register plugin. Please add manually."));
765
879
  return false;
766
880
  }
767
881
  }
@@ -780,21 +894,21 @@ var linkClaudeCode = async () => {
780
894
  try {
781
895
  fs4.copyFileSync(claudeSettingsPath, backupPath);
782
896
  } catch (ex) {
783
- console.warn(chalk4.yellow(` \u26A0 Could not create backup: ${ex.message}`));
897
+ console.warn(chalk5.yellow(` \u26A0 Could not create backup: ${ex.message}`));
784
898
  backupPath = null;
785
899
  }
786
900
  }
787
901
  try {
788
902
  fs4.mkdirSync(path4.dirname(claudeSettingsPath), { recursive: true });
789
- fs4.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
903
+ fs4.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 4), "utf-8");
790
904
  } catch (ex) {
791
905
  if (backupPath !== null) {
792
906
  try {
793
907
  fs4.copyFileSync(backupPath, claudeSettingsPath);
794
908
  fs4.unlinkSync(backupPath);
795
- console.warn(chalk4.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
909
+ console.warn(chalk5.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
796
910
  } catch {
797
- console.error(chalk4.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
911
+ console.error(chalk5.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
798
912
  }
799
913
  }
800
914
  throw ex;
@@ -806,16 +920,16 @@ var linkClaudeCode = async () => {
806
920
  }
807
921
  }
808
922
  console.log(`\u2705 Registered to Claude Code settings.`);
809
- console.log(chalk4.dim(` ${claudeSettingsPath}`));
923
+ console.log(chalk5.dim(` ${claudeSettingsPath}`));
810
924
  return true;
811
925
  } catch (ex) {
812
- console.error(chalk4.red(`\u274C Failed to update settings.json: ${ex.message}`));
813
- console.log(chalk4.dim(" Please add the plugin manually via Claude Code /plugins."));
926
+ console.error(chalk5.red(`\u274C Failed to update settings.json: ${ex.message}`));
927
+ console.log(chalk5.dim(" Please add the plugin manually via Claude Code /plugins."));
814
928
  return false;
815
929
  }
816
930
  };
817
931
  const patchInstalledPlugins = () => {
818
- const installPath = path4.join(CLAUDE_CODE_DIR, "plugins", PLUGIN_NAME);
932
+ const installPath = repoPath;
819
933
  const installedPluginsPath = path4.join(os2.homedir(), ".claude", "plugins", "installed_plugins.json");
820
934
  const pluginKey = `${PLUGIN_NAME}@${MARKET_NAME}`;
821
935
  try {
@@ -839,18 +953,18 @@ var linkClaudeCode = async () => {
839
953
  }
840
954
  ];
841
955
  fs4.mkdirSync(path4.dirname(installedPluginsPath), { recursive: true });
842
- fs4.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 2), "utf-8");
956
+ fs4.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 4), "utf-8");
843
957
  console.log(`\u2705 Patched installed_plugins.json \u2192 installPath points to source.`);
844
- console.log(chalk4.dim(` ${installPath}`));
958
+ console.log(chalk5.dim(` ${installPath}`));
845
959
  } catch (ex) {
846
- console.warn(chalk4.yellow(` \u26A0 Could not patch installed_plugins.json: ${ex.message}`));
960
+ console.warn(chalk5.yellow(` \u26A0 Could not patch installed_plugins.json: ${ex.message}`));
847
961
  }
848
962
  };
849
- console.log(chalk4.green(`
963
+ console.log(chalk5.green(`
850
964
  Setting up Claude Code plugin...`));
851
- console.log(chalk4.dim(CLAUDE_CODE_DIR));
852
- const structureOk = await setClaudeCodeAssets();
853
- if (structureOk === false) {
965
+ console.log(chalk5.dim(CLAUDE_CODE_DIR));
966
+ const marketplaceOk = buildMarketplace();
967
+ if (marketplaceOk === false) {
854
968
  return;
855
969
  }
856
970
  const settingsOk = registerToClaudeSettings();
@@ -861,49 +975,154 @@ Setting up Claude Code plugin...`));
861
975
  configManager.claude_code = { path: CLAUDE_CODE_DIR };
862
976
  configManager.save();
863
977
  };
978
+ var unlinkClaudeCode = async (force = false) => {
979
+ if (!force) {
980
+ const ok = await confirm3({
981
+ message: `Remove Claude Code plugin dir (${CLAUDE_CODE_DIR}) and settings entries?`,
982
+ default: false
983
+ });
984
+ if (!ok) {
985
+ console.log(chalk5.yellow("Cancelled."));
986
+ return;
987
+ }
988
+ }
989
+ console.log(chalk5.red(`
990
+ Removing Claude Code plugin...`));
991
+ console.log(chalk5.dim(CLAUDE_CODE_DIR));
992
+ const claudeSettingsPath = path4.join(os2.homedir(), ".claude", "settings.json");
993
+ if (fs4.existsSync(claudeSettingsPath)) {
994
+ try {
995
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
996
+ const backupPath = `${claudeSettingsPath}.bak.${timestamp}`;
997
+ fs4.copyFileSync(claudeSettingsPath, backupPath);
998
+ const settings = JSON.parse(fs4.readFileSync(claudeSettingsPath, "utf-8"));
999
+ if (settings?.extraKnownMarketplaces?.[MARKET_NAME] !== void 0) {
1000
+ delete settings.extraKnownMarketplaces[MARKET_NAME];
1001
+ }
1002
+ if (settings?.enabledPlugins?.[`${PLUGIN_NAME}@${MARKET_NAME}`] !== void 0) {
1003
+ delete settings.enabledPlugins[`${PLUGIN_NAME}@${MARKET_NAME}`];
1004
+ }
1005
+ try {
1006
+ fs4.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 4), "utf-8");
1007
+ fs4.unlinkSync(backupPath);
1008
+ console.log(chalk5.red(" removed") + chalk5.dim(` set-prompt entries from: ${claudeSettingsPath}`));
1009
+ } catch (ex) {
1010
+ fs4.copyFileSync(backupPath, claudeSettingsPath);
1011
+ fs4.unlinkSync(backupPath);
1012
+ console.warn(chalk5.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
1013
+ }
1014
+ } catch (ex) {
1015
+ console.error(chalk5.red(` \u274C Failed to clean up settings.json: ${ex.message}`));
1016
+ }
1017
+ }
1018
+ const claudePluginsDir = path4.join(os2.homedir(), ".claude", "plugins");
1019
+ const installedPluginsPath = path4.join(claudePluginsDir, "installed_plugins.json");
1020
+ if (fs4.existsSync(installedPluginsPath)) {
1021
+ try {
1022
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1023
+ const backupPath = `${installedPluginsPath}.bak.${timestamp}`;
1024
+ fs4.copyFileSync(installedPluginsPath, backupPath);
1025
+ const installed = JSON.parse(fs4.readFileSync(installedPluginsPath, "utf-8"));
1026
+ if (installed?.plugins && typeof installed.plugins === "object") {
1027
+ for (const key of Object.keys(installed.plugins)) {
1028
+ if (key.endsWith(`@${MARKET_NAME}`)) {
1029
+ delete installed.plugins[key];
1030
+ }
1031
+ }
1032
+ }
1033
+ try {
1034
+ fs4.writeFileSync(installedPluginsPath, JSON.stringify(installed, null, 4), "utf-8");
1035
+ fs4.unlinkSync(backupPath);
1036
+ console.log(chalk5.red(" removed") + chalk5.dim(` set-prompt entries from: ${installedPluginsPath}`));
1037
+ } catch (ex) {
1038
+ fs4.copyFileSync(backupPath, installedPluginsPath);
1039
+ fs4.unlinkSync(backupPath);
1040
+ console.warn(chalk5.yellow(" \u26A0 Write failed \u2014 rolled back installed_plugins.json."));
1041
+ }
1042
+ } catch (ex) {
1043
+ console.error(chalk5.red(` \u274C Failed to clean up installed_plugins.json: ${ex.message}`));
1044
+ }
1045
+ }
1046
+ const knownMarketplacesPath = path4.join(claudePluginsDir, "known_marketplaces.json");
1047
+ if (fs4.existsSync(knownMarketplacesPath)) {
1048
+ try {
1049
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1050
+ const backupPath = `${knownMarketplacesPath}.bak.${timestamp}`;
1051
+ fs4.copyFileSync(knownMarketplacesPath, backupPath);
1052
+ const marketplaces = JSON.parse(fs4.readFileSync(knownMarketplacesPath, "utf-8"));
1053
+ if (marketplaces?.[MARKET_NAME] !== void 0) {
1054
+ delete marketplaces[MARKET_NAME];
1055
+ }
1056
+ try {
1057
+ fs4.writeFileSync(knownMarketplacesPath, JSON.stringify(marketplaces, null, 4), "utf-8");
1058
+ fs4.unlinkSync(backupPath);
1059
+ console.log(chalk5.red(" removed") + chalk5.dim(` set-prompt entry from: ${knownMarketplacesPath}`));
1060
+ } catch (ex) {
1061
+ fs4.copyFileSync(backupPath, knownMarketplacesPath);
1062
+ fs4.unlinkSync(backupPath);
1063
+ console.warn(chalk5.yellow(" \u26A0 Write failed \u2014 rolled back known_marketplaces.json."));
1064
+ }
1065
+ } catch (ex) {
1066
+ console.error(chalk5.red(` \u274C Failed to clean up known_marketplaces.json: ${ex.message}`));
1067
+ }
1068
+ }
1069
+ if (fs4.existsSync(CLAUDE_CODE_DIR)) {
1070
+ fs4.rmSync(CLAUDE_CODE_DIR, { recursive: true, force: true });
1071
+ console.log(chalk5.red(" removed") + chalk5.dim(`: ${CLAUDE_CODE_DIR}`));
1072
+ }
1073
+ configManager.claude_code = null;
1074
+ configManager.save();
1075
+ };
1076
+
1077
+ // src/link/roocode.ts
1078
+ import path5 from "path";
1079
+ import fs5 from "fs";
1080
+ import chalk6 from "chalk";
1081
+ import { confirm as confirm4 } from "@inquirer/prompts";
1082
+ import { pathExists } from "fs-extra";
864
1083
  var linkRooCode = async () => {
865
1084
  const repoPath = resolveRepoPath();
866
1085
  if (repoPath == null) {
867
1086
  return;
868
1087
  }
869
- console.log(chalk4.green(`
1088
+ console.log(chalk6.green(`
870
1089
  Setting up RooCode integration...`));
871
- console.log(chalk4.dim(ROO_DIR));
1090
+ console.log(chalk6.dim(ROO_DIR));
872
1091
  const roocodeDirs = AGENT_PROMPT_DIRS["roocode" /* ROOCODE */];
873
1092
  const backupExistingRooCodeFiles = async () => {
874
1093
  try {
875
- fs4.mkdirSync(ROO_DIR, { recursive: true });
1094
+ fs5.mkdirSync(ROO_DIR, { recursive: true });
876
1095
  const dirsToBackup = [];
877
1096
  for (const dir of roocodeDirs) {
878
- const target = path4.join(ROO_DIR, dir);
879
- if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false && fs4.readdirSync(target).length > 0) {
1097
+ const target = path5.join(ROO_DIR, dir);
1098
+ if (fs5.existsSync(target) && fs5.lstatSync(target).isSymbolicLink() === false && fs5.readdirSync(target).length > 0) {
880
1099
  dirsToBackup.push(dir);
881
1100
  }
882
1101
  }
883
1102
  if (dirsToBackup.length === 0) {
884
1103
  return true;
885
1104
  }
886
- console.log(chalk4.yellow(`
1105
+ console.log(chalk6.yellow(`
887
1106
  \u26A0 The following existing directories will be replaced by symlinks:`));
888
1107
  for (const dir of dirsToBackup) {
889
- console.log(chalk4.dim(` - ${path4.join(ROO_DIR, dir)}`));
1108
+ console.log(chalk6.dim(` - ${path5.join(ROO_DIR, dir)}`));
890
1109
  }
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 });
1110
+ console.log(chalk6.yellow(` They will be backed up to: `) + chalk6.dim(ROO_BACKUP_DIR));
1111
+ const ok = await confirm4({ message: "Back up existing directories?", default: true });
893
1112
  if (!ok) {
894
- console.log(chalk4.yellow("Skipped RooCode linking."));
1113
+ console.log(chalk6.yellow("Skipped RooCode linking."));
895
1114
  return false;
896
1115
  }
897
- fs4.mkdirSync(ROO_BACKUP_DIR, { recursive: true });
1116
+ fs5.mkdirSync(ROO_BACKUP_DIR, { recursive: true });
898
1117
  for (const dir of dirsToBackup) {
899
- const src = path4.join(ROO_DIR, dir);
900
- const dest = path4.join(ROO_BACKUP_DIR, dir);
901
- fs4.renameSync(src, dest);
902
- console.log(chalk4.yellow(" backed up") + chalk4.dim(`: ${dir}/ \u2192 ${dest}`));
1118
+ const src = path5.join(ROO_DIR, dir);
1119
+ const dest = path5.join(ROO_BACKUP_DIR, dir);
1120
+ fs5.renameSync(src, dest);
1121
+ console.log(chalk6.yellow(" backed up") + chalk6.dim(`: ${dir}/ \u2192 ${dest}`));
903
1122
  }
904
1123
  return true;
905
1124
  } catch (ex) {
906
- console.error(chalk4.red(`\u274C Failed to backup existing directories: ${ex.message}`));
1125
+ console.error(chalk6.red(`\u274C Failed to backup existing directories: ${ex.message}`));
907
1126
  return false;
908
1127
  }
909
1128
  };
@@ -911,26 +1130,26 @@ Setting up RooCode integration...`));
911
1130
  try {
912
1131
  const linked = [];
913
1132
  for (const dir of roocodeDirs) {
914
- const src = path4.join(repoPath, dir);
915
- const dest = path4.join(ROO_DIR, dir);
1133
+ const src = path5.join(repoPath, dir);
1134
+ const dest = path5.join(ROO_DIR, dir);
916
1135
  if (await pathExists(src) === false) {
917
1136
  continue;
918
1137
  }
919
- if (fs4.existsSync(dest)) {
920
- fs4.rmSync(dest, { recursive: true, force: true });
1138
+ if (fs5.existsSync(dest)) {
1139
+ fs5.rmSync(dest, { recursive: true, force: true });
921
1140
  }
922
1141
  const symlinkType = process.platform === "win32" ? "junction" : "dir";
923
- fs4.symlinkSync(src, dest, symlinkType);
1142
+ fs5.symlinkSync(src, dest, symlinkType);
924
1143
  linked.push({ dir, src });
925
1144
  }
926
1145
  for (const { dir, src } of linked) {
927
1146
  const isLast = linked[linked.length - 1].dir === dir;
928
1147
  const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
929
- console.log(chalk4.dim(` ${branch} `) + chalk4.bold(`${dir}/`) + chalk4.dim(` \u2192 ${src}`) + chalk4.green(" \u2713"));
1148
+ console.log(chalk6.dim(` ${branch} `) + chalk6.bold(`${dir}/`) + chalk6.dim(` \u2192 ${src}`) + chalk6.green(" \u2713"));
930
1149
  }
931
1150
  return true;
932
1151
  } catch (ex) {
933
- console.error(chalk4.red(`\u274C Failed to create symlinks: ${ex.message}`));
1152
+ console.error(chalk6.red(`\u274C Failed to create symlinks: ${ex.message}`));
934
1153
  return false;
935
1154
  }
936
1155
  };
@@ -945,49 +1164,97 @@ Setting up RooCode integration...`));
945
1164
  configManager.roocode = { path: ROO_DIR, backup_path: ROO_BACKUP_DIR };
946
1165
  configManager.save();
947
1166
  };
1167
+ var unlinkRooCode = async (force = false) => {
1168
+ if (!force) {
1169
+ const ok = await confirm4({
1170
+ message: `Remove RooCode symlinks from ${ROO_DIR}?`,
1171
+ default: false
1172
+ });
1173
+ if (!ok) {
1174
+ console.log(chalk6.yellow("Cancelled."));
1175
+ return;
1176
+ }
1177
+ }
1178
+ console.log(chalk6.red(`
1179
+ Removing RooCode integration...`));
1180
+ console.log(chalk6.dim(ROO_DIR));
1181
+ const backupPath = configManager.roocode?.backup_path ?? ROO_BACKUP_DIR;
1182
+ for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
1183
+ const target = path5.join(ROO_DIR, dir);
1184
+ if (fs5.existsSync(target) && fs5.lstatSync(target).isSymbolicLink()) {
1185
+ fs5.unlinkSync(target);
1186
+ console.log(chalk6.red(" removed symlink") + chalk6.dim(`: ${target}`));
1187
+ }
1188
+ }
1189
+ if (fs5.existsSync(backupPath)) {
1190
+ try {
1191
+ for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
1192
+ const src = path5.join(backupPath, dir);
1193
+ const dest = path5.join(ROO_DIR, dir);
1194
+ if (!fs5.existsSync(src)) {
1195
+ continue;
1196
+ }
1197
+ fs5.renameSync(src, dest);
1198
+ console.log(chalk6.green(" restored") + chalk6.dim(`: ${dir}/`));
1199
+ }
1200
+ fs5.rmdirSync(backupPath);
1201
+ } catch (ex) {
1202
+ console.error(chalk6.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
1203
+ }
1204
+ }
1205
+ configManager.roocode = null;
1206
+ configManager.save();
1207
+ };
1208
+
1209
+ // src/link/openclaw.ts
1210
+ import path6 from "path";
1211
+ import fs6 from "fs";
1212
+ import chalk7 from "chalk";
1213
+ import { confirm as confirm5 } from "@inquirer/prompts";
1214
+ import { pathExists as pathExists2 } from "fs-extra";
948
1215
  var linkOpenclaw = async () => {
949
1216
  const repoPath = resolveRepoPath();
950
1217
  if (repoPath == null) {
951
1218
  return;
952
1219
  }
953
- console.log(chalk4.green(`
1220
+ console.log(chalk7.green(`
954
1221
  Setting up OpenClaw integration...`));
955
- console.log(chalk4.dim(OPENCLAW_DIR));
1222
+ console.log(chalk7.dim(OPENCLAW_DIR));
956
1223
  const openclawDirs = AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */];
957
1224
  const backupExistingOpenclawFiles = async () => {
958
1225
  try {
959
- fs4.mkdirSync(OPENCLAW_DIR, { recursive: true });
1226
+ fs6.mkdirSync(OPENCLAW_DIR, { recursive: true });
960
1227
  const dirsToBackup = [];
961
1228
  for (const dir of openclawDirs) {
962
- const target = path4.join(OPENCLAW_DIR, dir);
963
- if (fs4.existsSync(target) && fs4.lstatSync(target).isSymbolicLink() === false && fs4.readdirSync(target).length > 0) {
1229
+ const target = path6.join(OPENCLAW_DIR, dir);
1230
+ if (fs6.existsSync(target) && fs6.lstatSync(target).isSymbolicLink() === false && fs6.readdirSync(target).length > 0) {
964
1231
  dirsToBackup.push(dir);
965
1232
  }
966
1233
  }
967
1234
  if (dirsToBackup.length === 0) {
968
1235
  return true;
969
1236
  }
970
- console.log(chalk4.yellow(`
1237
+ console.log(chalk7.yellow(`
971
1238
  \u26A0 The following existing directories will be replaced by symlinks:`));
972
1239
  for (const dir of dirsToBackup) {
973
- console.log(chalk4.dim(` - ${path4.join(OPENCLAW_DIR, dir)}`));
1240
+ console.log(chalk7.dim(` - ${path6.join(OPENCLAW_DIR, dir)}`));
974
1241
  }
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 });
1242
+ console.log(chalk7.yellow(` They will be backed up to: `) + chalk7.dim(OPENCLAW_BACKUP_DIR));
1243
+ const ok = await confirm5({ message: "Back up existing directories?", default: true });
977
1244
  if (!ok) {
978
- console.log(chalk4.yellow("Skipped OpenClaw linking."));
1245
+ console.log(chalk7.yellow("Skipped OpenClaw linking."));
979
1246
  return false;
980
1247
  }
981
- fs4.mkdirSync(OPENCLAW_BACKUP_DIR, { recursive: true });
1248
+ fs6.mkdirSync(OPENCLAW_BACKUP_DIR, { recursive: true });
982
1249
  for (const dir of dirsToBackup) {
983
- const src = path4.join(OPENCLAW_DIR, dir);
984
- const dest = path4.join(OPENCLAW_BACKUP_DIR, dir);
985
- fs4.renameSync(src, dest);
986
- console.log(chalk4.yellow(" backed up") + chalk4.dim(`: ${dir}/ \u2192 ${dest}`));
1250
+ const src = path6.join(OPENCLAW_DIR, dir);
1251
+ const dest = path6.join(OPENCLAW_BACKUP_DIR, dir);
1252
+ fs6.renameSync(src, dest);
1253
+ console.log(chalk7.yellow(" backed up") + chalk7.dim(`: ${dir}/ \u2192 ${dest}`));
987
1254
  }
988
1255
  return true;
989
1256
  } catch (ex) {
990
- console.error(chalk4.red(`\u274C Failed to backup existing directories: ${ex.message}`));
1257
+ console.error(chalk7.red(`\u274C Failed to backup existing directories: ${ex.message}`));
991
1258
  return false;
992
1259
  }
993
1260
  };
@@ -995,26 +1262,26 @@ Setting up OpenClaw integration...`));
995
1262
  try {
996
1263
  const linked = [];
997
1264
  for (const dir of openclawDirs) {
998
- const src = path4.join(repoPath, dir);
999
- const dest = path4.join(OPENCLAW_DIR, dir);
1000
- if (await pathExists(src) === false) {
1265
+ const src = path6.join(repoPath, dir);
1266
+ const dest = path6.join(OPENCLAW_DIR, dir);
1267
+ if (await pathExists2(src) === false) {
1001
1268
  continue;
1002
1269
  }
1003
- if (fs4.existsSync(dest)) {
1004
- fs4.rmSync(dest, { recursive: true, force: true });
1270
+ if (fs6.existsSync(dest)) {
1271
+ fs6.rmSync(dest, { recursive: true, force: true });
1005
1272
  }
1006
1273
  const symlinkType = process.platform === "win32" ? "junction" : "dir";
1007
- fs4.symlinkSync(src, dest, symlinkType);
1274
+ fs6.symlinkSync(src, dest, symlinkType);
1008
1275
  linked.push({ dir, src });
1009
1276
  }
1010
1277
  for (const { dir, src } of linked) {
1011
1278
  const isLast = linked[linked.length - 1].dir === dir;
1012
1279
  const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
1013
- console.log(chalk4.dim(` ${branch} `) + chalk4.bold(`${dir}/`) + chalk4.dim(` \u2192 ${src}`) + chalk4.green(" \u2713"));
1280
+ console.log(chalk7.dim(` ${branch} `) + chalk7.bold(`${dir}/`) + chalk7.dim(` \u2192 ${src}`) + chalk7.green(" \u2713"));
1014
1281
  }
1015
1282
  return true;
1016
1283
  } catch (ex) {
1017
- console.error(chalk4.red(`\u274C Failed to create symlinks: ${ex.message}`));
1284
+ console.error(chalk7.red(`\u274C Failed to create symlinks: ${ex.message}`));
1018
1285
  return false;
1019
1286
  }
1020
1287
  };
@@ -1029,49 +1296,97 @@ Setting up OpenClaw integration...`));
1029
1296
  configManager.openclaw = { path: OPENCLAW_DIR, backup_path: OPENCLAW_BACKUP_DIR };
1030
1297
  configManager.save();
1031
1298
  };
1299
+ var unlinkOpenclaw = async (force = false) => {
1300
+ if (!force) {
1301
+ const ok = await confirm5({
1302
+ message: `Remove OpenClaw symlinks from ${OPENCLAW_DIR}?`,
1303
+ default: false
1304
+ });
1305
+ if (!ok) {
1306
+ console.log(chalk7.yellow("Cancelled."));
1307
+ return;
1308
+ }
1309
+ }
1310
+ console.log(chalk7.red(`
1311
+ Removing OpenClaw integration...`));
1312
+ console.log(chalk7.dim(OPENCLAW_DIR));
1313
+ const backupPath = configManager.openclaw?.backup_path ?? OPENCLAW_BACKUP_DIR;
1314
+ for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
1315
+ const target = path6.join(OPENCLAW_DIR, dir);
1316
+ if (fs6.existsSync(target) && fs6.lstatSync(target).isSymbolicLink()) {
1317
+ fs6.unlinkSync(target);
1318
+ console.log(chalk7.red(" removed symlink") + chalk7.dim(`: ${target}`));
1319
+ }
1320
+ }
1321
+ if (fs6.existsSync(backupPath)) {
1322
+ try {
1323
+ for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
1324
+ const src = path6.join(backupPath, dir);
1325
+ const dest = path6.join(OPENCLAW_DIR, dir);
1326
+ if (!fs6.existsSync(src)) {
1327
+ continue;
1328
+ }
1329
+ fs6.renameSync(src, dest);
1330
+ console.log(chalk7.green(" restored") + chalk7.dim(`: ${dir}/`));
1331
+ }
1332
+ fs6.rmdirSync(backupPath);
1333
+ } catch (ex) {
1334
+ console.error(chalk7.red(` \u274C Failed to restore OpenClaw backup: ${ex.message}`));
1335
+ }
1336
+ }
1337
+ configManager.openclaw = null;
1338
+ configManager.save();
1339
+ };
1340
+
1341
+ // src/link/antigravity.ts
1342
+ import path7 from "path";
1343
+ import fs7 from "fs";
1344
+ import chalk8 from "chalk";
1345
+ import { confirm as confirm6 } from "@inquirer/prompts";
1346
+ import { pathExists as pathExists3 } from "fs-extra";
1032
1347
  var linkAntigravity = async () => {
1033
1348
  const repoPath = resolveRepoPath();
1034
1349
  if (repoPath == null) {
1035
1350
  return;
1036
1351
  }
1037
- console.log(chalk4.green(`
1352
+ console.log(chalk8.green(`
1038
1353
  Setting up Antigravity integration...`));
1039
- console.log(chalk4.dim(ANTIGRAVITY_DIR));
1354
+ console.log(chalk8.dim(ANTIGRAVITY_DIR));
1040
1355
  const antigravityDirs = AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */];
1041
1356
  const backupExistingAntigravityFiles = async () => {
1042
1357
  try {
1043
- fs4.mkdirSync(ANTIGRAVITY_DIR, { recursive: true });
1358
+ fs7.mkdirSync(ANTIGRAVITY_DIR, { recursive: true });
1044
1359
  const dirsToBackup = [];
1045
1360
  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) {
1361
+ const target = path7.join(ANTIGRAVITY_DIR, dir);
1362
+ if (fs7.existsSync(target) && fs7.lstatSync(target).isSymbolicLink() === false && fs7.readdirSync(target).length > 0) {
1048
1363
  dirsToBackup.push(dir);
1049
1364
  }
1050
1365
  }
1051
1366
  if (dirsToBackup.length === 0) {
1052
1367
  return true;
1053
1368
  }
1054
- console.log(chalk4.yellow(`
1369
+ console.log(chalk8.yellow(`
1055
1370
  \u26A0 The following existing directories will be replaced by symlinks:`));
1056
1371
  for (const dir of dirsToBackup) {
1057
- console.log(chalk4.dim(` - ${path4.join(ANTIGRAVITY_DIR, dir)}`));
1372
+ console.log(chalk8.dim(` - ${path7.join(ANTIGRAVITY_DIR, dir)}`));
1058
1373
  }
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 });
1374
+ console.log(chalk8.yellow(` They will be backed up to: `) + chalk8.dim(ANTIGRAVITY_BACKUP_DIR));
1375
+ const ok = await confirm6({ message: "Back up existing directories?", default: true });
1061
1376
  if (!ok) {
1062
- console.log(chalk4.yellow("Skipped Antigravity linking."));
1377
+ console.log(chalk8.yellow("Skipped Antigravity linking."));
1063
1378
  return false;
1064
1379
  }
1065
- fs4.mkdirSync(ANTIGRAVITY_BACKUP_DIR, { recursive: true });
1380
+ fs7.mkdirSync(ANTIGRAVITY_BACKUP_DIR, { recursive: true });
1066
1381
  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}`));
1382
+ const src = path7.join(ANTIGRAVITY_DIR, dir);
1383
+ const dest = path7.join(ANTIGRAVITY_BACKUP_DIR, dir);
1384
+ fs7.renameSync(src, dest);
1385
+ console.log(chalk8.yellow(" backed up") + chalk8.dim(`: ${dir}/ \u2192 ${dest}`));
1071
1386
  }
1072
1387
  return true;
1073
1388
  } catch (ex) {
1074
- console.error(chalk4.red(`\u274C Failed to backup existing directories: ${ex.message}`));
1389
+ console.error(chalk8.red(`\u274C Failed to backup existing directories: ${ex.message}`));
1075
1390
  return false;
1076
1391
  }
1077
1392
  };
@@ -1079,26 +1394,26 @@ Setting up Antigravity integration...`));
1079
1394
  try {
1080
1395
  const linked = [];
1081
1396
  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) {
1397
+ const src = path7.join(repoPath, dir);
1398
+ const dest = path7.join(ANTIGRAVITY_DIR, dir);
1399
+ if (await pathExists3(src) === false) {
1085
1400
  continue;
1086
1401
  }
1087
- if (fs4.existsSync(dest)) {
1088
- fs4.rmSync(dest, { recursive: true, force: true });
1402
+ if (fs7.existsSync(dest)) {
1403
+ fs7.rmSync(dest, { recursive: true, force: true });
1089
1404
  }
1090
1405
  const symlinkType = process.platform === "win32" ? "junction" : "dir";
1091
- fs4.symlinkSync(src, dest, symlinkType);
1406
+ fs7.symlinkSync(src, dest, symlinkType);
1092
1407
  linked.push({ dir, src });
1093
1408
  }
1094
1409
  for (const { dir, src } of linked) {
1095
1410
  const isLast = linked[linked.length - 1].dir === dir;
1096
1411
  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"));
1412
+ console.log(chalk8.dim(` ${branch} `) + chalk8.bold(`${dir}/`) + chalk8.dim(` \u2192 ${src}`) + chalk8.green(" \u2713"));
1098
1413
  }
1099
1414
  return true;
1100
1415
  } catch (ex) {
1101
- console.error(chalk4.red(`\u274C Failed to create symlinks: ${ex.message}`));
1416
+ console.error(chalk8.red(`\u274C Failed to create symlinks: ${ex.message}`));
1102
1417
  return false;
1103
1418
  }
1104
1419
  };
@@ -1113,403 +1428,412 @@ Setting up Antigravity integration...`));
1113
1428
  configManager.antigravity = { path: ANTIGRAVITY_DIR, backup_path: ANTIGRAVITY_BACKUP_DIR };
1114
1429
  configManager.save();
1115
1430
  };
1116
- var linkCodex = async () => {
1117
- console.error(chalk4.red("\u274C Codex integration is not available in this version."));
1118
- return;
1431
+ var unlinkAntigravity = async (force = false) => {
1432
+ if (!force) {
1433
+ const ok = await confirm6({
1434
+ message: `Remove Antigravity symlinks from ${ANTIGRAVITY_DIR}?`,
1435
+ default: false
1436
+ });
1437
+ if (!ok) {
1438
+ console.log(chalk8.yellow("Cancelled."));
1439
+ return;
1440
+ }
1441
+ }
1442
+ console.log(chalk8.red(`
1443
+ Removing Antigravity integration...`));
1444
+ console.log(chalk8.dim(ANTIGRAVITY_DIR));
1445
+ const backupPath = configManager.antigravity?.backup_path ?? ANTIGRAVITY_BACKUP_DIR;
1446
+ for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
1447
+ const target = path7.join(ANTIGRAVITY_DIR, dir);
1448
+ if (fs7.existsSync(target) && fs7.lstatSync(target).isSymbolicLink()) {
1449
+ fs7.unlinkSync(target);
1450
+ console.log(chalk8.red(" removed symlink") + chalk8.dim(`: ${target}`));
1451
+ }
1452
+ }
1453
+ if (fs7.existsSync(backupPath)) {
1454
+ try {
1455
+ for (const dir of AGENT_PROMPT_DIRS["antigravity" /* ANTIGRAVITY */]) {
1456
+ const src = path7.join(backupPath, dir);
1457
+ const dest = path7.join(ANTIGRAVITY_DIR, dir);
1458
+ if (!fs7.existsSync(src)) {
1459
+ continue;
1460
+ }
1461
+ fs7.renameSync(src, dest);
1462
+ console.log(chalk8.green(" restored") + chalk8.dim(`: ${dir}/`));
1463
+ }
1464
+ fs7.rmdirSync(backupPath);
1465
+ } catch (ex) {
1466
+ console.error(chalk8.red(` \u274C Failed to restore Antigravity backup: ${ex.message}`));
1467
+ }
1468
+ }
1469
+ configManager.antigravity = null;
1470
+ configManager.save();
1119
1471
  };
1120
- var linkCursor = async () => {
1472
+
1473
+ // src/link/codex.ts
1474
+ import path8 from "path";
1475
+ import fs8 from "fs";
1476
+ import os3 from "os";
1477
+ import chalk9 from "chalk";
1478
+ import { confirm as confirm7 } from "@inquirer/prompts";
1479
+ import TOML from "smol-toml";
1480
+ var CODEX_AGENTS_DIR = path8.join(os3.homedir(), ".agents", "plugins");
1481
+ var CODEX_CACHE_DIR = path8.join(os3.homedir(), ".codex", "plugins", "cache");
1482
+ var CODEX_MARKETPLACE_NAME = "local-repo";
1483
+ var linkCodex = async () => {
1121
1484
  const repoPath = resolveRepoPath();
1122
1485
  if (repoPath == null) {
1123
1486
  return;
1124
1487
  }
1125
- const CURSOR_LOCAL_DIR = "local";
1126
- const CURSOR_PLUGIN_NAME = "set-prompt";
1127
- const setCursorAssets = async () => {
1488
+ ensureCodexPluginManifest(repoPath);
1489
+ ensureMcpJson(repoPath);
1490
+ ensureAppJson(repoPath);
1491
+ const registerToMarketplace = () => {
1492
+ const marketplacePath = path8.join(CODEX_AGENTS_DIR, "marketplace.json");
1128
1493
  try {
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" }]
1494
+ let marketplace = {
1495
+ name: CODEX_MARKETPLACE_NAME,
1496
+ interface: { displayName: "Local Repository" },
1497
+ plugins: []
1136
1498
  };
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}/`;
1499
+ if (fs8.existsSync(marketplacePath)) {
1500
+ const raw = fs8.readFileSync(marketplacePath, "utf-8");
1501
+ try {
1502
+ const parsed = JSON.parse(raw);
1503
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
1504
+ marketplace = parsed;
1505
+ }
1506
+ } catch {
1507
+ console.warn(chalk9.yellow(" \u26A0 Failed to parse marketplace.json \u2014 will not overwrite existing file"));
1508
+ console.error(chalk9.red("\u274C Could not register plugin. Please add manually."));
1509
+ return false;
1510
+ }
1156
1511
  }
1157
- fs4.writeFileSync(
1158
- path4.join(pluginMetaDir, "plugin.json"),
1159
- JSON.stringify(pluginJson, null, 2),
1160
- "utf-8"
1512
+ if (!Array.isArray(marketplace.plugins)) {
1513
+ marketplace.plugins = [];
1514
+ }
1515
+ marketplace.plugins = marketplace.plugins.filter(
1516
+ (p) => p?.name !== PLUGIN_NAME
1161
1517
  );
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;
1518
+ const relRepoPath = `./${path8.relative(os3.homedir(), repoPath).replace(/\\/g, "/")}`;
1519
+ marketplace.plugins.push({
1520
+ name: PLUGIN_NAME,
1521
+ source: {
1522
+ source: "local",
1523
+ path: relRepoPath
1524
+ },
1525
+ policy: {
1526
+ installation: "AVAILABLE"
1527
+ },
1528
+ category: "Productivity"
1529
+ });
1530
+ let backupPath = null;
1531
+ if (fs8.existsSync(marketplacePath)) {
1532
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1533
+ backupPath = `${marketplacePath}.bak.${timestamp}`;
1534
+ try {
1535
+ fs8.copyFileSync(marketplacePath, backupPath);
1536
+ } catch (ex) {
1537
+ console.warn(chalk9.yellow(` \u26A0 Could not create backup: ${ex.message}`));
1538
+ backupPath = null;
1172
1539
  }
1173
- if (fs4.existsSync(dest)) {
1174
- fs4.rmSync(dest, { recursive: true, force: true });
1540
+ }
1541
+ try {
1542
+ fs8.mkdirSync(path8.dirname(marketplacePath), { recursive: true });
1543
+ fs8.writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 4), "utf-8");
1544
+ } catch (ex) {
1545
+ if (backupPath !== null) {
1546
+ try {
1547
+ fs8.copyFileSync(backupPath, marketplacePath);
1548
+ fs8.unlinkSync(backupPath);
1549
+ console.warn(chalk9.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
1550
+ } catch {
1551
+ console.error(chalk9.red(` \u274C Rollback failed. Backup preserved at: ${backupPath}`));
1552
+ }
1175
1553
  }
1176
- const symlinkType2 = process.platform === "win32" ? "junction" : "dir";
1177
- fs4.symlinkSync(src, dest, symlinkType2);
1178
- linked.push({ dir, src });
1554
+ throw ex;
1179
1555
  }
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"));
1556
+ if (backupPath !== null) {
1557
+ try {
1558
+ fs8.unlinkSync(backupPath);
1559
+ } catch {
1560
+ }
1184
1561
  }
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}`));
1562
+ console.log(`\u2705 Registered to marketplace.json`);
1563
+ console.log(chalk9.dim(` ${marketplacePath}`));
1192
1564
  return true;
1193
1565
  } catch (ex) {
1194
- console.error(chalk4.red(`\u274C Failed to build Cursor plugin structure: ${ex.message}`));
1566
+ console.error(chalk9.red(`\u274C Failed to update marketplace.json: ${ex.message}`));
1195
1567
  return false;
1196
1568
  }
1197
1569
  };
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) {
1570
+ const patchPluginCache = () => {
1571
+ const cachePath = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME, PLUGIN_NAME, "1.0.0");
1572
+ try {
1573
+ fs8.mkdirSync(path8.dirname(cachePath), { recursive: true });
1574
+ if (fs8.existsSync(cachePath)) {
1575
+ fs8.rmSync(cachePath, { recursive: true, force: true });
1576
+ }
1577
+ const symlinkType = process.platform === "win32" ? "junction" : "dir";
1578
+ fs8.symlinkSync(repoPath, cachePath, symlinkType);
1579
+ console.log(`\u2705 Patched plugin cache.`);
1580
+ console.log(chalk9.dim(` ${cachePath}`) + chalk9.dim(" \u2192 ") + chalk9.dim(repoPath));
1581
+ } catch (ex) {
1582
+ console.warn(chalk9.yellow(` \u26A0 Could not patch plugin cache: ${ex.message}`));
1583
+ }
1584
+ };
1585
+ const enableInConfig = () => {
1586
+ const configPath = path8.join(os3.homedir(), ".codex", "config.toml");
1587
+ const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
1588
+ try {
1589
+ let config = {};
1590
+ if (fs8.existsSync(configPath)) {
1591
+ config = TOML.parse(fs8.readFileSync(configPath, "utf-8"));
1592
+ }
1593
+ if (config.plugins == null) {
1594
+ config.plugins = {};
1595
+ }
1596
+ config.plugins[pluginKey] = { enabled: true };
1597
+ fs8.mkdirSync(path8.dirname(configPath), { recursive: true });
1598
+ fs8.writeFileSync(configPath, TOML.stringify(config), "utf-8");
1599
+ console.log(`\u2705 Enabled plugin in config.toml`);
1600
+ console.log(chalk9.dim(` ${configPath}`));
1601
+ } catch (ex) {
1602
+ console.warn(chalk9.yellow(` \u26A0 Could not update config.toml: ${ex.message}`));
1603
+ }
1604
+ };
1605
+ console.log(chalk9.green(`
1606
+ Setting up Codex plugin...`));
1607
+ const marketplaceOk = registerToMarketplace();
1608
+ if (marketplaceOk === false) {
1203
1609
  return;
1204
1610
  }
1205
- configManager.cursor = { path: CURSOR_DIR, plugin_dir: CURSOR_PLUGIN_DIR };
1611
+ patchPluginCache();
1612
+ enableInConfig();
1613
+ configManager.codex = { path: CODEX_DIR };
1206
1614
  configManager.save();
1207
1615
  };
1208
- var unlinkClaudeCode = async (force = false) => {
1616
+ var unlinkCodex = async (force = false) => {
1209
1617
  if (!force) {
1210
- const ok = await confirm3({
1211
- message: `Remove Claude Code plugin dir (${CLAUDE_CODE_DIR}) and settings entries?`,
1618
+ const ok = await confirm7({
1619
+ message: `Remove Codex plugin and marketplace entries?`,
1212
1620
  default: false
1213
1621
  });
1214
1622
  if (!ok) {
1215
- console.log(chalk4.yellow("Cancelled."));
1623
+ console.log(chalk9.yellow("Cancelled."));
1216
1624
  return;
1217
1625
  }
1218
1626
  }
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)) {
1224
- try {
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];
1231
- }
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}`));
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)) {
1627
+ console.log(chalk9.red(`
1628
+ Removing Codex plugin...`));
1629
+ const marketplacePath = path8.join(CODEX_AGENTS_DIR, "marketplace.json");
1630
+ if (fs8.existsSync(marketplacePath)) {
1251
1631
  try {
1252
1632
  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
- }
1633
+ const backupPath = `${marketplacePath}.bak.${timestamp}`;
1634
+ fs8.copyFileSync(marketplacePath, backupPath);
1635
+ const marketplace = JSON.parse(fs8.readFileSync(marketplacePath, "utf-8"));
1636
+ if (Array.isArray(marketplace?.plugins)) {
1637
+ marketplace.plugins = marketplace.plugins.filter(
1638
+ (p) => p?.name !== PLUGIN_NAME
1639
+ );
1262
1640
  }
1263
1641
  try {
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}`));
1642
+ fs8.writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 4), "utf-8");
1643
+ fs8.unlinkSync(backupPath);
1644
+ console.log(chalk9.red(" removed") + chalk9.dim(` ${PLUGIN_NAME} from: ${marketplacePath}`));
1267
1645
  } 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."));
1646
+ fs8.copyFileSync(backupPath, marketplacePath);
1647
+ fs8.unlinkSync(backupPath);
1648
+ console.warn(chalk9.yellow(" \u26A0 Write failed \u2014 rolled back to original."));
1271
1649
  }
1272
1650
  } catch (ex) {
1273
- console.error(chalk4.red(` \u274C Failed to clean up installed_plugins.json: ${ex.message}`));
1651
+ console.error(chalk9.red(` \u274C Failed to clean up marketplace.json: ${ex.message}`));
1274
1652
  }
1275
1653
  }
1276
- const knownMarketplacesPath = path4.join(claudePluginsDir, "known_marketplaces.json");
1277
- if (fs4.existsSync(knownMarketplacesPath)) {
1654
+ const configPath = path8.join(os3.homedir(), ".codex", "config.toml");
1655
+ if (fs8.existsSync(configPath)) {
1278
1656
  try {
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."));
1657
+ const config = TOML.parse(fs8.readFileSync(configPath, "utf-8"));
1658
+ const pluginKey = `${PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
1659
+ if (config.plugins?.[pluginKey] !== void 0) {
1660
+ delete config.plugins[pluginKey];
1661
+ fs8.writeFileSync(configPath, TOML.stringify(config), "utf-8");
1662
+ console.log(chalk9.red(" removed") + chalk9.dim(` ${pluginKey} from: ${configPath}`));
1294
1663
  }
1295
1664
  } catch (ex) {
1296
- console.error(chalk4.red(` \u274C Failed to clean up known_marketplaces.json: ${ex.message}`));
1665
+ console.error(chalk9.red(` \u274C Failed to clean up config.toml: ${ex.message}`));
1297
1666
  }
1298
1667
  }
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}`));
1668
+ const cacheMarketDir = path8.join(CODEX_CACHE_DIR, CODEX_MARKETPLACE_NAME);
1669
+ if (fs8.existsSync(cacheMarketDir)) {
1670
+ fs8.rmSync(cacheMarketDir, { recursive: true, force: true });
1671
+ console.log(chalk9.red(" removed") + chalk9.dim(`: ${cacheMarketDir}`));
1302
1672
  }
1303
- configManager.claude_code = null;
1673
+ configManager.codex = null;
1304
1674
  configManager.save();
1305
1675
  };
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
- }
1676
+
1677
+ // src/link/cursor.ts
1678
+ import path9 from "path";
1679
+ import fs9 from "fs";
1680
+ import chalk10 from "chalk";
1681
+ import { confirm as confirm8 } from "@inquirer/prompts";
1682
+ import { pathExists as pathExists4 } from "fs-extra";
1683
+ var CURSOR_BACKUP_DIR = path9.join(CURSOR_DIR, "SET_PROMPT_BACKUP");
1684
+ var linkCursor = async () => {
1685
+ const repoPath = resolveRepoPath();
1686
+ if (repoPath == null) {
1687
+ return;
1316
1688
  }
1317
- console.log(chalk4.red(`
1318
- Removing RooCode integration...`));
1319
- console.log(chalk4.dim(ROO_DIR));
1320
- const backupPath = configManager.roocode?.backup_path ?? ROO_BACKUP_DIR;
1321
- for (const dir of AGENT_PROMPT_DIRS["roocode" /* ROOCODE */]) {
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}`));
1689
+ console.log(chalk10.green(`
1690
+ Setting up Cursor integration...`));
1691
+ console.log(chalk10.dim(CURSOR_DIR));
1692
+ const cursorDirs = AGENT_PROMPT_DIRS["cursor" /* CURSOR */];
1693
+ const dirsToBackup = [];
1694
+ for (const dir of cursorDirs) {
1695
+ const target = path9.join(CURSOR_DIR, dir);
1696
+ if (fs9.existsSync(target) && fs9.lstatSync(target).isSymbolicLink() === false && fs9.readdirSync(target).length > 0) {
1697
+ dirsToBackup.push(dir);
1326
1698
  }
1327
1699
  }
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}/`));
1338
- }
1339
- fs4.rmdirSync(backupPath);
1340
- } catch (ex) {
1341
- console.error(chalk4.red(` \u274C Failed to restore RooCode backup: ${ex.message}`));
1700
+ if (dirsToBackup.length > 0) {
1701
+ console.log(chalk10.yellow(`
1702
+ \u26A0 The following existing directories will be replaced by symlinks:`));
1703
+ for (const dir of dirsToBackup) {
1704
+ console.log(chalk10.dim(` - ${path9.join(CURSOR_DIR, dir)}`));
1342
1705
  }
1343
- }
1344
- configManager.roocode = null;
1345
- configManager.save();
1346
- };
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
- });
1706
+ console.log(chalk10.yellow(` They will be backed up to: `) + chalk10.dim(CURSOR_BACKUP_DIR));
1707
+ const ok = await confirm8({ message: "Back up existing directories?", default: true });
1353
1708
  if (!ok) {
1354
- console.log(chalk4.yellow("Cancelled."));
1709
+ console.log(chalk10.yellow("Skipped Cursor linking."));
1355
1710
  return;
1356
1711
  }
1357
- }
1358
- console.log(chalk4.red(`
1359
- Removing OpenClaw integration...`));
1360
- console.log(chalk4.dim(OPENCLAW_DIR));
1361
- const backupPath = configManager.openclaw?.backup_path ?? OPENCLAW_BACKUP_DIR;
1362
- for (const dir of AGENT_PROMPT_DIRS["openclaw" /* OPENCLAW */]) {
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}`));
1712
+ fs9.mkdirSync(CURSOR_BACKUP_DIR, { recursive: true });
1713
+ for (const dir of dirsToBackup) {
1714
+ const src = path9.join(CURSOR_DIR, dir);
1715
+ const dest = path9.join(CURSOR_BACKUP_DIR, dir);
1716
+ fs9.renameSync(src, dest);
1717
+ console.log(chalk10.yellow(" backed up") + chalk10.dim(`: ${dir}/ \u2192 ${dest}`));
1367
1718
  }
1368
1719
  }
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}/`));
1720
+ try {
1721
+ const linked = [];
1722
+ for (const dir of cursorDirs) {
1723
+ const src = path9.join(repoPath, dir);
1724
+ const dest = path9.join(CURSOR_DIR, dir);
1725
+ if (await pathExists4(src) === false) {
1726
+ continue;
1379
1727
  }
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;
1728
+ if (fs9.existsSync(dest)) {
1729
+ fs9.rmSync(dest, { recursive: true, force: true });
1730
+ }
1731
+ const symlinkType = process.platform === "win32" ? "junction" : "dir";
1732
+ fs9.symlinkSync(src, dest, symlinkType);
1733
+ linked.push({ dir, src });
1397
1734
  }
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}`));
1735
+ for (const { dir, src } of linked) {
1736
+ console.log(chalk10.dim(` \u251C\u2500\u2500 `) + chalk10.bold(`${dir}/`) + chalk10.dim(` \u2192 ${src}`) + chalk10.green(" \u2713"));
1408
1737
  }
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}/`));
1738
+ const mcpSrc = path9.join(repoPath, "mcp.json");
1739
+ const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
1740
+ if (fs9.existsSync(mcpSrc)) {
1741
+ if (fs9.existsSync(mcpDest) && fs9.statSync(mcpDest).ino !== fs9.statSync(mcpSrc).ino) {
1742
+ const mcpBackup = path9.join(CURSOR_BACKUP_DIR, "mcp.json");
1743
+ fs9.mkdirSync(CURSOR_BACKUP_DIR, { recursive: true });
1744
+ fs9.renameSync(mcpDest, mcpBackup);
1745
+ console.log(chalk10.yellow(" backed up") + chalk10.dim(`: mcp.json \u2192 ${mcpBackup}`));
1420
1746
  }
1421
- fs4.rmdirSync(backupPath);
1422
- } catch (ex) {
1423
- console.error(chalk4.red(` \u274C Failed to restore Antigravity backup: ${ex.message}`));
1747
+ if (fs9.existsSync(mcpDest)) {
1748
+ fs9.unlinkSync(mcpDest);
1749
+ }
1750
+ fs9.linkSync(mcpSrc, mcpDest);
1751
+ console.log(chalk10.dim(` \u2514\u2500\u2500 `) + chalk10.bold("mcp.json") + chalk10.dim(` \u21D4 ${mcpSrc}`) + chalk10.green(" \u2713"));
1424
1752
  }
1753
+ } catch (ex) {
1754
+ console.error(chalk10.red(`\u274C Failed to set up Cursor: ${ex.message}`));
1755
+ return;
1425
1756
  }
1426
- configManager.antigravity = null;
1757
+ configManager.cursor = { path: CURSOR_DIR, backup_path: CURSOR_BACKUP_DIR };
1427
1758
  configManager.save();
1428
1759
  };
1429
- var unlinkCodex = async (force = false) => {
1760
+ var unlinkCursor = async (force = false) => {
1430
1761
  if (!force) {
1431
- const ok = await confirm3({
1432
- message: `Remove Codex symlinks from ${CODEX_DIR}?`,
1762
+ const ok = await confirm8({
1763
+ message: `Remove Cursor symlinks from ${CURSOR_DIR}?`,
1433
1764
  default: false
1434
1765
  });
1435
1766
  if (!ok) {
1436
- console.log(chalk4.yellow("Cancelled."));
1767
+ console.log(chalk10.yellow("Cancelled."));
1437
1768
  return;
1438
1769
  }
1439
1770
  }
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}`));
1771
+ console.log(chalk10.red(`
1772
+ Removing Cursor integration...`));
1773
+ console.log(chalk10.dim(CURSOR_DIR));
1774
+ const backupPath = configManager.cursor?.backup_path ?? CURSOR_BACKUP_DIR;
1775
+ for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
1776
+ const target = path9.join(CURSOR_DIR, dir);
1777
+ if (fs9.existsSync(target) && fs9.lstatSync(target).isSymbolicLink()) {
1778
+ fs9.unlinkSync(target);
1779
+ console.log(chalk10.red(" removed symlink") + chalk10.dim(`: ${target}`));
1449
1780
  }
1450
1781
  }
1451
- if (fs4.existsSync(backupPath)) {
1782
+ const mcpDest = path9.join(CURSOR_DIR, "mcp.json");
1783
+ if (fs9.existsSync(mcpDest)) {
1784
+ fs9.unlinkSync(mcpDest);
1785
+ console.log(chalk10.red(" removed") + chalk10.dim(`: ${mcpDest}`));
1786
+ }
1787
+ if (fs9.existsSync(backupPath)) {
1452
1788
  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)) {
1789
+ for (const dir of AGENT_PROMPT_DIRS["cursor" /* CURSOR */]) {
1790
+ const src = path9.join(backupPath, dir);
1791
+ const dest = path9.join(CURSOR_DIR, dir);
1792
+ if (!fs9.existsSync(src)) {
1457
1793
  continue;
1458
1794
  }
1459
- fs4.renameSync(src, dest);
1460
- console.log(chalk4.green(" restored") + chalk4.dim(`: ${dir}/`));
1795
+ fs9.renameSync(src, dest);
1796
+ console.log(chalk10.green(" restored") + chalk10.dim(`: ${dir}/`));
1797
+ }
1798
+ const mcpBackup = path9.join(backupPath, "mcp.json");
1799
+ if (fs9.existsSync(mcpBackup)) {
1800
+ fs9.renameSync(mcpBackup, mcpDest);
1801
+ console.log(chalk10.green(" restored") + chalk10.dim(`: mcp.json`));
1461
1802
  }
1462
- fs4.rmdirSync(backupPath);
1803
+ fs9.rmSync(backupPath, { recursive: true, force: true });
1463
1804
  } 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;
1805
+ console.error(chalk10.red(` \u274C Failed to restore Cursor backup: ${ex.message}`));
1479
1806
  }
1480
1807
  }
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
1808
  configManager.cursor = null;
1491
1809
  configManager.save();
1492
1810
  };
1811
+
1812
+ // src/commands/link-command.ts
1813
+ var LINK_MAP = {
1814
+ ["claudecode" /* CLAUDECODE */]: linkClaudeCode,
1815
+ ["roocode" /* ROOCODE */]: linkRooCode,
1816
+ ["openclaw" /* OPENCLAW */]: linkOpenclaw,
1817
+ ["codex" /* CODEX */]: linkCodex,
1818
+ ["antigravity" /* ANTIGRAVITY */]: linkAntigravity,
1819
+ ["cursor" /* CURSOR */]: linkCursor
1820
+ };
1821
+ var UNLINK_MAP = {
1822
+ ["claudecode" /* CLAUDECODE */]: unlinkClaudeCode,
1823
+ ["roocode" /* ROOCODE */]: unlinkRooCode,
1824
+ ["openclaw" /* OPENCLAW */]: unlinkOpenclaw,
1825
+ ["codex" /* CODEX */]: unlinkCodex,
1826
+ ["antigravity" /* ANTIGRAVITY */]: unlinkAntigravity,
1827
+ ["cursor" /* CURSOR */]: unlinkCursor
1828
+ };
1493
1829
  var linkCommand = async (tool) => {
1494
1830
  if (tool != null) {
1495
1831
  const known = ALL_AGENTS.some((a) => a.value === tool);
1496
1832
  if (!known) {
1497
- console.log(chalk4.red(`Unknown vendor: ${tool}`));
1833
+ console.log(chalk11.red(`Unknown vendor: ${tool}`));
1498
1834
  process.exit(1);
1499
1835
  }
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
- }
1836
+ await LINK_MAP[tool]();
1513
1837
  return;
1514
1838
  }
1515
1839
  const prevLinked = {
@@ -1523,7 +1847,7 @@ var linkCommand = async (tool) => {
1523
1847
  const selected = await checkbox({
1524
1848
  message: "Which AI agent do you want to integrate?",
1525
1849
  choices: ALL_AGENTS.map((a) => ({
1526
- name: prevLinked[a.value] ? `${a.name} ${chalk4.dim("(applied)")}` : a.name,
1850
+ name: prevLinked[a.value] ? `${a.name} ${chalk11.dim("(applied)")}` : a.name,
1527
1851
  value: a.value,
1528
1852
  checked: prevLinked[a.value]
1529
1853
  }))
@@ -1532,10 +1856,10 @@ var linkCommand = async (tool) => {
1532
1856
  const toUnlink = ALL_AGENTS.filter((a) => prevLinked[a.value] && !selected.includes(a.value));
1533
1857
  console.log();
1534
1858
  if (toLink.length > 0) {
1535
- console.log(chalk4.green(" Link ") + chalk4.dim("\u2192 ") + toLink.map((a) => chalk4.bold(a.name)).join(chalk4.dim(", ")));
1859
+ console.log(chalk11.green(" Link ") + chalk11.dim("\u2192 ") + toLink.map((a) => chalk11.bold(a.name)).join(chalk11.dim(", ")));
1536
1860
  }
1537
1861
  if (toUnlink.length > 0) {
1538
- console.log(chalk4.red(" Unlink ") + chalk4.dim("\u2192 ") + toUnlink.map((a) => chalk4.bold(a.name)).join(chalk4.dim(", ")));
1862
+ console.log(chalk11.red(" Unlink ") + chalk11.dim("\u2192 ") + toUnlink.map((a) => chalk11.bold(a.name)).join(chalk11.dim(", ")));
1539
1863
  }
1540
1864
  console.log();
1541
1865
  if (toLink.length === 0 && toUnlink.length === 0) {
@@ -1545,47 +1869,23 @@ var linkCommand = async (tool) => {
1545
1869
  const was = prevLinked[a.value];
1546
1870
  const now = selected.includes(a.value);
1547
1871
  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
- }
1872
+ await LINK_MAP[a.value]();
1561
1873
  }
1562
1874
  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);
1575
- }
1875
+ await UNLINK_MAP[a.value](true);
1576
1876
  }
1577
1877
  }
1578
1878
  };
1579
1879
 
1580
1880
  // src/commands/uninstall-command.ts
1581
- import fs5 from "fs";
1582
- import chalk5 from "chalk";
1583
- import { confirm as confirm4 } from "@inquirer/prompts";
1881
+ import fs10 from "fs";
1882
+ import chalk12 from "chalk";
1883
+ import { confirm as confirm9 } from "@inquirer/prompts";
1584
1884
  var uninstallCommand = async () => {
1585
1885
  const targets = [
1586
- { label: `Config file ${chalk5.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
1587
- { label: `Home dir ${chalk5.dim(HOME_DIR)}`, path: HOME_DIR }
1588
- ].filter((t) => fs5.existsSync(t.path));
1886
+ { label: `Config file ${chalk12.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
1887
+ { label: `Home dir ${chalk12.dim(HOME_DIR)}`, path: HOME_DIR }
1888
+ ].filter((t) => fs10.existsSync(t.path));
1589
1889
  const hasClaudeCode = configManager.isClaudeCodeEnabled();
1590
1890
  const hasRooCode = configManager.isRooCodeEnabled();
1591
1891
  const hasOpenclaw = configManager.isOpenclawEnabled();
@@ -1593,32 +1893,32 @@ var uninstallCommand = async () => {
1593
1893
  const hasCodex = configManager.isCodexEnabled();
1594
1894
  const hasCursor = configManager.isCursorEnabled();
1595
1895
  if (targets.length === 0 && !hasClaudeCode && !hasRooCode && !hasOpenclaw && !hasAntigravity && !hasCodex && !hasCursor) {
1596
- console.log(chalk5.yellow("Nothing to remove."));
1896
+ console.log(chalk12.yellow("Nothing to remove."));
1597
1897
  return;
1598
1898
  }
1599
- console.log(chalk5.red("\nThe following will be removed:"));
1899
+ console.log(chalk12.red("\nThe following will be removed:"));
1600
1900
  targets.forEach((t) => console.log(` ${t.label}`));
1601
1901
  if (hasClaudeCode) {
1602
- console.log(` Claude Code plugin dir ${chalk5.dim(CLAUDE_CODE_DIR)}`);
1902
+ console.log(` Claude Code plugin dir ${chalk12.dim(CLAUDE_CODE_DIR)}`);
1603
1903
  }
1604
1904
  if (hasRooCode) {
1605
- console.log(` RooCode symlinks ${chalk5.dim("(backup will be restored)")}`);
1905
+ console.log(` RooCode symlinks ${chalk12.dim("(backup will be restored)")}`);
1606
1906
  }
1607
1907
  if (hasOpenclaw) {
1608
- console.log(` OpenClaw symlinks ${chalk5.dim("(backup will be restored)")}`);
1908
+ console.log(` OpenClaw symlinks ${chalk12.dim("(backup will be restored)")}`);
1609
1909
  }
1610
1910
  if (hasAntigravity) {
1611
- console.log(` Antigravity symlinks ${chalk5.dim("(backup will be restored)")}`);
1911
+ console.log(` Antigravity symlinks ${chalk12.dim("(backup will be restored)")}`);
1612
1912
  }
1613
1913
  if (hasCodex) {
1614
- console.log(` Codex symlinks ${chalk5.dim("(backup will be restored)")}`);
1914
+ console.log(` Codex symlinks ${chalk12.dim("(backup will be restored)")}`);
1615
1915
  }
1616
1916
  if (hasCursor) {
1617
- console.log(` Cursor plugin dir ${chalk5.dim("(symlink will be removed)")}`);
1917
+ console.log(` Cursor plugin dir ${chalk12.dim("(symlink will be removed)")}`);
1618
1918
  }
1619
- const ok = await confirm4({ message: "Proceed?", default: false });
1919
+ const ok = await confirm9({ message: "Proceed?", default: false });
1620
1920
  if (!ok) {
1621
- console.log(chalk5.yellow("Cancelled."));
1921
+ console.log(chalk12.yellow("Cancelled."));
1622
1922
  return;
1623
1923
  }
1624
1924
  if (hasClaudeCode) {
@@ -1640,26 +1940,26 @@ var uninstallCommand = async () => {
1640
1940
  await unlinkCursor(true);
1641
1941
  }
1642
1942
  for (const t of targets) {
1643
- fs5.rmSync(t.path, { recursive: true, force: true });
1644
- console.log(chalk5.dim(` removed: ${t.path}`));
1943
+ fs10.rmSync(t.path, { recursive: true, force: true });
1944
+ console.log(chalk12.dim(` removed: ${t.path}`));
1645
1945
  }
1646
- console.log(chalk5.green("\nUninstalled."));
1946
+ console.log(chalk12.green("\nUninstalled."));
1647
1947
  };
1648
1948
 
1649
1949
  // src/commands/status-command.ts
1650
- import chalk6 from "chalk";
1950
+ import chalk13 from "chalk";
1651
1951
  var statusCommand = () => {
1652
1952
  if (configManager.repo_path == null) {
1653
- console.log(chalk6.yellow("\u274C No repo installed."));
1654
- console.log(chalk6.dim(` Run: set-prompt install <repo-url>`));
1953
+ console.log(chalk13.yellow("\u274C No repo installed."));
1954
+ console.log(chalk13.dim(` Run: set-prompt install <repo-url>`));
1655
1955
  return;
1656
1956
  }
1657
- console.log(chalk6.bold("\nRepo"));
1658
- console.log(`${TAB}path ${chalk6.cyan(configManager.repo_path)}`);
1957
+ console.log(chalk13.bold("\nRepo"));
1958
+ console.log(`${TAB}path ${chalk13.cyan(configManager.repo_path)}`);
1659
1959
  if (configManager.remote_url != null) {
1660
- console.log(`${TAB}remote ${chalk6.dim(configManager.remote_url)}`);
1960
+ console.log(`${TAB}remote ${chalk13.dim(configManager.remote_url)}`);
1661
1961
  }
1662
- console.log(chalk6.bold("\nLinked agents"));
1962
+ console.log(chalk13.bold("\nLinked agents"));
1663
1963
  for (const agent of ALL_AGENTS) {
1664
1964
  let linked = false;
1665
1965
  let agentPath = null;
@@ -1679,8 +1979,8 @@ var statusCommand = () => {
1679
1979
  linked = configManager.isAntigravityEnabled();
1680
1980
  agentPath = configManager.antigravity?.path;
1681
1981
  }
1682
- const label = linked ? chalk6.green("linked") : chalk6.dim("not linked");
1683
- const pathStr = linked && agentPath ? chalk6.dim(` \u2192 ${agentPath}`) : "";
1982
+ const label = linked ? chalk13.green("linked") : chalk13.dim("not linked");
1983
+ const pathStr = linked && agentPath ? chalk13.dim(` \u2192 ${agentPath}`) : "";
1684
1984
  console.log(`${TAB}${agent.name.padEnd(12)} ${label}${pathStr}`);
1685
1985
  }
1686
1986
  console.log("");
@@ -1688,69 +1988,69 @@ var statusCommand = () => {
1688
1988
 
1689
1989
  // src/commands/update-command.ts
1690
1990
  import { spawnSync as spawnSync2 } from "child_process";
1691
- import chalk7 from "chalk";
1991
+ import chalk14 from "chalk";
1692
1992
  var updateCommand = () => {
1693
1993
  const repoPath = configManager.repo_path;
1694
1994
  if (repoPath == null) {
1695
- console.error(chalk7.red("\u274C No repo installed."));
1696
- console.log(chalk7.yellow("Run: set-prompt install <git-url>"));
1995
+ console.error(chalk14.red("\u274C No repo installed."));
1996
+ console.log(chalk14.yellow("Run: set-prompt install <git-url>"));
1697
1997
  return;
1698
1998
  }
1699
1999
  if (configManager.remote_url == null) {
1700
- console.error(chalk7.red("\u274C No remote URL registered. Cannot update."));
2000
+ console.error(chalk14.red("\u274C No remote URL registered. Cannot update."));
1701
2001
  return;
1702
2002
  }
1703
- console.log(chalk7.green("\nUpdating prompt repo..."));
1704
- console.log(chalk7.dim(repoPath));
2003
+ console.log(chalk14.green("\nUpdating prompt repo..."));
2004
+ console.log(chalk14.dim(repoPath));
1705
2005
  const fetch = spawnSync2("git", ["fetch"], { cwd: repoPath, stdio: "inherit" });
1706
2006
  if (fetch.status !== 0) {
1707
- console.error(chalk7.red("\u274C git fetch failed."));
2007
+ console.error(chalk14.red("\u274C git fetch failed."));
1708
2008
  return;
1709
2009
  }
1710
2010
  const pull = spawnSync2("git", ["pull"], { cwd: repoPath, stdio: "inherit" });
1711
2011
  if (pull.status !== 0) {
1712
- console.error(chalk7.red("\u274C git pull failed."));
2012
+ console.error(chalk14.red("\u274C git pull failed."));
1713
2013
  return;
1714
2014
  }
1715
- console.log(chalk7.green("\u2705 Repo updated."));
2015
+ console.log(chalk14.green("\u2705 Repo updated."));
1716
2016
  };
1717
2017
 
1718
2018
  // src/index.ts
1719
2019
  process.on("SIGINT", () => {
1720
- console.log(chalk8.yellow("\nCancelled."));
2020
+ console.log(chalk15.yellow("\nCancelled."));
1721
2021
  process.exit(0);
1722
2022
  });
1723
2023
  process.on("unhandledRejection", (reason) => {
1724
2024
  if (reason instanceof Error && reason.name === "ExitPromptError") {
1725
- console.log(chalk8.yellow("\nCancelled."));
2025
+ console.log(chalk15.yellow("\nCancelled."));
1726
2026
  process.exit(0);
1727
2027
  }
1728
2028
  throw reason;
1729
2029
  });
1730
- var __dirname = path5.dirname(fileURLToPath(import.meta.url));
1731
- var pkg = JSON.parse(fs6.readFileSync(path5.join(__dirname, "../package.json"), "utf-8"));
2030
+ var __dirname = path10.dirname(fileURLToPath(import.meta.url));
2031
+ var pkg = JSON.parse(fs11.readFileSync(path10.join(__dirname, "../package.json"), "utf-8"));
1732
2032
  configManager.init();
1733
2033
  var program = new Command();
1734
- var banner = chalk8.cyan(figlet.textSync("Set-Prompt", { horizontalLayout: "full" }));
2034
+ var banner = chalk15.cyan(figlet.textSync("Set-Prompt", { horizontalLayout: "full" }));
1735
2035
  program.name("set-prompt").description(pkg.description).version(pkg.version).addHelpText("beforeAll", banner + "\n").action(() => {
1736
2036
  program.help();
1737
2037
  });
1738
- program.command("install").description(`\u{1F4E6} Clone a ${chalk8.cyan("git repo")} into ${chalk8.dim("~/.set-prompt/repo/")} and register it as your prompt source`).argument("<url>", "remote git URL").action(async (source) => {
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) => {
1739
2039
  await installCommand(source);
1740
2040
  });
1741
- program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${chalk8.cyan("AI agent")} plugin dir ${chalk8.dim("(claudecode | roocode | openclaw | codex | antigravity)")}`).argument("[agent]", `target agent ${chalk8.dim("(omit for interactive selection)")}`).action(async (agent) => {
2041
+ program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${chalk15.cyan("AI agent")} plugin dir ${chalk15.dim("(claudecode | roocode | openclaw | codex | antigravity)")}`).argument("[agent]", `target agent ${chalk15.dim("(omit for interactive selection)")}`).action(async (agent) => {
1742
2042
  await linkCommand(agent);
1743
2043
  });
1744
- program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${chalk8.cyan("required directories")} in a prompt repo ${chalk8.dim("(-f to force overwrite)")}`).argument("[path]", `path to repo ${chalk8.dim("(defaults to installed source)")}`).option("-f, --force", "overwrite existing files without prompting").action(async (localPath, options) => {
1745
- await scaffoldCommand(localPath, options);
2044
+ program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${chalk15.cyan("required directories")} in a prompt repo ${chalk15.dim("(-f to force overwrite)")}`).argument("[path]", `path to repo ${chalk15.dim("(defaults to installed source)")}`).action(async (localPath) => {
2045
+ await scaffoldCommand(localPath);
1746
2046
  });
1747
- program.command("status").description(`\u{1F4CB} Show registered ${chalk8.cyan("repo")} and which ${chalk8.cyan("agents")} are linked`).action(() => {
2047
+ program.command("status").description(`\u{1F4CB} Show registered ${chalk15.cyan("repo")} and which ${chalk15.cyan("agents")} are linked`).action(() => {
1748
2048
  statusCommand();
1749
2049
  });
1750
- program.command("update").description(`\u{1F504} Fetch and pull the latest changes from the ${chalk8.cyan("remote repo")}`).action(() => {
2050
+ program.command("update").description(`\u{1F504} Fetch and pull the latest changes from the ${chalk15.cyan("remote repo")}`).action(() => {
1751
2051
  updateCommand();
1752
2052
  });
1753
- program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${chalk8.dim("(~/.set-prompt/, plugin dirs, settings entries)")}`).action(async () => {
2053
+ program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${chalk15.dim("(~/.set-prompt/, plugin dirs, settings entries)")}`).action(async () => {
1754
2054
  await uninstallCommand();
1755
2055
  });
1756
2056
  program.parse(process.argv);