@jgordijn/opencode-remote-config 0.1.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.
Files changed (3) hide show
  1. package/README.md +535 -0
  2. package/dist/index.js +8558 -0
  3. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,535 @@
1
+ # opencode-remote-config
2
+
3
+ An OpenCode plugin that syncs skills and agents from Git repositories, making them available to OpenCode without polluting your local configuration.
4
+
5
+ ## Features
6
+
7
+ - **Git-based sync**: Clone once, fetch updates on startup
8
+ - **Local directories**: Use `file://` URLs for local directories (great for development)
9
+ - **Skills import**: Import skill definitions from `skill/` directory
10
+ - **Agents import**: Import agent definitions from `agent/` directory
11
+ - **Plugins import**: Import OpenCode hook plugins from `plugin/` directory
12
+ - **Selective import**: Import all or specify which skills/agents/plugins to include
13
+ - **Ref pinning**: Pin to branch, tag, or commit SHA
14
+ - **Priority handling**: User config > first repository > subsequent repositories
15
+ - **Conflict handling**: Local definitions take precedence, warns on conflicts
16
+ - **Gitignore management**: Automatically adds `_plugins/` to `.gitignore`
17
+
18
+ ---
19
+
20
+ ## For Humans
21
+
22
+ ### Installation
23
+
24
+ #### Option 1: npm (Recommended)
25
+
26
+ ```bash
27
+ # Global installation
28
+ npm install -g @jgordijn/opencode-remote-config
29
+
30
+ # Or with bun
31
+ bun add -g @jgordijn/opencode-remote-config
32
+ ```
33
+
34
+ Then add the plugin to your OpenCode config (`~/.config/opencode/opencode.json` or `.opencode/opencode.json`):
35
+
36
+ ```json
37
+ {
38
+ "plugins": ["@jgordijn/opencode-remote-config"]
39
+ }
40
+ ```
41
+
42
+ #### Option 2: Git clone
43
+
44
+ For development or to get the latest changes:
45
+
46
+ ```bash
47
+ # Global installation
48
+ mkdir -p ~/.config/opencode/plugin
49
+ cd ~/.config/opencode/plugin
50
+ git clone https://github.com/jgordijn/opencode-remote-config.git
51
+ cd opencode-remote-config
52
+ bun install && bun run build
53
+ ```
54
+
55
+ Or for a project-specific installation:
56
+ ```bash
57
+ mkdir -p .opencode/plugin
58
+ cd .opencode/plugin
59
+ git clone https://github.com/jgordijn/opencode-remote-config.git
60
+ cd opencode-remote-config
61
+ bun install && bun run build
62
+ ```
63
+
64
+ ### Configuration
65
+
66
+ **Create the configuration file** (`~/.config/opencode/remote-config.json` or `.opencode/remote-config.json`):
67
+
68
+ ```jsonc
69
+ {
70
+ "repositories": [
71
+ {
72
+ "url": "git@github.com:company/shared-skills.git",
73
+ "ref": "main",
74
+ "skills": ["code-review", "kotlin-pro"],
75
+ "agents": ["code-reviewer", "specialized/db-expert"],
76
+ "plugins": ["notify", "utils-logger"]
77
+ },
78
+ {
79
+ "url": "git@github.com:team/team-skills.git",
80
+ "ref": "v1.2.0"
81
+ }
82
+ ]
83
+ }
84
+ ```
85
+
86
+ 3. **Restart OpenCode** to load the plugin.
87
+
88
+ ### Configuration
89
+
90
+ The plugin reads its configuration from a separate JSON file (not `opencode.json`):
91
+
92
+ | Location | Description |
93
+ |----------|-------------|
94
+ | `.opencode/remote-config.json` | Project-level config (checked first) |
95
+ | `~/.config/opencode/remote-config.json` | Global config (fallback) |
96
+
97
+ ### Configuration Options
98
+
99
+ | Option | Type | Default | Description |
100
+ |--------|------|---------|-------------|
101
+ | `repositories` | Array | `[]` | List of repositories to sync |
102
+ | `repositories[].url` | String | Required | Git URL, HTTPS URL, or `file://` path |
103
+ | `repositories[].ref` | String | Default branch | Branch, tag, or commit SHA (git only) |
104
+ | `repositories[].skills` | Array or `"*"` | All skills | Specific skills to import |
105
+ | `repositories[].agents` | Array or `"*"` | All agents | Specific agents to import |
106
+ | `repositories[].plugins` | Array or `"*"` | All plugins | Specific plugins to import |
107
+
108
+ ### Local Directories
109
+
110
+ For development or local skill repositories, use `file://` URLs:
111
+
112
+ ```jsonc
113
+ {
114
+ "repositories": [
115
+ {
116
+ "url": "file:///path/to/my/local-skills"
117
+ }
118
+ ]
119
+ }
120
+ ```
121
+
122
+ **Benefits of `file://` URLs:**
123
+ - No cloning or caching - symlinks directly to the source directory
124
+ - Changes are immediately visible (great for development)
125
+ - Works with any local directory containing `skill/`, `agent/`, or `plugin/` folders
126
+
127
+ ### How It Works
128
+
129
+ Skills are cloned to a cache directory and symlinked into the OpenCode skill directory:
130
+
131
+ ```
132
+ ~/.cache/opencode/remote-skills/repos/
133
+ └── github.com-company-shared-skills/
134
+ └── <full git clone>
135
+
136
+ ~/.config/opencode/skill/
137
+ ├── _plugins/ # Plugin-managed (auto-gitignored)
138
+ │ └── shared-skills/
139
+ │ └── code-review -> ~/.cache/.../skill/code-review/
140
+ └── my-local-skill/ # Your own skills (not touched)
141
+ └── SKILL.md
142
+ ```
143
+
144
+ **Key points:**
145
+ - Your local skills in `~/.config/opencode/skill/` are never modified
146
+ - Imported skills go into `_plugins/` subdirectory
147
+ - `_plugins/` is automatically added to `.gitignore`
148
+ - Local skills always take precedence over imported ones with the same name
149
+
150
+ ### Agents
151
+
152
+ Agents are discovered from `agent/` or `agents/` directories in repositories. Each agent is defined in a markdown file with YAML frontmatter:
153
+
154
+ ```markdown
155
+ ---
156
+ description: A specialized code reviewer agent
157
+ mode: subagent
158
+ model: anthropic/claude-3-5-sonnet
159
+ temperature: 0.7
160
+ ---
161
+
162
+ You are an expert code reviewer. Focus on...
163
+ ```
164
+
165
+ Agent names are derived from the file path:
166
+ - `agent/code-reviewer.md` -> `code-reviewer`
167
+ - `agent/specialized/db-expert.md` -> `specialized/db-expert`
168
+
169
+ Agents are injected into OpenCode's config via the `config` hook with this priority:
170
+ 1. **User's local config** - highest priority (defined in `opencode.json`)
171
+ 2. **First repository** - first repo in the config list wins
172
+ 3. **Subsequent repositories** - logged and skipped if name conflicts
173
+
174
+ ### Plugins
175
+
176
+ Plugins are OpenCode hook files (`.ts` or `.js`) discovered from `plugin/` or `plugins/` directories. They are symlinked to `~/.config/opencode/plugin/` using a flat naming convention.
177
+
178
+ **Discovery rules:**
179
+ - Scans `plugin/` directory first; falls back to `plugins/` if `plugin/` doesn't exist
180
+ - Recursively discovers `.ts` and `.js` files (case-insensitive extensions)
181
+ - Skips hidden files/directories (starting with `.`)
182
+ - Maximum depth: 10 levels
183
+ - Maximum file size: 256KB
184
+
185
+ **Plugin requirements:**
186
+ - Files must be **self-contained** (no local imports like `./utils` or `../helpers`)
187
+ - Must export a valid OpenCode plugin hook
188
+ - Must have `.ts` or `.js` extension
189
+
190
+ **Symlink naming:**
191
+ All remote plugins are symlinked with the `_remote_` prefix to distinguish them from local plugins:
192
+ - `plugin/notify.ts` in repo `my-hooks` → `_remote_my-hooks_notify.ts`
193
+ - `plugin/utils/logger.ts` in repo `shared` → `_remote_shared_utils-logger.ts`
194
+
195
+ Nested paths are converted to dashes: `plugin/foo/bar/baz.ts` becomes `foo-bar-baz`.
196
+
197
+ **Name collision handling:** If two repos have plugins that result in the same symlink name, the first repository in your config wins. Subsequent duplicates are logged and skipped.
198
+
199
+ **Why self-contained?** OpenCode loads plugins as individual files. If your plugin imports `./helper.ts`, that file won't be symlinked and the import will fail. Bundle your dependencies or use npm packages instead.
200
+
201
+ **Plugin changes require restart:** Unlike skills, plugins are loaded at OpenCode startup. When plugin changes are detected, you'll see:
202
+ ```
203
+ [remote-skills] Plugin changes detected. Restart OpenCode to apply.
204
+ ```
205
+
206
+ ### Example Output
207
+
208
+ ```
209
+ [remote-skills] Syncing 2 repositories...
210
+ [remote-skills] ✓ company/shared-skills (main) - 5 skills
211
+ [remote-skills] ✓ team/team-skills (v1.2.0) - 3 skills
212
+ [remote-skills] ⚠ Conflict: 'git-commit' exists locally, skipping
213
+ [remote-skills] Discovered 4 remote agents
214
+ [remote-skills] Discovered 2 remote plugins
215
+ [remote-skills] 7 skills, 2 plugins available
216
+ [remote-skills] Injected 4 remote agents into config
217
+ ```
218
+
219
+ ### Authentication
220
+
221
+ The plugin uses your system's Git configuration for authentication:
222
+ - **SSH keys**: Ensure your SSH key is configured for the repository host
223
+ - **HTTPS**: Use credential helpers or tokens configured in Git
224
+
225
+ ### Requirements
226
+
227
+ - OpenCode v1.0.0 or later
228
+ - Bun runtime (used by OpenCode)
229
+ - Git installed and accessible in PATH
230
+
231
+ ---
232
+
233
+ ## For OpenCode (LLM Agents)
234
+
235
+ This section contains instructions for LLM agents helping users set up the opencode-remote-config plugin.
236
+
237
+ ### Installation Steps
238
+
239
+ 1. **Check if the user has OpenCode installed:**
240
+ ```bash
241
+ opencode --version
242
+ ```
243
+
244
+ 2. **Install the plugin via npm:**
245
+
246
+ ```bash
247
+ npm install -g @jgordijn/opencode-remote-config
248
+ ```
249
+
250
+ Then add to OpenCode config (`~/.config/opencode/opencode.json`):
251
+ ```json
252
+ {
253
+ "plugins": ["@jgordijn/opencode-remote-config"]
254
+ }
255
+ ```
256
+
257
+ **Alternative: Git clone installation**
258
+ ```bash
259
+ mkdir -p ~/.config/opencode/plugin
260
+ cd ~/.config/opencode/plugin
261
+ git clone https://github.com/jgordijn/opencode-remote-config.git
262
+ cd opencode-remote-config
263
+ bun install && bun run build
264
+ ```
265
+
266
+ 3. **Create the configuration file:**
267
+
268
+ Create `~/.config/opencode/remote-config.json`:
269
+ ```jsonc
270
+ {
271
+ "repositories": [
272
+ {
273
+ "url": "<git-url-from-user>",
274
+ "ref": "<branch-or-tag-optional>"
275
+ }
276
+ ]
277
+ }
278
+ ```
279
+
280
+ 4. **Verify authentication:**
281
+
282
+ Test that the user can clone the repository:
283
+ ```bash
284
+ git ls-remote <git-url>
285
+ ```
286
+
287
+ If this fails, help them set up SSH keys or HTTPS credentials.
288
+
289
+ 5. **Restart OpenCode:**
290
+
291
+ The plugin will sync on next startup. Instruct the user to restart OpenCode.
292
+
293
+ ### Troubleshooting Guide
294
+
295
+ **Problem: "Failed to clone" error**
296
+ - Check Git authentication (SSH keys, tokens)
297
+ - Verify the URL is correct
298
+ - Ensure the user has access to the repository
299
+
300
+ **Problem: Skills not appearing**
301
+ - Verify the repository has a `skill/` directory with `SKILL.md` files
302
+ - Check if there's a naming conflict with local skills
303
+ - Look for warnings in the startup output
304
+
305
+ **Problem: Updates not reflected**
306
+ - In background mode, restart OpenCode to apply updates
307
+ - Check that the `ref` (branch/tag) is correct
308
+ - Try removing the cached repo: `rm -rf ~/.cache/opencode/remote-skills/repos/<repo-id>`
309
+
310
+ ### Repository Structure Requirements
311
+
312
+ For a repository to provide skills, agents, and/or plugins, use this structure:
313
+
314
+ ```
315
+ <repo-root>/
316
+ ├── skill/ # Skills directory
317
+ │ ├── code-review/
318
+ │ │ └── SKILL.md
319
+ │ └── testing/
320
+ │ └── SKILL.md
321
+ ├── agent/ # Agents directory
322
+ │ ├── code-reviewer.md
323
+ │ └── specialized/
324
+ │ └── db-expert.md
325
+ └── plugin/ # Plugins directory
326
+ ├── notify.ts
327
+ └── utils/
328
+ └── logger.ts
329
+ ```
330
+
331
+ **Skill format** - Each `SKILL.md` must have YAML frontmatter:
332
+ ```yaml
333
+ ---
334
+ name: skill-name
335
+ description: Brief description of what this skill does
336
+ ---
337
+
338
+ # Skill Content
339
+
340
+ Instructions and content for the skill...
341
+ ```
342
+
343
+ **Agent format** - Each agent markdown file has YAML frontmatter:
344
+ ```yaml
345
+ ---
346
+ description: When to use this agent
347
+ mode: subagent # subagent | primary | all
348
+ model: anthropic/claude-3-5-sonnet
349
+ temperature: 0.7
350
+ color: "#FF5733"
351
+ ---
352
+
353
+ You are an expert assistant. Your role is to...
354
+ ```
355
+
356
+ Available agent configuration fields:
357
+ - `description` - When to use this agent (shown in agent list)
358
+ - `mode` - Agent mode: `subagent`, `primary`, or `all`
359
+ - `model` - Model to use (e.g., `anthropic/claude-3-5-sonnet`)
360
+ - `temperature`, `top_p` - Sampling parameters
361
+ - `color` - Hex color code (e.g., `#FF5733`)
362
+ - `steps`, `maxSteps` - Maximum agentic iterations
363
+ - `tools` - Tool enable/disable map (e.g., `{ bash: true, edit: false }`)
364
+ - `permission` - Permission rules for tools
365
+ - `disable` - Disable the agent
366
+
367
+ **Plugin format** - Each plugin file must be a self-contained TypeScript or JavaScript file:
368
+ ```typescript
369
+ // plugin/notify.ts
370
+ import type { Plugin } from "@opencode-ai/plugin"
371
+
372
+ export const NotifyPlugin: Plugin = async (ctx) => {
373
+ return {
374
+ event: async ({ event }) => {
375
+ if (event.type === "session.completed") {
376
+ // Send notification...
377
+ }
378
+ }
379
+ }
380
+ }
381
+
382
+ export default NotifyPlugin
383
+ ```
384
+
385
+ **Important:** Plugins must be self-contained. Do NOT use local imports:
386
+ ```typescript
387
+ // ❌ BAD - local import will fail
388
+ import { helper } from "./utils/helper"
389
+
390
+ // ✅ GOOD - npm package imports work
391
+ import { z } from "zod"
392
+
393
+ // ✅ GOOD - Node.js built-ins work
394
+ import * as fs from "fs"
395
+ ```
396
+
397
+ ### Example Configurations
398
+
399
+ **Single repository, all skills and agents:**
400
+ ```jsonc
401
+ {
402
+ "repositories": [
403
+ { "url": "git@github.com:company/skills.git" }
404
+ ]
405
+ }
406
+ ```
407
+
408
+ **Multiple repositories, selective import:**
409
+ ```jsonc
410
+ {
411
+ "repositories": [
412
+ {
413
+ "url": "git@github.com:company/shared-skills.git",
414
+ "ref": "main",
415
+ "skills": ["code-review", "testing"],
416
+ "agents": ["code-reviewer"]
417
+ },
418
+ {
419
+ "url": "git@github.com:team/team-skills.git",
420
+ "ref": "v2.0.0",
421
+ "agents": "*" // Import all agents from this repo
422
+ }
423
+ ]
424
+ }
425
+ ```
426
+
427
+ **Skills only (no agents):**
428
+ ```jsonc
429
+ {
430
+ "repositories": [
431
+ {
432
+ "url": "git@github.com:company/skills.git",
433
+ "agents": [] // Empty array imports no agents
434
+ }
435
+ ]
436
+ }
437
+ ```
438
+
439
+ **With plugins:**
440
+ ```jsonc
441
+ {
442
+ "repositories": [
443
+ {
444
+ "url": "git@github.com:company/shared-skills.git",
445
+ "skills": "*",
446
+ "agents": ["code-reviewer"],
447
+ "plugins": ["notify", "analytics"]
448
+ }
449
+ ]
450
+ }
451
+ ```
452
+
453
+ ### Uninstalling
454
+
455
+ To cleanly remove imported skills, agents, and plugins:
456
+
457
+ 1. **Remove repositories from config** - Set `repositories` to empty array or remove the file:
458
+ ```jsonc
459
+ {
460
+ "repositories": []
461
+ }
462
+ ```
463
+
464
+ 2. **Restart OpenCode** - This triggers cleanup of stale symlinks
465
+
466
+ 3. **Remove the plugin** (optional):
467
+
468
+ If installed via npm:
469
+ ```bash
470
+ npm uninstall -g @jgordijn/opencode-remote-config
471
+ ```
472
+
473
+ Then remove from `opencode.json`:
474
+ ```json
475
+ {
476
+ "plugins": []
477
+ }
478
+ ```
479
+
480
+ If installed via git clone (global):
481
+ ```bash
482
+ rm -rf ~/.config/opencode/plugin/opencode-remote-config
483
+ ```
484
+
485
+ If installed via git clone (project-local):
486
+ ```bash
487
+ rm -rf .opencode/plugin/opencode-remote-config
488
+ ```
489
+
490
+ **Important:** Always empty the config and restart OpenCode first before removing the plugin. This ensures all symlinks are properly cleaned up.
491
+
492
+ **If you skip this step,** orphaned symlinks may remain:
493
+ - Skills: `~/.config/opencode/skill/_plugins/<repo-name>/`
494
+ - Plugins: `~/.config/opencode/plugin/_remote_*`
495
+
496
+ To manually clean up orphaned symlinks:
497
+ ```bash
498
+ # Remove skill symlinks
499
+ rm -rf ~/.config/opencode/skill/_plugins
500
+
501
+ # Remove remote plugin symlinks
502
+ rm ~/.config/opencode/plugin/_remote_*
503
+ ```
504
+
505
+ ---
506
+
507
+ ## Development
508
+
509
+ ### Building
510
+
511
+ ```bash
512
+ bun install
513
+ bun run build
514
+ ```
515
+
516
+ ### Testing
517
+
518
+ ```bash
519
+ bun test
520
+ ```
521
+
522
+ ### Local Development
523
+
524
+ The plugin is loaded from the `plugin/` directory:
525
+
526
+ ```bash
527
+ # Build and the plugin will be available in ~/.config/opencode/plugin/opencode-remote-config/
528
+ bun run build
529
+ ```
530
+
531
+ ---
532
+
533
+ ## License
534
+
535
+ MIT