@fakhrulraharjo/opencode-skill-creator 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 ADDED
@@ -0,0 +1,343 @@
1
+ # opencode-skill-creator
2
+
3
+ [![npm](https://img.shields.io/npm/v/opencode-skill-creator)](https://www.npmjs.com/package/opencode-skill-creator)
4
+
5
+ A **skill + plugin** for [OpenCode](https://opencode.ai) that helps you create, test, and optimize other OpenCode skills.
6
+
7
+ This is a faithful adaptation of Anthropic's official [skill-creator](https://github.com/anthropics/skills/tree/main/skills/skill-creator) for Claude Code, fully rewritten to work with OpenCode's extensibility mechanisms. The Python scripts from the original have been ported to TypeScript and packaged as an OpenCode plugin with custom tools.
8
+
9
+ ## Install
10
+
11
+ Package: https://www.npmjs.com/package/opencode-skill-creator
12
+
13
+ ### Pick your option
14
+
15
+ | If you are... | Use this |
16
+ |---|---|
17
+ | New to OpenCode / non-developer | **Option A (Recommended)** |
18
+ | Already using other plugins | **Option B** |
19
+ | Setting up all projects on your computer | **Option C (Global config)** |
20
+ | Setting up only one project | **Option D (Project config)** |
21
+ | Cannot use npm / offline environment | **Option E (Manual install)** |
22
+
23
+ ### Option A (Recommended): easiest setup for most users
24
+
25
+ Run one command (global install, recommended):
26
+
27
+ ```bash
28
+ npx opencode-skill-creator install --global
29
+ ```
30
+
31
+ Optional checks:
32
+
33
+ ```bash
34
+ npx opencode-skill-creator --version
35
+ npx opencode-skill-creator --help
36
+ npx opencode-skill-creator --about
37
+ ```
38
+
39
+ What this command does:
40
+
41
+ 1. Creates/updates `~/.config/opencode/opencode.json`
42
+ 2. Adds `"opencode-skill-creator"` to the `plugin` array
43
+ 3. Leaves your existing plugins untouched
44
+
45
+ Then:
46
+
47
+ 4. Restart OpenCode
48
+ 5. Ask OpenCode: `Create a skill that helps with Docker compose files`
49
+
50
+ That's it.
51
+
52
+ Manual equivalent for the same result:
53
+
54
+ 1. Open (or create) `~/.config/opencode/opencode.json`
55
+ 2. Paste this:
56
+
57
+ ```json
58
+ {
59
+ "plugin": ["opencode-skill-creator"]
60
+ }
61
+ ```
62
+
63
+ 3. Restart OpenCode.
64
+
65
+ If you want project-only install instead, use:
66
+
67
+ ```bash
68
+ npx opencode-skill-creator install --project
69
+ ```
70
+
71
+ ### Option B: you already have plugins
72
+
73
+ If your file already has plugins, append this package to the list:
74
+
75
+ ```json
76
+ {
77
+ "plugin": [
78
+ "your-existing-plugin",
79
+ "opencode-skill-creator"
80
+ ]
81
+ }
82
+ ```
83
+
84
+ Do not remove your existing plugins.
85
+
86
+ ### Option C: global config (works in all projects)
87
+
88
+ Use global config when you want this plugin available everywhere.
89
+
90
+ Command version:
91
+
92
+ ```bash
93
+ npx opencode-skill-creator install --global
94
+ ```
95
+
96
+ 1. Open (or create) `~/.config/opencode/opencode.json`
97
+ 2. Add:
98
+
99
+ ```json
100
+ {
101
+ "plugin": ["opencode-skill-creator"]
102
+ }
103
+ ```
104
+
105
+ 3. Restart OpenCode.
106
+
107
+ ### Option D: project config (only one project)
108
+
109
+ Use project config when you want this plugin only for one repo.
110
+
111
+ Command version:
112
+
113
+ ```bash
114
+ npx opencode-skill-creator install --project
115
+ ```
116
+
117
+ 1. Open (or create) `opencode.json` in that project root
118
+ 2. Add:
119
+
120
+ ```json
121
+ {
122
+ "plugin": ["opencode-skill-creator"]
123
+ }
124
+ ```
125
+
126
+ 3. Restart OpenCode in that project.
127
+
128
+ ### Option E: manual install (no npm)
129
+
130
+ ```bash
131
+ git clone https://github.com/antongulin/opencode-skill-creator.git
132
+ cd opencode-skill-creator
133
+
134
+ # Install the skill (global)
135
+ cp -r opencode-skill-creator/ ~/.config/opencode/skills/opencode-skill-creator/
136
+
137
+ # Install the plugin (global)
138
+ cp -r plugin/ ~/.config/opencode/plugins/skill-creator/
139
+ ```
140
+
141
+ Then create `~/.config/opencode/package.json` if needed:
142
+
143
+ ```json
144
+ {
145
+ "dependencies": {
146
+ "@opencode-ai/plugin": ">=1.0.0"
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### What happens after install
152
+
153
+ After you add `opencode-skill-creator` and restart OpenCode:
154
+
155
+ 1. OpenCode installs the plugin from npm automatically.
156
+ 2. The npm package loads compiled JavaScript from `dist/skill-creator.js`.
157
+ 3. On first plugin startup, it auto-copies skill files to `~/.config/opencode/skills/opencode-skill-creator/`.
158
+ 4. Restart OpenCode after changing config because plugin config is loaded at startup.
159
+
160
+ ### Verify install
161
+
162
+ Check that the skill file exists:
163
+
164
+ ```bash
165
+ ls ~/.config/opencode/skills/opencode-skill-creator/SKILL.md
166
+ ```
167
+
168
+ Then ask OpenCode:
169
+
170
+ ```text
171
+ Use opencode-skill-creator to create a skill that helps with API documentation.
172
+ ```
173
+
174
+ You should see it use the opencode-skill-creator workflow/tools.
175
+
176
+ ### Migration from the old `skill-creator` folder
177
+
178
+ Earlier versions installed the bundled skill as the generic `skill-creator` skill. That could conflict with other plugins, including Superpowers, that also provide a skill with the same name.
179
+
180
+ Current versions install the bundled skill as `opencode-skill-creator` instead. On startup, if the plugin finds an old plugin-owned folder at `~/.config/opencode/skills/skill-creator/`, it moves that folder to an inactive backup such as:
181
+
182
+ ```text
183
+ ~/.config/opencode/skills/skill-creator.opencode-skill-creator-backup-YYYYMMDDTHHMMSS/
184
+ ```
185
+
186
+ The backup preserves user files and renames `SKILL.md` to `SKILL.md.backup` so OpenCode will not keep loading the old generic skill. If the old `skill-creator` folder does not contain the plugin's `.opencode-skill-creator-version` marker, the plugin leaves it untouched because it may belong to another plugin or a manually installed skill.
187
+
188
+ ### Troubleshooting
189
+
190
+ - `I don't have opencode.json or opencode.jsonc`: create one in project root (or use global config path).
191
+ - `Nothing changed after edit`: fully restart OpenCode.
192
+ - `I already had plugins`: keep them; just add `opencode-skill-creator` to the same array.
193
+ - `I want a clean reinstall`: delete `~/.config/opencode/skills/opencode-skill-creator/` and restart OpenCode.
194
+ - `I still see another skill-creator skill`: if `~/.config/opencode/skills/skill-creator/` has no `.opencode-skill-creator-version` marker, it is not managed by this plugin and must be reviewed separately.
195
+ - `npx command failed`: run `npx opencode-skill-creator --help` and then use `install` or `install --global`.
196
+
197
+ ### Compatibility fixes
198
+
199
+ - The installer supports existing `opencode.jsonc` files and preserves JSONC comments when adding the plugin entry.
200
+ - The npm package loads compiled JavaScript from `dist/skill-creator.js` so OpenCode does not need to strip TypeScript under `node_modules`.
201
+ - The plugin resolves bundled assets with `import.meta.url`, which works in OpenCode Desktop runtimes where `import.meta.path` is unavailable.
202
+ - Trigger evaluations run with an explicit OpenCode agent, defaulting to `build`, to avoid false 0% scores from delegating default agents.
203
+ - Release-safety tests now verify the compiled plugin entrypoint imports correctly and that `dist/` was built from the current TypeScript sources.
204
+
205
+ ### For LLMs / automation (compact)
206
+
207
+ ```json
208
+ { "plugin": ["opencode-skill-creator"] }
209
+ ```
210
+
211
+ ## What it does
212
+
213
+ When loaded, this skill guides OpenCode through the full skill development lifecycle:
214
+
215
+ 1. **Analyze** the user's request and determine what kind of skill to build
216
+ 2. **Create** a well-structured skill with proper frontmatter, SKILL.md, and supporting files
217
+ 3. **Generate** an eval set of test queries (should-trigger and should-not-trigger)
218
+ 4. **Evaluate** the skill's description by testing whether it triggers correctly
219
+ 5. **Optimize** the description through iterative improvement loops
220
+ 6. **Benchmark** skill performance with variance analysis
221
+ 7. **Install** the skill to the project or global OpenCode skills directory
222
+
223
+ ## Plugin tools
224
+
225
+ The plugin registers these custom tools that OpenCode can call:
226
+
227
+ | Tool | Purpose |
228
+ |------|---------|
229
+ | `skill_validate` | Validate SKILL.md structure and frontmatter |
230
+ | `skill_parse` | Parse SKILL.md and extract name/description |
231
+ | `skill_eval` | Test trigger accuracy for eval queries |
232
+ | `skill_improve_description` | LLM-powered description improvement |
233
+ | `skill_optimize_loop` | Full eval->improve optimization loop |
234
+ | `skill_aggregate_benchmark` | Aggregate grading results into statistics |
235
+ | `skill_generate_report` | Generate HTML optimization report |
236
+ | `skill_serve_review` | Start the eval review viewer (HTTP server) |
237
+ | `skill_stop_review` | Stop a running review server |
238
+ | `skill_export_static_review` | Generate standalone HTML review file |
239
+ | `skill_add_gold_standard` | Save an exemplary skill response for future guidance |
240
+ | `skill_list_gold_standards` | List saved gold-standard examples for a skill |
241
+ | `skill_remove_gold_standard` | Remove a saved gold-standard example |
242
+ | `skill_get_gold_advice` | Get guidance from saved gold-standard examples |
243
+
244
+ ### Review workflow guard (strict by default)
245
+
246
+ The review launch tools now enforce paired comparison data by default:
247
+
248
+ - `skill_serve_review` and `skill_export_static_review` require each `eval-*` directory to include:
249
+ - `with_skill`
250
+ - baseline (`without_skill` or `old_skill`)
251
+ - If pairs are missing, the tools fail fast with a clear list of missing items.
252
+ - Override only when intentionally reviewing partial data by passing `allowPartial: true`.
253
+ - If `benchmarkPath` is omitted, the tools auto-generate `benchmark.json` and `benchmark.md` in the workspace.
254
+
255
+ ### Skill draft staging (recommended)
256
+
257
+ When creating new skills, use a staging path in the system temp directory outside your current repository:
258
+
259
+ - Unix/macOS draft skill path: `/tmp/opencode-skills/<skill-name>/` (or `$TMPDIR/opencode-skills/<skill-name>/`)
260
+ - Unix/macOS eval workspace path: `/tmp/opencode-skills/<skill-name>-workspace/`
261
+ - Windows draft/eval paths: `%TEMP%\\opencode-skills\\<skill-name>\\` and `%TEMP%\\opencode-skills\\<skill-name>-workspace\\`
262
+ - Install only the final validated skill to:
263
+ - project: `.opencode/skills/<skill-name>/`
264
+ - global: `~/.config/opencode/skills/<skill-name>/`
265
+
266
+ This keeps plugin/source repositories clean while preserving the full eval loop.
267
+
268
+ ## Usage
269
+
270
+ Once installed, OpenCode will automatically detect the skill when you ask it to create or improve a skill. For example:
271
+
272
+ - "Create a skill that helps with Docker compose files"
273
+ - "Build me a skill for generating API documentation"
274
+ - "Help me make a skill that assists with database migrations"
275
+ - "Optimize the description of my existing skill"
276
+
277
+ OpenCode will load the opencode-skill-creator instructions and use the plugin tools to walk through the full workflow.
278
+
279
+ ## Architecture
280
+
281
+ This project has two components:
282
+
283
+ | Component | What it is |
284
+ |-----------|-----------|
285
+ | **Skill** | Markdown instructions (SKILL.md + agents + templates) that tell the agent how to create, evaluate, and improve skills |
286
+ | **Plugin** | TypeScript module that registers custom tools for validation, eval, benchmarking, and review |
287
+
288
+ The skill provides the workflow knowledge; the plugin provides the executable tools the agent calls during that workflow.
289
+
290
+ On first startup, the plugin automatically copies the bundled skill files to `~/.config/opencode/skills/opencode-skill-creator/`. If you need to reinstall the skill (e.g., after an update), delete that directory and restart OpenCode.
291
+
292
+ ## Project structure
293
+
294
+ ```
295
+ opencode-skill-creator/
296
+ ├── README.md
297
+ ├── LICENSE # Apache 2.0
298
+ ├── opencode-skill-creator/ # The SKILL
299
+ │ ├── SKILL.md # Main skill instructions
300
+ │ ├── agents/
301
+ │ │ ├── grader.md # Assertion evaluation
302
+ │ │ ├── analyzer.md # Benchmark analysis
303
+ │ │ └── comparator.md # Blind A/B comparison
304
+ │ ├── references/
305
+ │ │ └── schemas.md # JSON schema definitions
306
+ │ └── templates/
307
+ │ └── eval-review.html # Eval set review/edit UI
308
+ └── plugin/ # The PLUGIN (npm: opencode-skill-creator)
309
+ ├── package.json # npm package metadata
310
+ ├── skill-creator.ts # Entry point — registers all tools
311
+ ├── skill/ # Bundled copy of skill (auto-installed)
312
+ ├── lib/
313
+ │ ├── utils.ts # SKILL.md frontmatter parsing
314
+ │ ├── validate.ts # Skill structure validation
315
+ │ ├── run-eval.ts # Trigger evaluation via opencode run
316
+ │ ├── improve-description.ts # LLM-powered description improvement
317
+ │ ├── run-loop.ts # Eval→improve optimization loop
318
+ │ ├── aggregate.ts # Benchmark aggregation
319
+ │ ├── report.ts # HTML report generation
320
+ │ └── review-server.ts # Eval review HTTP server
321
+ └── templates/
322
+ └── viewer.html # Eval review viewer UI
323
+ ```
324
+
325
+ ## Differences from the Anthropic original
326
+
327
+ | Area | Anthropic (Claude Code) | This repo (OpenCode) |
328
+ |------|------------------------|---------------------|
329
+ | CLI invocation | `claude -p "prompt"` | `opencode run "prompt"` |
330
+ | Skill location | `.claude/commands/` | `.opencode/skills/` |
331
+ | Automation scripts | Python (`scripts/*.py`) | TypeScript plugin (`plugin/lib/*.ts`) |
332
+ | Script execution | `python -m scripts.run_loop` | `skill_optimize_loop` tool call |
333
+ | Eval viewer | `python generate_review.py` | `skill_serve_review` tool call |
334
+ | Benchmarking | `python aggregate_benchmark.py` | `skill_aggregate_benchmark` tool call |
335
+ | Dependencies | Python 3.11+, pyyaml | Bun (via OpenCode), @opencode-ai/plugin |
336
+ | Packaging | `.skill` zip files | npm package + skill directory |
337
+ | Subagents | Built-in subagent concept | Task tool with `general`/`explore` types |
338
+
339
+ ## License
340
+
341
+ Apache License 2.0 — see [LICENSE](LICENSE) for details.
342
+
343
+ Based on [anthropics/skills](https://github.com/anthropics/skills) by Anthropic.
@@ -0,0 +1,338 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"
4
+ import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser"
5
+ import { homedir } from "os"
6
+ import { join, dirname } from "path"
7
+
8
+ const PKG_PATH = new URL("../package.json", import.meta.url)
9
+ const PACKAGE_NAME = "@fakhrulraharjo/opencode-skill-creator"
10
+ const PLUGIN_LOAD_ERROR_PREFIX = `Failed to load plugin ${PACKAGE_NAME}:`
11
+
12
+ function getVersion() {
13
+ try {
14
+ const pkg = JSON.parse(readFileSync(PKG_PATH, "utf-8"))
15
+ return pkg.version || "unknown"
16
+ } catch {
17
+ return "unknown"
18
+ }
19
+ }
20
+
21
+ function printHelp() {
22
+ console.log(`${PACKAGE_NAME} installer
23
+
24
+ Links:
25
+ npm: https://www.npmjs.com/package/${PACKAGE_NAME}
26
+ repo: https://github.com/fakhrulraharjo/opencode-skill-creator
27
+
28
+ Usage:
29
+ npx ${PACKAGE_NAME} install [--global|--project]
30
+ npx ${PACKAGE_NAME} [--global|--project]
31
+ npx ${PACKAGE_NAME} --version
32
+ npx ${PACKAGE_NAME} --about
33
+
34
+ Options:
35
+ --global Update ~/.config/opencode/opencode.jsonc if present, otherwise opencode.json (default)
36
+ --project Update ./opencode.jsonc if present, otherwise opencode.json in current directory
37
+ -v, --version Show installer version
38
+ --about Show package links
39
+ -h, --help Show help
40
+ `)
41
+ }
42
+
43
+ function printAbout() {
44
+ console.log(`${PACKAGE_NAME} ${getVersion()}
45
+ npm: https://www.npmjs.com/package/${PACKAGE_NAME}
46
+ repo: https://github.com/fakhrulraharjo/opencode-skill-creator`)
47
+ }
48
+
49
+ function parseArgs(argv) {
50
+ const input = argv.slice(2)
51
+ const args = new Set(input)
52
+
53
+ if (args.has("-h") || args.has("--help")) {
54
+ return {
55
+ help: true,
56
+ about: false,
57
+ version: false,
58
+ global: false,
59
+ command: "install",
60
+ }
61
+ }
62
+
63
+ if (args.has("-v") || args.has("--version")) {
64
+ return {
65
+ help: false,
66
+ about: false,
67
+ version: true,
68
+ global: false,
69
+ command: "install",
70
+ }
71
+ }
72
+
73
+ if (args.has("--about")) {
74
+ return {
75
+ help: false,
76
+ about: true,
77
+ version: false,
78
+ global: false,
79
+ command: "install",
80
+ }
81
+ }
82
+
83
+ const hasProject = args.has("--project")
84
+ const hasGlobal = args.has("--global")
85
+
86
+ if (hasProject && hasGlobal) {
87
+ throw new Error("Use either --project or --global, not both.")
88
+ }
89
+
90
+ const command = input.find((arg) => !arg.startsWith("-")) || "install"
91
+ if (command !== "install") {
92
+ throw new Error(`Unknown command: ${command}`)
93
+ }
94
+
95
+ return {
96
+ help: false,
97
+ about: false,
98
+ version: false,
99
+ global: !hasProject,
100
+ command,
101
+ }
102
+ }
103
+
104
+ function getConfigPath(globalInstall) {
105
+ const configDir = globalInstall
106
+ ? join(homedir(), ".config", "opencode")
107
+ : process.cwd()
108
+ const jsoncPath = join(configDir, "opencode.jsonc")
109
+
110
+ if (existsSync(jsoncPath)) {
111
+ return jsoncPath
112
+ }
113
+
114
+ return join(configDir, "opencode.json")
115
+ }
116
+
117
+ function clearStaleOpenCodePackageCache() {
118
+ const currentVersion = getVersion()
119
+ if (currentVersion === "unknown") return { cleared: false, error: null }
120
+
121
+ const cacheDir = process.env.XDG_CACHE_HOME || join(homedir(), ".cache")
122
+ const packageCacheRoot = join(
123
+ cacheDir,
124
+ "opencode",
125
+ "packages",
126
+ `${PACKAGE_NAME}@latest`
127
+ )
128
+ const cachedPackageJson = join(
129
+ packageCacheRoot,
130
+ "node_modules",
131
+ ...PACKAGE_NAME.split("/"),
132
+ "package.json"
133
+ )
134
+
135
+ if (!existsSync(cachedPackageJson)) return { cleared: false, error: null }
136
+
137
+ try {
138
+ const cachedPackage = JSON.parse(readFileSync(cachedPackageJson, "utf-8"))
139
+ if (cachedPackage.version === currentVersion) {
140
+ return { cleared: false, error: null }
141
+ }
142
+ } catch {
143
+ // Broken cache entries should be removed so OpenCode can recreate them.
144
+ }
145
+
146
+ try {
147
+ rmSync(packageCacheRoot, { recursive: true, force: true })
148
+ return { cleared: true, error: null }
149
+ } catch (error) {
150
+ return { cleared: false, error }
151
+ }
152
+ }
153
+
154
+ function getDesktopGlobalDataPath() {
155
+ if (process.platform === "darwin") {
156
+ return join(
157
+ homedir(),
158
+ "Library",
159
+ "Application Support",
160
+ "ai.opencode.desktop",
161
+ "opencode.global.dat"
162
+ )
163
+ }
164
+
165
+ if (process.platform === "win32") {
166
+ const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming")
167
+ return join(appData, "ai.opencode.desktop", "opencode.global.dat")
168
+ }
169
+
170
+ const configDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config")
171
+ return join(configDir, "ai.opencode.desktop", "opencode.global.dat")
172
+ }
173
+
174
+ function clearPluginFaultNotifications() {
175
+ const dataPath = getDesktopGlobalDataPath()
176
+ if (!existsSync(dataPath)) return 0
177
+
178
+ try {
179
+ const data = JSON.parse(readFileSync(dataPath, "utf-8"))
180
+ if (typeof data.notification !== "string") return 0
181
+
182
+ const notifications = JSON.parse(data.notification)
183
+ if (!Array.isArray(notifications.list)) return 0
184
+
185
+ const originalCount = notifications.list.length
186
+ notifications.list = notifications.list.filter((notification) => {
187
+ if (notification?.type !== "error") return true
188
+
189
+ const message = notification?.error?.data?.message
190
+ return typeof message !== "string" || !message.startsWith(PLUGIN_LOAD_ERROR_PREFIX)
191
+ })
192
+
193
+ const removedCount = originalCount - notifications.list.length
194
+ if (removedCount === 0) return 0
195
+
196
+ data.notification = JSON.stringify(notifications)
197
+ writeFileSync(dataPath, `${JSON.stringify(data, null, "\t")}\n`, "utf-8")
198
+ return removedCount
199
+ } catch {
200
+ // Desktop state cleanup is best-effort; installation should not fail here.
201
+ return 0
202
+ }
203
+ }
204
+
205
+ function loadConfig(path) {
206
+ if (!existsSync(path)) {
207
+ return {
208
+ raw: "{\n}\n",
209
+ config: {},
210
+ }
211
+ }
212
+
213
+ const raw = readFileSync(path, "utf-8")
214
+ if (!raw.trim()) {
215
+ return {
216
+ raw: "{\n}\n",
217
+ config: {},
218
+ }
219
+ }
220
+
221
+ const errors = []
222
+ const config = parse(raw, errors, {
223
+ allowTrailingComma: true,
224
+ disallowComments: false,
225
+ })
226
+
227
+ if (errors.length) {
228
+ const message = errors
229
+ .map((error) => printParseErrorCode(error.error))
230
+ .join(", ")
231
+ throw new Error(
232
+ `Could not parse JSONC in ${path}: ${message}. Please fix the file, then re-run this installer.`
233
+ )
234
+ }
235
+
236
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
237
+ throw new Error(`Expected top-level config in ${path} to be an object.`)
238
+ }
239
+
240
+ return { raw, config }
241
+ }
242
+
243
+ function saveConfig(path, raw, config) {
244
+ const formattingOptions = {
245
+ insertSpaces: true,
246
+ tabSize: 2,
247
+ }
248
+
249
+ const edits = Array.isArray(config.plugin)
250
+ ? modify(raw, ["plugin", -1], PACKAGE_NAME, {
251
+ formattingOptions,
252
+ })
253
+ : modify(raw, ["plugin"], [PACKAGE_NAME], {
254
+ formattingOptions,
255
+ })
256
+
257
+ mkdirSync(dirname(path), { recursive: true })
258
+ writeFileSync(path, applyEdits(raw, edits), "utf-8")
259
+ }
260
+
261
+ function ensurePlugin(config) {
262
+ if (typeof config.plugin === "undefined") {
263
+ return true
264
+ }
265
+
266
+ if (!Array.isArray(config.plugin)) {
267
+ throw new Error('Expected "plugin" to be an array in opencode config')
268
+ }
269
+
270
+ return !config.plugin.includes(PACKAGE_NAME)
271
+ }
272
+
273
+ function main() {
274
+ const { help, about, version, global } = parseArgs(process.argv)
275
+ if (help) {
276
+ printHelp()
277
+ process.exit(0)
278
+ }
279
+
280
+ if (about) {
281
+ printAbout()
282
+ process.exit(0)
283
+ }
284
+
285
+ if (version) {
286
+ console.log(getVersion())
287
+ process.exit(0)
288
+ }
289
+
290
+ const configPath = getConfigPath(global)
291
+ const { raw, config } = loadConfig(configPath)
292
+ const changed = ensurePlugin(config)
293
+ if (changed) {
294
+ saveConfig(configPath, raw, config)
295
+ console.log(`Updated ${configPath}`)
296
+ console.log(`Added "${PACKAGE_NAME}" to the "plugin" array.`)
297
+ } else {
298
+ console.log(`No changes needed for ${configPath}`)
299
+ console.log(`"${PACKAGE_NAME}" is already in the "plugin" array.`)
300
+ }
301
+
302
+ if (global) {
303
+ const cacheCleanup = clearStaleOpenCodePackageCache()
304
+ if (cacheCleanup.cleared) {
305
+ console.log(`Cleared stale OpenCode package cache for ${PACKAGE_NAME}.`)
306
+ } else if (cacheCleanup.error) {
307
+ console.warn(
308
+ `Could not clear stale OpenCode package cache: ${cacheCleanup.error.message}`
309
+ )
310
+ }
311
+ }
312
+
313
+ if (global) {
314
+ const removedNotifications = clearPluginFaultNotifications()
315
+ if (removedNotifications > 0) {
316
+ const noun = removedNotifications === 1 ? "notification" : "notifications"
317
+ console.log(
318
+ `Removed ${removedNotifications} stale ${PACKAGE_NAME} plugin fault ${noun}.`
319
+ )
320
+ }
321
+ }
322
+
323
+ console.log("\nNext steps:")
324
+ console.log("1) Restart OpenCode")
325
+ console.log("2) Ask: Create a skill that helps with API documentation")
326
+ console.log(
327
+ "\nOn first startup, the plugin auto-installs skill files to ~/.config/opencode/skills/opencode-skill-creator/"
328
+ )
329
+ }
330
+
331
+ try {
332
+ main()
333
+ } catch (error) {
334
+ printHelp()
335
+ console.error()
336
+ console.error(error.message)
337
+ process.exit(1)
338
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "entrypoint": "skill-creator.ts",
3
+ "runtimeEntrypoint": "runtime-entry.ts",
4
+ "sourceHash": "3218735af8e73b6ab4a501b15bf9498e44327ad74d20252fad56a769dac2dcd7",
5
+ "builtAt": "2026-07-07T02:43:32.112Z"
6
+ }