opencode-skill-autodiscovery 1.0.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 +47 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# opencode-skill-autodiscovery
|
|
2
|
+
|
|
3
|
+
An [opencode](https://opencode.ai) plugin that auto-discovers skills installed by
|
|
4
|
+
VS Code agent plugins and Claude Code plugins on the current machine, and
|
|
5
|
+
registers them with opencode's `skills.paths` so they appear in every session.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Skills live in different places depending on the tool that installed them:
|
|
10
|
+
|
|
11
|
+
- VS Code agent plugins: `~/.vscode/agent-plugins/installed.json`
|
|
12
|
+
- Claude Code plugins: `~/.claude/plugins/installed_plugins.json`
|
|
13
|
+
|
|
14
|
+
Each points at plugin directories that contain `SKILL.md` files. This plugin
|
|
15
|
+
walks those manifests, finds every skill directory, and adds them to the
|
|
16
|
+
opencode config.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Add the package name to the `plugin` array in your `opencode.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"plugin": ["opencode-skill-autodiscovery"]
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Notes
|
|
29
|
+
|
|
30
|
+
- Discovery is inherently **machine-local**: it reads manifests from the home
|
|
31
|
+
directory of the machine opencode is running on. Remote sessions on a
|
|
32
|
+
different machine will discover that machine's skills.
|
|
33
|
+
- The plugin is a no-op when no VS Code or Claude plugin manifests exist, or
|
|
34
|
+
when they contain no skills.
|
|
35
|
+
|
|
36
|
+
## Development
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm install
|
|
40
|
+
npm run build # tsc -> dist/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Publish:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm publish --access public
|
|
47
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,qBAAqB,CAAC;;kBAkGlC,MAAM;;AAF9B,wBAyBoB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const VSCODE_INSTALLED = join(homedir(), ".vscode", "agent-plugins", "installed.json");
|
|
5
|
+
const CLAUDE_INSTALLED = join(homedir(), ".claude", "plugins", "installed_plugins.json");
|
|
6
|
+
function findSkillDirs(root, out, seen) {
|
|
7
|
+
const resolved = join(root);
|
|
8
|
+
if (seen.has(resolved))
|
|
9
|
+
return;
|
|
10
|
+
seen.add(resolved);
|
|
11
|
+
let entries;
|
|
12
|
+
try {
|
|
13
|
+
entries = readdirSync(resolved);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const full = join(resolved, entry);
|
|
20
|
+
let isDir = false;
|
|
21
|
+
try {
|
|
22
|
+
isDir = statSync(full).isDirectory();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (isDir) {
|
|
28
|
+
if (existsSync(join(full, "SKILL.md"))) {
|
|
29
|
+
out.add(full);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
findSkillDirs(full, out, seen);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function vscodePluginPath(pluginUri) {
|
|
38
|
+
const m = /^file:\/\/(.+)$/.exec(pluginUri);
|
|
39
|
+
if (!m)
|
|
40
|
+
return pluginUri;
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = decodeURIComponent(m[1]);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
raw = m[1];
|
|
47
|
+
}
|
|
48
|
+
if (raw.startsWith("/"))
|
|
49
|
+
raw = raw.slice(1);
|
|
50
|
+
return raw;
|
|
51
|
+
}
|
|
52
|
+
function collectVscode(out) {
|
|
53
|
+
if (!existsSync(VSCODE_INSTALLED))
|
|
54
|
+
return;
|
|
55
|
+
let manifest;
|
|
56
|
+
try {
|
|
57
|
+
manifest = JSON.parse(readFileSync(VSCODE_INSTALLED, "utf8"));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const plugin of manifest.installed ?? []) {
|
|
63
|
+
if (!plugin.pluginUri)
|
|
64
|
+
continue;
|
|
65
|
+
const dir = vscodePluginPath(plugin.pluginUri);
|
|
66
|
+
if (dir)
|
|
67
|
+
findSkillDirs(dir, out, new Set());
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function collectClaude(out) {
|
|
71
|
+
if (!existsSync(CLAUDE_INSTALLED))
|
|
72
|
+
return;
|
|
73
|
+
let manifest;
|
|
74
|
+
try {
|
|
75
|
+
manifest = JSON.parse(readFileSync(CLAUDE_INSTALLED, "utf8"));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
for (const versions of Object.values(manifest.plugins ?? {})) {
|
|
81
|
+
for (const plugin of versions) {
|
|
82
|
+
if (plugin.installPath) {
|
|
83
|
+
findSkillDirs(plugin.installPath, out, new Set());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export default (async () => {
|
|
89
|
+
return {
|
|
90
|
+
config: async (cfg) => {
|
|
91
|
+
const config = cfg;
|
|
92
|
+
const dirs = new Set();
|
|
93
|
+
collectVscode(dirs);
|
|
94
|
+
collectClaude(dirs);
|
|
95
|
+
if (dirs.size === 0)
|
|
96
|
+
return;
|
|
97
|
+
const seen = new Set();
|
|
98
|
+
const unique = [];
|
|
99
|
+
for (const dir of dirs) {
|
|
100
|
+
const name = dir.split(/[\\/]/).pop();
|
|
101
|
+
if (seen.has(name))
|
|
102
|
+
continue;
|
|
103
|
+
seen.add(name);
|
|
104
|
+
unique.push(dir);
|
|
105
|
+
}
|
|
106
|
+
config.skills ??= {};
|
|
107
|
+
config.skills.paths ??= [];
|
|
108
|
+
for (const dir of unique) {
|
|
109
|
+
if (!config.skills.paths.includes(dir)) {
|
|
110
|
+
config.skills.paths.push(dir);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-skill-autodiscovery",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode plugin that auto-discovers skills installed by VS Code agent plugins and Claude Code plugins, and registers them with the local opencode config.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"opencode",
|
|
27
|
+
"plugin",
|
|
28
|
+
"skill",
|
|
29
|
+
"autodiscovery",
|
|
30
|
+
"claude",
|
|
31
|
+
"vscode"
|
|
32
|
+
],
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@opencode-ai/plugin": "1.18.13",
|
|
35
|
+
"typescript": "^5.5.0",
|
|
36
|
+
"@types/node": "^20.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|