opencode-skill-autodiscovery 1.1.4 → 1.2.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 +62 -10
- package/dist/discovery.d.ts +59 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +665 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -270
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# opencode-skill-autodiscovery
|
|
2
2
|
|
|
3
3
|
An [opencode](https://opencode.ai) plugin that auto-discovers skills installed by
|
|
4
|
-
VS Code agent plugins
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
VS Code agent plugins, Claude Code plugins, and [Agent Plugins
|
|
5
|
+
1.0.0](https://agent-plugins.org) conformant packages on the current machine,
|
|
6
|
+
and registers them with opencode's `skills.paths` so they appear in every
|
|
7
|
+
session. Each discovered skill is also exposed as a `/skill-name` slash command
|
|
8
|
+
that loads the skill and routes the rest of your message through it.
|
|
8
9
|
|
|
9
10
|
## Why
|
|
10
11
|
|
|
@@ -26,10 +27,40 @@ setup:
|
|
|
26
27
|
- Claude Code plugins: `~/.claude/plugins/installed_plugins.json`
|
|
27
28
|
- Claude Code plugins on a remote host (SSH/remote sessions):
|
|
28
29
|
`~/.claude/remote/plugins/installed_plugins.json`
|
|
30
|
+
- **Agent Plugins 1.0.0 packages** distributed via npm. opencode installs npm
|
|
31
|
+
plugins into its own cache (`~/.cache/opencode/packages/...`), not the
|
|
32
|
+
project's `node_modules`, and a `skills.paths` entry relative to the project
|
|
33
|
+
dir silently resolves to nothing. This plugin scans both the opencode plugin
|
|
34
|
+
cache and the project's `node_modules` for packages carrying a root
|
|
35
|
+
`plugin.json` whose `$schema` is `https://agent-plugins.org/schemas/...`,
|
|
36
|
+
and registers their `skills/` with **absolute** paths — so an npm-distributed
|
|
37
|
+
Agent Plugins package (e.g. `@dodopayments/opencode-plugin`) just works with
|
|
38
|
+
`"plugin": ["opencode-skill-autodiscovery"]` and nothing else.
|
|
29
39
|
|
|
30
40
|
Each points at plugin directories that contain `SKILL.md` files. This plugin
|
|
31
41
|
reads the manifests (including the remote `cache.json` LRU), resolves each
|
|
32
42
|
entry to its on-disk skill directories, and registers them with opencode.
|
|
43
|
+
When a discovered package carries a conformant root `plugin.json`, that manifest
|
|
44
|
+
is preferred (its `skills/` children are registered as-is); otherwise the plugin
|
|
45
|
+
falls back to a tree walk so legacy layouts keep working.
|
|
46
|
+
|
|
47
|
+
### MCP servers (opt-in)
|
|
48
|
+
|
|
49
|
+
With the `mcp` option, the plugin also reads each discovered package's `mcp.json`
|
|
50
|
+
and maps it onto opencode's `config.mcp`:
|
|
51
|
+
|
|
52
|
+
| Agent Plugins server | opencode entry |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `{ "type": "stdio", "command", "args", "env" }` | `{ "type": "local", "command": [...], "environment": {...} }` |
|
|
55
|
+
| `{ "type": "streamable-http", "url" }` | `{ "type": "remote", "url" }` |
|
|
56
|
+
| `{ "type": "sse" }` | skipped (opencode has no SSE transport) |
|
|
57
|
+
|
|
58
|
+
`${PLUGIN_ROOT}` and `${PLUGIN_DATA}` placeholders are expanded in `args`/`env`,
|
|
59
|
+
and both variables are injected into each stdio server's environment
|
|
60
|
+
(`PLUGIN_DATA` points at
|
|
61
|
+
`{opencode state}/plugin-data/{packageName}`). Invalid entries are skipped
|
|
62
|
+
per-entry, never fatally. `sse` servers and stdio `cwd` (which opencode cannot
|
|
63
|
+
represent) are dropped with a log line.
|
|
33
64
|
|
|
34
65
|
### Slash commands
|
|
35
66
|
|
|
@@ -45,7 +76,8 @@ Context: $ARGUMENTS
|
|
|
45
76
|
|
|
46
77
|
So `/spec plan the migration` loads the `spec` skill and runs it against
|
|
47
78
|
`plan the migration`. The command's description is taken from the skill's
|
|
48
|
-
frontmatter; existing commands with the same name are
|
|
79
|
+
frontmatter; existing commands with the same name are never overwritten (a
|
|
80
|
+
colliding skill from a different source is registered as `/package-skill`).
|
|
49
81
|
|
|
50
82
|
## Install
|
|
51
83
|
|
|
@@ -57,20 +89,31 @@ Add the package name to the `plugin` array in your `opencode.json`:
|
|
|
57
89
|
}
|
|
58
90
|
```
|
|
59
91
|
|
|
60
|
-
Use the tuple form to
|
|
61
|
-
VS Code data location on a remote host):
|
|
92
|
+
Use the tuple form to configure options:
|
|
62
93
|
|
|
63
94
|
```json
|
|
64
95
|
{
|
|
65
96
|
"plugin": [
|
|
66
97
|
[
|
|
67
98
|
"opencode-skill-autodiscovery",
|
|
68
|
-
{
|
|
99
|
+
{
|
|
100
|
+
"extraRoots": ["/home/user/.vscode-server"],
|
|
101
|
+
"scanCache": true,
|
|
102
|
+
"scanNodeModules": true,
|
|
103
|
+
"mcp": false
|
|
104
|
+
}
|
|
69
105
|
]
|
|
70
106
|
]
|
|
71
107
|
}
|
|
72
108
|
```
|
|
73
109
|
|
|
110
|
+
| Option | Default | Meaning |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `extraRoots` | `[]` | Extra root directories to scan (e.g. a non-standard VS Code data location on a remote host). |
|
|
113
|
+
| `scanCache` | `true` | Scan opencode's plugin cache (`~/.cache/opencode/packages/*`) for Agent Plugins packages. |
|
|
114
|
+
| `scanNodeModules` | `true` | Scan the project's `node_modules` (incl. `@scope/*`) for Agent Plugins packages. |
|
|
115
|
+
| `mcp` | `false` | Also register MCP servers from discovered packages' `mcp.json`. |
|
|
116
|
+
|
|
74
117
|
## Notes
|
|
75
118
|
|
|
76
119
|
- Discovery is inherently **machine-local**: it reads manifests from the home
|
|
@@ -89,14 +132,23 @@ VS Code data location on a remote host):
|
|
|
89
132
|
cloned-but-uninstalled marketplaces on setups that do have a manifest.
|
|
90
133
|
- VS Code account sync only syncs your marketplace extension list; each machine
|
|
91
134
|
still has its own `installed.json`/`cache.json` that this plugin reads.
|
|
92
|
-
-
|
|
93
|
-
|
|
135
|
+
- A package is only treated as an Agent Plugins package when its root
|
|
136
|
+
`plugin.json` declares a `$schema` under `https://agent-plugins.org/schemas/`.
|
|
137
|
+
Everything else is ignored by the cache/node_modules scanners and falls back
|
|
138
|
+
to the tree walk elsewhere.
|
|
139
|
+
- The same plugin can be materialised in several VS Code layouts at once
|
|
140
|
+
(local clone + synced bundle + marketplace clone). `skills.paths` keeps all
|
|
141
|
+
paths; slash commands and MCP servers are de-duplicated so mirrors don't
|
|
142
|
+
create a wall of `/mirror-of-...` junk.
|
|
143
|
+
- The plugin is a no-op when no manifests or conformant packages exist, or when
|
|
144
|
+
they contain no skills.
|
|
94
145
|
|
|
95
146
|
## Development
|
|
96
147
|
|
|
97
148
|
```sh
|
|
98
149
|
npm install
|
|
99
150
|
npm run build # tsc -> dist/
|
|
151
|
+
npm test # build + node --test (fixture-based unit tests)
|
|
100
152
|
```
|
|
101
153
|
|
|
102
154
|
Publish:
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type PackageSource = "claude" | "vscode" | "opencode-cache" | "node_modules" | "extra";
|
|
2
|
+
export type PluginPackage = {
|
|
3
|
+
source: PackageSource;
|
|
4
|
+
name: string;
|
|
5
|
+
root: string;
|
|
6
|
+
skillDirs: string[];
|
|
7
|
+
mcpPath?: string;
|
|
8
|
+
/** Agent Plugins version declared by plugin.json, e.g. "1.0.0". */
|
|
9
|
+
schemaVersion?: string;
|
|
10
|
+
};
|
|
11
|
+
export type SkillInfo = {
|
|
12
|
+
dir: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
};
|
|
16
|
+
export type McpEntry = {
|
|
17
|
+
type: "local";
|
|
18
|
+
command: string[];
|
|
19
|
+
environment?: Record<string, string>;
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
type: "remote";
|
|
23
|
+
url: string;
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type ConfigPatch = {
|
|
28
|
+
skillPaths: string[];
|
|
29
|
+
commands: Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
template: string;
|
|
33
|
+
}>;
|
|
34
|
+
mcp: Array<{
|
|
35
|
+
key: string;
|
|
36
|
+
entry: McpEntry;
|
|
37
|
+
}>;
|
|
38
|
+
};
|
|
39
|
+
export declare function log(message: string): void;
|
|
40
|
+
export declare function contains(parent: string, child: string): boolean;
|
|
41
|
+
export declare function readSkillInfo(dir: string): SkillInfo | null;
|
|
42
|
+
export declare function readPackage(root: string, source: PackageSource): PluginPackage | null;
|
|
43
|
+
export declare function findSkillDirs(root: string, out: Set<string>, seen: Set<string>): void;
|
|
44
|
+
export declare function packageFromDir(root: string, source: PackageSource): PluginPackage | null;
|
|
45
|
+
export declare function collectVscode(out: PluginPackage[], extra: string[]): void;
|
|
46
|
+
export declare function collectClaude(out: PluginPackage[]): void;
|
|
47
|
+
export declare function opencodeCacheRoot(): string;
|
|
48
|
+
export declare function collectOpencodeCache(packagesRoot: string, out: PluginPackage[]): void;
|
|
49
|
+
export declare function collectNodeModules(nodeModulesRoot: string, out: PluginPackage[]): void;
|
|
50
|
+
export declare function pluginDataRoot(name: string): string;
|
|
51
|
+
export declare function readMcp(pkg: PluginPackage, out: Array<{
|
|
52
|
+
key: string;
|
|
53
|
+
entry: McpEntry;
|
|
54
|
+
}>): void;
|
|
55
|
+
export declare function planConfig(packages: PluginPackage[], taken?: {
|
|
56
|
+
commands?: Iterable<string>;
|
|
57
|
+
mcp?: Iterable<string>;
|
|
58
|
+
}): ConfigPatch;
|
|
59
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, sep } from "node:path";
|
|
4
|
+
const PLUGIN_SCHEMA = /^https:\/\/agent-plugins\.org\/schemas\/1\.\d+\.\d+\/plugin\.schema\.json$/;
|
|
5
|
+
const MCP_SCHEMA = /^https:\/\/agent-plugins\.org\/schemas\/1\.\d+\.\d+\/mcp\.schema\.json$/;
|
|
6
|
+
const VERSION = /^https:\/\/agent-plugins\.org\/schemas\/(\d+\.\d+\.\d+)\//;
|
|
7
|
+
const STDIO_KEYS = new Set(["type", "command", "args", "env", "cwd"]);
|
|
8
|
+
const HTTP_KEYS = new Set(["type", "url", "headers"]);
|
|
9
|
+
export function log(message) {
|
|
10
|
+
console.error(`[opencode-skill-autodiscovery] ${message}`);
|
|
11
|
+
}
|
|
12
|
+
function isDirectory(p) {
|
|
13
|
+
try {
|
|
14
|
+
return statSync(p).isDirectory();
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function isRegularFile(p) {
|
|
21
|
+
try {
|
|
22
|
+
return statSync(p).isFile();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// True when `child` resolves (through symlinks) inside `parent`.
|
|
29
|
+
export function contains(parent, child) {
|
|
30
|
+
const p = realpathSync(parent);
|
|
31
|
+
const c = realpathSync(child);
|
|
32
|
+
if (p === c)
|
|
33
|
+
return true;
|
|
34
|
+
const rel = relative(p, c);
|
|
35
|
+
return rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
36
|
+
}
|
|
37
|
+
// Parses the YAML frontmatter of a SKILL.md (name, description). Returns null
|
|
38
|
+
// when the file is unreadable or lacks a valid `name`.
|
|
39
|
+
export function readSkillInfo(dir) {
|
|
40
|
+
const skillMd = join(dir, "SKILL.md");
|
|
41
|
+
let content;
|
|
42
|
+
try {
|
|
43
|
+
content = readFileSync(skillMd, "utf8");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const frontmatter = /^---\s*\n([\s\S]*?)\n---/.exec(content)?.[1];
|
|
49
|
+
if (!frontmatter)
|
|
50
|
+
return null;
|
|
51
|
+
const field = (key) => {
|
|
52
|
+
const m = new RegExp(`^${key}:[ \\t]*(.*)$`, "m").exec(frontmatter);
|
|
53
|
+
if (!m)
|
|
54
|
+
return undefined;
|
|
55
|
+
return m[1].trim().replace(/^["']|["']$/g, "");
|
|
56
|
+
};
|
|
57
|
+
const name = field("name");
|
|
58
|
+
if (!name)
|
|
59
|
+
return null;
|
|
60
|
+
return { dir, name, description: field("description") ?? "" };
|
|
61
|
+
}
|
|
62
|
+
// Reads a conformant Agent Plugins 1.0.0 package from a directory root.
|
|
63
|
+
// Returns null when the root has no valid plugin.json, so callers can fall
|
|
64
|
+
// back to legacy discovery. The $schema URL is the discriminator that makes
|
|
65
|
+
// scanning untrusted directories safe.
|
|
66
|
+
export function readPackage(root, source) {
|
|
67
|
+
const manifestPath = join(root, "plugin.json");
|
|
68
|
+
if (!isRegularFile(manifestPath))
|
|
69
|
+
return null;
|
|
70
|
+
let manifest;
|
|
71
|
+
try {
|
|
72
|
+
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (typeof manifest !== "object" || manifest === null)
|
|
78
|
+
return null;
|
|
79
|
+
if (typeof manifest.$schema !== "string" || !PLUGIN_SCHEMA.test(manifest.$schema)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (typeof manifest.name !== "string" || manifest.name.length === 0) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const skillDirs = [];
|
|
86
|
+
const skillsRoot = join(root, "skills");
|
|
87
|
+
if (isDirectory(skillsRoot)) {
|
|
88
|
+
let entries;
|
|
89
|
+
try {
|
|
90
|
+
entries = readdirSync(skillsRoot);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
entries = [];
|
|
94
|
+
}
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const dir = join(skillsRoot, entry);
|
|
97
|
+
if (!isDirectory(dir))
|
|
98
|
+
continue;
|
|
99
|
+
if (!isRegularFile(join(dir, "SKILL.md")))
|
|
100
|
+
continue;
|
|
101
|
+
let resolved;
|
|
102
|
+
try {
|
|
103
|
+
resolved = realpathSync(dir);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!contains(root, resolved))
|
|
109
|
+
continue;
|
|
110
|
+
skillDirs.push(resolved);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const mcpPath = isRegularFile(join(root, "mcp.json"))
|
|
114
|
+
? join(root, "mcp.json")
|
|
115
|
+
: undefined;
|
|
116
|
+
return {
|
|
117
|
+
source,
|
|
118
|
+
name: manifest.name,
|
|
119
|
+
root,
|
|
120
|
+
skillDirs,
|
|
121
|
+
mcpPath,
|
|
122
|
+
schemaVersion: VERSION.exec(manifest.$schema)?.[1],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Legacy tree walk: every directory containing a SKILL.md, at any depth.
|
|
126
|
+
export function findSkillDirs(root, out, seen) {
|
|
127
|
+
const resolved = join(root);
|
|
128
|
+
if (seen.has(resolved))
|
|
129
|
+
return;
|
|
130
|
+
seen.add(resolved);
|
|
131
|
+
let entries;
|
|
132
|
+
try {
|
|
133
|
+
entries = readdirSync(resolved);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (entry === ".git")
|
|
140
|
+
continue;
|
|
141
|
+
const full = join(resolved, entry);
|
|
142
|
+
if (!isDirectory(full))
|
|
143
|
+
continue;
|
|
144
|
+
if (isRegularFile(join(full, "SKILL.md"))) {
|
|
145
|
+
out.add(full);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
findSkillDirs(full, out, seen);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Prefers a conformant package manifest; falls back to a legacy tree walk so
|
|
153
|
+
// non-conformant layouts keep working. Returns null when nothing is found.
|
|
154
|
+
export function packageFromDir(root, source) {
|
|
155
|
+
const pkg = readPackage(root, source);
|
|
156
|
+
if (pkg)
|
|
157
|
+
return pkg;
|
|
158
|
+
const skillDirs = new Set();
|
|
159
|
+
findSkillDirs(root, skillDirs, new Set());
|
|
160
|
+
if (skillDirs.size === 0)
|
|
161
|
+
return null;
|
|
162
|
+
return {
|
|
163
|
+
source,
|
|
164
|
+
name: root.split(/[\\/]/).pop() || root,
|
|
165
|
+
root,
|
|
166
|
+
skillDirs: [...skillDirs],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// --- VS Code agent plugin discovery ---------------------------------------
|
|
170
|
+
// VS Code keeps agent plugins in a per-platform "data dir". The holding
|
|
171
|
+
// folder is named `agent-plugins` on older builds (e.g. ~/.vscode) and
|
|
172
|
+
// `agentPlugins` on newer builds; remote servers nest theirs under `data/`
|
|
173
|
+
// (~/.vscode-server/data/agentPlugins). We list every known candidate so the
|
|
174
|
+
// discovery works regardless of OS, build channel, or local/remote setup.
|
|
175
|
+
function vsCodeDataRoots(extra) {
|
|
176
|
+
const home = homedir();
|
|
177
|
+
const roots = new Set([
|
|
178
|
+
join(home, ".vscode"),
|
|
179
|
+
// Linux
|
|
180
|
+
join(home, ".config", "Code"),
|
|
181
|
+
join(home, ".config", "Code - Insiders"),
|
|
182
|
+
// macOS
|
|
183
|
+
join(home, "Library", "Application Support", "Code"),
|
|
184
|
+
join(home, "Library", "Application Support", "Code - Insiders"),
|
|
185
|
+
// Windows
|
|
186
|
+
...(process.env.APPDATA
|
|
187
|
+
? [
|
|
188
|
+
join(process.env.APPDATA, "Code"),
|
|
189
|
+
join(process.env.APPDATA, "Code - Insiders"),
|
|
190
|
+
]
|
|
191
|
+
: []),
|
|
192
|
+
// Remote hosts (Remote-SSH, Dev Containers, Codespaces, WSL)
|
|
193
|
+
join(home, ".vscode-server"),
|
|
194
|
+
join(home, ".vscode-server-insiders"),
|
|
195
|
+
join(home, ".vscode-remote"),
|
|
196
|
+
]);
|
|
197
|
+
for (const root of extra)
|
|
198
|
+
roots.add(root);
|
|
199
|
+
return [...roots];
|
|
200
|
+
}
|
|
201
|
+
function agentPluginDirs(roots) {
|
|
202
|
+
const dirs = new Set();
|
|
203
|
+
for (const root of roots) {
|
|
204
|
+
dirs.add(join(root, "agent-plugins"));
|
|
205
|
+
dirs.add(join(root, "agentPlugins"));
|
|
206
|
+
dirs.add(join(root, "data", "agent-plugins"));
|
|
207
|
+
dirs.add(join(root, "data", "agentPlugins"));
|
|
208
|
+
}
|
|
209
|
+
return [...dirs];
|
|
210
|
+
}
|
|
211
|
+
function vscodePluginPath(pluginUri) {
|
|
212
|
+
const m = /^file:\/\/(.+)$/.exec(pluginUri);
|
|
213
|
+
if (!m)
|
|
214
|
+
return pluginUri;
|
|
215
|
+
let raw;
|
|
216
|
+
try {
|
|
217
|
+
raw = decodeURIComponent(m[1]);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
raw = m[1];
|
|
221
|
+
}
|
|
222
|
+
if (raw.startsWith("/"))
|
|
223
|
+
raw = raw.slice(1);
|
|
224
|
+
return raw;
|
|
225
|
+
}
|
|
226
|
+
function collectVscodeManifest(out, installedJson) {
|
|
227
|
+
if (!existsSync(installedJson))
|
|
228
|
+
return;
|
|
229
|
+
let manifest;
|
|
230
|
+
try {
|
|
231
|
+
manifest = JSON.parse(readFileSync(installedJson, "utf8"));
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
for (const plugin of manifest.installed ?? []) {
|
|
237
|
+
if (!plugin.pluginUri)
|
|
238
|
+
continue;
|
|
239
|
+
const dir = vscodePluginPath(plugin.pluginUri);
|
|
240
|
+
if (dir) {
|
|
241
|
+
const pkg = packageFromDir(dir, "vscode");
|
|
242
|
+
if (pkg)
|
|
243
|
+
out.push(pkg);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Remote hosts: VS Code syncs client skills into
|
|
248
|
+
// {data}/agentPlugins/{sanitizedUri}/{nonce}/ and records the LRU in
|
|
249
|
+
// cache.json. Resolve each entry so the materialized synced-customization
|
|
250
|
+
// bundle ("VS Code Synced Data" Open Plugin, skills/<name>/SKILL.md) is
|
|
251
|
+
// discovered.
|
|
252
|
+
function collectVscodeCache(out, cacheJson) {
|
|
253
|
+
if (!existsSync(cacheJson))
|
|
254
|
+
return;
|
|
255
|
+
let entries;
|
|
256
|
+
try {
|
|
257
|
+
entries = JSON.parse(readFileSync(cacheJson, "utf8"));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (!Array.isArray(entries))
|
|
263
|
+
return;
|
|
264
|
+
const parent = dirname(cacheJson);
|
|
265
|
+
for (const entry of entries) {
|
|
266
|
+
if (typeof entry?.uri !== "string")
|
|
267
|
+
continue;
|
|
268
|
+
const key = sanitizeKey(entry.uri) || "default";
|
|
269
|
+
const nonce = typeof entry.nonce === "string" && entry.nonce
|
|
270
|
+
? sanitizeKey(entry.nonce)
|
|
271
|
+
: "default";
|
|
272
|
+
for (const dir of [join(parent, key, nonce), join(parent, key)]) {
|
|
273
|
+
const pkg = packageFromDir(dir, "vscode");
|
|
274
|
+
if (pkg)
|
|
275
|
+
out.push(pkg);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Mirrors the server-side AgentPluginManager sanitizer so we can resolve the
|
|
280
|
+
// cache.json entries to their on-disk directories.
|
|
281
|
+
function sanitizeKey(value) {
|
|
282
|
+
return value
|
|
283
|
+
.replace(/[^a-zA-Z0-9]/g, "-")
|
|
284
|
+
.replace(/-+/g, "-")
|
|
285
|
+
.replace(/^-|-$/g, "")
|
|
286
|
+
.substring(0, 128);
|
|
287
|
+
}
|
|
288
|
+
function collectAgentPluginRoot(out, root) {
|
|
289
|
+
const installedJson = join(root, "installed.json");
|
|
290
|
+
const cacheJson = join(root, "cache.json");
|
|
291
|
+
const hasManifest = existsSync(installedJson) || existsSync(cacheJson);
|
|
292
|
+
collectVscodeManifest(out, installedJson);
|
|
293
|
+
collectVscodeCache(out, cacheJson);
|
|
294
|
+
// Newer VS Code installs marketplaces directly as {host}/{org}/{repo}
|
|
295
|
+
// subdirectories with no manifest file at all. Fall back to a full tree walk
|
|
296
|
+
// only when no metadata exists, so we don't surface skills from cloned-but-
|
|
297
|
+
// not-installed marketplaces on setups that do have a manifest.
|
|
298
|
+
if (!hasManifest) {
|
|
299
|
+
const pkg = packageFromDir(root, "vscode");
|
|
300
|
+
if (pkg)
|
|
301
|
+
out.push(pkg);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
export function collectVscode(out, extra) {
|
|
305
|
+
for (const dir of agentPluginDirs(vsCodeDataRoots(extra))) {
|
|
306
|
+
collectAgentPluginRoot(out, dir);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// --- Claude Code plugin discovery ------------------------------------------
|
|
310
|
+
function collectClaudeManifest(out, installedJson) {
|
|
311
|
+
if (!existsSync(installedJson))
|
|
312
|
+
return;
|
|
313
|
+
let manifest;
|
|
314
|
+
try {
|
|
315
|
+
manifest = JSON.parse(readFileSync(installedJson, "utf8"));
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
for (const versions of Object.values(manifest.plugins ?? {})) {
|
|
321
|
+
for (const plugin of versions) {
|
|
322
|
+
if (plugin.installPath) {
|
|
323
|
+
const pkg = packageFromDir(plugin.installPath, "claude");
|
|
324
|
+
if (pkg)
|
|
325
|
+
out.push(pkg);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
export function collectClaude(out) {
|
|
331
|
+
const home = homedir();
|
|
332
|
+
const installedJsons = [
|
|
333
|
+
join(home, ".claude", "plugins", "installed_plugins.json"),
|
|
334
|
+
join(home, ".claude", "remote", "plugins", "installed_plugins.json"),
|
|
335
|
+
];
|
|
336
|
+
let found = false;
|
|
337
|
+
for (const installedJson of installedJsons) {
|
|
338
|
+
if (existsSync(installedJson)) {
|
|
339
|
+
found = true;
|
|
340
|
+
collectClaudeManifest(out, installedJson);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Remote hosts sync Claude plugins as {nonce}/ dirs with per-plugin
|
|
344
|
+
// manifest.json but no installed_plugins.json; tree-walk the remote plugins
|
|
345
|
+
// dir as a fallback so those skills are discovered too.
|
|
346
|
+
if (!found) {
|
|
347
|
+
const remoteRoot = join(home, ".claude", "remote", "plugins");
|
|
348
|
+
if (existsSync(remoteRoot)) {
|
|
349
|
+
const pkg = packageFromDir(remoteRoot, "claude");
|
|
350
|
+
if (pkg)
|
|
351
|
+
out.push(pkg);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// --- npm-distributed Agent Plugins packages --------------------------------
|
|
356
|
+
export function opencodeCacheRoot() {
|
|
357
|
+
const base = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
|
|
358
|
+
return join(base, "opencode");
|
|
359
|
+
}
|
|
360
|
+
// opencode installs npm plugins into its own cache, not the project's
|
|
361
|
+
// node_modules: {cache}/packages/{name}@{version}/node_modules/{name}. Scanning
|
|
362
|
+
// it is what makes an npm-distributed Agent Plugins package work without any
|
|
363
|
+
// manual skills.paths entry.
|
|
364
|
+
export function collectOpencodeCache(packagesRoot, out) {
|
|
365
|
+
let pkgEntries;
|
|
366
|
+
try {
|
|
367
|
+
pkgEntries = readdirSync(packagesRoot);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
for (const pkgEntry of pkgEntries) {
|
|
373
|
+
const nodeModules = join(packagesRoot, pkgEntry, "node_modules");
|
|
374
|
+
if (!isDirectory(nodeModules))
|
|
375
|
+
continue;
|
|
376
|
+
collectNodeModules(nodeModules, out);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Enumerates immediate package roots of a node_modules dir, including scoped
|
|
380
|
+
// packages (@scope/*). Only conformant packages (root plugin.json) are read;
|
|
381
|
+
// nothing else is walked.
|
|
382
|
+
export function collectNodeModules(nodeModulesRoot, out) {
|
|
383
|
+
if (!isDirectory(nodeModulesRoot))
|
|
384
|
+
return;
|
|
385
|
+
let entries;
|
|
386
|
+
try {
|
|
387
|
+
entries = readdirSync(nodeModulesRoot);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
for (const entry of entries) {
|
|
393
|
+
if (entry === ".bin" || entry.startsWith("."))
|
|
394
|
+
continue;
|
|
395
|
+
const candidate = join(nodeModulesRoot, entry);
|
|
396
|
+
if (!isDirectory(candidate))
|
|
397
|
+
continue;
|
|
398
|
+
if (entry.startsWith("@")) {
|
|
399
|
+
let scoped;
|
|
400
|
+
try {
|
|
401
|
+
scoped = readdirSync(candidate);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
for (const sub of scoped) {
|
|
407
|
+
if (sub.startsWith("."))
|
|
408
|
+
continue;
|
|
409
|
+
const pkg = readPackage(join(candidate, sub), "node_modules");
|
|
410
|
+
if (pkg)
|
|
411
|
+
out.push(pkg);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
const pkg = readPackage(candidate, "node_modules");
|
|
416
|
+
if (pkg)
|
|
417
|
+
out.push(pkg);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// --- MCP servers (mcp.json) -------------------------------------------------
|
|
422
|
+
function opencodeStateRoot() {
|
|
423
|
+
const base = process.env.XDG_STATE_HOME || join(homedir(), ".local", "state");
|
|
424
|
+
return join(base, "opencode");
|
|
425
|
+
}
|
|
426
|
+
export function pluginDataRoot(name) {
|
|
427
|
+
return join(opencodeStateRoot(), "plugin-data", name);
|
|
428
|
+
}
|
|
429
|
+
function expandPluginVars(value, root, dataDir) {
|
|
430
|
+
return value
|
|
431
|
+
.split("${PLUGIN_ROOT}")
|
|
432
|
+
.join(root)
|
|
433
|
+
.split("${PLUGIN_DATA}")
|
|
434
|
+
.join(dataDir);
|
|
435
|
+
}
|
|
436
|
+
function collectHeaders(value) {
|
|
437
|
+
const headers = {};
|
|
438
|
+
if (typeof value === "object" && value !== null) {
|
|
439
|
+
for (const [k, v] of Object.entries(value)) {
|
|
440
|
+
if (typeof v === "string")
|
|
441
|
+
headers[k] = v;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return headers;
|
|
445
|
+
}
|
|
446
|
+
function hasUnknownKeys(server, allowed) {
|
|
447
|
+
return Object.keys(server).some((k) => !allowed.has(k));
|
|
448
|
+
}
|
|
449
|
+
// Maps the portable mcp.json shape onto opencode's native config.mcp. Per the
|
|
450
|
+
// Agent Plugins spec, failures are per-entry (and per-package for an invalid
|
|
451
|
+
// mcp.json): a bad server never blocks other servers or the package's skills.
|
|
452
|
+
export function readMcp(pkg, out) {
|
|
453
|
+
if (!pkg.mcpPath)
|
|
454
|
+
return;
|
|
455
|
+
let raw;
|
|
456
|
+
try {
|
|
457
|
+
raw = readFileSync(pkg.mcpPath, "utf8");
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
let parsed;
|
|
463
|
+
try {
|
|
464
|
+
parsed = JSON.parse(raw);
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
log(`ignoring mcp.json for package "${pkg.name}": not valid JSON`);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
471
|
+
log(`ignoring mcp.json for package "${pkg.name}": not an object`);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (typeof parsed.$schema !== "string" || !MCP_SCHEMA.test(parsed.$schema)) {
|
|
475
|
+
log(`ignoring mcp.json for package "${pkg.name}": unsupported or missing $schema`);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const mcpVersion = VERSION.exec(parsed.$schema)?.[1];
|
|
479
|
+
if (pkg.schemaVersion && mcpVersion && mcpVersion !== pkg.schemaVersion) {
|
|
480
|
+
log(`ignoring mcp.json for package "${pkg.name}": schema version ${mcpVersion} does not match plugin.json (${pkg.schemaVersion})`);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (typeof parsed.mcpServers !== "object" || parsed.mcpServers === null) {
|
|
484
|
+
log(`ignoring mcp.json for package "${pkg.name}": missing mcpServers`);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const dataDir = pluginDataRoot(pkg.name);
|
|
488
|
+
const servers = parsed.mcpServers;
|
|
489
|
+
for (const [name, serverValue] of Object.entries(servers)) {
|
|
490
|
+
if (typeof serverValue !== "object" || serverValue === null) {
|
|
491
|
+
log(`skipping MCP server "${pkg.name}/${name}": invalid entry`);
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
const server = serverValue;
|
|
495
|
+
if (server.type === "stdio") {
|
|
496
|
+
if (hasUnknownKeys(server, STDIO_KEYS)) {
|
|
497
|
+
log(`skipping MCP server "${pkg.name}/${name}": unknown fields in stdio entry`);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (typeof server.command !== "string" || server.command.length === 0) {
|
|
501
|
+
log(`skipping MCP server "${pkg.name}/${name}": stdio requires a string command`);
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const command = server.command.startsWith("./")
|
|
505
|
+
? join(pkg.root, server.command)
|
|
506
|
+
: server.command;
|
|
507
|
+
const args = Array.isArray(server.args)
|
|
508
|
+
? server.args
|
|
509
|
+
.filter((a) => typeof a === "string")
|
|
510
|
+
.map((a) => expandPluginVars(a, pkg.root, dataDir))
|
|
511
|
+
: [];
|
|
512
|
+
const environment = {};
|
|
513
|
+
if (typeof server.env === "object" && server.env !== null) {
|
|
514
|
+
for (const [k, v] of Object.entries(server.env)) {
|
|
515
|
+
if (k === "PLUGIN_ROOT" || k === "PLUGIN_DATA") {
|
|
516
|
+
log(`dropping reserved env key "${k}" for MCP server "${pkg.name}/${name}"`);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
if (typeof v === "string") {
|
|
520
|
+
environment[k] = expandPluginVars(v, pkg.root, dataDir);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
environment.PLUGIN_ROOT = pkg.root;
|
|
525
|
+
environment.PLUGIN_DATA = dataDir;
|
|
526
|
+
if (server.cwd !== undefined) {
|
|
527
|
+
const cwd = typeof server.cwd === "string"
|
|
528
|
+
? expandPluginVars(server.cwd, pkg.root, dataDir)
|
|
529
|
+
: String(server.cwd);
|
|
530
|
+
log(`dropping cwd "${cwd}" for MCP server "${pkg.name}/${name}": opencode has no cwd support`);
|
|
531
|
+
}
|
|
532
|
+
try {
|
|
533
|
+
mkdirSync(dataDir, { recursive: true });
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
// Non-fatal: the subprocess env still points at the (uncreated) dir.
|
|
537
|
+
}
|
|
538
|
+
out.push({
|
|
539
|
+
key: name,
|
|
540
|
+
entry: { type: "local", command: [command, ...args], environment, enabled: true },
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
else if (server.type === "streamable-http") {
|
|
544
|
+
if (hasUnknownKeys(server, HTTP_KEYS)) {
|
|
545
|
+
log(`skipping MCP server "${pkg.name}/${name}": unknown fields in streamable-http entry`);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (typeof server.url !== "string" || server.url.length === 0) {
|
|
549
|
+
log(`skipping MCP server "${pkg.name}/${name}": streamable-http requires a string url`);
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
out.push({
|
|
553
|
+
key: name,
|
|
554
|
+
entry: {
|
|
555
|
+
type: "remote",
|
|
556
|
+
url: server.url,
|
|
557
|
+
headers: collectHeaders(server.headers),
|
|
558
|
+
enabled: true,
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
else if (server.type === "sse") {
|
|
563
|
+
if (hasUnknownKeys(server, HTTP_KEYS)) {
|
|
564
|
+
log(`skipping MCP server "${pkg.name}/${name}": unknown fields in sse entry`);
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
log(`skipping MCP server "${pkg.name}/${name}": opencode does not support the sse transport`);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
log(`skipping MCP server "${pkg.name}/${name}": unknown transport "${String(server.type)}"`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
// --- Merge logic ------------------------------------------------------------
|
|
575
|
+
// Computes the config contribution from the discovered packages: every unique
|
|
576
|
+
// skill path, slash commands keyed by frontmatter name with collisions
|
|
577
|
+
// namespaced by package name, and MCP servers keyed by server name with
|
|
578
|
+
// collisions namespaced by package name. `taken` seeds the reserved names from
|
|
579
|
+
// the user's existing config so user-defined entries are never overwritten.
|
|
580
|
+
export function planConfig(packages, taken = {}) {
|
|
581
|
+
const skillPaths = [];
|
|
582
|
+
const seenDir = new Set();
|
|
583
|
+
for (const pkg of packages) {
|
|
584
|
+
for (const dir of pkg.skillDirs) {
|
|
585
|
+
if (seenDir.has(dir))
|
|
586
|
+
continue;
|
|
587
|
+
seenDir.add(dir);
|
|
588
|
+
skillPaths.push(dir);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const commands = [];
|
|
592
|
+
const usedCommands = new Set(taken.commands ?? []);
|
|
593
|
+
const commandOwner = new Map();
|
|
594
|
+
for (const name of taken.commands ?? [])
|
|
595
|
+
commandOwner.set(name, "user");
|
|
596
|
+
const seenCommandDir = new Set();
|
|
597
|
+
for (const pkg of packages) {
|
|
598
|
+
for (const dir of pkg.skillDirs) {
|
|
599
|
+
if (seenCommandDir.has(dir))
|
|
600
|
+
continue;
|
|
601
|
+
seenCommandDir.add(dir);
|
|
602
|
+
const info = readSkillInfo(dir);
|
|
603
|
+
if (!info)
|
|
604
|
+
continue;
|
|
605
|
+
let name = info.name;
|
|
606
|
+
const owner = commandOwner.get(name);
|
|
607
|
+
if (owner !== undefined) {
|
|
608
|
+
if (owner === pkg.source) {
|
|
609
|
+
// Same client layout mirroring one plugin (e.g. a VS Code synced
|
|
610
|
+
// bundle next to the local clone): redundant, keep the first.
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
const namespaced = `${pkg.name}-${info.name}`;
|
|
614
|
+
if (usedCommands.has(namespaced)) {
|
|
615
|
+
log(`skipping slash command for skill "${info.name}": name already taken`);
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
name = namespaced;
|
|
619
|
+
}
|
|
620
|
+
commandOwner.set(name, pkg.source);
|
|
621
|
+
usedCommands.add(name);
|
|
622
|
+
commands.push({
|
|
623
|
+
name,
|
|
624
|
+
description: info.description || `Run the ${info.name} skill`,
|
|
625
|
+
template: [
|
|
626
|
+
`Load the \`${info.name}\` skill and follow its instructions.`,
|
|
627
|
+
`Context: $ARGUMENTS`,
|
|
628
|
+
].join("\n"),
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const mcp = [];
|
|
633
|
+
const usedMcp = new Set(taken.mcp ?? []);
|
|
634
|
+
const mcpOwner = new Map();
|
|
635
|
+
for (const name of taken.mcp ?? [])
|
|
636
|
+
mcpOwner.set(name, "user");
|
|
637
|
+
const seenMcpEntry = new Set();
|
|
638
|
+
for (const pkg of packages) {
|
|
639
|
+
const entries = [];
|
|
640
|
+
readMcp(pkg, entries);
|
|
641
|
+
for (const { key, entry } of entries) {
|
|
642
|
+
const dedupeKey = `${pkg.root}\u0000${key}`;
|
|
643
|
+
if (seenMcpEntry.has(dedupeKey))
|
|
644
|
+
continue;
|
|
645
|
+
seenMcpEntry.add(dedupeKey);
|
|
646
|
+
let k = key;
|
|
647
|
+
const owner = mcpOwner.get(k);
|
|
648
|
+
if (owner !== undefined) {
|
|
649
|
+
if (owner === pkg.source)
|
|
650
|
+
continue;
|
|
651
|
+
const namespaced = `${pkg.name}/${key}`;
|
|
652
|
+
if (usedMcp.has(namespaced)) {
|
|
653
|
+
log(`skipping MCP server "${pkg.name}/${key}": name already taken`);
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
k = namespaced;
|
|
657
|
+
}
|
|
658
|
+
mcpOwner.set(k, pkg.source);
|
|
659
|
+
usedMcp.add(k);
|
|
660
|
+
mcp.push({ key: k, entry });
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return { skillPaths, commands, mcp };
|
|
664
|
+
}
|
|
665
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,qBAAqB,CAAC;;kBAoBlC,MAAM;;AAF9B,wBAwDoB"}
|
package/dist/index.js
CHANGED
|
@@ -1,284 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
// Parses the YAML frontmatter of a SKILL.md (name, description). Returns null
|
|
5
|
-
// when the file is unreadable or lacks a valid `name`.
|
|
6
|
-
function readSkillInfo(dir) {
|
|
7
|
-
const skillMd = join(dir, "SKILL.md");
|
|
8
|
-
let content;
|
|
9
|
-
try {
|
|
10
|
-
content = readFileSync(skillMd, "utf8");
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
const frontmatter = /^---\s*\n([\s\S]*?)\n---/.exec(content)?.[1];
|
|
16
|
-
if (!frontmatter)
|
|
17
|
-
return null;
|
|
18
|
-
const field = (key) => {
|
|
19
|
-
const m = new RegExp(`^${key}:[ \\t]*(.*)$`, "m").exec(frontmatter);
|
|
20
|
-
if (!m)
|
|
21
|
-
return undefined;
|
|
22
|
-
return m[1].trim().replace(/^["']|["']$/g, "");
|
|
23
|
-
};
|
|
24
|
-
const name = field("name");
|
|
25
|
-
if (!name)
|
|
26
|
-
return null;
|
|
27
|
-
return { dir, name, description: field("description") ?? "" };
|
|
28
|
-
}
|
|
29
|
-
// VS Code keeps agent plugins in a per-platform "data dir". The holding
|
|
30
|
-
// folder is named `agent-plugins` on older builds (e.g. ~/.vscode) and
|
|
31
|
-
// `agentPlugins` on newer builds; remote servers nest theirs under `data/`
|
|
32
|
-
// (~/.vscode-server/data/agentPlugins). We list every known candidate so the
|
|
33
|
-
// discovery works regardless of OS, build channel, or local/remote setup.
|
|
34
|
-
function vsCodeDataRoots(extra) {
|
|
35
|
-
const home = homedir();
|
|
36
|
-
const roots = new Set([
|
|
37
|
-
join(home, ".vscode"),
|
|
38
|
-
// Linux
|
|
39
|
-
join(home, ".config", "Code"),
|
|
40
|
-
join(home, ".config", "Code - Insiders"),
|
|
41
|
-
// macOS
|
|
42
|
-
join(home, "Library", "Application Support", "Code"),
|
|
43
|
-
join(home, "Library", "Application Support", "Code - Insiders"),
|
|
44
|
-
// Windows
|
|
45
|
-
...(process.env.APPDATA
|
|
46
|
-
? [
|
|
47
|
-
join(process.env.APPDATA, "Code"),
|
|
48
|
-
join(process.env.APPDATA, "Code - Insiders"),
|
|
49
|
-
]
|
|
50
|
-
: []),
|
|
51
|
-
// Remote hosts (Remote-SSH, Dev Containers, Codespaces, WSL)
|
|
52
|
-
join(home, ".vscode-server"),
|
|
53
|
-
join(home, ".vscode-server-insiders"),
|
|
54
|
-
join(home, ".vscode-remote"),
|
|
55
|
-
]);
|
|
56
|
-
for (const root of extra)
|
|
57
|
-
roots.add(root);
|
|
58
|
-
return [...roots];
|
|
59
|
-
}
|
|
60
|
-
function agentPluginDirs(roots) {
|
|
61
|
-
const dirs = new Set();
|
|
62
|
-
for (const root of roots) {
|
|
63
|
-
dirs.add(join(root, "agent-plugins"));
|
|
64
|
-
dirs.add(join(root, "agentPlugins"));
|
|
65
|
-
dirs.add(join(root, "data", "agent-plugins"));
|
|
66
|
-
dirs.add(join(root, "data", "agentPlugins"));
|
|
67
|
-
}
|
|
68
|
-
return [...dirs];
|
|
69
|
-
}
|
|
70
|
-
function findSkillDirs(root, out, seen) {
|
|
71
|
-
const resolved = join(root);
|
|
72
|
-
if (seen.has(resolved))
|
|
73
|
-
return;
|
|
74
|
-
seen.add(resolved);
|
|
75
|
-
let entries;
|
|
76
|
-
try {
|
|
77
|
-
entries = readdirSync(resolved);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
for (const entry of entries) {
|
|
83
|
-
if (entry === ".git")
|
|
84
|
-
continue;
|
|
85
|
-
const full = join(resolved, entry);
|
|
86
|
-
let isDir = false;
|
|
87
|
-
try {
|
|
88
|
-
isDir = statSync(full).isDirectory();
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (isDir) {
|
|
94
|
-
if (existsSync(join(full, "SKILL.md"))) {
|
|
95
|
-
out.add(full);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
findSkillDirs(full, out, seen);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function vscodePluginPath(pluginUri) {
|
|
104
|
-
const m = /^file:\/\/(.+)$/.exec(pluginUri);
|
|
105
|
-
if (!m)
|
|
106
|
-
return pluginUri;
|
|
107
|
-
let raw;
|
|
108
|
-
try {
|
|
109
|
-
raw = decodeURIComponent(m[1]);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
raw = m[1];
|
|
113
|
-
}
|
|
114
|
-
if (raw.startsWith("/"))
|
|
115
|
-
raw = raw.slice(1);
|
|
116
|
-
return raw;
|
|
117
|
-
}
|
|
118
|
-
function collectVscodeManifest(out, installedJson) {
|
|
119
|
-
if (!existsSync(installedJson))
|
|
120
|
-
return;
|
|
121
|
-
let manifest;
|
|
122
|
-
try {
|
|
123
|
-
manifest = JSON.parse(readFileSync(installedJson, "utf8"));
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
for (const plugin of manifest.installed ?? []) {
|
|
129
|
-
if (!plugin.pluginUri)
|
|
130
|
-
continue;
|
|
131
|
-
const dir = vscodePluginPath(plugin.pluginUri);
|
|
132
|
-
if (dir)
|
|
133
|
-
findSkillDirs(dir, out, new Set());
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Remote hosts: VS Code syncs client skills into
|
|
137
|
-
// {data}/agentPlugins/{sanitizedUri}/{nonce}/ and records the LRU in
|
|
138
|
-
// cache.json. Resolve each entry so the materialized synced-customization
|
|
139
|
-
// bundle ("VS Code Synced Data" Open Plugin, skills/<name>/SKILL.md) is
|
|
140
|
-
// discovered.
|
|
141
|
-
function collectVscodeCache(out, cacheJson) {
|
|
142
|
-
if (!existsSync(cacheJson))
|
|
143
|
-
return;
|
|
144
|
-
let entries;
|
|
145
|
-
try {
|
|
146
|
-
entries = JSON.parse(readFileSync(cacheJson, "utf8"));
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
if (!Array.isArray(entries))
|
|
152
|
-
return;
|
|
153
|
-
const parent = dirname(cacheJson);
|
|
154
|
-
for (const entry of entries) {
|
|
155
|
-
if (typeof entry?.uri !== "string")
|
|
156
|
-
continue;
|
|
157
|
-
const key = sanitizeKey(entry.uri) || "default";
|
|
158
|
-
const nonce = typeof entry.nonce === "string" && entry.nonce
|
|
159
|
-
? sanitizeKey(entry.nonce)
|
|
160
|
-
: "default";
|
|
161
|
-
findSkillDirs(join(parent, key, nonce), out, new Set());
|
|
162
|
-
// Some remote builds materialize the synced bundle directly as
|
|
163
|
-
// {parent}/{key}/skills/... without the {nonce} subdirectory.
|
|
164
|
-
findSkillDirs(join(parent, key), out, new Set());
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
// Mirrors the server-side AgentPluginManager sanitizer so we can resolve the
|
|
168
|
-
// cache.json entries to their on-disk directories.
|
|
169
|
-
function sanitizeKey(value) {
|
|
170
|
-
return value
|
|
171
|
-
.replace(/[^a-zA-Z0-9]/g, "-")
|
|
172
|
-
.replace(/-+/g, "-")
|
|
173
|
-
.replace(/^-|-$/g, "")
|
|
174
|
-
.substring(0, 128);
|
|
175
|
-
}
|
|
176
|
-
function collectAgentPluginRoot(out, root) {
|
|
177
|
-
const installedJson = join(root, "installed.json");
|
|
178
|
-
const cacheJson = join(root, "cache.json");
|
|
179
|
-
const hasManifest = existsSync(installedJson) || existsSync(cacheJson);
|
|
180
|
-
collectVscodeManifest(out, installedJson);
|
|
181
|
-
collectVscodeCache(out, cacheJson);
|
|
182
|
-
// Newer VS Code installs marketplaces directly as {host}/{org}/{repo}
|
|
183
|
-
// subdirectories with no manifest file at all. Fall back to a full tree walk
|
|
184
|
-
// only when no metadata exists, so we don't surface skills from cloned-but-
|
|
185
|
-
// not-installed marketplaces on setups that do have a manifest.
|
|
186
|
-
if (!hasManifest) {
|
|
187
|
-
findSkillDirs(root, out, new Set());
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function collectVscode(out, extra) {
|
|
191
|
-
for (const dir of agentPluginDirs(vsCodeDataRoots(extra))) {
|
|
192
|
-
collectAgentPluginRoot(out, dir);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function collectClaudeManifest(out, installedJson) {
|
|
196
|
-
if (!existsSync(installedJson))
|
|
197
|
-
return;
|
|
198
|
-
let manifest;
|
|
199
|
-
try {
|
|
200
|
-
manifest = JSON.parse(readFileSync(installedJson, "utf8"));
|
|
201
|
-
}
|
|
202
|
-
catch {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
for (const versions of Object.values(manifest.plugins ?? {})) {
|
|
206
|
-
for (const plugin of versions) {
|
|
207
|
-
if (plugin.installPath) {
|
|
208
|
-
findSkillDirs(plugin.installPath, out, new Set());
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function collectClaude(out) {
|
|
214
|
-
const home = homedir();
|
|
215
|
-
const installedJsons = [
|
|
216
|
-
join(home, ".claude", "plugins", "installed_plugins.json"),
|
|
217
|
-
join(home, ".claude", "remote", "plugins", "installed_plugins.json"),
|
|
218
|
-
];
|
|
219
|
-
let found = false;
|
|
220
|
-
for (const installedJson of installedJsons) {
|
|
221
|
-
if (existsSync(installedJson)) {
|
|
222
|
-
found = true;
|
|
223
|
-
collectClaudeManifest(out, installedJson);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
// Remote hosts sync Claude plugins as {nonce}/ dirs with per-plugin
|
|
227
|
-
// manifest.json but no installed_plugins.json; tree-walk the remote plugins
|
|
228
|
-
// dir as a fallback so those skills are discovered too.
|
|
229
|
-
if (!found) {
|
|
230
|
-
const remoteRoot = join(home, ".claude", "remote", "plugins");
|
|
231
|
-
if (existsSync(remoteRoot)) {
|
|
232
|
-
findSkillDirs(remoteRoot, out, new Set());
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { collectClaude, collectNodeModules, collectOpencodeCache, collectVscode, opencodeCacheRoot, planConfig, } from "./discovery.js";
|
|
236
3
|
export default (async (_input, options) => {
|
|
237
4
|
return {
|
|
238
5
|
config: async (cfg) => {
|
|
239
6
|
const config = cfg;
|
|
240
|
-
const extra = Array.isArray(options?.extraRoots)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
continue;
|
|
252
|
-
seen.add(name);
|
|
253
|
-
unique.push(dir);
|
|
7
|
+
const extra = Array.isArray(options?.extraRoots)
|
|
8
|
+
? options.extraRoots
|
|
9
|
+
: [];
|
|
10
|
+
const scanCache = options?.scanCache !== false;
|
|
11
|
+
const scanNodeModules = options?.scanNodeModules !== false;
|
|
12
|
+
const mcpEnabled = options?.mcp === true;
|
|
13
|
+
const packages = [];
|
|
14
|
+
collectClaude(packages);
|
|
15
|
+
collectVscode(packages, extra);
|
|
16
|
+
if (scanCache) {
|
|
17
|
+
collectOpencodeCache(join(opencodeCacheRoot(), "packages"), packages);
|
|
254
18
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
19
|
+
if (scanNodeModules) {
|
|
20
|
+
collectNodeModules(join(process.cwd(), "node_modules"), packages);
|
|
21
|
+
}
|
|
22
|
+
const plan = planConfig(packages, {
|
|
23
|
+
commands: Object.keys(config.command ?? {}),
|
|
24
|
+
mcp: Object.keys(config.mcp ?? {}),
|
|
25
|
+
});
|
|
26
|
+
if (plan.skillPaths.length === 0 && !mcpEnabled)
|
|
27
|
+
return;
|
|
28
|
+
if (plan.skillPaths.length > 0) {
|
|
29
|
+
config.skills ??= {};
|
|
30
|
+
config.skills.paths ??= [];
|
|
31
|
+
for (const dir of plan.skillPaths) {
|
|
32
|
+
if (!config.skills.paths.includes(dir)) {
|
|
33
|
+
config.skills.paths.push(dir);
|
|
34
|
+
}
|
|
260
35
|
}
|
|
261
36
|
}
|
|
262
|
-
// Expose each discovered skill as a `/name` slash command. opencode
|
|
263
|
-
// treats skills and commands as separate mechanisms: a skill is only
|
|
264
|
-
// loaded via the `skill` tool, so without this a discovered skill is
|
|
265
|
-
// never invocable as `/name`. The command body tells the agent to load
|
|
266
|
-
// the skill and route the user's arguments through it.
|
|
267
37
|
config.command ??= {};
|
|
268
|
-
for (const
|
|
269
|
-
|
|
270
|
-
if (!info)
|
|
271
|
-
continue;
|
|
272
|
-
if (config.command[info.name])
|
|
38
|
+
for (const cmd of plan.commands) {
|
|
39
|
+
if (config.command[cmd.name])
|
|
273
40
|
continue;
|
|
274
|
-
config.command[
|
|
275
|
-
description:
|
|
276
|
-
template:
|
|
277
|
-
`Load the \`${info.name}\` skill and follow its instructions.`,
|
|
278
|
-
`Context: $ARGUMENTS`,
|
|
279
|
-
].join("\n"),
|
|
41
|
+
config.command[cmd.name] = {
|
|
42
|
+
description: cmd.description,
|
|
43
|
+
template: cmd.template,
|
|
280
44
|
};
|
|
281
45
|
}
|
|
46
|
+
if (mcpEnabled) {
|
|
47
|
+
config.mcp ??= {};
|
|
48
|
+
for (const { key, entry } of plan.mcp) {
|
|
49
|
+
if (config.mcp[key])
|
|
50
|
+
continue;
|
|
51
|
+
config.mcp[key] = entry;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
282
54
|
},
|
|
283
55
|
};
|
|
284
56
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-skill-autodiscovery",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "OpenCode plugin that auto-discovers skills installed by VS Code agent plugins
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "OpenCode plugin that auto-discovers skills installed by VS Code agent plugins, Claude Code plugins, and Agent Plugins 1.0.0 packages, and registers them with the local opencode config.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "tsc -p tsconfig.json",
|
|
31
|
+
"test": "npm run build && node --test",
|
|
31
32
|
"prepublishOnly": "npm run build"
|
|
32
33
|
},
|
|
33
34
|
"keywords": [
|