set-prompt 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +51 -36
- package/dist/index.js +575 -141
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk23 from "chalk";
|
|
6
6
|
import figlet from "figlet";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import fs14 from "fs";
|
|
8
|
+
import path13 from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
10
|
|
|
11
11
|
// src/commands/install-command.ts
|
|
@@ -34,6 +34,10 @@ var ANTIGRAVITY_BACKUP_DIR = path.join(ANTIGRAVITY_DIR, "SET_PROMPT_BACKUP");
|
|
|
34
34
|
var CODEX_DIR = path.join(HOME_DIR, "codex");
|
|
35
35
|
var CODEX_BACKUP_DIR = path.join(CODEX_DIR, "SET_PROMPT_BACKUP");
|
|
36
36
|
var CURSOR_DIR = path.join(os.homedir(), ".cursor");
|
|
37
|
+
var OPENCODE_DIR = path.join(os.homedir(), ".config", "opencode");
|
|
38
|
+
var OPENCODE_BACKUP_DIR = path.join(OPENCODE_DIR, "SET_PROMPT_BACKUP");
|
|
39
|
+
var GEMINICLI_DIR = path.join(os.homedir(), ".gemini");
|
|
40
|
+
var GEMINICLI_BACKUP_DIR = path.join(GEMINICLI_DIR, "SET_PROMPT_BACKUP");
|
|
37
41
|
var PROMPT_DIR_NAMES = ["skills", "commands", "hooks", "agents", "rules"];
|
|
38
42
|
var AGENT_PROMPT_DIRS = {
|
|
39
43
|
["claudecode" /* CLAUDECODE */]: ["skills", "commands", "hooks", "agents"],
|
|
@@ -41,7 +45,9 @@ var AGENT_PROMPT_DIRS = {
|
|
|
41
45
|
["openclaw" /* OPENCLAW */]: ["skills"],
|
|
42
46
|
["codex" /* CODEX */]: ["skills"],
|
|
43
47
|
["antigravity" /* ANTIGRAVITY */]: ["skills"],
|
|
44
|
-
["cursor" /* CURSOR */]: ["skills", "agents", "commands", "hooks"]
|
|
48
|
+
["cursor" /* CURSOR */]: ["skills", "agents", "commands", "hooks"],
|
|
49
|
+
["opencode" /* OPENCODE */]: ["skills", "commands", "agents"],
|
|
50
|
+
["geminicli" /* GEMINICLI */]: ["skills", "commands", "agents"]
|
|
45
51
|
};
|
|
46
52
|
var ALL_AGENTS = [
|
|
47
53
|
{ name: "Claude Code", value: "claudecode" /* CLAUDECODE */ },
|
|
@@ -49,7 +55,9 @@ var ALL_AGENTS = [
|
|
|
49
55
|
{ name: "OpenClaw", value: "openclaw" /* OPENCLAW */ },
|
|
50
56
|
{ name: "Codex", value: "codex" /* CODEX */ },
|
|
51
57
|
{ name: "Antigravity", value: "antigravity" /* ANTIGRAVITY */ },
|
|
52
|
-
{ name: "Cursor", value: "cursor" /* CURSOR */ }
|
|
58
|
+
{ name: "Cursor", value: "cursor" /* CURSOR */ },
|
|
59
|
+
{ name: "OpenCode", value: "opencode" /* OPENCODE */ },
|
|
60
|
+
{ name: "Gemini CLI", value: "geminicli" /* GEMINICLI */ }
|
|
53
61
|
];
|
|
54
62
|
|
|
55
63
|
// src/_libs/config.ts
|
|
@@ -83,6 +91,14 @@ var CursorConfigSchema = z.object({
|
|
|
83
91
|
path: z.string().nullable(),
|
|
84
92
|
backup_path: z.string().nullish().optional()
|
|
85
93
|
});
|
|
94
|
+
var OpencodeConfigSchema = z.object({
|
|
95
|
+
path: z.string().nullable(),
|
|
96
|
+
backup_path: z.string().nullish().optional()
|
|
97
|
+
});
|
|
98
|
+
var GeminicliConfigSchema = z.object({
|
|
99
|
+
path: z.string().nullable(),
|
|
100
|
+
backup_path: z.string().nullish().optional()
|
|
101
|
+
});
|
|
86
102
|
var GlobalConfigSchema = z.object({
|
|
87
103
|
repo_path: z.string(),
|
|
88
104
|
remote_url: z.string().nullable(),
|
|
@@ -91,7 +107,9 @@ var GlobalConfigSchema = z.object({
|
|
|
91
107
|
openclaw: OpenclawConfigSchema.nullable(),
|
|
92
108
|
codex: CodexConfigSchema.nullish().optional(),
|
|
93
109
|
antigravity: AntigravityConfigSchema.nullish().optional(),
|
|
94
|
-
cursor: CursorConfigSchema.nullish().optional()
|
|
110
|
+
cursor: CursorConfigSchema.nullish().optional(),
|
|
111
|
+
opencode: OpencodeConfigSchema.nullish().optional(),
|
|
112
|
+
geminicli: GeminicliConfigSchema.nullish().optional()
|
|
95
113
|
});
|
|
96
114
|
|
|
97
115
|
// src/_libs/config.ts
|
|
@@ -105,6 +123,8 @@ var ConfigManager = class {
|
|
|
105
123
|
this._codex = null;
|
|
106
124
|
this._antigravity = null;
|
|
107
125
|
this._cursor = null;
|
|
126
|
+
this._opencode = null;
|
|
127
|
+
this._geminicli = null;
|
|
108
128
|
}
|
|
109
129
|
get repo_path() {
|
|
110
130
|
return this._repo_path;
|
|
@@ -130,6 +150,12 @@ var ConfigManager = class {
|
|
|
130
150
|
get cursor() {
|
|
131
151
|
return this._cursor;
|
|
132
152
|
}
|
|
153
|
+
get opencode() {
|
|
154
|
+
return this._opencode;
|
|
155
|
+
}
|
|
156
|
+
get geminicli() {
|
|
157
|
+
return this._geminicli;
|
|
158
|
+
}
|
|
133
159
|
set repo_path(v) {
|
|
134
160
|
this._repo_path = v;
|
|
135
161
|
}
|
|
@@ -154,6 +180,12 @@ var ConfigManager = class {
|
|
|
154
180
|
set cursor(v) {
|
|
155
181
|
this._cursor = v;
|
|
156
182
|
}
|
|
183
|
+
set opencode(v) {
|
|
184
|
+
this._opencode = v;
|
|
185
|
+
}
|
|
186
|
+
set geminicli(v) {
|
|
187
|
+
this._geminicli = v;
|
|
188
|
+
}
|
|
157
189
|
init() {
|
|
158
190
|
this._loadFromDisk();
|
|
159
191
|
if (this._repo_path != null) {
|
|
@@ -175,7 +207,9 @@ var ConfigManager = class {
|
|
|
175
207
|
openclaw: this._openclaw,
|
|
176
208
|
codex: this._codex,
|
|
177
209
|
antigravity: this._antigravity,
|
|
178
|
-
cursor: this._cursor
|
|
210
|
+
cursor: this._cursor,
|
|
211
|
+
opencode: this._opencode,
|
|
212
|
+
geminicli: this._geminicli
|
|
179
213
|
}, null, 4);
|
|
180
214
|
fs.writeFileSync(CONFIG_PATH, configStr, "utf-8");
|
|
181
215
|
console.log(chalk.green(`Config saved`) + chalk.dim(` \u2192 ${CONFIG_PATH}`));
|
|
@@ -212,6 +246,12 @@ var ConfigManager = class {
|
|
|
212
246
|
isCursorEnabled() {
|
|
213
247
|
return this._cursor != null;
|
|
214
248
|
}
|
|
249
|
+
isOpencodeEnabled() {
|
|
250
|
+
return this._opencode != null;
|
|
251
|
+
}
|
|
252
|
+
isGeminicliEnabled() {
|
|
253
|
+
return this._geminicli != null;
|
|
254
|
+
}
|
|
215
255
|
_assign(config) {
|
|
216
256
|
this._repo_path = config.repo_path;
|
|
217
257
|
this._remote_url = config.remote_url;
|
|
@@ -221,6 +261,8 @@ var ConfigManager = class {
|
|
|
221
261
|
this._codex = config.codex ?? null;
|
|
222
262
|
this._antigravity = config.antigravity ?? null;
|
|
223
263
|
this._cursor = config.cursor ?? null;
|
|
264
|
+
this._opencode = config.opencode ?? null;
|
|
265
|
+
this._geminicli = config.geminicli ?? null;
|
|
224
266
|
}
|
|
225
267
|
_loadFromDisk() {
|
|
226
268
|
if (fs.existsSync(CONFIG_PATH) === false) {
|
|
@@ -337,7 +379,7 @@ This is a shared prompt repository linked to various AI agents via \`set-prompt
|
|
|
337
379
|
\u2502 \u251C\u2500\u2500 COMMAND.md # Platform-specific frontmatter + prompt content
|
|
338
380
|
\u2502 \u2514\u2500\u2500 ... # Supporting files
|
|
339
381
|
\u251C\u2500\u2500 hooks/ # Lifecycle shell hooks (Claude Code)
|
|
340
|
-
\u251C\u2500\u2500 agents/ # Agent definitions (Claude Code, Cursor)
|
|
382
|
+
\u251C\u2500\u2500 agents/ # Agent definitions (Claude Code, Cursor, OpenCode, Gemini CLI)
|
|
341
383
|
\u2502 \u2514\u2500\u2500 <agent-name>/
|
|
342
384
|
\u2502 \u2514\u2500\u2500 AGENT.md
|
|
343
385
|
\u251C\u2500\u2500 rules/ # Rule definitions (Cursor)
|
|
@@ -436,13 +478,27 @@ compatibility: "Requires Node.js 18+"
|
|
|
436
478
|
metadata:
|
|
437
479
|
category: "development"
|
|
438
480
|
disable-model-invocation: false
|
|
481
|
+
|
|
482
|
+
# OpenCode
|
|
483
|
+
name: "my-skill"
|
|
484
|
+
description: "What this skill does and when to use it"
|
|
485
|
+
license: "MIT"
|
|
486
|
+
compatibility: "opencode"
|
|
487
|
+
metadata:
|
|
488
|
+
audience: "maintainers"
|
|
489
|
+
|
|
490
|
+
# Gemini CLI
|
|
491
|
+
name: my-skill
|
|
492
|
+
description: "What this skill does and when Gemini should use it"
|
|
439
493
|
---
|
|
440
494
|
\`\`\`
|
|
441
495
|
|
|
496
|
+
> **Gemini CLI note**: Only \`name\` and \`description\` are recognized. \`name\` must be lowercase with hyphens and match the directory name.
|
|
497
|
+
|
|
442
498
|
| Field | Required | Platform | Description |
|
|
443
499
|
|-------|----------|----------|-------------|
|
|
444
|
-
| \`name\` | Yes | All | Display name. Claude Code: lowercase, numbers, hyphens only (
|
|
445
|
-
| \`description\` | Yes | All | What it does and when to use it. Claude uses this to decide auto-loading. |
|
|
500
|
+
| \`name\` | Yes | All | Display name. Claude Code / OpenCode / RooCode: lowercase, numbers, hyphens only (no underscores; Claude Code / OpenCode limit to 64 chars). Gemini CLI: lowercase with hyphens, must match the directory name. Antigravity: optional, defaults to folder name. |
|
|
501
|
+
| \`description\` | Yes | All | What it does and when to use it. Claude / OpenCode / Gemini CLI uses this to decide auto-loading. OpenCode limits to 1\u20131024 chars. |
|
|
446
502
|
| \`allowed-tools\` | No | Claude Code | Tools Claude can use without asking. e.g. \`Read\` \`Write\` \`Edit\` \`Bash\` \`Grep\` \`Glob\` |
|
|
447
503
|
| \`model\` | No | Claude Code | Model to use when active. \`sonnet\` or \`haiku\` |
|
|
448
504
|
| \`context\` | No | Claude Code | \`fork\` = run in a forked subagent context |
|
|
@@ -461,9 +517,9 @@ disable-model-invocation: false
|
|
|
461
517
|
| \`command-dispatch\` | No | OpenClaw | \`"tool"\` = bypass model, dispatch directly to a tool |
|
|
462
518
|
| \`command-tool\` | No | OpenClaw | Tool to invoke when \`command-dispatch: "tool"\` |
|
|
463
519
|
| \`command-arg-mode\` | No | OpenClaw | How arguments are forwarded to the tool. (default: \`"raw"\`) |
|
|
464
|
-
| \`license\` | No | Cursor | License name or reference to a bundled license file. |
|
|
465
|
-
| \`compatibility\` | No | Cursor | Environment requirements (system packages, network access, etc.) |
|
|
466
|
-
| \`metadata\` | No | Cursor | Arbitrary key-value mapping for additional metadata. |
|
|
520
|
+
| \`license\` | No | Cursor, OpenCode | License name or reference to a bundled license file. |
|
|
521
|
+
| \`compatibility\` | No | Cursor, OpenCode | Environment requirements (system packages, network access, etc.) |
|
|
522
|
+
| \`metadata\` | No | Cursor, OpenCode | Arbitrary key-value mapping for additional metadata. OpenCode requires string-to-string values only. |
|
|
467
523
|
|
|
468
524
|
---
|
|
469
525
|
|
|
@@ -500,9 +556,41 @@ hooks:
|
|
|
500
556
|
user-invocable: true
|
|
501
557
|
command-dispatch: "tool" # bypass model, dispatch directly to a tool
|
|
502
558
|
command-tool: "Bash"
|
|
559
|
+
|
|
560
|
+
# OpenCode
|
|
561
|
+
description: "What this command does"
|
|
562
|
+
template: "Run the full test suite and summarise failures for $ARGUMENTS"
|
|
563
|
+
agent: build
|
|
564
|
+
model: anthropic/claude-sonnet-4-20250514
|
|
565
|
+
subtask: false
|
|
503
566
|
---
|
|
504
567
|
\`\`\`
|
|
505
568
|
|
|
569
|
+
> **OpenCode note**: \`template\` is required in the frontmatter \u2014 it's the prompt sent to the LLM when the command runs. The markdown body is ignored. Placeholders: \`$ARGUMENTS\`, \`$1\`/\`$2\`/\`$3\`, \`\` !\`cmd\` \`\` (bash output), \`@path\` (file contents).
|
|
570
|
+
|
|
571
|
+
#### Gemini CLI commands (TOML, not Markdown)
|
|
572
|
+
|
|
573
|
+
Gemini CLI reads \`.toml\` files \u2014 not \`.md\`. The entire command is a TOML file with two top-level keys:
|
|
574
|
+
|
|
575
|
+
\`\`\`toml
|
|
576
|
+
# ~/.gemini/commands/refactor/pure.toml \u2192 /refactor:pure
|
|
577
|
+
description = "Refactor current context into a pure function."
|
|
578
|
+
prompt = """
|
|
579
|
+
Please analyze the code provided.
|
|
580
|
+
Refactor it into a pure function.
|
|
581
|
+
Include: 1) Refactored code. 2) Explanation of changes.
|
|
582
|
+
"""
|
|
583
|
+
\`\`\`
|
|
584
|
+
|
|
585
|
+
| Field | Required | Description |
|
|
586
|
+
|-------|----------|-------------|
|
|
587
|
+
| \`prompt\` | Yes | Single or multi-line prompt sent to Gemini. |
|
|
588
|
+
| \`description\` | No | One-line description shown in \`/help\` menu. Auto-generated from prompt if omitted. |
|
|
589
|
+
|
|
590
|
+
**Placeholders inside the prompt**: \`{{args}}\` (user input, shell-escaped inside \`!{...}\`), \`!{cmd}\` (shell output injection, asks for confirmation), \`@{path}\` (file/dir content injection, supports images/PDFs). If \`{{args}}\` is absent, the user's text is appended to the prompt end.
|
|
591
|
+
|
|
592
|
+
**Namespacing**: subdirectories create namespaced commands \u2014 \`commands/git/commit.toml\` becomes \`/git:commit\`. After edits, run \`/commands reload\` in Gemini CLI.
|
|
593
|
+
|
|
506
594
|
| Field | Required | Platform | Description |
|
|
507
595
|
|-------|----------|----------|-------------|
|
|
508
596
|
| \`name\` | No | All | Display name \u2014 lowercase, numbers, hyphens only (max 64 chars). Defaults to directory name. |
|
|
@@ -514,6 +602,10 @@ command-tool: "Bash"
|
|
|
514
602
|
| \`context\` | No | Claude Code | \`fork\` = run in a forked subagent context |
|
|
515
603
|
| \`agent\` | No | Claude Code | Subagent type when \`context: fork\`. e.g. \`general-purpose\` \`Explore\` \`Plan\` |
|
|
516
604
|
| \`hooks\` | No | Claude Code | Lifecycle hooks for pre/post processing. |
|
|
605
|
+
| \`template\` | Yes | OpenCode | Prompt text sent to the LLM when the command runs. |
|
|
606
|
+
| \`agent\` | No | OpenCode | Agent to route the command to. Defaults to the current agent. |
|
|
607
|
+
| \`model\` | No | OpenCode | Overrides default model. Format: \`provider/model-id\`. |
|
|
608
|
+
| \`subtask\` | No | OpenCode | \`true\` = force subagent invocation to avoid polluting main context. (default: \`false\`) |
|
|
517
609
|
|
|
518
610
|
---
|
|
519
611
|
|
|
@@ -538,18 +630,79 @@ description: "What this agent does and when to use it"
|
|
|
538
630
|
model: inherit
|
|
539
631
|
readonly: false
|
|
540
632
|
is_background: false
|
|
633
|
+
|
|
634
|
+
# OpenCode
|
|
635
|
+
description: "Reviews code for quality and best practices"
|
|
636
|
+
mode: subagent
|
|
637
|
+
model: anthropic/claude-sonnet-4-20250514
|
|
638
|
+
temperature: 0.1
|
|
639
|
+
top_p: 0.9
|
|
640
|
+
steps: 20
|
|
641
|
+
color: "#FF5733"
|
|
642
|
+
hidden: false
|
|
643
|
+
disable: false
|
|
644
|
+
prompt: "{file:./prompts/review.txt}"
|
|
645
|
+
tools:
|
|
646
|
+
write: false
|
|
647
|
+
edit: false
|
|
648
|
+
bash: false
|
|
649
|
+
permission:
|
|
650
|
+
edit: deny
|
|
651
|
+
bash:
|
|
652
|
+
"*": ask
|
|
653
|
+
"git diff": allow
|
|
654
|
+
webfetch: deny
|
|
655
|
+
|
|
656
|
+
# Gemini CLI
|
|
657
|
+
name: security-auditor
|
|
658
|
+
description: "Specialized in finding security vulnerabilities in code."
|
|
659
|
+
kind: local
|
|
660
|
+
tools:
|
|
661
|
+
- read_file
|
|
662
|
+
- grep_search
|
|
663
|
+
model: gemini-3-flash-preview
|
|
664
|
+
temperature: 0.2
|
|
665
|
+
max_turns: 10
|
|
666
|
+
timeout_mins: 15
|
|
667
|
+
mcpServers:
|
|
668
|
+
my-custom-server:
|
|
669
|
+
command: 'node'
|
|
670
|
+
args: ['path/to/server.js']
|
|
541
671
|
---
|
|
542
672
|
\`\`\`
|
|
543
673
|
|
|
674
|
+
> **OpenCode note**: The filename (without \`.md\`) becomes the agent ID. \`name\` is **not** a frontmatter field \u2014 don't include it.
|
|
675
|
+
|
|
676
|
+
> **\u26A0 Gemini CLI note (strict validation)**: Gemini CLI **rejects any unknown frontmatter key** and fails to load the agent with an error like:
|
|
677
|
+
> \`\`\`
|
|
678
|
+
> Agent loading error: ... Validation failed:
|
|
679
|
+
> Unrecognized key(s) in object: 'color', 'skills'
|
|
680
|
+
> \`\`\`
|
|
681
|
+
> Only these keys are allowed: \`name\`, \`description\`, \`kind\`, \`tools\`, \`mcpServers\`, \`model\`, \`temperature\`, \`max_turns\`, \`timeout_mins\`. Fields from other platforms (\`allowed-tools\`, \`mode\`, \`context\`, \`color\`, \`readonly\`, \`is_background\`, etc.) **must not appear** in an agent file if you want Gemini CLI to load it. If you need platform-specific agents, keep them in separate \`.md\` files per agent.
|
|
682
|
+
|
|
544
683
|
| Field | Required | Platform | Description |
|
|
545
684
|
|-------|----------|----------|-------------|
|
|
546
|
-
| \`name\` | Yes |
|
|
685
|
+
| \`name\` | Yes | Claude Code, Cursor, Gemini CLI | Display name. Claude Code: lowercase, numbers, hyphens only (max 64 chars). Cursor: defaults to folder name. OpenCode uses the filename instead. Gemini CLI uses \`name\` as the tool slug. |
|
|
547
686
|
| \`description\` | Yes | All | When and how to use this agent. Used to decide when to spawn/delegate. |
|
|
548
687
|
| \`allowed-tools\` | No | Claude Code | Tools this agent can use without asking |
|
|
549
|
-
| \`
|
|
688
|
+
| \`tools\` | No | OpenCode, Gemini CLI | OpenCode: per-tool enable/disable map with wildcards. Gemini CLI: array of tool names the agent can use (e.g. \`[read_file, grep_search]\`). |
|
|
689
|
+
| \`model\` | No | All | Claude Code: \`sonnet\` or \`haiku\`. Cursor: \`fast\`, \`inherit\`, or a specific model ID. OpenCode: \`provider/model-id\`. Gemini CLI: specific Gemini model override. |
|
|
550
690
|
| \`context\` | No | Claude Code | \`fork\` = run in isolated subagent context |
|
|
551
691
|
| \`readonly\` | No | Cursor | \`true\` = sub-agent runs with restricted write permissions (no file edits or state-changing shell commands). (default: \`false\`) |
|
|
552
692
|
| \`is_background\` | No | Cursor | \`true\` = sub-agent runs in background without blocking parent. (default: \`false\`) |
|
|
693
|
+
| \`mode\` | No | OpenCode | \`primary\`, \`subagent\`, or \`all\`. (default: \`all\`) |
|
|
694
|
+
| \`temperature\` | No | OpenCode, Gemini CLI | Response randomness. OpenCode: \`0.0\`\u2013\`1.0\`. Gemini CLI: \`0.0\`\u2013\`2.0\`. |
|
|
695
|
+
| \`top_p\` | No | OpenCode | Alternative diversity control, \`0.0\`\u2013\`1.0\`. |
|
|
696
|
+
| \`steps\` | No | OpenCode | Max agentic iterations before forcing a text response. |
|
|
697
|
+
| \`disable\` | No | OpenCode | \`true\` = disable the agent. (default: \`false\`) |
|
|
698
|
+
| \`hidden\` | No | OpenCode | \`true\` = hide from \`@\` autocomplete. Subagents only. (default: \`false\`) |
|
|
699
|
+
| \`color\` | No | OpenCode | Hex color (e.g. \`#FF5733\`) or theme color. |
|
|
700
|
+
| \`prompt\` | No | OpenCode | Custom system prompt source. Supports file references like \`{file:./prompts/review.txt}\`. |
|
|
701
|
+
| \`permission\` | No | OpenCode | Fine-grained action permissions. Values: \`allow\`, \`ask\`, \`deny\`. Applies to \`edit\`, \`bash\` (supports per-command globs like \`"git diff": allow\`), \`webfetch\`, \`task\`. |
|
|
702
|
+
| \`kind\` | No | Gemini CLI | \`local\` or \`remote\`. (default: \`local\`) |
|
|
703
|
+
| \`max_turns\` | No | Gemini CLI | Conversation turn limit. (default: \`30\`) |
|
|
704
|
+
| \`timeout_mins\` | No | Gemini CLI | Execution time limit in minutes. (default: \`10\`) |
|
|
705
|
+
| \`mcpServers\` | No | Gemini CLI | Inline MCP server configuration. Each server is a nested YAML map with \`command\` and \`args\` keys \u2014 define MCP servers unique to this agent (not from the global registry). |
|
|
553
706
|
|
|
554
707
|
---
|
|
555
708
|
|
|
@@ -945,7 +1098,7 @@ var installCommand = async (target) => {
|
|
|
945
1098
|
};
|
|
946
1099
|
|
|
947
1100
|
// src/commands/link-command.ts
|
|
948
|
-
import
|
|
1101
|
+
import chalk14 from "chalk";
|
|
949
1102
|
import { checkbox } from "@inquirer/prompts";
|
|
950
1103
|
|
|
951
1104
|
// src/link/claudecode.ts
|
|
@@ -1940,6 +2093,279 @@ Removing Cursor integration...`));
|
|
|
1940
2093
|
configManager.save();
|
|
1941
2094
|
};
|
|
1942
2095
|
|
|
2096
|
+
// src/link/opencode.ts
|
|
2097
|
+
import path10 from "path";
|
|
2098
|
+
import fs11 from "fs";
|
|
2099
|
+
import chalk12 from "chalk";
|
|
2100
|
+
import { confirm as confirm9 } from "@inquirer/prompts";
|
|
2101
|
+
import { pathExists as pathExists5 } from "fs-extra";
|
|
2102
|
+
var linkOpencode = async () => {
|
|
2103
|
+
const repoPath = resolveRepoPath();
|
|
2104
|
+
if (repoPath == null) {
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
console.log(chalk12.green(`
|
|
2108
|
+
Setting up OpenCode integration...`));
|
|
2109
|
+
console.log(chalk12.dim(OPENCODE_DIR));
|
|
2110
|
+
const opencodeDirs = AGENT_PROMPT_DIRS["opencode" /* OPENCODE */];
|
|
2111
|
+
const backupExistingOpencodeFiles = async () => {
|
|
2112
|
+
try {
|
|
2113
|
+
fs11.mkdirSync(OPENCODE_DIR, { recursive: true });
|
|
2114
|
+
const dirsToBackup = [];
|
|
2115
|
+
for (const dir of opencodeDirs) {
|
|
2116
|
+
const target = path10.join(OPENCODE_DIR, dir);
|
|
2117
|
+
if (fs11.existsSync(target) && fs11.lstatSync(target).isSymbolicLink() === false && fs11.readdirSync(target).length > 0) {
|
|
2118
|
+
dirsToBackup.push(dir);
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
if (dirsToBackup.length === 0) {
|
|
2122
|
+
return true;
|
|
2123
|
+
}
|
|
2124
|
+
console.log(chalk12.yellow(`
|
|
2125
|
+
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
2126
|
+
for (const dir of dirsToBackup) {
|
|
2127
|
+
console.log(chalk12.dim(` - ${path10.join(OPENCODE_DIR, dir)}`));
|
|
2128
|
+
}
|
|
2129
|
+
console.log(chalk12.yellow(` They will be backed up to: `) + chalk12.dim(OPENCODE_BACKUP_DIR));
|
|
2130
|
+
const ok = await confirm9({ message: "Back up existing directories?", default: true });
|
|
2131
|
+
if (!ok) {
|
|
2132
|
+
console.log(chalk12.yellow("Skipped OpenCode linking."));
|
|
2133
|
+
return false;
|
|
2134
|
+
}
|
|
2135
|
+
fs11.mkdirSync(OPENCODE_BACKUP_DIR, { recursive: true });
|
|
2136
|
+
for (const dir of opencodeDirs) {
|
|
2137
|
+
const src = path10.join(OPENCODE_DIR, dir);
|
|
2138
|
+
const dest = path10.join(OPENCODE_BACKUP_DIR, dir);
|
|
2139
|
+
if (!fs11.existsSync(src)) {
|
|
2140
|
+
continue;
|
|
2141
|
+
}
|
|
2142
|
+
fs11.renameSync(src, dest);
|
|
2143
|
+
console.log(chalk12.yellow(" backed up") + chalk12.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
2144
|
+
}
|
|
2145
|
+
return true;
|
|
2146
|
+
} catch (ex) {
|
|
2147
|
+
console.error(chalk12.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
const setOpencodeAssets = async () => {
|
|
2152
|
+
try {
|
|
2153
|
+
const linked = [];
|
|
2154
|
+
for (const dir of opencodeDirs) {
|
|
2155
|
+
const src = path10.join(repoPath, dir);
|
|
2156
|
+
const dest = path10.join(OPENCODE_DIR, dir);
|
|
2157
|
+
if (await pathExists5(src) === false) {
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
if (fs11.existsSync(dest)) {
|
|
2161
|
+
fs11.rmSync(dest, { recursive: true, force: true });
|
|
2162
|
+
}
|
|
2163
|
+
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
2164
|
+
fs11.symlinkSync(src, dest, symlinkType);
|
|
2165
|
+
linked.push({ dir, src });
|
|
2166
|
+
}
|
|
2167
|
+
for (const { dir, src } of linked) {
|
|
2168
|
+
const isLast = linked[linked.length - 1].dir === dir;
|
|
2169
|
+
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
2170
|
+
console.log(chalk12.dim(` ${branch} `) + chalk12.bold(`${dir}/`) + chalk12.dim(` \u2192 ${src}`) + chalk12.green(" \u2713"));
|
|
2171
|
+
}
|
|
2172
|
+
return true;
|
|
2173
|
+
} catch (ex) {
|
|
2174
|
+
console.error(chalk12.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
2175
|
+
return false;
|
|
2176
|
+
}
|
|
2177
|
+
};
|
|
2178
|
+
const backupOk = await backupExistingOpencodeFiles();
|
|
2179
|
+
if (backupOk === false) {
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
const linkOk = await setOpencodeAssets();
|
|
2183
|
+
if (linkOk === false) {
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
configManager.opencode = { path: OPENCODE_DIR, backup_path: OPENCODE_BACKUP_DIR };
|
|
2187
|
+
configManager.save();
|
|
2188
|
+
};
|
|
2189
|
+
var unlinkOpencode = async (force = false) => {
|
|
2190
|
+
if (!force) {
|
|
2191
|
+
const ok = await confirm9({
|
|
2192
|
+
message: `Remove OpenCode symlinks from ${OPENCODE_DIR}?`,
|
|
2193
|
+
default: false
|
|
2194
|
+
});
|
|
2195
|
+
if (!ok) {
|
|
2196
|
+
console.log(chalk12.yellow("Cancelled."));
|
|
2197
|
+
return;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
console.log(chalk12.red(`
|
|
2201
|
+
Removing OpenCode integration...`));
|
|
2202
|
+
console.log(chalk12.dim(OPENCODE_DIR));
|
|
2203
|
+
const backupPath = configManager.opencode?.backup_path ?? OPENCODE_BACKUP_DIR;
|
|
2204
|
+
for (const dir of AGENT_PROMPT_DIRS["opencode" /* OPENCODE */]) {
|
|
2205
|
+
const target = path10.join(OPENCODE_DIR, dir);
|
|
2206
|
+
if (fs11.existsSync(target) && fs11.lstatSync(target).isSymbolicLink()) {
|
|
2207
|
+
fs11.unlinkSync(target);
|
|
2208
|
+
console.log(chalk12.red(" removed symlink") + chalk12.dim(`: ${target}`));
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
if (fs11.existsSync(backupPath)) {
|
|
2212
|
+
try {
|
|
2213
|
+
for (const dir of AGENT_PROMPT_DIRS["opencode" /* OPENCODE */]) {
|
|
2214
|
+
const src = path10.join(backupPath, dir);
|
|
2215
|
+
const dest = path10.join(OPENCODE_DIR, dir);
|
|
2216
|
+
if (!fs11.existsSync(src)) {
|
|
2217
|
+
continue;
|
|
2218
|
+
}
|
|
2219
|
+
fs11.renameSync(src, dest);
|
|
2220
|
+
console.log(chalk12.green(" restored") + chalk12.dim(`: ${dir}/`));
|
|
2221
|
+
}
|
|
2222
|
+
fs11.rmdirSync(backupPath);
|
|
2223
|
+
} catch (ex) {
|
|
2224
|
+
console.error(chalk12.red(` \u274C Failed to restore OpenCode backup: ${ex.message}`));
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
configManager.opencode = null;
|
|
2228
|
+
configManager.save();
|
|
2229
|
+
};
|
|
2230
|
+
|
|
2231
|
+
// src/link/geminicli.ts
|
|
2232
|
+
import path11 from "path";
|
|
2233
|
+
import fs12 from "fs";
|
|
2234
|
+
import chalk13 from "chalk";
|
|
2235
|
+
import { confirm as confirm10 } from "@inquirer/prompts";
|
|
2236
|
+
import { pathExists as pathExists6 } from "fs-extra";
|
|
2237
|
+
var linkGeminicli = async () => {
|
|
2238
|
+
const repoPath = resolveRepoPath();
|
|
2239
|
+
if (repoPath == null) {
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
console.log(chalk13.green(`
|
|
2243
|
+
Setting up Gemini CLI integration...`));
|
|
2244
|
+
console.log(chalk13.dim(GEMINICLI_DIR));
|
|
2245
|
+
const geminicliDirs = AGENT_PROMPT_DIRS["geminicli" /* GEMINICLI */];
|
|
2246
|
+
const backupExistingGeminicliFiles = async () => {
|
|
2247
|
+
try {
|
|
2248
|
+
fs12.mkdirSync(GEMINICLI_DIR, { recursive: true });
|
|
2249
|
+
const dirsToBackup = [];
|
|
2250
|
+
for (const dir of geminicliDirs) {
|
|
2251
|
+
const target = path11.join(GEMINICLI_DIR, dir);
|
|
2252
|
+
if (fs12.existsSync(target) && fs12.lstatSync(target).isSymbolicLink() === false && fs12.readdirSync(target).length > 0) {
|
|
2253
|
+
dirsToBackup.push(dir);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
if (dirsToBackup.length === 0) {
|
|
2257
|
+
return true;
|
|
2258
|
+
}
|
|
2259
|
+
console.log(chalk13.yellow(`
|
|
2260
|
+
\u26A0 The following existing directories will be replaced by symlinks:`));
|
|
2261
|
+
for (const dir of dirsToBackup) {
|
|
2262
|
+
console.log(chalk13.dim(` - ${path11.join(GEMINICLI_DIR, dir)}`));
|
|
2263
|
+
}
|
|
2264
|
+
console.log(chalk13.yellow(` They will be backed up to: `) + chalk13.dim(GEMINICLI_BACKUP_DIR));
|
|
2265
|
+
const ok = await confirm10({ message: "Back up existing directories?", default: true });
|
|
2266
|
+
if (!ok) {
|
|
2267
|
+
console.log(chalk13.yellow("Skipped Gemini CLI linking."));
|
|
2268
|
+
return false;
|
|
2269
|
+
}
|
|
2270
|
+
fs12.mkdirSync(GEMINICLI_BACKUP_DIR, { recursive: true });
|
|
2271
|
+
for (const dir of geminicliDirs) {
|
|
2272
|
+
const src = path11.join(GEMINICLI_DIR, dir);
|
|
2273
|
+
const dest = path11.join(GEMINICLI_BACKUP_DIR, dir);
|
|
2274
|
+
if (!fs12.existsSync(src)) {
|
|
2275
|
+
continue;
|
|
2276
|
+
}
|
|
2277
|
+
fs12.renameSync(src, dest);
|
|
2278
|
+
console.log(chalk13.yellow(" backed up") + chalk13.dim(`: ${dir}/ \u2192 ${dest}`));
|
|
2279
|
+
}
|
|
2280
|
+
return true;
|
|
2281
|
+
} catch (ex) {
|
|
2282
|
+
console.error(chalk13.red(`\u274C Failed to backup existing directories: ${ex.message}`));
|
|
2283
|
+
return false;
|
|
2284
|
+
}
|
|
2285
|
+
};
|
|
2286
|
+
const setGeminicliAssets = async () => {
|
|
2287
|
+
try {
|
|
2288
|
+
const linked = [];
|
|
2289
|
+
for (const dir of geminicliDirs) {
|
|
2290
|
+
const src = path11.join(repoPath, dir);
|
|
2291
|
+
const dest = path11.join(GEMINICLI_DIR, dir);
|
|
2292
|
+
if (await pathExists6(src) === false) {
|
|
2293
|
+
continue;
|
|
2294
|
+
}
|
|
2295
|
+
if (fs12.existsSync(dest)) {
|
|
2296
|
+
fs12.rmSync(dest, { recursive: true, force: true });
|
|
2297
|
+
}
|
|
2298
|
+
const symlinkType = process.platform === "win32" ? "junction" : "dir";
|
|
2299
|
+
fs12.symlinkSync(src, dest, symlinkType);
|
|
2300
|
+
linked.push({ dir, src });
|
|
2301
|
+
}
|
|
2302
|
+
for (const { dir, src } of linked) {
|
|
2303
|
+
const isLast = linked[linked.length - 1].dir === dir;
|
|
2304
|
+
const branch = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
2305
|
+
console.log(chalk13.dim(` ${branch} `) + chalk13.bold(`${dir}/`) + chalk13.dim(` \u2192 ${src}`) + chalk13.green(" \u2713"));
|
|
2306
|
+
}
|
|
2307
|
+
return true;
|
|
2308
|
+
} catch (ex) {
|
|
2309
|
+
console.error(chalk13.red(`\u274C Failed to create symlinks: ${ex.message}`));
|
|
2310
|
+
return false;
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
const backupOk = await backupExistingGeminicliFiles();
|
|
2314
|
+
if (backupOk === false) {
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
const linkOk = await setGeminicliAssets();
|
|
2318
|
+
if (linkOk === false) {
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
configManager.geminicli = { path: GEMINICLI_DIR, backup_path: GEMINICLI_BACKUP_DIR };
|
|
2322
|
+
configManager.save();
|
|
2323
|
+
console.log(chalk13.dim(`
|
|
2324
|
+
\u2139 Gemini CLI file formats: skills/<name>/SKILL.md \xB7 commands/*.toml \xB7 agents/*.md`));
|
|
2325
|
+
console.log(chalk13.yellow(` \u26A0 Gemini CLI rejects agents with unknown frontmatter keys. Allowed keys only: `) + chalk13.dim(`name, description, kind, tools, mcpServers, model, temperature, max_turns, timeout_mins`));
|
|
2326
|
+
};
|
|
2327
|
+
var unlinkGeminicli = async (force = false) => {
|
|
2328
|
+
if (!force) {
|
|
2329
|
+
const ok = await confirm10({
|
|
2330
|
+
message: `Remove Gemini CLI symlinks from ${GEMINICLI_DIR}?`,
|
|
2331
|
+
default: false
|
|
2332
|
+
});
|
|
2333
|
+
if (!ok) {
|
|
2334
|
+
console.log(chalk13.yellow("Cancelled."));
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
console.log(chalk13.red(`
|
|
2339
|
+
Removing Gemini CLI integration...`));
|
|
2340
|
+
console.log(chalk13.dim(GEMINICLI_DIR));
|
|
2341
|
+
const backupPath = configManager.geminicli?.backup_path ?? GEMINICLI_BACKUP_DIR;
|
|
2342
|
+
for (const dir of AGENT_PROMPT_DIRS["geminicli" /* GEMINICLI */]) {
|
|
2343
|
+
const target = path11.join(GEMINICLI_DIR, dir);
|
|
2344
|
+
if (fs12.existsSync(target) && fs12.lstatSync(target).isSymbolicLink()) {
|
|
2345
|
+
fs12.unlinkSync(target);
|
|
2346
|
+
console.log(chalk13.red(" removed symlink") + chalk13.dim(`: ${target}`));
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
if (fs12.existsSync(backupPath)) {
|
|
2350
|
+
try {
|
|
2351
|
+
for (const dir of AGENT_PROMPT_DIRS["geminicli" /* GEMINICLI */]) {
|
|
2352
|
+
const src = path11.join(backupPath, dir);
|
|
2353
|
+
const dest = path11.join(GEMINICLI_DIR, dir);
|
|
2354
|
+
if (!fs12.existsSync(src)) {
|
|
2355
|
+
continue;
|
|
2356
|
+
}
|
|
2357
|
+
fs12.renameSync(src, dest);
|
|
2358
|
+
console.log(chalk13.green(" restored") + chalk13.dim(`: ${dir}/`));
|
|
2359
|
+
}
|
|
2360
|
+
fs12.rmdirSync(backupPath);
|
|
2361
|
+
} catch (ex) {
|
|
2362
|
+
console.error(chalk13.red(` \u274C Failed to restore Gemini CLI backup: ${ex.message}`));
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
configManager.geminicli = null;
|
|
2366
|
+
configManager.save();
|
|
2367
|
+
};
|
|
2368
|
+
|
|
1943
2369
|
// src/commands/link-command.ts
|
|
1944
2370
|
var LINK_MAP = {
|
|
1945
2371
|
["claudecode" /* CLAUDECODE */]: linkClaudeCode,
|
|
@@ -1947,7 +2373,9 @@ var LINK_MAP = {
|
|
|
1947
2373
|
["openclaw" /* OPENCLAW */]: linkOpenclaw,
|
|
1948
2374
|
["codex" /* CODEX */]: linkCodex,
|
|
1949
2375
|
["antigravity" /* ANTIGRAVITY */]: linkAntigravity,
|
|
1950
|
-
["cursor" /* CURSOR */]: linkCursor
|
|
2376
|
+
["cursor" /* CURSOR */]: linkCursor,
|
|
2377
|
+
["opencode" /* OPENCODE */]: linkOpencode,
|
|
2378
|
+
["geminicli" /* GEMINICLI */]: linkGeminicli
|
|
1951
2379
|
};
|
|
1952
2380
|
var UNLINK_MAP = {
|
|
1953
2381
|
["claudecode" /* CLAUDECODE */]: unlinkClaudeCode,
|
|
@@ -1955,13 +2383,15 @@ var UNLINK_MAP = {
|
|
|
1955
2383
|
["openclaw" /* OPENCLAW */]: unlinkOpenclaw,
|
|
1956
2384
|
["codex" /* CODEX */]: unlinkCodex,
|
|
1957
2385
|
["antigravity" /* ANTIGRAVITY */]: unlinkAntigravity,
|
|
1958
|
-
["cursor" /* CURSOR */]: unlinkCursor
|
|
2386
|
+
["cursor" /* CURSOR */]: unlinkCursor,
|
|
2387
|
+
["opencode" /* OPENCODE */]: unlinkOpencode,
|
|
2388
|
+
["geminicli" /* GEMINICLI */]: unlinkGeminicli
|
|
1959
2389
|
};
|
|
1960
2390
|
var linkCommand = async (tool) => {
|
|
1961
2391
|
if (tool != null) {
|
|
1962
2392
|
const known = ALL_AGENTS.some((a) => a.value === tool);
|
|
1963
2393
|
if (!known) {
|
|
1964
|
-
console.log(
|
|
2394
|
+
console.log(chalk14.red(`Unknown vendor: ${tool}`));
|
|
1965
2395
|
process.exit(1);
|
|
1966
2396
|
}
|
|
1967
2397
|
await LINK_MAP[tool]();
|
|
@@ -1973,24 +2403,28 @@ var linkCommand = async (tool) => {
|
|
|
1973
2403
|
["openclaw" /* OPENCLAW */]: configManager.isOpenclawEnabled(),
|
|
1974
2404
|
["codex" /* CODEX */]: configManager.isCodexEnabled(),
|
|
1975
2405
|
["antigravity" /* ANTIGRAVITY */]: configManager.isAntigravityEnabled(),
|
|
1976
|
-
["cursor" /* CURSOR */]: configManager.isCursorEnabled()
|
|
2406
|
+
["cursor" /* CURSOR */]: configManager.isCursorEnabled(),
|
|
2407
|
+
["opencode" /* OPENCODE */]: configManager.isOpencodeEnabled(),
|
|
2408
|
+
["geminicli" /* GEMINICLI */]: configManager.isGeminicliEnabled()
|
|
1977
2409
|
};
|
|
1978
2410
|
const selected = await checkbox({
|
|
1979
2411
|
message: "Which AI agent do you want to integrate?",
|
|
1980
2412
|
choices: ALL_AGENTS.map((a) => ({
|
|
1981
|
-
name: prevLinked[a.value] ? `${a.name} ${
|
|
2413
|
+
name: prevLinked[a.value] ? `${a.name} ${chalk14.dim("(applied)")}` : a.name,
|
|
1982
2414
|
value: a.value,
|
|
1983
2415
|
checked: prevLinked[a.value]
|
|
1984
|
-
}))
|
|
2416
|
+
})),
|
|
2417
|
+
pageSize: ALL_AGENTS.length,
|
|
2418
|
+
loop: false
|
|
1985
2419
|
});
|
|
1986
2420
|
const toLink = ALL_AGENTS.filter((a) => !prevLinked[a.value] && selected.includes(a.value));
|
|
1987
2421
|
const toUnlink = ALL_AGENTS.filter((a) => prevLinked[a.value] && !selected.includes(a.value));
|
|
1988
2422
|
console.log();
|
|
1989
2423
|
if (toLink.length > 0) {
|
|
1990
|
-
console.log(
|
|
2424
|
+
console.log(chalk14.green(" Link ") + chalk14.dim("\u2192 ") + toLink.map((a) => chalk14.bold(a.name)).join(chalk14.dim(", ")));
|
|
1991
2425
|
}
|
|
1992
2426
|
if (toUnlink.length > 0) {
|
|
1993
|
-
console.log(
|
|
2427
|
+
console.log(chalk14.red(" Unlink ") + chalk14.dim("\u2192 ") + toUnlink.map((a) => chalk14.bold(a.name)).join(chalk14.dim(", ")));
|
|
1994
2428
|
}
|
|
1995
2429
|
console.log();
|
|
1996
2430
|
if (toLink.length === 0 && toUnlink.length === 0) {
|
|
@@ -2009,14 +2443,14 @@ var linkCommand = async (tool) => {
|
|
|
2009
2443
|
};
|
|
2010
2444
|
|
|
2011
2445
|
// src/commands/uninstall-command.ts
|
|
2012
|
-
import
|
|
2013
|
-
import
|
|
2014
|
-
import { confirm as
|
|
2446
|
+
import fs13 from "fs";
|
|
2447
|
+
import chalk15 from "chalk";
|
|
2448
|
+
import { confirm as confirm11 } from "@inquirer/prompts";
|
|
2015
2449
|
var uninstallCommand = async () => {
|
|
2016
2450
|
const targets = [
|
|
2017
|
-
{ label: `Config file ${
|
|
2018
|
-
{ label: `Home dir ${
|
|
2019
|
-
].filter((t) =>
|
|
2451
|
+
{ label: `Config file ${chalk15.dim(CONFIG_PATH)}`, path: CONFIG_PATH },
|
|
2452
|
+
{ label: `Home dir ${chalk15.dim(HOME_DIR)}`, path: HOME_DIR }
|
|
2453
|
+
].filter((t) => fs13.existsSync(t.path));
|
|
2020
2454
|
const hasClaudeCode = configManager.isClaudeCodeEnabled();
|
|
2021
2455
|
const hasRooCode = configManager.isRooCodeEnabled();
|
|
2022
2456
|
const hasOpenclaw = configManager.isOpenclawEnabled();
|
|
@@ -2024,32 +2458,32 @@ var uninstallCommand = async () => {
|
|
|
2024
2458
|
const hasCodex = configManager.isCodexEnabled();
|
|
2025
2459
|
const hasCursor = configManager.isCursorEnabled();
|
|
2026
2460
|
if (targets.length === 0 && !hasClaudeCode && !hasRooCode && !hasOpenclaw && !hasAntigravity && !hasCodex && !hasCursor) {
|
|
2027
|
-
console.log(
|
|
2461
|
+
console.log(chalk15.yellow("Nothing to remove."));
|
|
2028
2462
|
return;
|
|
2029
2463
|
}
|
|
2030
|
-
console.log(
|
|
2464
|
+
console.log(chalk15.red("\nThe following will be removed:"));
|
|
2031
2465
|
targets.forEach((t) => console.log(` ${t.label}`));
|
|
2032
2466
|
if (hasClaudeCode) {
|
|
2033
|
-
console.log(` Claude Code plugin dir ${
|
|
2467
|
+
console.log(` Claude Code plugin dir ${chalk15.dim(CLAUDE_CODE_DIR)}`);
|
|
2034
2468
|
}
|
|
2035
2469
|
if (hasRooCode) {
|
|
2036
|
-
console.log(` RooCode symlinks ${
|
|
2470
|
+
console.log(` RooCode symlinks ${chalk15.dim("(backup will be restored)")}`);
|
|
2037
2471
|
}
|
|
2038
2472
|
if (hasOpenclaw) {
|
|
2039
|
-
console.log(` OpenClaw symlinks ${
|
|
2473
|
+
console.log(` OpenClaw symlinks ${chalk15.dim("(backup will be restored)")}`);
|
|
2040
2474
|
}
|
|
2041
2475
|
if (hasAntigravity) {
|
|
2042
|
-
console.log(` Antigravity symlinks ${
|
|
2476
|
+
console.log(` Antigravity symlinks ${chalk15.dim("(backup will be restored)")}`);
|
|
2043
2477
|
}
|
|
2044
2478
|
if (hasCodex) {
|
|
2045
|
-
console.log(` Codex symlinks ${
|
|
2479
|
+
console.log(` Codex symlinks ${chalk15.dim("(backup will be restored)")}`);
|
|
2046
2480
|
}
|
|
2047
2481
|
if (hasCursor) {
|
|
2048
|
-
console.log(` Cursor plugin dir ${
|
|
2482
|
+
console.log(` Cursor plugin dir ${chalk15.dim("(symlink will be removed)")}`);
|
|
2049
2483
|
}
|
|
2050
|
-
const ok = await
|
|
2484
|
+
const ok = await confirm11({ message: "Proceed?", default: false });
|
|
2051
2485
|
if (!ok) {
|
|
2052
|
-
console.log(
|
|
2486
|
+
console.log(chalk15.yellow("Cancelled."));
|
|
2053
2487
|
return;
|
|
2054
2488
|
}
|
|
2055
2489
|
if (hasClaudeCode) {
|
|
@@ -2071,26 +2505,26 @@ var uninstallCommand = async () => {
|
|
|
2071
2505
|
await unlinkCursor(true);
|
|
2072
2506
|
}
|
|
2073
2507
|
for (const t of targets) {
|
|
2074
|
-
|
|
2075
|
-
console.log(
|
|
2508
|
+
fs13.rmSync(t.path, { recursive: true, force: true });
|
|
2509
|
+
console.log(chalk15.dim(` removed: ${t.path}`));
|
|
2076
2510
|
}
|
|
2077
|
-
console.log(
|
|
2511
|
+
console.log(chalk15.green("\nUninstalled."));
|
|
2078
2512
|
};
|
|
2079
2513
|
|
|
2080
2514
|
// src/commands/status-command.ts
|
|
2081
|
-
import
|
|
2515
|
+
import chalk16 from "chalk";
|
|
2082
2516
|
var statusCommand = () => {
|
|
2083
2517
|
if (configManager.repo_path == null) {
|
|
2084
|
-
console.log(
|
|
2085
|
-
console.log(
|
|
2518
|
+
console.log(chalk16.yellow("\u274C No repo installed."));
|
|
2519
|
+
console.log(chalk16.dim(` Run: set-prompt install <repo-url>`));
|
|
2086
2520
|
return;
|
|
2087
2521
|
}
|
|
2088
|
-
console.log(
|
|
2089
|
-
console.log(`${TAB}path ${
|
|
2522
|
+
console.log(chalk16.bold("\nRepo"));
|
|
2523
|
+
console.log(`${TAB}path ${chalk16.cyan(configManager.repo_path)}`);
|
|
2090
2524
|
if (configManager.remote_url != null) {
|
|
2091
|
-
console.log(`${TAB}remote ${
|
|
2525
|
+
console.log(`${TAB}remote ${chalk16.dim(configManager.remote_url)}`);
|
|
2092
2526
|
}
|
|
2093
|
-
console.log(
|
|
2527
|
+
console.log(chalk16.bold("\nLinked agents"));
|
|
2094
2528
|
for (const agent of ALL_AGENTS) {
|
|
2095
2529
|
let linked = false;
|
|
2096
2530
|
let agentPath = null;
|
|
@@ -2110,8 +2544,8 @@ var statusCommand = () => {
|
|
|
2110
2544
|
linked = configManager.isAntigravityEnabled();
|
|
2111
2545
|
agentPath = configManager.antigravity?.path;
|
|
2112
2546
|
}
|
|
2113
|
-
const label = linked ?
|
|
2114
|
-
const pathStr = linked && agentPath ?
|
|
2547
|
+
const label = linked ? chalk16.green("linked") : chalk16.dim("not linked");
|
|
2548
|
+
const pathStr = linked && agentPath ? chalk16.dim(` \u2192 ${agentPath}`) : "";
|
|
2115
2549
|
console.log(`${TAB}${agent.name.padEnd(12)} ${label}${pathStr}`);
|
|
2116
2550
|
}
|
|
2117
2551
|
console.log("");
|
|
@@ -2119,92 +2553,92 @@ var statusCommand = () => {
|
|
|
2119
2553
|
|
|
2120
2554
|
// src/commands/repo/pull-command.ts
|
|
2121
2555
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2122
|
-
import
|
|
2556
|
+
import chalk17 from "chalk";
|
|
2123
2557
|
var repoPullCommand = () => {
|
|
2124
2558
|
const repoPath = configManager.repo_path;
|
|
2125
2559
|
if (repoPath == null) {
|
|
2126
|
-
console.error(
|
|
2127
|
-
console.log(
|
|
2560
|
+
console.error(chalk17.red("\u274C No repo installed."));
|
|
2561
|
+
console.log(chalk17.yellow("Run: set-prompt install <git-url>"));
|
|
2128
2562
|
return;
|
|
2129
2563
|
}
|
|
2130
2564
|
if (configManager.remote_url == null) {
|
|
2131
|
-
console.error(
|
|
2565
|
+
console.error(chalk17.red("\u274C No remote URL registered. Cannot pull."));
|
|
2132
2566
|
return;
|
|
2133
2567
|
}
|
|
2134
|
-
console.log(
|
|
2135
|
-
console.log(
|
|
2568
|
+
console.log(chalk17.green("\nPulling prompt repo..."));
|
|
2569
|
+
console.log(chalk17.dim(repoPath));
|
|
2136
2570
|
const fetch = spawnSync4("git", ["fetch"], { cwd: repoPath, stdio: "inherit" });
|
|
2137
2571
|
if (fetch.status !== 0) {
|
|
2138
|
-
console.error(
|
|
2572
|
+
console.error(chalk17.red("\u274C git fetch failed."));
|
|
2139
2573
|
return;
|
|
2140
2574
|
}
|
|
2141
2575
|
const pull = spawnSync4("git", ["pull"], { cwd: repoPath, stdio: "inherit" });
|
|
2142
2576
|
if (pull.status !== 0) {
|
|
2143
|
-
console.error(
|
|
2577
|
+
console.error(chalk17.red("\u274C git pull failed."));
|
|
2144
2578
|
return;
|
|
2145
2579
|
}
|
|
2146
|
-
console.log(
|
|
2580
|
+
console.log(chalk17.green("\u2705 Repo pulled."));
|
|
2147
2581
|
};
|
|
2148
2582
|
|
|
2149
2583
|
// src/commands/repo/commit-command.ts
|
|
2150
2584
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
2151
|
-
import
|
|
2585
|
+
import chalk18 from "chalk";
|
|
2152
2586
|
var repoCommitCommand = (options = {}) => {
|
|
2153
2587
|
const repoPath = configManager.repo_path;
|
|
2154
2588
|
if (repoPath == null) {
|
|
2155
|
-
console.error(
|
|
2156
|
-
console.log(
|
|
2589
|
+
console.error(chalk18.red("\u274C No repo installed."));
|
|
2590
|
+
console.log(chalk18.yellow("Run: set-prompt install <git-url>"));
|
|
2157
2591
|
return false;
|
|
2158
2592
|
}
|
|
2159
2593
|
let message = options.message;
|
|
2160
2594
|
if (message == null || message.trim() === "") {
|
|
2161
2595
|
const generated = generateCommitMessage(repoPath);
|
|
2162
2596
|
if (generated == null) {
|
|
2163
|
-
console.error(
|
|
2597
|
+
console.error(chalk18.red("\u274C Nothing to commit \u2014 working tree is clean."));
|
|
2164
2598
|
return false;
|
|
2165
2599
|
}
|
|
2166
2600
|
message = generated;
|
|
2167
2601
|
const subject = message.split("\n")[0];
|
|
2168
|
-
console.log(
|
|
2602
|
+
console.log(chalk18.dim(` (auto-generated: ${subject})`));
|
|
2169
2603
|
}
|
|
2170
|
-
console.log(
|
|
2171
|
-
console.log(
|
|
2604
|
+
console.log(chalk18.green("\nCommitting prompt repo changes..."));
|
|
2605
|
+
console.log(chalk18.dim(repoPath));
|
|
2172
2606
|
const add = spawnSync5("git", ["add", "-A"], { cwd: repoPath, stdio: "inherit" });
|
|
2173
2607
|
if (add.status !== 0) {
|
|
2174
|
-
console.error(
|
|
2608
|
+
console.error(chalk18.red("\u274C git add failed."));
|
|
2175
2609
|
return false;
|
|
2176
2610
|
}
|
|
2177
2611
|
const commit = spawnSync5("git", ["commit", "-m", message], { cwd: repoPath, stdio: "inherit" });
|
|
2178
2612
|
if (commit.status !== 0) {
|
|
2179
|
-
console.error(
|
|
2613
|
+
console.error(chalk18.red("\u274C git commit failed \u2014 nothing to commit, or commit rejected."));
|
|
2180
2614
|
return false;
|
|
2181
2615
|
}
|
|
2182
|
-
console.log(
|
|
2616
|
+
console.log(chalk18.green("\u2705 Committed."));
|
|
2183
2617
|
return true;
|
|
2184
2618
|
};
|
|
2185
2619
|
|
|
2186
2620
|
// src/commands/repo/push-command.ts
|
|
2187
2621
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
2188
|
-
import
|
|
2622
|
+
import chalk19 from "chalk";
|
|
2189
2623
|
var repoPushCommand = () => {
|
|
2190
2624
|
const repoPath = configManager.repo_path;
|
|
2191
2625
|
if (repoPath == null) {
|
|
2192
|
-
console.error(
|
|
2193
|
-
console.log(
|
|
2626
|
+
console.error(chalk19.red("\u274C No repo installed."));
|
|
2627
|
+
console.log(chalk19.yellow("Run: set-prompt install <git-url>"));
|
|
2194
2628
|
return false;
|
|
2195
2629
|
}
|
|
2196
2630
|
if (configManager.remote_url == null) {
|
|
2197
|
-
console.error(
|
|
2631
|
+
console.error(chalk19.red("\u274C No remote URL registered. Cannot push."));
|
|
2198
2632
|
return false;
|
|
2199
2633
|
}
|
|
2200
|
-
console.log(
|
|
2201
|
-
console.log(
|
|
2634
|
+
console.log(chalk19.green("\nPushing prompt repo..."));
|
|
2635
|
+
console.log(chalk19.dim(repoPath));
|
|
2202
2636
|
const push = spawnSync6("git", ["push"], { cwd: repoPath, stdio: "inherit" });
|
|
2203
2637
|
if (push.status !== 0) {
|
|
2204
|
-
console.error(
|
|
2638
|
+
console.error(chalk19.red("\u274C git push failed."));
|
|
2205
2639
|
return false;
|
|
2206
2640
|
}
|
|
2207
|
-
console.log(
|
|
2641
|
+
console.log(chalk19.green("\u2705 Pushed."));
|
|
2208
2642
|
return true;
|
|
2209
2643
|
};
|
|
2210
2644
|
|
|
@@ -2217,7 +2651,7 @@ var repoSaveCommand = (options = {}) => {
|
|
|
2217
2651
|
|
|
2218
2652
|
// src/commands/repo/status-command.ts
|
|
2219
2653
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
2220
|
-
import
|
|
2654
|
+
import chalk20 from "chalk";
|
|
2221
2655
|
var parseBranchLine = (line) => {
|
|
2222
2656
|
const body = line.replace(/^## /, "");
|
|
2223
2657
|
if (body.startsWith("HEAD ") || body.includes("(no branch)")) {
|
|
@@ -2245,27 +2679,27 @@ var parseFileLine = (line) => {
|
|
|
2245
2679
|
const arrowIdx = name.indexOf(" -> ");
|
|
2246
2680
|
if (arrowIdx >= 0) name = name.slice(arrowIdx + 4);
|
|
2247
2681
|
if (name.startsWith('"') && name.endsWith('"')) name = name.slice(1, -1);
|
|
2248
|
-
if (status.includes("?")) return { label: "untracked", color:
|
|
2249
|
-
if (status.includes("D")) return { label: "deleted", color:
|
|
2250
|
-
if (status.includes("R")) return { label: "renamed", color:
|
|
2251
|
-
if (status.includes("A")) return { label: "added", color:
|
|
2252
|
-
if (status.includes("M")) return { label: "modified", color:
|
|
2682
|
+
if (status.includes("?")) return { label: "untracked", color: chalk20.gray, path: name };
|
|
2683
|
+
if (status.includes("D")) return { label: "deleted", color: chalk20.red, path: name };
|
|
2684
|
+
if (status.includes("R")) return { label: "renamed", color: chalk20.cyan, path: name };
|
|
2685
|
+
if (status.includes("A")) return { label: "added", color: chalk20.green, path: name };
|
|
2686
|
+
if (status.includes("M")) return { label: "modified", color: chalk20.yellow, path: name };
|
|
2253
2687
|
return null;
|
|
2254
2688
|
};
|
|
2255
2689
|
var formatUpstream = (info) => {
|
|
2256
|
-
if (info.branch == null) return
|
|
2257
|
-
if (info.upstream == null) return `${info.branch} ${
|
|
2690
|
+
if (info.branch == null) return chalk20.red("(detached HEAD)");
|
|
2691
|
+
if (info.upstream == null) return `${info.branch} ${chalk20.yellow("(no upstream)")}`;
|
|
2258
2692
|
const segs = [];
|
|
2259
|
-
if (info.ahead > 0) segs.push(
|
|
2260
|
-
if (info.behind > 0) segs.push(
|
|
2261
|
-
const trailing = segs.length > 0 ? ` (${segs.join(", ")})` :
|
|
2262
|
-
return `${info.branch} ${
|
|
2693
|
+
if (info.ahead > 0) segs.push(chalk20.green(`ahead ${info.ahead}`));
|
|
2694
|
+
if (info.behind > 0) segs.push(chalk20.red(`behind ${info.behind}`));
|
|
2695
|
+
const trailing = segs.length > 0 ? ` (${segs.join(", ")})` : chalk20.dim(" (up to date)");
|
|
2696
|
+
return `${info.branch} ${chalk20.dim("\u2192")} ${info.upstream}${trailing}`;
|
|
2263
2697
|
};
|
|
2264
2698
|
var repoStatusCommand = () => {
|
|
2265
2699
|
const repoPath = configManager.repo_path;
|
|
2266
2700
|
if (repoPath == null) {
|
|
2267
|
-
console.error(
|
|
2268
|
-
console.log(
|
|
2701
|
+
console.error(chalk20.red("\u274C No repo installed."));
|
|
2702
|
+
console.log(chalk20.yellow("Run: set-prompt install <git-url>"));
|
|
2269
2703
|
return;
|
|
2270
2704
|
}
|
|
2271
2705
|
const result = spawnSync7("git", ["status", "--porcelain=v1", "--branch", "--untracked-files=all"], {
|
|
@@ -2273,8 +2707,8 @@ var repoStatusCommand = () => {
|
|
|
2273
2707
|
encoding: "utf8"
|
|
2274
2708
|
});
|
|
2275
2709
|
if (result.status !== 0) {
|
|
2276
|
-
console.error(
|
|
2277
|
-
if (result.stderr) console.error(
|
|
2710
|
+
console.error(chalk20.red("\u274C git status failed."));
|
|
2711
|
+
if (result.stderr) console.error(chalk20.dim(result.stderr));
|
|
2278
2712
|
return;
|
|
2279
2713
|
}
|
|
2280
2714
|
const lines = result.stdout.split("\n").filter((l) => l.length > 0);
|
|
@@ -2282,14 +2716,14 @@ var repoStatusCommand = () => {
|
|
|
2282
2716
|
const fileLines = lines.slice(1);
|
|
2283
2717
|
const branchInfo = parseBranchLine(branchLine);
|
|
2284
2718
|
const changes = fileLines.map(parseFileLine).filter((f) => f !== null);
|
|
2285
|
-
console.log(`${
|
|
2286
|
-
console.log(`${
|
|
2719
|
+
console.log(`${chalk20.cyan("\u{1F4C2}")} ${chalk20.dim(repoPath)}`);
|
|
2720
|
+
console.log(`${chalk20.cyan("\u{1F33F}")} ${formatUpstream(branchInfo)}`);
|
|
2287
2721
|
console.log("");
|
|
2288
2722
|
if (changes.length === 0) {
|
|
2289
|
-
console.log(
|
|
2723
|
+
console.log(chalk20.green("\u2705 Working tree clean"));
|
|
2290
2724
|
return;
|
|
2291
2725
|
}
|
|
2292
|
-
console.log(
|
|
2726
|
+
console.log(chalk20.bold(`\u{1F4DD} Changes (${changes.length}):`));
|
|
2293
2727
|
const labelWidth = Math.max(...changes.map((c) => c.label.length));
|
|
2294
2728
|
for (const c of changes) {
|
|
2295
2729
|
const label = c.color(c.label.padEnd(labelWidth));
|
|
@@ -2298,12 +2732,12 @@ var repoStatusCommand = () => {
|
|
|
2298
2732
|
};
|
|
2299
2733
|
|
|
2300
2734
|
// src/commands/repo/path-command.ts
|
|
2301
|
-
import
|
|
2735
|
+
import chalk21 from "chalk";
|
|
2302
2736
|
var repoPathCommand = () => {
|
|
2303
2737
|
const repoPath = configManager.repo_path;
|
|
2304
2738
|
if (repoPath == null) {
|
|
2305
|
-
console.error(
|
|
2306
|
-
console.error(
|
|
2739
|
+
console.error(chalk21.red("\u274C No repo installed."));
|
|
2740
|
+
console.error(chalk21.yellow("Run: set-prompt install <git-url>"));
|
|
2307
2741
|
process.exitCode = 1;
|
|
2308
2742
|
return;
|
|
2309
2743
|
}
|
|
@@ -2312,8 +2746,8 @@ var repoPathCommand = () => {
|
|
|
2312
2746
|
|
|
2313
2747
|
// src/commands/repo/open-command.ts
|
|
2314
2748
|
import { spawn } from "child_process";
|
|
2315
|
-
import
|
|
2316
|
-
import
|
|
2749
|
+
import path12 from "path";
|
|
2750
|
+
import chalk22 from "chalk";
|
|
2317
2751
|
var resolveVscodeTarget = (repoPath) => {
|
|
2318
2752
|
if (isOnPath("code") === false) return null;
|
|
2319
2753
|
return { bin: "code", args: [repoPath] };
|
|
@@ -2324,9 +2758,9 @@ var resolveSourcetreeTarget = (repoPath) => {
|
|
|
2324
2758
|
}
|
|
2325
2759
|
if (process.platform === "win32") {
|
|
2326
2760
|
const exe = firstExistingPath([
|
|
2327
|
-
process.env.LOCALAPPDATA &&
|
|
2328
|
-
process.env["ProgramFiles(x86)"] &&
|
|
2329
|
-
process.env.ProgramFiles &&
|
|
2761
|
+
process.env.LOCALAPPDATA && path12.join(process.env.LOCALAPPDATA, "SourceTree", "SourceTree.exe"),
|
|
2762
|
+
process.env["ProgramFiles(x86)"] && path12.join(process.env["ProgramFiles(x86)"], "Atlassian", "SourceTree", "SourceTree.exe"),
|
|
2763
|
+
process.env.ProgramFiles && path12.join(process.env.ProgramFiles, "Atlassian", "SourceTree", "SourceTree.exe")
|
|
2330
2764
|
]);
|
|
2331
2765
|
if (exe != null) return { bin: exe, args: ["-f", repoPath] };
|
|
2332
2766
|
}
|
|
@@ -2343,22 +2777,22 @@ var sourcetreeInstallHint = () => {
|
|
|
2343
2777
|
return "Sourcetree is not available on Linux \u2014 try a native Git GUI instead";
|
|
2344
2778
|
};
|
|
2345
2779
|
var runLaunch = (label, target) => {
|
|
2346
|
-
console.log(
|
|
2780
|
+
console.log(chalk22.green(`Opening in ${label}: ${chalk22.dim(target.args[target.args.length - 1])}`));
|
|
2347
2781
|
const child = spawn(target.bin, target.args, { stdio: "ignore", detached: true, shell: true });
|
|
2348
2782
|
child.unref();
|
|
2349
2783
|
};
|
|
2350
2784
|
var repoOpenCommand = (options = {}) => {
|
|
2351
2785
|
const repoPath = configManager.repo_path;
|
|
2352
2786
|
if (repoPath == null) {
|
|
2353
|
-
console.error(
|
|
2354
|
-
console.log(
|
|
2787
|
+
console.error(chalk22.red("\u274C No repo installed."));
|
|
2788
|
+
console.log(chalk22.yellow("Run: set-prompt install <git-url>"));
|
|
2355
2789
|
return;
|
|
2356
2790
|
}
|
|
2357
2791
|
if (options.code === true) {
|
|
2358
2792
|
const target = resolveVscodeTarget(repoPath);
|
|
2359
2793
|
if (target == null) {
|
|
2360
|
-
console.error(
|
|
2361
|
-
console.log(
|
|
2794
|
+
console.error(chalk22.red("\u274C VSCode CLI (`code`) not found on PATH."));
|
|
2795
|
+
console.log(chalk22.dim(` ${VSCODE_INSTALL_HINT}`));
|
|
2362
2796
|
return;
|
|
2363
2797
|
}
|
|
2364
2798
|
runLaunch("VSCode", target);
|
|
@@ -2367,8 +2801,8 @@ var repoOpenCommand = (options = {}) => {
|
|
|
2367
2801
|
if (options.stree === true) {
|
|
2368
2802
|
const target = resolveSourcetreeTarget(repoPath);
|
|
2369
2803
|
if (target == null) {
|
|
2370
|
-
console.error(
|
|
2371
|
-
console.log(
|
|
2804
|
+
console.error(chalk22.red("\u274C Sourcetree not found."));
|
|
2805
|
+
console.log(chalk22.dim(` ${sourcetreeInstallHint()}`));
|
|
2372
2806
|
return;
|
|
2373
2807
|
}
|
|
2374
2808
|
runLaunch("Sourcetree", target);
|
|
@@ -2376,46 +2810,46 @@ var repoOpenCommand = (options = {}) => {
|
|
|
2376
2810
|
}
|
|
2377
2811
|
const platform = process.platform;
|
|
2378
2812
|
const opener = platform === "win32" ? "explorer" : platform === "darwin" ? "open" : "xdg-open";
|
|
2379
|
-
console.log(
|
|
2813
|
+
console.log(chalk22.green(`Opening: ${chalk22.dim(repoPath)}`));
|
|
2380
2814
|
const child = spawn(opener, [repoPath], { stdio: "ignore", detached: true });
|
|
2381
2815
|
child.on("error", (ex) => {
|
|
2382
|
-
console.error(
|
|
2816
|
+
console.error(chalk22.red(`\u274C Failed to open: ${ex.message}`));
|
|
2383
2817
|
});
|
|
2384
2818
|
child.unref();
|
|
2385
2819
|
};
|
|
2386
2820
|
|
|
2387
2821
|
// src/index.ts
|
|
2388
2822
|
process.on("SIGINT", () => {
|
|
2389
|
-
console.log(
|
|
2823
|
+
console.log(chalk23.yellow("\nCancelled."));
|
|
2390
2824
|
process.exit(0);
|
|
2391
2825
|
});
|
|
2392
2826
|
process.on("unhandledRejection", (reason) => {
|
|
2393
2827
|
if (reason instanceof Error && reason.name === "ExitPromptError") {
|
|
2394
|
-
console.log(
|
|
2828
|
+
console.log(chalk23.yellow("\nCancelled."));
|
|
2395
2829
|
process.exit(0);
|
|
2396
2830
|
}
|
|
2397
2831
|
throw reason;
|
|
2398
2832
|
});
|
|
2399
|
-
var __dirname =
|
|
2400
|
-
var pkg = JSON.parse(
|
|
2833
|
+
var __dirname = path13.dirname(fileURLToPath(import.meta.url));
|
|
2834
|
+
var pkg = JSON.parse(fs14.readFileSync(path13.join(__dirname, "../package.json"), "utf-8"));
|
|
2401
2835
|
configManager.init();
|
|
2402
2836
|
var program = new Command();
|
|
2403
|
-
var banner =
|
|
2837
|
+
var banner = chalk23.cyan(figlet.textSync("Set-Prompt", { horizontalLayout: "full" }));
|
|
2404
2838
|
program.name("set-prompt").description(pkg.description).version(pkg.version).addHelpText("beforeAll", ({ command }) => command === program ? banner + "\n" : "");
|
|
2405
|
-
program.command("install").description(`\u{1F4E6} Clone a ${
|
|
2839
|
+
program.command("install").description(`\u{1F4E6} Clone a ${chalk23.cyan("git repo")} into ${chalk23.dim("~/.set-prompt/repo/")} and register it as your prompt source`).argument("<url>", "remote git URL").action(async (source) => {
|
|
2406
2840
|
await installCommand(source);
|
|
2407
2841
|
});
|
|
2408
|
-
program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${
|
|
2842
|
+
program.command("link").description(`\u{1F517} Symlink your prompt repo into an ${chalk23.cyan("AI agent")} plugin dir ${chalk23.dim("(claudecode | roocode | openclaw | codex | antigravity)")}`).argument("[agent]", `target agent ${chalk23.dim("(omit for interactive selection)")}`).action(async (agent) => {
|
|
2409
2843
|
await linkCommand(agent);
|
|
2410
2844
|
});
|
|
2411
|
-
program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${
|
|
2845
|
+
program.command("scaffold").description(`\u{1F6E0}\uFE0F Verify and create ${chalk23.cyan("required directories")} in a prompt repo ${chalk23.dim("(-f to force overwrite)")}`).argument("[path]", `path to repo ${chalk23.dim("(defaults to installed source)")}`).action(async (localPath) => {
|
|
2412
2846
|
await scaffoldCommand(localPath);
|
|
2413
2847
|
});
|
|
2414
|
-
program.command("status").description(`\u{1F4CB} Show registered ${
|
|
2848
|
+
program.command("status").description(`\u{1F4CB} Show registered ${chalk23.cyan("repo")} and which ${chalk23.cyan("agents")} are linked`).action(() => {
|
|
2415
2849
|
statusCommand();
|
|
2416
2850
|
});
|
|
2417
|
-
var repo = program.command("repo").description(`\u{1F5C2}\uFE0F Manage the installed prompt repo ${
|
|
2418
|
-
repo.command("status").description(`\u{1F4CB} Show VCS status of the repo ${
|
|
2851
|
+
var repo = program.command("repo").description(`\u{1F5C2}\uFE0F Manage the installed prompt repo ${chalk23.dim("(status | pull | commit | push | save | path | open)")}`);
|
|
2852
|
+
repo.command("status").description(`\u{1F4CB} Show VCS status of the repo ${chalk23.dim("(branch, ahead/behind, changed files)")}`).addHelpText("after", `
|
|
2419
2853
|
Example output:
|
|
2420
2854
|
\u{1F4C2} ~/.set-prompt/repo
|
|
2421
2855
|
\u{1F33F} main \u2192 origin/main (ahead 2)
|
|
@@ -2426,47 +2860,47 @@ Example output:
|
|
|
2426
2860
|
`).action(() => {
|
|
2427
2861
|
repoStatusCommand();
|
|
2428
2862
|
});
|
|
2429
|
-
repo.command("pull").description(`\u{1F504} Fetch and pull the latest changes from the ${
|
|
2863
|
+
repo.command("pull").description(`\u{1F504} Fetch and pull the latest changes from the ${chalk23.cyan("remote repo")}`).action(() => {
|
|
2430
2864
|
repoPullCommand();
|
|
2431
2865
|
});
|
|
2432
|
-
repo.command("commit").description(`\u{1F4DD} Stage all changes and commit ${
|
|
2866
|
+
repo.command("commit").description(`\u{1F4DD} Stage all changes and commit ${chalk23.dim("(auto-generates message if -m omitted; does not push)")}`).option("-m, --message <msg>", "commit message (auto-generated from changed files if omitted)").addHelpText("after", `
|
|
2433
2867
|
Examples:
|
|
2434
2868
|
$ sppt repo commit -m "edit dbml skill"
|
|
2435
|
-
$ sppt repo commit ${
|
|
2869
|
+
$ sppt repo commit ${chalk23.dim('# auto-generates "update N files" + file list')}
|
|
2436
2870
|
`).action((opts) => {
|
|
2437
2871
|
repoCommitCommand({ message: opts.message });
|
|
2438
2872
|
});
|
|
2439
2873
|
repo.command("push").description(`\u2B06\uFE0F Push local commits to the remote`).action(() => {
|
|
2440
2874
|
repoPushCommand();
|
|
2441
2875
|
});
|
|
2442
|
-
repo.command("save").description(`\u{1F4BE} Stage + commit + push in one step ${
|
|
2876
|
+
repo.command("save").description(`\u{1F4BE} Stage + commit + push in one step ${chalk23.dim("(macro for commit \u2192 push; auto-generates message if -m omitted)")}`).option("-m, --message <msg>", "commit message (auto-generated from changed files if omitted)").addHelpText("after", `
|
|
2443
2877
|
Examples:
|
|
2444
2878
|
$ sppt repo save -m "edit dbml skill"
|
|
2445
|
-
$ sppt repo save ${
|
|
2879
|
+
$ sppt repo save ${chalk23.dim("# auto-generates message and pushes")}
|
|
2446
2880
|
|
|
2447
2881
|
Equivalent to: sppt repo commit && sppt repo push
|
|
2448
2882
|
`).action((opts) => {
|
|
2449
2883
|
repoSaveCommand({ message: opts.message });
|
|
2450
2884
|
});
|
|
2451
|
-
repo.command("path").description(`\u{1F4CD} Print the repo path to stdout ${
|
|
2885
|
+
repo.command("path").description(`\u{1F4CD} Print the repo path to stdout ${chalk23.dim("(e.g. cd $(sppt repo path))")}`).addHelpText("after", `
|
|
2452
2886
|
Examples:
|
|
2453
2887
|
$ sppt repo path
|
|
2454
|
-
${
|
|
2888
|
+
${chalk23.dim("/Users/me/.set-prompt/repo")}
|
|
2455
2889
|
|
|
2456
|
-
$ cd "$(sppt repo path)" ${
|
|
2457
|
-
$ code "$(sppt repo path)" ${
|
|
2890
|
+
$ cd "$(sppt repo path)" ${chalk23.dim("# jump into the repo")}
|
|
2891
|
+
$ code "$(sppt repo path)" ${chalk23.dim("# open in VSCode")}
|
|
2458
2892
|
`).action(() => {
|
|
2459
2893
|
repoPathCommand();
|
|
2460
2894
|
});
|
|
2461
|
-
repo.command("open").description(`\u{1F4C2} Open the repo in the OS file manager ${
|
|
2895
|
+
repo.command("open").description(`\u{1F4C2} Open the repo in the OS file manager ${chalk23.dim("(--code: VSCode, --stree: Sourcetree)")}`).option("--code", "open with VSCode (`code` CLI)").option("--stree", "open with Sourcetree (`stree` CLI)").addHelpText("after", `
|
|
2462
2896
|
Examples:
|
|
2463
|
-
$ sppt repo open ${
|
|
2464
|
-
$ sppt repo open --code ${
|
|
2465
|
-
$ sppt repo open --stree ${
|
|
2897
|
+
$ sppt repo open ${chalk23.dim("# Explorer / Finder / xdg-open")}
|
|
2898
|
+
$ sppt repo open --code ${chalk23.dim("# open in VSCode")}
|
|
2899
|
+
$ sppt repo open --stree ${chalk23.dim("# open in Sourcetree")}
|
|
2466
2900
|
`).action((opts) => {
|
|
2467
2901
|
repoOpenCommand({ code: opts.code, stree: opts.stree });
|
|
2468
2902
|
});
|
|
2469
|
-
program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${
|
|
2903
|
+
program.command("uninstall").description(`\u{1F5D1}\uFE0F Remove all set-prompt data ${chalk23.dim("(~/.set-prompt/, plugin dirs, settings entries)")}`).action(async () => {
|
|
2470
2904
|
await uninstallCommand();
|
|
2471
2905
|
});
|
|
2472
2906
|
program.parse(process.argv);
|