@dragonbot-skills/cli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -29
- package/dist/cli.js +153 -48
- package/dist/cli.js.map +1 -1
- package/dist/cowork-plugin.js +176 -0
- package/dist/cowork-plugin.js.map +1 -0
- package/dist/install.js +168 -72
- package/dist/install.js.map +1 -1
- package/dist/platforms.js +170 -0
- package/dist/platforms.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
# @dragonbot-skills/cli
|
|
2
2
|
|
|
3
|
-
Install
|
|
4
|
-
|
|
3
|
+
Install Claude skills from the DragonBot catalog into every AI coding
|
|
4
|
+
tool you use, with one command:
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
7
|
npx @dragonbot-skills/cli install amazon-kw-research
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
That
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
That auto-detects every AI coding platform installed on your machine
|
|
11
|
+
(Claude Code, Cursor, Codex CLI, GitHub Copilot, Windsurf, Cline,
|
|
12
|
+
OpenCode, Continue, Gemini CLI, Roo, Zed) and drops the skill folder
|
|
13
|
+
into each one's skills directory. Install once, available everywhere.
|
|
14
14
|
|
|
15
15
|
## Commands
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
# What
|
|
18
|
+
# What skills are in the catalog?
|
|
19
19
|
dragonbot-skills list
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# What platforms am I targeting?
|
|
22
|
+
dragonbot-skills list-platforms
|
|
23
|
+
|
|
24
|
+
# Install (auto-detects every supported platform)
|
|
22
25
|
dragonbot-skills install amazon-kw-research
|
|
23
26
|
|
|
24
|
-
#
|
|
25
|
-
dragonbot-skills install amazon-kw-research --
|
|
27
|
+
# Scope to specific platforms
|
|
28
|
+
dragonbot-skills install amazon-kw-research --target claude-code,cursor
|
|
29
|
+
|
|
30
|
+
# Install to a raw directory (useful for clients we don't recognize yet)
|
|
31
|
+
dragonbot-skills install amazon-kw-research --dir ./.claude/skills
|
|
26
32
|
|
|
27
|
-
#
|
|
28
|
-
dragonbot-skills install amazon-kw-research --
|
|
33
|
+
# Preview what would happen, write nothing
|
|
34
|
+
dragonbot-skills install amazon-kw-research --dry-run
|
|
29
35
|
|
|
30
36
|
# Reinstall over an existing copy
|
|
31
37
|
dragonbot-skills install amazon-kw-research --force
|
|
32
38
|
|
|
33
|
-
# Remove
|
|
39
|
+
# Remove (also multi-platform by default)
|
|
34
40
|
dragonbot-skills uninstall amazon-kw-research
|
|
35
41
|
```
|
|
36
42
|
|
|
@@ -42,33 +48,44 @@ dragonbot-skills uninstall amazon-kw-research
|
|
|
42
48
|
|---|---|
|
|
43
49
|
| `amazon-kw-research` | Amazon keyword research → workbook + PPC setup (uses Keepa + Jungle Scout via the DragonBot MCP). |
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
after upgrading.
|
|
51
|
+
Catalog grows over time — run `dragonbot-skills list` after upgrading.
|
|
47
52
|
|
|
48
53
|
## Where it installs
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| `user` *(default)* | `~/.claude/skills/<slug>/` | one install, every project on this machine sees it |
|
|
53
|
-
| `--project` | `<cwd>/.claude/skills/<slug>/` | this repo only |
|
|
54
|
-
| `--target <dir>` | `<dir>/<slug>/` | custom — for clients that use a different skills directory |
|
|
55
|
+
Default behavior: install to **every detected platform**. The registry:
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
| Platform id | Install path | Detected by |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `claude-code` | `~/.claude/skills/<slug>/` | `~/.claude` exists |
|
|
60
|
+
| `cursor` | `~/.cursor/skills/<slug>/` | `~/.cursor` exists |
|
|
61
|
+
| `codex` | `~/.codex/skills/<slug>/` | `~/.codex` exists |
|
|
62
|
+
| `copilot` | `<cwd>/.github/copilot/skills/<slug>/` | `.github/copilot/` or `.github/copilot-instructions.md` |
|
|
63
|
+
| `windsurf` | `~/.windsurf/skills/<slug>/` | `~/.windsurf` or `.windsurfrules` |
|
|
64
|
+
| `cline` | `~/.cline/skills/<slug>/` | `~/.cline` or `.clinerules` |
|
|
65
|
+
| `opencode` | `~/.opencode/skills/<slug>/` | `~/.opencode` exists |
|
|
66
|
+
| `continue` | `~/.continue/skills/<slug>/` | `~/.continue` exists |
|
|
67
|
+
| `gemini` | `~/.gemini/skills/<slug>/` | `~/.gemini` exists |
|
|
68
|
+
| `roo` | `~/.roo/skills/<slug>/` | `~/.roo` or `.roorules` |
|
|
69
|
+
| `zed` | `~/Library/Application Support/Zed/skills/<slug>/` (macOS) | parent dir exists |
|
|
70
|
+
|
|
71
|
+
Some paths are best-effort (the platform hasn't documented a canonical
|
|
72
|
+
skills directory). They're marked in the source — open an issue if
|
|
73
|
+
you know better.
|
|
74
|
+
|
|
75
|
+
Run `dragonbot-skills list-platforms` on your machine to see what's
|
|
76
|
+
detected and where each install would land.
|
|
60
77
|
|
|
61
78
|
## Updating
|
|
62
79
|
|
|
63
|
-
Skills are bundled with this package, so
|
|
64
|
-
latest
|
|
80
|
+
Skills are bundled with this package, so upgrading is just re-running
|
|
81
|
+
`npx` with `@latest`:
|
|
65
82
|
|
|
66
83
|
```bash
|
|
67
84
|
npx @dragonbot-skills/cli@latest install amazon-kw-research --force
|
|
68
85
|
```
|
|
69
86
|
|
|
70
87
|
`--force` is needed because we won't silently overwrite an existing
|
|
71
|
-
install.
|
|
88
|
+
install.
|
|
72
89
|
|
|
73
90
|
## Development
|
|
74
91
|
|
|
@@ -77,15 +94,22 @@ npm install
|
|
|
77
94
|
npm run typecheck
|
|
78
95
|
npm test
|
|
79
96
|
npm run build # → dist/cli.js (chmod +x)
|
|
80
|
-
node dist/cli.js list
|
|
97
|
+
node dist/cli.js list-platforms
|
|
81
98
|
```
|
|
82
99
|
|
|
83
100
|
Skills live in `skills/<slug>/SKILL.md` at the package root. Adding a
|
|
84
|
-
new skill = adding a
|
|
101
|
+
new skill = adding a folder there with a `SKILL.md` containing
|
|
85
102
|
frontmatter (`name:`, `description:`) and a markdown body. The
|
|
86
103
|
`bundledRoot` test override pattern in `src/install.test.ts` lets you
|
|
87
104
|
unit-test against synthetic skills without touching the real catalog.
|
|
88
105
|
|
|
106
|
+
## Credits
|
|
107
|
+
|
|
108
|
+
The auto-detect-and-install-everywhere pattern is adapted from
|
|
109
|
+
[skills-hub.ai](https://skills-hub.ai)'s
|
|
110
|
+
[@skills-hub-ai/cli](https://www.npmjs.com/package/@skills-hub-ai/cli)
|
|
111
|
+
(MIT). They pioneered this UX for Claude-style skills.
|
|
112
|
+
|
|
89
113
|
## License
|
|
90
114
|
|
|
91
115
|
MIT — see [LICENSE](LICENSE).
|
package/dist/cli.js
CHANGED
|
@@ -1,36 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @dragonbot-skills/cli — installer for DragonBot's Claude skills.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// Default install behavior: auto-detect every AI coding platform
|
|
5
|
+
// installed on this machine (Claude Code, Cursor, Codex, Copilot,
|
|
6
|
+
// Windsurf, ...) and drop the skill into each one. Match the
|
|
7
|
+
// "install once, works everywhere" UX from other skills hubs.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// reach for one.
|
|
9
|
+
// Override with `--target claude-code,cursor` (specific platforms)
|
|
10
|
+
// or `--dir <path>` (raw directory).
|
|
12
11
|
import { listBundledSkills } from "./skills.js";
|
|
13
|
-
import { install, uninstall } from "./install.js";
|
|
12
|
+
import { install, uninstall, resolveDestinations, parsePlatformIds, detectAllPlatforms, } from "./install.js";
|
|
13
|
+
import { PLATFORM_REGISTRY, realEnv } from "./platforms.js";
|
|
14
14
|
const USAGE = `dragonbot-skills — install Claude skills from the DragonBot catalog
|
|
15
15
|
|
|
16
16
|
Usage:
|
|
17
17
|
dragonbot-skills list
|
|
18
|
-
dragonbot-skills
|
|
19
|
-
dragonbot-skills
|
|
18
|
+
dragonbot-skills list-platforms
|
|
19
|
+
dragonbot-skills install <slug> [--target IDS] [--dir DIR] [--force] [--dry-run]
|
|
20
|
+
dragonbot-skills uninstall <slug> [--target IDS] [--dir DIR]
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
--target
|
|
22
|
+
Default behavior:
|
|
23
|
+
install / uninstall auto-detects every installed AI coding platform
|
|
24
|
+
(Claude Code, Cursor, Codex, Copilot, Windsurf, Cline, ...) and
|
|
25
|
+
applies the action to ALL of them. Use --target or --dir to scope.
|
|
25
26
|
|
|
26
27
|
Flags:
|
|
27
|
-
--
|
|
28
|
-
|
|
28
|
+
--target IDS comma-separated platform ids (e.g. claude-code,cursor)
|
|
29
|
+
see \`list-platforms\` for the full set
|
|
30
|
+
--dir DIR install to <DIR>/<slug>/ instead of any detected
|
|
31
|
+
platform — useful for clients we don't recognize
|
|
32
|
+
--force overwrite an existing install
|
|
33
|
+
--dry-run show what install would do without writing anything
|
|
34
|
+
-h, --help show this help
|
|
29
35
|
|
|
30
36
|
Examples:
|
|
31
37
|
dragonbot-skills install amazon-kw-research
|
|
32
|
-
dragonbot-skills install amazon-kw-research --
|
|
33
|
-
dragonbot-skills
|
|
38
|
+
dragonbot-skills install amazon-kw-research --target claude-code,cursor
|
|
39
|
+
dragonbot-skills install amazon-kw-research --dir ./.claude/skills
|
|
40
|
+
dragonbot-skills install amazon-kw-research --dry-run
|
|
41
|
+
dragonbot-skills list-platforms
|
|
34
42
|
`;
|
|
35
43
|
function main(argv) {
|
|
36
44
|
const args = argv.slice(2);
|
|
@@ -43,6 +51,8 @@ function main(argv) {
|
|
|
43
51
|
switch (command) {
|
|
44
52
|
case "list":
|
|
45
53
|
return runList();
|
|
54
|
+
case "list-platforms":
|
|
55
|
+
return runListPlatforms();
|
|
46
56
|
case "install":
|
|
47
57
|
return runInstall(rest);
|
|
48
58
|
case "uninstall":
|
|
@@ -61,29 +71,105 @@ function runList() {
|
|
|
61
71
|
process.stdout.write(`Available skills (${skills.length}):\n\n`);
|
|
62
72
|
const slugWidth = Math.max(...skills.map((s) => s.slug.length));
|
|
63
73
|
for (const s of skills) {
|
|
64
|
-
|
|
65
|
-
process.stdout.write(` ${padded} ${s.description}\n`);
|
|
74
|
+
process.stdout.write(` ${s.slug.padEnd(slugWidth, " ")} ${s.description}\n`);
|
|
66
75
|
}
|
|
67
76
|
process.stdout.write("\nInstall one with: dragonbot-skills install <slug>\n");
|
|
68
77
|
return 0;
|
|
69
78
|
}
|
|
79
|
+
function runListPlatforms() {
|
|
80
|
+
const env = realEnv();
|
|
81
|
+
const detected = new Set(detectAllPlatforms(env).map((p) => p.id));
|
|
82
|
+
process.stdout.write("Supported platforms:\n\n");
|
|
83
|
+
const idWidth = Math.max(...PLATFORM_REGISTRY.map((p) => p.id.length));
|
|
84
|
+
for (const p of PLATFORM_REGISTRY) {
|
|
85
|
+
const tag = detected.has(p.id) ? "✓ detected" : " (not detected)";
|
|
86
|
+
process.stdout.write(` ${p.id.padEnd(idWidth, " ")} ${tag} ${p.label} → ${p.skillsRoot(env)}\n`);
|
|
87
|
+
}
|
|
88
|
+
process.stdout.write("\nDefault install targets every detected platform. Override with " +
|
|
89
|
+
"--target <id>[,<id>...] or --dir <path>.\n");
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
70
92
|
function runInstall(rest) {
|
|
71
|
-
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = parseFlags(rest);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
process.stderr.write(`${err.message}\n`);
|
|
99
|
+
return 2;
|
|
100
|
+
}
|
|
101
|
+
const { positionals, flags } = parsed;
|
|
72
102
|
const slug = positionals[0];
|
|
73
103
|
if (!slug) {
|
|
74
104
|
process.stderr.write("install: missing <slug>\n\n" + USAGE);
|
|
75
105
|
return 2;
|
|
76
106
|
}
|
|
77
|
-
|
|
107
|
+
if (flags.target && flags.dir) {
|
|
108
|
+
process.stderr.write("install: --target and --dir are mutually exclusive\n");
|
|
109
|
+
return 2;
|
|
110
|
+
}
|
|
111
|
+
// Resolve --target into known platforms; warn on typos before installing.
|
|
112
|
+
let targets;
|
|
113
|
+
if (flags.target) {
|
|
114
|
+
const { known, unknown } = parsePlatformIds(flags.target);
|
|
115
|
+
if (unknown.length > 0) {
|
|
116
|
+
process.stderr.write(`Unknown platform id(s): ${unknown.join(", ")}\n` +
|
|
117
|
+
`Run \`dragonbot-skills list-platforms\` for the full set.\n`);
|
|
118
|
+
return 2;
|
|
119
|
+
}
|
|
120
|
+
targets = known;
|
|
121
|
+
}
|
|
122
|
+
// Preview the destinations before doing the work. If nothing was
|
|
123
|
+
// detected and the user didn't override, explain it before
|
|
124
|
+
// throwing — much nicer than a wall of text from the thrown error.
|
|
125
|
+
const previewDests = resolveDestinations({ slug, targets, dir: flags.dir });
|
|
126
|
+
if (previewDests.length === 0) {
|
|
127
|
+
process.stderr.write("No supported AI coding platforms were detected on this machine.\n" +
|
|
128
|
+
"Pass --target <id> (see `dragonbot-skills list-platforms`) or " +
|
|
129
|
+
"--dir <path> to install anyway.\n");
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
78
132
|
try {
|
|
79
133
|
const result = install({
|
|
80
134
|
slug,
|
|
81
|
-
|
|
82
|
-
|
|
135
|
+
targets,
|
|
136
|
+
dir: flags.dir,
|
|
83
137
|
force: flags.force,
|
|
138
|
+
dryRun: flags.dryRun,
|
|
84
139
|
});
|
|
85
|
-
|
|
86
|
-
|
|
140
|
+
let installed = 0;
|
|
141
|
+
let skipped = 0;
|
|
142
|
+
let errored = 0;
|
|
143
|
+
for (const entry of result.entries) {
|
|
144
|
+
const tag = entry.status === "installed"
|
|
145
|
+
? "✓"
|
|
146
|
+
: entry.status === "would-install"
|
|
147
|
+
? "·"
|
|
148
|
+
: entry.status === "skipped-exists"
|
|
149
|
+
? "⊝"
|
|
150
|
+
: "✗";
|
|
151
|
+
const trailer = entry.reason ? ` (${entry.reason})` : "";
|
|
152
|
+
process.stdout.write(`${tag} ${entry.label.padEnd(16)} → ${entry.installedTo}${trailer}\n`);
|
|
153
|
+
if (entry.status === "installed")
|
|
154
|
+
installed++;
|
|
155
|
+
else if (entry.status === "skipped-exists")
|
|
156
|
+
skipped++;
|
|
157
|
+
else if (entry.status === "error")
|
|
158
|
+
errored++;
|
|
159
|
+
}
|
|
160
|
+
if (flags.dryRun) {
|
|
161
|
+
process.stdout.write(`\n(dry run — nothing written)\n`);
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
const summary = [];
|
|
165
|
+
if (installed)
|
|
166
|
+
summary.push(`${installed} installed`);
|
|
167
|
+
if (skipped)
|
|
168
|
+
summary.push(`${skipped} skipped (use --force to overwrite)`);
|
|
169
|
+
if (errored)
|
|
170
|
+
summary.push(`${errored} failed`);
|
|
171
|
+
process.stdout.write(`\n${summary.join(", ") || "no-op"}\n`);
|
|
172
|
+
return errored > 0 ? 1 : 0;
|
|
87
173
|
}
|
|
88
174
|
catch (err) {
|
|
89
175
|
process.stderr.write(`${err.message}\n`);
|
|
@@ -91,31 +177,46 @@ function runInstall(rest) {
|
|
|
91
177
|
}
|
|
92
178
|
}
|
|
93
179
|
function runUninstall(rest) {
|
|
94
|
-
|
|
180
|
+
let parsed;
|
|
181
|
+
try {
|
|
182
|
+
parsed = parseFlags(rest);
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
process.stderr.write(`${err.message}\n`);
|
|
186
|
+
return 2;
|
|
187
|
+
}
|
|
188
|
+
const { positionals, flags } = parsed;
|
|
95
189
|
const slug = positionals[0];
|
|
96
190
|
if (!slug) {
|
|
97
191
|
process.stderr.write("uninstall: missing <slug>\n\n" + USAGE);
|
|
98
192
|
return 2;
|
|
99
193
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
if (
|
|
108
|
-
process.
|
|
194
|
+
if (flags.target && flags.dir) {
|
|
195
|
+
process.stderr.write("uninstall: --target and --dir are mutually exclusive\n");
|
|
196
|
+
return 2;
|
|
197
|
+
}
|
|
198
|
+
let targets;
|
|
199
|
+
if (flags.target) {
|
|
200
|
+
const { known, unknown } = parsePlatformIds(flags.target);
|
|
201
|
+
if (unknown.length > 0) {
|
|
202
|
+
process.stderr.write(`Unknown platform id(s): ${unknown.join(", ")}\n`);
|
|
203
|
+
return 2;
|
|
204
|
+
}
|
|
205
|
+
targets = known;
|
|
206
|
+
}
|
|
207
|
+
const result = uninstall({ slug, targets, dir: flags.dir });
|
|
208
|
+
let removed = 0;
|
|
209
|
+
for (const entry of result.entries) {
|
|
210
|
+
if (entry.removed) {
|
|
211
|
+
process.stdout.write(`✓ ${entry.label.padEnd(16)} → ${entry.path}\n`);
|
|
212
|
+
removed++;
|
|
109
213
|
}
|
|
110
214
|
else {
|
|
111
|
-
process.stdout.write(
|
|
215
|
+
process.stdout.write(`· ${entry.label.padEnd(16)} → ${entry.path} (not installed)\n`);
|
|
112
216
|
}
|
|
113
|
-
return 0;
|
|
114
|
-
}
|
|
115
|
-
catch (err) {
|
|
116
|
-
process.stderr.write(`${err.message}\n`);
|
|
117
|
-
return 1;
|
|
118
217
|
}
|
|
218
|
+
process.stdout.write(`\n${removed} removed\n`);
|
|
219
|
+
return 0;
|
|
119
220
|
}
|
|
120
221
|
function parseFlags(args) {
|
|
121
222
|
const positionals = [];
|
|
@@ -130,17 +231,21 @@ function parseFlags(args) {
|
|
|
130
231
|
const key = eq < 0 ? arg.slice(2) : arg.slice(2, eq);
|
|
131
232
|
const inlineValue = eq < 0 ? undefined : arg.slice(eq + 1);
|
|
132
233
|
switch (key) {
|
|
133
|
-
case "project":
|
|
134
|
-
flags.project = true;
|
|
135
|
-
break;
|
|
136
234
|
case "force":
|
|
137
235
|
flags.force = true;
|
|
138
236
|
break;
|
|
237
|
+
case "dry-run":
|
|
238
|
+
flags.dryRun = true;
|
|
239
|
+
break;
|
|
139
240
|
case "target":
|
|
140
241
|
flags.target = inlineValue ?? args[++i];
|
|
141
|
-
if (!flags.target)
|
|
142
|
-
throw new Error("--target needs a
|
|
143
|
-
|
|
242
|
+
if (!flags.target)
|
|
243
|
+
throw new Error("--target needs a value");
|
|
244
|
+
break;
|
|
245
|
+
case "dir":
|
|
246
|
+
flags.dir = inlineValue ?? args[++i];
|
|
247
|
+
if (!flags.dir)
|
|
248
|
+
throw new Error("--dir needs a directory path");
|
|
144
249
|
break;
|
|
145
250
|
default:
|
|
146
251
|
throw new Error(`Unknown flag: --${key}`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,mEAAmE;AACnE,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Cowork / Claude Desktop "plugin bundle" installer.
|
|
2
|
+
//
|
|
3
|
+
// Cowork and Claude Desktop don't load skills from ~/.claude/skills/.
|
|
4
|
+
// They load them from a per-app plugin tree under:
|
|
5
|
+
//
|
|
6
|
+
// ~/Library/Application Support/<App>/local-agent-mode-sessions/skills-plugin/
|
|
7
|
+
// <plugin-uuid>/<snapshot-uuid>/
|
|
8
|
+
// .claude-plugin/plugin.json {name, version, description}
|
|
9
|
+
// manifest.json {lastUpdated, skills: [...]}
|
|
10
|
+
// skills/<slug>/SKILL.md (+ nested files)
|
|
11
|
+
//
|
|
12
|
+
// Each "plugin" is a bundle of one or more skills. We ship our
|
|
13
|
+
// catalog as a single bundle named "dragonbot-skills". The UUIDs in
|
|
14
|
+
// the path are hardcoded so subsequent installs (and --force
|
|
15
|
+
// reinstalls) land in the same directory, and the manifest is
|
|
16
|
+
// merged across calls so `install amazon-kw-research` followed by
|
|
17
|
+
// `install other-skill` ends up with both listed under the same
|
|
18
|
+
// plugin.
|
|
19
|
+
//
|
|
20
|
+
// Unknowns we accept:
|
|
21
|
+
// - Cowork's docs don't describe a user-installable plugin path;
|
|
22
|
+
// this layout is reverse-engineered from the Anthropic-managed
|
|
23
|
+
// skills bundle that ships with the app. It may not load until
|
|
24
|
+
// Cowork is restarted, and could in theory be wiped on resync.
|
|
25
|
+
// Mark this installer as best-effort in the README.
|
|
26
|
+
import fs from "node:fs";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
// Bundle identity. Stable forever for this package — same on every
|
|
29
|
+
// machine, so reinstalls find the right directory.
|
|
30
|
+
//
|
|
31
|
+
// Generated with crypto.randomUUID(); not derived from the package
|
|
32
|
+
// name. If we ever ship multiple plugin bundles, give each its own
|
|
33
|
+
// pair of UUIDs.
|
|
34
|
+
export const DRAGONBOT_PLUGIN_UUID = "d4a900b1-7e3f-4b8a-9c1d-2e3f4a5b6c7d";
|
|
35
|
+
export const DRAGONBOT_SNAPSHOT_UUID = "f1e2d3c4-5b6a-7c80-9d12-3456789abcde";
|
|
36
|
+
export const PLUGIN_NAME = "dragonbot-skills";
|
|
37
|
+
export const PLUGIN_DESCRIPTION = "Amazon analytics + ops skills for Claude (DragonBot catalog).";
|
|
38
|
+
const APP_SUBDIRS = {
|
|
39
|
+
// Both apps live under ~/Library/Application Support on macOS.
|
|
40
|
+
// Claude is the consumer Desktop app, Claude-Work is Cowork.
|
|
41
|
+
"claude-desktop": "Claude",
|
|
42
|
+
cowork: "Claude-Work",
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Absolute path to the app-specific plugin bundle directory for our
|
|
46
|
+
* plugin. Doesn't check whether the dir exists yet.
|
|
47
|
+
*/
|
|
48
|
+
export function bundleDir(app, env) {
|
|
49
|
+
return path.join(env.home, "Library", "Application Support", APP_SUBDIRS[app], "local-agent-mode-sessions", "skills-plugin", DRAGONBOT_PLUGIN_UUID, DRAGONBOT_SNAPSHOT_UUID);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Path to the parent "skills-plugin" dir for an app. Used by the
|
|
53
|
+
* detect() probe — if this dir exists, the app is installed and
|
|
54
|
+
* supports plugin-style skills.
|
|
55
|
+
*/
|
|
56
|
+
export function appPluginRoot(app, env) {
|
|
57
|
+
return path.join(env.home, "Library", "Application Support", APP_SUBDIRS[app], "local-agent-mode-sessions", "skills-plugin");
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Install a single skill into the Cowork/Claude-Desktop plugin
|
|
61
|
+
* bundle for `app`. Atomic-ish: stages the new skill folder under a
|
|
62
|
+
* tmp name and renames into place. The manifest is updated in
|
|
63
|
+
* place — read, splice/replace the entry for `slug`, write back.
|
|
64
|
+
*
|
|
65
|
+
* `pluginVersion` becomes the `version` field in plugin.json. Bump
|
|
66
|
+
* it when our skill content changes so Cowork can detect updates;
|
|
67
|
+
* we default to the CLI's own package version.
|
|
68
|
+
*/
|
|
69
|
+
export function installToCowork(args) {
|
|
70
|
+
const dir = bundleDir(args.app, args.env);
|
|
71
|
+
const skillsDir = path.join(dir, "skills");
|
|
72
|
+
const skillDest = path.join(skillsDir, args.slug);
|
|
73
|
+
if (fs.existsSync(skillDest) && !args.force) {
|
|
74
|
+
return {
|
|
75
|
+
installed: false,
|
|
76
|
+
bundlePath: skillDest,
|
|
77
|
+
reason: "destination exists; pass --force to overwrite",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
81
|
+
// Write/refresh plugin.json — cheap, ensures version bumps land.
|
|
82
|
+
const pluginJsonDir = path.join(dir, ".claude-plugin");
|
|
83
|
+
fs.mkdirSync(pluginJsonDir, { recursive: true });
|
|
84
|
+
fs.writeFileSync(path.join(pluginJsonDir, "plugin.json"), JSON.stringify({ name: PLUGIN_NAME, version: args.pluginVersion, description: PLUGIN_DESCRIPTION }, null, 2) + "\n");
|
|
85
|
+
// Copy skill folder atomically.
|
|
86
|
+
if (fs.existsSync(skillDest)) {
|
|
87
|
+
fs.rmSync(skillDest, { recursive: true, force: true });
|
|
88
|
+
}
|
|
89
|
+
const staging = fs.mkdtempSync(path.join(skillsDir, `.${args.slug}-staging-`));
|
|
90
|
+
try {
|
|
91
|
+
copyDirRecursive(args.srcSkillDir, staging);
|
|
92
|
+
fs.renameSync(staging, skillDest);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
// Merge into manifest.
|
|
99
|
+
const manifestPath = path.join(dir, "manifest.json");
|
|
100
|
+
const manifest = readManifest(manifestPath);
|
|
101
|
+
upsertSkill(manifest, {
|
|
102
|
+
skillId: args.slug,
|
|
103
|
+
name: args.name,
|
|
104
|
+
description: args.description,
|
|
105
|
+
creatorType: "third-party",
|
|
106
|
+
updatedAt: new Date().toISOString(),
|
|
107
|
+
enabled: true,
|
|
108
|
+
});
|
|
109
|
+
manifest.lastUpdated = Date.now();
|
|
110
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
111
|
+
return { installed: true, bundlePath: skillDest };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Remove a single skill from the bundle. If it was the last skill,
|
|
115
|
+
* removes the whole plugin directory so we don't leave an empty
|
|
116
|
+
* plugin advertised in Cowork's plugin list.
|
|
117
|
+
*/
|
|
118
|
+
export function uninstallFromCowork(args) {
|
|
119
|
+
const dir = bundleDir(args.app, args.env);
|
|
120
|
+
const skillDest = path.join(dir, "skills", args.slug);
|
|
121
|
+
if (!fs.existsSync(skillDest)) {
|
|
122
|
+
return { removed: false, bundlePath: skillDest };
|
|
123
|
+
}
|
|
124
|
+
fs.rmSync(skillDest, { recursive: true, force: true });
|
|
125
|
+
const manifestPath = path.join(dir, "manifest.json");
|
|
126
|
+
const manifest = readManifest(manifestPath);
|
|
127
|
+
manifest.skills = manifest.skills.filter((s) => s.skillId !== args.slug);
|
|
128
|
+
manifest.lastUpdated = Date.now();
|
|
129
|
+
if (manifest.skills.length === 0) {
|
|
130
|
+
// Last skill — wipe the whole plugin dir so Cowork doesn't
|
|
131
|
+
// load an empty bundle.
|
|
132
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
136
|
+
}
|
|
137
|
+
return { removed: true, bundlePath: skillDest };
|
|
138
|
+
}
|
|
139
|
+
function readManifest(p) {
|
|
140
|
+
if (!fs.existsSync(p)) {
|
|
141
|
+
return { lastUpdated: Date.now(), skills: [] };
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const parsed = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
145
|
+
// Be lenient — start fresh if the existing file is garbled
|
|
146
|
+
// rather than crashing the user mid-install.
|
|
147
|
+
if (typeof parsed !== "object" || !Array.isArray(parsed.skills)) {
|
|
148
|
+
return { lastUpdated: Date.now(), skills: [] };
|
|
149
|
+
}
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return { lastUpdated: Date.now(), skills: [] };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function upsertSkill(manifest, entry) {
|
|
157
|
+
const i = manifest.skills.findIndex((s) => s.skillId === entry.skillId);
|
|
158
|
+
if (i < 0)
|
|
159
|
+
manifest.skills.push(entry);
|
|
160
|
+
else
|
|
161
|
+
manifest.skills[i] = entry;
|
|
162
|
+
}
|
|
163
|
+
function copyDirRecursive(src, dest) {
|
|
164
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
165
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
166
|
+
const s = path.join(src, entry.name);
|
|
167
|
+
const d = path.join(dest, entry.name);
|
|
168
|
+
if (entry.isDirectory()) {
|
|
169
|
+
copyDirRecursive(s, d);
|
|
170
|
+
}
|
|
171
|
+
else if (entry.isFile()) {
|
|
172
|
+
fs.copyFileSync(s, d);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=cowork-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cowork-plugin.js","sourceRoot":"","sources":["../src/cowork-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/install.js
CHANGED
|
@@ -1,68 +1,170 @@
|
|
|
1
|
-
// Install / uninstall skills
|
|
2
|
-
// directory.
|
|
1
|
+
// Install / uninstall skills across one or more AI-coding platforms.
|
|
3
2
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Default behavior (no --target): auto-detect every installed
|
|
4
|
+
// platform and write the skill to each one. Most platforms get the
|
|
5
|
+
// simple "<skillsRoot>/<slug>/" copy; Cowork and Claude Desktop go
|
|
6
|
+
// through their plugin-bundle installer (writes .claude-plugin/
|
|
7
|
+
// plugin.json + manifest.json + skills/<slug>/) instead.
|
|
7
8
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// Override with `--target claude-code,cursor` (specific platforms)
|
|
10
|
+
// or `--dir <path>` (raw directory). `--dir` always uses the simple
|
|
11
|
+
// copy; the plugin-bundle installer is reachable only via the
|
|
12
|
+
// `cowork` / `claude-desktop` platform ids.
|
|
12
13
|
//
|
|
13
|
-
//
|
|
14
|
-
// destination, then rename
|
|
15
|
-
//
|
|
16
|
-
// explicit, not silent.
|
|
14
|
+
// Each standard install is atomic-ish: copy to a staging dir next
|
|
15
|
+
// to the destination, then rename. Custom installers handle their
|
|
16
|
+
// own atomicity (see src/cowork-plugin.ts).
|
|
17
17
|
import fs from "node:fs";
|
|
18
|
-
import os from "node:os";
|
|
19
18
|
import path from "node:path";
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (opts.
|
|
27
|
-
return
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import { findBundledSkill, listBundledSkills } from "./skills.js";
|
|
21
|
+
import { detectAllPlatforms, realEnv, } from "./platforms.js";
|
|
22
|
+
/** Resolve where install() will write, given the user's flags. */
|
|
23
|
+
export function resolveDestinations(opts) {
|
|
24
|
+
const env = opts.env ?? realEnv();
|
|
25
|
+
if (opts.dir) {
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
platform: "custom",
|
|
29
|
+
label: "Custom directory",
|
|
30
|
+
skillPath: path.join(path.resolve(opts.dir), opts.slug),
|
|
31
|
+
},
|
|
32
|
+
];
|
|
28
33
|
}
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const platforms = opts.targets ?? detectAllPlatforms(env);
|
|
35
|
+
return platforms.map((p) => ({
|
|
36
|
+
platform: p.id,
|
|
37
|
+
label: p.label,
|
|
38
|
+
skillPath: path.join(p.skillsRoot(env), opts.slug),
|
|
39
|
+
entry: p,
|
|
40
|
+
}));
|
|
36
41
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Copy the bundled skill folder for `slug` into the chosen skills
|
|
39
|
-
* directory. Throws when:
|
|
40
|
-
* - the slug isn't bundled in this package
|
|
41
|
-
* - the destination exists and `force` is false
|
|
42
|
-
*/
|
|
43
42
|
export function install(opts) {
|
|
44
43
|
const src = findBundledSkill(opts.slug, opts.bundledRoot);
|
|
45
44
|
if (!src) {
|
|
46
45
|
throw new Error(`Skill not found in this package: ${opts.slug}\n` +
|
|
47
46
|
`Run \`dragonbot-skills list\` to see what's available.`);
|
|
48
47
|
}
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
const env = opts.env ?? realEnv();
|
|
49
|
+
const destinations = resolveDestinations({
|
|
50
|
+
slug: opts.slug,
|
|
51
|
+
targets: opts.targets,
|
|
52
|
+
dir: opts.dir,
|
|
53
|
+
env,
|
|
54
|
+
});
|
|
55
|
+
if (destinations.length === 0) {
|
|
56
|
+
throw new Error("No install destinations resolved. None of the supported AI " +
|
|
57
|
+
"coding platforms were detected on this machine. Pass " +
|
|
58
|
+
"--target claude-code (or another platform id, see " +
|
|
59
|
+
"`dragonbot-skills list-platforms`) or --dir <path> to " +
|
|
60
|
+
"install anyway.");
|
|
61
|
+
}
|
|
62
|
+
const skillMeta = listBundledSkills(opts.bundledRoot).find((s) => s.slug === opts.slug);
|
|
63
|
+
const skillName = skillMeta?.name ?? opts.slug;
|
|
64
|
+
const skillDescription = skillMeta?.description ?? "";
|
|
65
|
+
const pluginVersion = opts.packageVersion ?? detectPackageVersion();
|
|
66
|
+
const entries = [];
|
|
67
|
+
for (const dest of destinations) {
|
|
68
|
+
if (opts.dryRun) {
|
|
69
|
+
entries.push({
|
|
70
|
+
platform: dest.platform,
|
|
71
|
+
label: dest.label,
|
|
72
|
+
installedTo: dest.skillPath,
|
|
73
|
+
status: "would-install",
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// Custom installer (Cowork / Claude Desktop plugin bundle).
|
|
78
|
+
if (dest.entry?.customInstaller) {
|
|
79
|
+
const result = dest.entry.customInstaller.install({
|
|
80
|
+
env,
|
|
81
|
+
srcSkillDir: src,
|
|
82
|
+
slug: opts.slug,
|
|
83
|
+
name: skillName,
|
|
84
|
+
description: skillDescription,
|
|
85
|
+
pluginVersion,
|
|
86
|
+
force: opts.force,
|
|
87
|
+
});
|
|
88
|
+
entries.push({
|
|
89
|
+
platform: dest.platform,
|
|
90
|
+
label: dest.label,
|
|
91
|
+
installedTo: result.installedTo,
|
|
92
|
+
status: result.status,
|
|
93
|
+
reason: result.reason,
|
|
94
|
+
});
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Standard "<dir>/<slug>" copy.
|
|
98
|
+
try {
|
|
99
|
+
const installedTo = dest.skillPath;
|
|
100
|
+
if (fs.existsSync(installedTo)) {
|
|
101
|
+
if (!opts.force) {
|
|
102
|
+
entries.push({
|
|
103
|
+
platform: dest.platform,
|
|
104
|
+
label: dest.label,
|
|
105
|
+
installedTo,
|
|
106
|
+
status: "skipped-exists",
|
|
107
|
+
reason: "destination exists; pass --force to overwrite",
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
fs.rmSync(installedTo, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
const parentDir = path.dirname(installedTo);
|
|
114
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
115
|
+
copyIntoPlace(src, installedTo, opts.slug, parentDir);
|
|
116
|
+
entries.push({
|
|
117
|
+
platform: dest.platform,
|
|
118
|
+
label: dest.label,
|
|
119
|
+
installedTo,
|
|
120
|
+
status: "installed",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
entries.push({
|
|
125
|
+
platform: dest.platform,
|
|
126
|
+
label: dest.label,
|
|
127
|
+
installedTo: dest.skillPath,
|
|
128
|
+
status: "error",
|
|
129
|
+
reason: err.message,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { slug: opts.slug, entries };
|
|
134
|
+
}
|
|
135
|
+
export function uninstall(opts) {
|
|
136
|
+
const env = opts.env ?? realEnv();
|
|
137
|
+
const destinations = resolveDestinations({
|
|
138
|
+
slug: opts.slug,
|
|
139
|
+
targets: opts.targets,
|
|
140
|
+
dir: opts.dir,
|
|
141
|
+
env,
|
|
54
142
|
});
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
143
|
+
const entries = [];
|
|
144
|
+
for (const dest of destinations) {
|
|
145
|
+
if (dest.entry?.customInstaller) {
|
|
146
|
+
const result = dest.entry.customInstaller.uninstall({ env, slug: opts.slug });
|
|
147
|
+
entries.push({
|
|
148
|
+
platform: dest.platform,
|
|
149
|
+
label: dest.label,
|
|
150
|
+
path: result.path,
|
|
151
|
+
removed: result.removed,
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
59
154
|
}
|
|
60
|
-
|
|
155
|
+
const target = dest.skillPath;
|
|
156
|
+
if (!fs.existsSync(target)) {
|
|
157
|
+
entries.push({ platform: dest.platform, label: dest.label, path: target, removed: false });
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
161
|
+
entries.push({ platform: dest.platform, label: dest.label, path: target, removed: true });
|
|
61
162
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
163
|
+
return { slug: opts.slug, entries };
|
|
164
|
+
}
|
|
165
|
+
// Stage in a sibling tmp dir, then rename.
|
|
166
|
+
function copyIntoPlace(src, dest, slug, parent) {
|
|
167
|
+
const staging = fs.mkdtempSync(path.join(parent, `.${slug}-staging-`));
|
|
66
168
|
try {
|
|
67
169
|
copyDirRecursive(src, staging);
|
|
68
170
|
fs.renameSync(staging, dest);
|
|
@@ -71,29 +173,7 @@ export function install(opts) {
|
|
|
71
173
|
fs.rmSync(staging, { recursive: true, force: true });
|
|
72
174
|
throw err;
|
|
73
175
|
}
|
|
74
|
-
return { installedTo: dest, scope };
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Remove the installed skill folder. Idempotent: returns
|
|
78
|
-
* `removed: false` (no error) when the folder isn't present.
|
|
79
|
-
*/
|
|
80
|
-
export function uninstall(opts) {
|
|
81
|
-
const { root, scope } = resolveSkillsRoot({
|
|
82
|
-
scope: opts.scope,
|
|
83
|
-
targetDir: opts.targetDir,
|
|
84
|
-
cwd: opts.cwd,
|
|
85
|
-
home: opts.home,
|
|
86
|
-
});
|
|
87
|
-
const dest = path.join(root, opts.slug);
|
|
88
|
-
if (!fs.existsSync(dest)) {
|
|
89
|
-
return { removed: false, path: dest, scope };
|
|
90
|
-
}
|
|
91
|
-
fs.rmSync(dest, { recursive: true, force: true });
|
|
92
|
-
return { removed: true, path: dest, scope };
|
|
93
176
|
}
|
|
94
|
-
// Minimal recursive copy — no externals, follows directories and
|
|
95
|
-
// regular files only. Symlinks aren't expected in skills today; if
|
|
96
|
-
// we ever ship one, switch to fs.cp({ recursive: true, verbatimSymlinks: true }).
|
|
97
177
|
function copyDirRecursive(src, dest) {
|
|
98
178
|
fs.mkdirSync(dest, { recursive: true });
|
|
99
179
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
@@ -105,7 +185,23 @@ function copyDirRecursive(src, dest) {
|
|
|
105
185
|
else if (entry.isFile()) {
|
|
106
186
|
fs.copyFileSync(s, d);
|
|
107
187
|
}
|
|
108
|
-
// Symlinks + special files: skip silently.
|
|
109
188
|
}
|
|
110
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Read our own package.json's `version` field. Used as the
|
|
192
|
+
* `plugin.json` version when installing into Cowork/Desktop plugin
|
|
193
|
+
* bundles, so Cowork can see updates as we bump the CLI.
|
|
194
|
+
*/
|
|
195
|
+
function detectPackageVersion() {
|
|
196
|
+
try {
|
|
197
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
198
|
+
const pkg = JSON.parse(fs.readFileSync(path.resolve(here, "..", "package.json"), "utf8"));
|
|
199
|
+
return pkg.version ?? "0.0.0";
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return "0.0.0";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** Re-exports so the CLI doesn't have to import from two modules. */
|
|
206
|
+
export { parsePlatformIds, detectAllPlatforms, getPlatform, } from "./platforms.js";
|
|
111
207
|
//# sourceMappingURL=install.js.map
|
package/dist/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Registry of supported AI coding platforms — each entry knows
|
|
2
|
+
// where to drop a skill folder and how to tell whether the platform
|
|
3
|
+
// is installed on this machine.
|
|
4
|
+
//
|
|
5
|
+
// Most platforms use the simple "<dir>/<slug>/SKILL.md" convention
|
|
6
|
+
// (Claude Code, Cursor, Codex, etc.). A few use richer formats —
|
|
7
|
+
// notably Cowork and Claude Desktop, which load skills as plugin
|
|
8
|
+
// bundles (.claude-plugin/plugin.json + manifest.json + skills/<slug>).
|
|
9
|
+
// For those, the entry carries a `customInstaller` callback that
|
|
10
|
+
// owns the full install/uninstall flow.
|
|
11
|
+
//
|
|
12
|
+
// Standard-platform layout adapted from skills-hub.ai's
|
|
13
|
+
// @skills-hub-ai/cli (MIT). They pioneered the auto-detect-and-
|
|
14
|
+
// install-everywhere UX for Claude-style skills.
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import os from "node:os";
|
|
18
|
+
import { installToCowork, uninstallFromCowork, appPluginRoot, bundleDir, } from "./cowork-plugin.js";
|
|
19
|
+
export function realEnv() {
|
|
20
|
+
return { home: os.homedir(), cwd: process.cwd() };
|
|
21
|
+
}
|
|
22
|
+
const has = (...segments) => fs.existsSync(path.join(...segments));
|
|
23
|
+
const coworkInstaller = (app) => ({
|
|
24
|
+
install: (args) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = installToCowork({ app, ...args });
|
|
27
|
+
return {
|
|
28
|
+
installedTo: result.bundlePath,
|
|
29
|
+
status: result.installed ? "installed" : "skipped-exists",
|
|
30
|
+
reason: result.reason,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return {
|
|
35
|
+
installedTo: path.join(bundleDir(app, args.env), "skills", args.slug),
|
|
36
|
+
status: "error",
|
|
37
|
+
reason: err.message,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
uninstall: (args) => {
|
|
42
|
+
const result = uninstallFromCowork({ app, ...args });
|
|
43
|
+
return { path: result.bundlePath, removed: result.removed };
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
export const PLATFORM_REGISTRY = [
|
|
47
|
+
{
|
|
48
|
+
id: "claude-code",
|
|
49
|
+
label: "Claude Code",
|
|
50
|
+
skillsRoot: (e) => path.join(e.home, ".claude", "skills"),
|
|
51
|
+
detect: (e) => has(e.home, ".claude"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "claude-desktop",
|
|
55
|
+
label: "Claude Desktop",
|
|
56
|
+
// Custom installer writes the plugin bundle; the "skillsRoot"
|
|
57
|
+
// we expose for list-platforms / dry-run is the bundle's
|
|
58
|
+
// skills/ subdir.
|
|
59
|
+
skillsRoot: (e) => path.join(bundleDir("claude-desktop", e), "skills"),
|
|
60
|
+
detect: (e) => fs.existsSync(appPluginRoot("claude-desktop", e)),
|
|
61
|
+
customInstaller: coworkInstaller("claude-desktop"),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "cowork",
|
|
65
|
+
label: "Claude Cowork",
|
|
66
|
+
skillsRoot: (e) => path.join(bundleDir("cowork", e), "skills"),
|
|
67
|
+
detect: (e) => fs.existsSync(appPluginRoot("cowork", e)),
|
|
68
|
+
customInstaller: coworkInstaller("cowork"),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "cursor",
|
|
72
|
+
label: "Cursor",
|
|
73
|
+
skillsRoot: (e) => path.join(e.home, ".cursor", "skills"),
|
|
74
|
+
detect: (e) => has(e.home, ".cursor"),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "codex",
|
|
78
|
+
label: "Codex CLI",
|
|
79
|
+
skillsRoot: (e) => path.join(e.home, ".codex", "skills"),
|
|
80
|
+
detect: (e) => has(e.home, ".codex"),
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "copilot",
|
|
84
|
+
label: "GitHub Copilot",
|
|
85
|
+
// Copilot uses .github/copilot-instructions.md at workspace root;
|
|
86
|
+
// we drop per-skill folders under .github/copilot/skills/ so the
|
|
87
|
+
// user can opt them in via custom instructions without colliding
|
|
88
|
+
// with the single documented file.
|
|
89
|
+
skillsRoot: (e) => path.join(e.cwd, ".github", "copilot", "skills"),
|
|
90
|
+
detect: (e) => has(e.cwd, ".github", "copilot") ||
|
|
91
|
+
has(e.cwd, ".github", "copilot-instructions.md"),
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "windsurf",
|
|
95
|
+
label: "Windsurf",
|
|
96
|
+
skillsRoot: (e) => path.join(e.home, ".windsurf", "skills"),
|
|
97
|
+
detect: (e) => has(e.home, ".windsurf") || has(e.cwd, ".windsurfrules"),
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "cline",
|
|
101
|
+
label: "Cline",
|
|
102
|
+
skillsRoot: (e) => path.join(e.home, ".cline", "skills"),
|
|
103
|
+
detect: (e) => has(e.home, ".cline") || has(e.cwd, ".clinerules"),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "opencode",
|
|
107
|
+
label: "OpenCode",
|
|
108
|
+
skillsRoot: (e) => path.join(e.home, ".opencode", "skills"),
|
|
109
|
+
detect: (e) => has(e.home, ".opencode"),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "continue",
|
|
113
|
+
label: "Continue",
|
|
114
|
+
// Best-effort: Continue uses ~/.continue/config.json; the skills
|
|
115
|
+
// subdir is not yet a documented loader location.
|
|
116
|
+
skillsRoot: (e) => path.join(e.home, ".continue", "skills"),
|
|
117
|
+
detect: (e) => has(e.home, ".continue"),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "gemini",
|
|
121
|
+
label: "Gemini CLI",
|
|
122
|
+
// Best-effort: ~/.gemini is the published config root; the
|
|
123
|
+
// skills subdir is not (yet) documented.
|
|
124
|
+
skillsRoot: (e) => path.join(e.home, ".gemini", "skills"),
|
|
125
|
+
detect: (e) => has(e.home, ".gemini"),
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: "roo",
|
|
129
|
+
label: "Roo Code",
|
|
130
|
+
skillsRoot: (e) => path.join(e.home, ".roo", "skills"),
|
|
131
|
+
detect: (e) => has(e.home, ".roo") || has(e.cwd, ".roorules"),
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "zed",
|
|
135
|
+
label: "Zed",
|
|
136
|
+
// macOS uses ~/Library/Application Support/Zed; Linux uses
|
|
137
|
+
// ~/.config/zed. We pick per-platform at call time.
|
|
138
|
+
skillsRoot: (e) => zedSkillsRoot(e.home),
|
|
139
|
+
detect: (e) => fs.existsSync(path.dirname(zedSkillsRoot(e.home))),
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
function zedSkillsRoot(home) {
|
|
143
|
+
if (os.platform() === "darwin") {
|
|
144
|
+
return path.join(home, "Library", "Application Support", "Zed", "skills");
|
|
145
|
+
}
|
|
146
|
+
return path.join(home, ".config", "zed", "skills");
|
|
147
|
+
}
|
|
148
|
+
export const ALL_PLATFORM_IDS = PLATFORM_REGISTRY.map((p) => p.id);
|
|
149
|
+
export function getPlatform(id) {
|
|
150
|
+
return PLATFORM_REGISTRY.find((p) => p.id === id);
|
|
151
|
+
}
|
|
152
|
+
export function detectAllPlatforms(env = realEnv()) {
|
|
153
|
+
return PLATFORM_REGISTRY.filter((p) => p.detect(env));
|
|
154
|
+
}
|
|
155
|
+
export function parsePlatformIds(value) {
|
|
156
|
+
const known = [];
|
|
157
|
+
const unknown = [];
|
|
158
|
+
for (const raw of value.split(",")) {
|
|
159
|
+
const id = raw.trim();
|
|
160
|
+
if (!id)
|
|
161
|
+
continue;
|
|
162
|
+
const entry = getPlatform(id);
|
|
163
|
+
if (entry)
|
|
164
|
+
known.push(entry);
|
|
165
|
+
else
|
|
166
|
+
unknown.push(id);
|
|
167
|
+
}
|
|
168
|
+
return { known, unknown };
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=platforms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platforms.js","sourceRoot":"","sources":["../src/platforms.ts"],"names":[],"mappings":"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"}
|