@capybearista/opencode-agents-loader 1.0.0 → 2.0.1

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 CHANGED
@@ -1,32 +1,103 @@
1
- # @capybearista/opencode-agents-loader
1
+ # opencode-agents-loader
2
2
 
3
- An [OpenCode](https://opencode.ai) plugin that extends command and agent discovery to `~/.agents/` and `.agents/` directories.
3
+ <p align="center">Extend V2 agent and command discovery to the .agents/ directory standard</p>
4
+ <p align="center">
5
+ <a href="https://www.npmjs.com/package/@capybearista/opencode-agents-loader"><img alt="npm version" src="https://img.shields.io/npm/v/@capybearista/opencode-agents-loader?style=flat-square&color=8d60e6" /></a>
6
+ <a href="https://www.npmjs.com/package/@capybearista/opencode-agents-loader"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@capybearista/opencode-agents-loader?style=flat-square&color=6067e6" /></a>
7
+ <a href="https://opencode.ai"><img alt="opencode" src="https://img.shields.io/badge/OpenCode-Plugin-orange?style=flat-square&color=60a5e6" /></a>
8
+ <a href="https://opensource.org/licenses/MPL-2.0"><img alt="license" src="https://img.shields.io/badge/License-MPL--2.0-blue.svg?style=flat-square&color=60dfe6" /></a>
9
+ </p>
10
+
11
+ ---
4
12
 
5
13
  ## Why?
6
14
 
7
- While OpenCode natively uses `.opencode/` for its configuration, the `.agents/` directory is becoming an open standard for agent-based tools. This plugin's primary intention is to support this convention, enabling better interoperability between OpenCode and other harnesses, especially if...
8
- - you want to commit project-specific agent capabilities for other contributors to make use of
9
- - you yourself use other harnesses (that aren't named "Claude Code", though you could symlink `.agents/<commands|agents>/` and `.claude/<commands|agents>/`)
15
+ > The `.agents/` directory is becoming an open standard for agent-based tools. This plugin lets OpenCode read **commands** and **agents** from `~/.agents/` and `.agents/` directories, enabling interoperability with other harnesses and cleaner project organization.
16
+
17
+ ## Philosophy: Extending OpenCode
18
+
19
+ OpenCode is designed to be highly extensible. This plugin expands the "Agents" standard.
20
+
21
+ ### Architecture
22
+
23
+ ```text
24
+ src/index.ts
25
+ └── starts the command and agent bridges
26
+
27
+ command-bridge.ts
28
+ ├── links .agents/ command and agent files into native .opencode/ directories
29
+ ├── records link ownership in manifests and locks
30
+ └── watches the sources for changes
31
+
32
+ agent-source.ts
33
+ └── validates agent frontmatter before an agent link is created
34
+ ```
35
+
36
+ OpenCode natively reads from `.opencode/` and configuration files. This plugin links `.agents/`
37
+ command and agent files into the matching native directories with managed relative symlinks, so
38
+ OpenCode discovers and runs them as if they lived in `.opencode/`. It only extends discovery:
39
+ source files are never copied or rewritten, and native files and explicit config entries always
40
+ win.
41
+
42
+ ## Features
10
43
 
11
- It is also useful if you want to keep your OpenCode config separate from your custom commands and agents, or if you want to share agents across multiple projects via a global `~/.agents/` directory.
44
+ - **Discovery**: finds command and agent markdown files in `~/.agents/` and `.agents/` directories.
45
+ - **Managed symlinks**: materializes relative symlinks so native OpenCode owns parsing and execution.
46
+ - **Native precedence**: respects existing native files and explicit config entries — plugin entries never overwrite native config.
47
+ - **Automatic startup**: starts both native bridges automatically; no manual sync step is required.
48
+ - **Byte preservation**: preserves complete command and agent source bytes and nested relative names by symlink, including shell and subagent templates.
49
+ - **Global destination**: uses `OPENCODE_CONFIG_DIR` for the global native destination; global sources remain in `~/.agents/`.
12
50
 
13
- ## Installation
51
+ ## Install
14
52
 
15
- Add the plugin to your `opencode.json`:
53
+ ### OpenCode V2
54
+
55
+ Add it under the `"plugins"` key in `opencode.json(c)`:
56
+
57
+ ```json
58
+ {
59
+ "plugins": ["@capybearista/opencode-agents-loader@latest"]
60
+ }
61
+ ```
62
+
63
+ Server entry only, so `cli.json` needs no entry.
64
+
65
+ ### OpenCode V1
66
+
67
+ Add it under the `"plugin"` key in `opencode.json(c)`:
16
68
 
17
69
  ```json
18
70
  {
19
- "plugin": ["@capybearista/opencode-agents-loader"]
71
+ "plugin": ["@capybearista/opencode-agents-loader@1.0.0"]
20
72
  }
21
73
  ```
22
74
 
23
- ## Directory Layout
75
+ Server entry only, so `tui.json(c)` needs no entry.
76
+
77
+ See the [V1 plugin guide](../../docs/v1-plugins.md) for details.
78
+
79
+ ### Uninstall
80
+
81
+ Remove the plugin from `"plugin(s)"` from the respective config files they were added to.
82
+
83
+ ## Usage
84
+
85
+ Create markdown files with YAML frontmatter:
86
+
87
+ ```md
88
+ ---
89
+ description: "Does something useful"
90
+ ---
91
+
92
+ # Command Body
93
+ This is the command content that the agent will process.
94
+ ```
24
95
 
25
96
  ### Commands
26
97
 
27
98
  Place command markdown files in `command/` or `commands/` subdirectories:
28
99
 
29
- ```
100
+ ```text
30
101
  ~/.agents/
31
102
  commands/
32
103
  hello.md
@@ -42,7 +113,7 @@ Place command markdown files in `command/` or `commands/` subdirectories:
42
113
 
43
114
  Place agent markdown files in `agent/` or `agents/` subdirectories:
44
115
 
45
- ```
116
+ ```text
46
117
  ~/.agents/
47
118
  agents/
48
119
  reviewer.md
@@ -53,28 +124,81 @@ Place agent markdown files in `agent/` or `agents/` subdirectories:
53
124
  project-expert.md
54
125
  ```
55
126
 
56
- ## File Format
127
+ Only `agent/` and `agents/` are plugin source directories. `mode/` and `modes/` remain native
128
+ OpenCode aliases and are not treated as new plugin agent sources; a native mode with the same name
129
+ still reserves that name. A source agent's declared `mode` is preserved, including `subagent`; the
130
+ bridge never infers or forces `primary`.
131
+
132
+ ### How it works
133
+
134
+ Setup links `.agents/` files into the matching native `.opencode/` directories with managed
135
+ relative symlinks: each project scope maps into its own scope, and global `~/.agents/` maps into
136
+ the global native root. Native OpenCode owns parsing, precedence, and execution; source files are
137
+ never copied or rewritten, and destination directories must support symlink creation (there is no
138
+ copy fallback). Native files and explicit config entries always win over bridged links; where
139
+ singular and plural source spellings both exist, the plural (`commands/`, `agents/`) wins, and
140
+ nested names stay nested. Sources with invalid metadata are skipped with a diagnostic rather than
141
+ linked. Links reconcile automatically as sources change; if an update does not appear, restart
142
+ OpenCode. Command execution itself is not emulated — `$ARGUMENTS`, shell blocks, and `subagent`
143
+ behavior stay native. See [Development Notes](#development-notes) for the bridge internals.
144
+
145
+ ## Configuration
146
+
147
+ There are no plugin-specific settings. After registering the plugin in the V2 server profile, it
148
+ reads the documented `.agents/` directories automatically. Keep the V2 profile separate from any
149
+ V1 configuration as described in [Install](#install).
150
+
151
+ ## Troubleshooting
152
+
153
+ - If commands or agents don't appear, verify your files end in `.md` and include valid YAML frontmatter
154
+ - Confirm the directory naming is `commands/` or `command/`, `agents/` or `agent/`
155
+ - Inspect the scoped `.agents-loader/{commands,agents}-manifest.json` and diagnostics before removing
156
+ anything; unowned native files are intentionally preserved
157
+ - If synchronization stops after a crash, inspect `.agents-loader/agents.lock` and
158
+ `.agents-loader/commands.lock`. The bridge deliberately fails closed on held locks,
159
+ including abandoned ones. Stop **all** OpenCode processes using that config directory
160
+ before moving lock files aside for recovery; never remove a lock while a process might
161
+ be reconciling. Preserve the manifests, then restart OpenCode.
162
+ - An active plugin does not guarantee every scope reconciled. Unsafe scopes emit
163
+ diagnostic errors; when safe reconciliation resumes, the bridge reports that pending
164
+ cleanup may remain. This message does not mean all stale links have been removed.
165
+
166
+ ## Development Notes
167
+
168
+ ### Bridge internals
169
+
170
+ Each destination parent keeps version-1 ownership metadata under `.agents-loader/`
171
+ (`commands-manifest.json` + `commands.lock` for commands, `agents-manifest.json` + `agents.lock`
172
+ for agents; project-local under `.opencode/.agents-loader/`, global under
173
+ `$OPENCODE_CONFIG_DIR/.agents-loader/`). Only exact recorded symlinks are ever removed; anything
174
+ else fails closed with a diagnostic. Writes are atomic behind a bounded per-domain lock — never
175
+ delete a stale lock while OpenCode instances are running.
176
+
177
+ Each bridge polls every 500 ms for source edits, creations, deletions, renames, and
178
+ native-name reservation changes, emitting a reload signal once per observed change. A reload
179
+ signal is not a native rescan: changes may need an OpenCode rescan or a restart, and no
180
+ universal hot-reload guarantee is made.
57
181
 
58
- Both commands and agents use markdown files with YAML frontmatter. Find the specifics at the official OpenCode docs:
59
- - Commands: https://opencode.ai/docs/commands/#markdown
60
- - Agents: https://opencode.ai/docs/agents/#markdown
61
182
 
62
- ## Precedence
183
+ The package checks include the real local-directory resolver regression, build/static checks, and
184
+ the scoped bridge tests. In one isolated OpenCode setup, human verification confirmed agent and
185
+ command discovery and native execution, global/project precedence fixtures, live additions,
186
+ restart-required description changes, and removal cleanup. These observations do not promise
187
+ identical watcher behavior for every OpenCode version, platform, provider, or config layout.
63
188
 
64
- Existing config entries from `.opencode/` directories always take precedence over `.agents/` entries. The plugin only injects entries that **do not already exist**.
189
+ ## Contributing
65
190
 
66
- Within `.agents/` directories, the closest directory to your project wins. The precedence order (highest to lowest):
191
+ This package lives in the `opencode-plugins` monorepo.
67
192
 
68
- 1. `.opencode/` directory (project-local)
69
- 2. `.agents/` directory (closest to project root)
70
- 3. `.agents/` parent directories (walking up the tree)
71
- 4. `~/.config/opencode/` directory (global)
72
- 5. `~/.agents/` directory (global)
193
+ See the [contribution guidelines](../../CONTRIBUTING.md) before opening a pull request.
73
194
 
74
- ## Requirements
195
+ - From the monorepo root, run `bun run build` before artifact checks, then `bun run typecheck`,`bun run lint`, and the canonical `bun run test` Turbo pipeline. Do not use bare root `bun test` as the workspace check.
196
+ - For a focused run, `bun test` is supported from this package directory; its tests include the real local-directory resolver regression.
197
+ - `bun run check` writes Biome changes; use it only when formatting changes are intended.
198
+ - Prefer small, direct changes.
75
199
 
76
- - OpenCode >= 1.14.25
200
+ Please open an issue or check for existing ones before creating a pull request.
77
201
 
78
202
  ## License
79
203
 
80
- MPL-2.0
204
+ [MPL-2.0](./LICENSE.txt)
@@ -0,0 +1,28 @@
1
+ import type { Agent as AgentSchema } from "@opencode/plugin";
2
+ export interface MarkdownEntry {
3
+ readonly data: Record<string, unknown>;
4
+ readonly content: string;
5
+ }
6
+ type AgentModel = NonNullable<AgentSchema.Info["model"]>;
7
+ type AgentPermission = AgentSchema.Info["permissions"][number];
8
+ export interface AgentPatch {
9
+ readonly system: string;
10
+ readonly model?: AgentModel;
11
+ readonly request?: {
12
+ readonly headers?: Record<string, string>;
13
+ readonly body?: Record<string, unknown>;
14
+ };
15
+ readonly description?: string;
16
+ readonly mode?: AgentSchema.Info["mode"];
17
+ readonly hidden?: boolean;
18
+ readonly color?: NonNullable<AgentSchema.Info["color"]>;
19
+ readonly steps?: NonNullable<AgentSchema.Info["steps"]>;
20
+ readonly disabled?: boolean;
21
+ readonly permissions: AgentPermission[];
22
+ }
23
+ export declare function fallbackSanitization(content: string): string;
24
+ export declare function parseMarkdown(filePath: string): Promise<MarkdownEntry>;
25
+ export declare function parseMarkdownContent(template: string, source: string): MarkdownEntry;
26
+ export declare function validateAgentContent(source: string, content: Buffer, home?: string): string | undefined;
27
+ export declare function convertAgent(_name: string, entry: MarkdownEntry, home?: string): AgentPatch | undefined;
28
+ export {};