opencode-command-hooks 0.1.7 → 0.1.8
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 +31 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 🪝 OpenCode Command Hooks
|
|
1
|
+
# 🪝 OpenCode Command Hooks 🪝
|
|
2
2
|
|
|
3
3
|
Use simple configs to declaratively define shell command hooks on tool/subagent invocations. With a single line of configuration, you can inject a hook's output directly into context for your agent to read.
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ Use simple configs to declaratively define shell command hooks on tool/subagent
|
|
|
6
6
|
|
|
7
7
|
Define hooks in just a couple lines of markdown frontmatter. Putting them here is also really nice because you can see your entire agent's config in one place.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```yaml
|
|
10
10
|
---
|
|
11
11
|
description: Analyzes the codebase and implements code changes.
|
|
12
12
|
mode: subagent
|
|
@@ -15,7 +15,8 @@ hooks:
|
|
|
15
15
|
- run: "npm run test"
|
|
16
16
|
inject: "Test Output:\n{stdout}\n{stderr}"
|
|
17
17
|
---
|
|
18
|
-
|
|
18
|
+
```
|
|
19
|
+
**This plugin was not built by the OpenCode team nor is it affiliated with them.**
|
|
19
20
|
|
|
20
21
|
## Table of Contents
|
|
21
22
|
|
|
@@ -34,11 +35,11 @@ hooks:
|
|
|
34
35
|
|
|
35
36
|
## Why?
|
|
36
37
|
|
|
37
|
-
When working with a fleet of subagents, automatic validation of the state of your codebase is really useful. By setting up quality gates (lint/typecheck/test/etc.) or other automation, you can catch and prevent errors quickly and reliably.
|
|
38
|
+
When working with a fleet of subagents, automatic validation of the state of your codebase is really useful. By setting up quality gates (lint/typecheck/test/etc.) or other automation, you can catch and prevent errors quickly and reliably.
|
|
38
39
|
|
|
39
|
-
Doing this by asking your orchestrator agent to use the bash tool (or call a validator subagent) is non-deterministic and can cost a lot of tokens over time. You could always write your own custom plugin to achieve this automatic validation behavior, but I found myself writing the same boilerplate, error handling, output capture, and session injection logic over and over again.
|
|
40
|
+
Doing this by asking your orchestrator agent to use the bash tool (or call a validator subagent) is non-deterministic and can cost a lot of tokens over time. You could always write your own custom plugin to achieve this automatic validation behavior, but I found myself writing the same boilerplate, error handling, output capture, and session injection logic over and over again.
|
|
40
41
|
|
|
41
|
-
Though this plugin is mostly a wrapper around accessing hooks that
|
|
42
|
+
Though this plugin is mostly a wrapper around accessing hooks that OpenCode already exposes, it provides basic plumbing that reduces overhead, giving you a simple, opinionated system for integrating command hooks into your OpenCode workflow. I also just like having hooks/config for my agents all colocated in one place (markdown files) and thought that maybe somebody else would like this too.
|
|
42
43
|
|
|
43
44
|
---
|
|
44
45
|
|
|
@@ -136,14 +137,12 @@ You can set up tool hooks to only trigger on specific arguments via `when.toolAr
|
|
|
136
137
|
"when": {
|
|
137
138
|
"phase": "after",
|
|
138
139
|
"tool": "playwright_browser_navigate",
|
|
139
|
-
"toolArgs": { "url": "http://localhost:3000]" }
|
|
140
|
+
"toolArgs": { "url": "http://localhost:3000]" },
|
|
140
141
|
},
|
|
141
|
-
"run": [
|
|
142
|
-
"osascript -e 'display notification \"Agent triggered playwright\"'"
|
|
143
|
-
],
|
|
142
|
+
"run": ["osascript -e 'display notification \"Agent triggered playwright\"'"],
|
|
144
143
|
"toast": {
|
|
145
|
-
"message": "Agent used the playwright {tool} tool"
|
|
146
|
-
}
|
|
144
|
+
"message": "Agent used the playwright {tool} tool",
|
|
145
|
+
},
|
|
147
146
|
}
|
|
148
147
|
```
|
|
149
148
|
|
|
@@ -166,7 +165,7 @@ Add to your `opencode.json`:
|
|
|
166
165
|
|
|
167
166
|
```jsonc
|
|
168
167
|
{
|
|
169
|
-
"plugin": ["opencode-command-hooks"]
|
|
168
|
+
"plugin": ["opencode-command-hooks"],
|
|
170
169
|
}
|
|
171
170
|
```
|
|
172
171
|
|
|
@@ -192,11 +191,11 @@ Create `.opencode/command-hooks.jsonc` in your project (the plugin searches upwa
|
|
|
192
191
|
|
|
193
192
|
#### JSON Config Options
|
|
194
193
|
|
|
195
|
-
| Option
|
|
196
|
-
|
|
|
197
|
-
| `truncationLimit` | `number`
|
|
198
|
-
| `tool`
|
|
199
|
-
| `session`
|
|
194
|
+
| Option | Type | Description |
|
|
195
|
+
| ----------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
196
|
+
| `truncationLimit` | `number` | Maximum characters to capture from command output. Defaults to 30,000 (matching OpenCode's bash tool). Must be a positive integer. |
|
|
197
|
+
| `tool` | `ToolHook[]` | Array of tool execution hooks |
|
|
198
|
+
| `session` | `SessionHook[]` | Array of session lifecycle hooks |
|
|
200
199
|
|
|
201
200
|
### Markdown Frontmatter
|
|
202
201
|
|
|
@@ -349,8 +348,10 @@ All inject/toast string templates support these placeholders:
|
|
|
349
348
|
---
|
|
350
349
|
|
|
351
350
|
## Why Use This Plugin?
|
|
351
|
+
|
|
352
352
|
**It lets you easily set up bash hooks with ~3-5 lines of YAML which are cleanly colocated with your subagent configuration.**
|
|
353
353
|
Conversely, rolling your own looks something like this (for each project and set of hooks you want to set up):
|
|
354
|
+
|
|
354
355
|
```ts
|
|
355
356
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
356
357
|
|
|
@@ -377,22 +378,26 @@ export const MyHooks: Plugin = async ({ $, client }) => {
|
|
|
377
378
|
try {
|
|
378
379
|
// Run commands sequentially, even if they fail
|
|
379
380
|
let lastResult = { exitCode: 0, stdout: "", stderr: "" };
|
|
380
|
-
|
|
381
|
+
|
|
381
382
|
for (const cmd of ["npm run typecheck", "npm run lint"]) {
|
|
382
383
|
try {
|
|
383
384
|
const result = await $`sh -c ${cmd}`.nothrow().quiet();
|
|
384
385
|
const stdout = result.stdout?.toString() || "";
|
|
385
386
|
const stderr = result.stderr?.toString() || "";
|
|
386
|
-
|
|
387
|
+
|
|
387
388
|
// Truncate to 30k chars to match OpenCode's bash tool
|
|
388
389
|
lastResult = {
|
|
389
390
|
exitCode: result.exitCode ?? 0,
|
|
390
|
-
stdout:
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
391
|
+
stdout:
|
|
392
|
+
stdout.length > 30000
|
|
393
|
+
? stdout.slice(0, 30000) +
|
|
394
|
+
"\n[Output truncated: exceeded 30000 character limit]"
|
|
395
|
+
: stdout,
|
|
396
|
+
stderr:
|
|
397
|
+
stderr.length > 30000
|
|
398
|
+
? stderr.slice(0, 30000) +
|
|
399
|
+
"\n[Output truncated: exceeded 30000 character limit]"
|
|
400
|
+
: stderr,
|
|
396
401
|
};
|
|
397
402
|
} catch (err) {
|
|
398
403
|
lastResult = { exitCode: 1, stdout: "", stderr: String(err) };
|
package/package.json
CHANGED