opencode-idea 0.0.17 → 0.0.19
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 +408 -183
- package/package.json +5 -1
- package/skills/idea-run-config-manager/SKILL.md +62 -0
- package/skills/idea-run-config-manager/assets/AGENTS.template.md +46 -0
- package/skills/idea-run-config-manager/assets/types/go-build.md +44 -0
- package/skills/idea-run-config-manager/assets/types/gradle.md +57 -0
- package/skills/idea-run-config-manager/assets/types/maven.md +61 -0
- package/skills/idea-run-config-manager/assets/types/node.md +30 -0
- package/skills/idea-run-config-manager/assets/types/npm.md +58 -0
- package/skills/idea-run-config-manager/assets/types/python.md +59 -0
- package/skills/idea-run-config-manager/assets/types/shell.md +77 -0
- package/skills/idea-standalone/SKILL.md +5 -3
- package/skills/idea-standalone/assets/AGENTS.template.md +18 -13
- package/src/ide-guidance.js +183 -38
- package/src/ide-guidance.template.md +131 -37
- package/src/ide-launcher.js +87 -27
- package/src/ide-projects.js +262 -0
- package/src/mcp/enhance.js +111 -29
- package/src/mcp/idea-tool-defaults.js +27 -12
- package/src/mcp/idea.js +9 -75
- package/src/plugin.js +726 -365
- package/src/skill/loader.js +43 -3
package/src/skill/loader.js
CHANGED
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
// and deliberately kept OUT of the registered definition — the caller filters on
|
|
28
28
|
// it instead (see `readSkills`), because a skill whose tools are absent must not
|
|
29
29
|
// be registered at all.
|
|
30
|
+
//
|
|
31
|
+
// The other key is OpenCode's own, written in the portable frontmatter spelling
|
|
32
|
+
// OpenCode documents: a nested `metadata:` block holding
|
|
33
|
+
// `opencode/autoinvoke: false`. It is translated to the definition's
|
|
34
|
+
// `autoinvoke` — the name the registration API uses — which is what makes a
|
|
35
|
+
// skill user-invoked only: OpenCode keeps it registered and loadable on request,
|
|
36
|
+
// but leaves it out of the model's available list.
|
|
30
37
|
|
|
31
38
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
32
39
|
import { fileURLToPath } from 'node:url';
|
|
@@ -87,11 +94,37 @@ function splitList(value) {
|
|
|
87
94
|
.filter((entry) => entry !== '');
|
|
88
95
|
}
|
|
89
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Read `opencode/autoinvoke` out of the frontmatter, or `undefined` when absent.
|
|
99
|
+
*
|
|
100
|
+
* The spelling is OpenCode's portable one — a nested `metadata:` block holding
|
|
101
|
+
* `opencode/autoinvoke: false`. That shape is exactly what the flat reader above
|
|
102
|
+
* already produces: the indented line trims to `opencode/autoinvoke: false` and
|
|
103
|
+
* lands under that namespaced key, while the bare `metadata:` line comes out
|
|
104
|
+
* empty and is ignored. One nesting level is therefore supported on purpose, not
|
|
105
|
+
* by accident.
|
|
106
|
+
*
|
|
107
|
+
* The value must be `true` or `false`. Anything else throws: a typo that
|
|
108
|
+
* silently left the skill model-invocable is the failure this whole mechanism
|
|
109
|
+
* exists to prevent, so it must not pass quietly.
|
|
110
|
+
*
|
|
111
|
+
* @param {Record<string, string>} fields
|
|
112
|
+
* @param {string} source Used in error messages.
|
|
113
|
+
* @returns {boolean | undefined}
|
|
114
|
+
*/
|
|
115
|
+
export function readAutoinvoke(fields, source) {
|
|
116
|
+
const raw = fields['opencode/autoinvoke'];
|
|
117
|
+
if (raw === undefined) return undefined;
|
|
118
|
+
if (raw === 'true') return true;
|
|
119
|
+
if (raw === 'false') return false;
|
|
120
|
+
throw new Error(`${source}: "opencode/autoinvoke" must be true or false, got "${raw}"`);
|
|
121
|
+
}
|
|
122
|
+
|
|
90
123
|
/**
|
|
91
124
|
* Load one skill directory into a `Skill.Info`-shaped definition.
|
|
92
125
|
*
|
|
93
126
|
* @param {string} id Directory name, used as the skill id.
|
|
94
|
-
* @returns {{ id: string, name: string, description: string, path: string, content: string }}
|
|
127
|
+
* @returns {{ id: string, name: string, description: string, autoinvoke?: boolean, path: string, content: string }}
|
|
95
128
|
*/
|
|
96
129
|
export function readSkill(id) {
|
|
97
130
|
return readSkillPackage(id).skill;
|
|
@@ -104,8 +137,13 @@ export function readSkill(id) {
|
|
|
104
137
|
* while `requires` is this package's own metadata and must NOT be registered —
|
|
105
138
|
* it is what the caller filters on.
|
|
106
139
|
*
|
|
140
|
+
* `autoinvoke` is OpenCode's, so it goes the other way: it ships in the
|
|
141
|
+
* frontmatter as `opencode/autoinvoke` and is translated onto the definition,
|
|
142
|
+
* where it picks user-invoked-only over model-invocable. It is only set when the
|
|
143
|
+
* frontmatter asks for it, so a skill that says nothing keeps the plain shape.
|
|
144
|
+
*
|
|
107
145
|
* @param {string} id Directory name, used as the skill id.
|
|
108
|
-
* @returns {{ skill: { id: string, name: string, description: string, path: string, content: string }, requires: string[] }}
|
|
146
|
+
* @returns {{ skill: { id: string, name: string, description: string, autoinvoke?: boolean, path: string, content: string }, requires: string[] }}
|
|
109
147
|
*/
|
|
110
148
|
export function readSkillPackage(id) {
|
|
111
149
|
const file = new URL(`${id}/${SKILL_FILE_NAME}`, SKILLS_DIR);
|
|
@@ -116,11 +154,13 @@ export function readSkillPackage(id) {
|
|
|
116
154
|
if (!description) {
|
|
117
155
|
throw new Error(`${source}: frontmatter needs a "description", otherwise the skill is never offered`);
|
|
118
156
|
}
|
|
157
|
+
const autoinvoke = readAutoinvoke(fields, source);
|
|
119
158
|
return {
|
|
120
159
|
skill: {
|
|
121
160
|
id,
|
|
122
161
|
name: fields.name || id,
|
|
123
162
|
description,
|
|
163
|
+
...(autoinvoke === undefined ? {} : { autoinvoke }),
|
|
124
164
|
path: fileURLToPath(file),
|
|
125
165
|
content: text.replace(FRONTMATTER, '').replace(/^\s+/, '').trimEnd(),
|
|
126
166
|
},
|
|
@@ -131,7 +171,7 @@ export function readSkillPackage(id) {
|
|
|
131
171
|
/**
|
|
132
172
|
* Every shipped skill, sorted by id, each with the tools it requires.
|
|
133
173
|
*
|
|
134
|
-
* @returns {Array<{ skill: { id: string, name: string, description: string, path: string, content: string }, requires: string[] }>}
|
|
174
|
+
* @returns {Array<{ skill: { id: string, name: string, description: string, autoinvoke?: boolean, path: string, content: string }, requires: string[] }>}
|
|
135
175
|
*/
|
|
136
176
|
export function readSkills() {
|
|
137
177
|
return readdirSync(SKILLS_DIR, { withFileTypes: true })
|