opencode-froggy 0.1.0 → 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/LICENSE +21 -0
- package/README.md +508 -246
- package/agent/architect.md +91 -0
- package/agent/partner.md +143 -0
- package/agent/rubber-duck.md +129 -0
- package/command/commit-push.md +21 -0
- package/command/doc-changes.md +45 -0
- package/command/review-changes.md +1 -21
- package/command/review-pr.md +1 -22
- package/command/send-to.md +21 -0
- package/command/simplify-changes.md +2 -20
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -52
- package/dist/index.test.js +29 -8
- package/dist/loaders.d.ts +9 -5
- package/dist/loaders.js +5 -1
- package/dist/tools/blockchain/eth-address-balance.d.ts +20 -0
- package/dist/tools/blockchain/eth-address-balance.js +37 -0
- package/dist/tools/blockchain/eth-address-txs.d.ts +23 -0
- package/dist/tools/blockchain/eth-address-txs.js +41 -0
- package/dist/tools/blockchain/eth-token-transfers.d.ts +23 -0
- package/dist/tools/blockchain/eth-token-transfers.js +41 -0
- package/dist/tools/blockchain/eth-transaction.d.ts +20 -0
- package/dist/tools/blockchain/eth-transaction.js +40 -0
- package/dist/tools/blockchain/etherscan-client.d.ts +25 -0
- package/dist/tools/blockchain/etherscan-client.js +156 -0
- package/dist/tools/blockchain/etherscan-client.test.d.ts +1 -0
- package/dist/tools/blockchain/etherscan-client.test.js +211 -0
- package/dist/tools/blockchain/formatters.d.ts +10 -0
- package/dist/tools/blockchain/formatters.js +147 -0
- package/dist/tools/blockchain/index.d.ts +10 -0
- package/dist/tools/blockchain/index.js +10 -0
- package/dist/tools/blockchain/tools.test.d.ts +1 -0
- package/dist/tools/blockchain/tools.test.js +208 -0
- package/dist/tools/blockchain/types.d.ts +90 -0
- package/dist/tools/blockchain/types.js +8 -0
- package/dist/tools/diff-summary.d.ts +20 -0
- package/dist/tools/diff-summary.js +111 -0
- package/dist/tools/gitingest.d.ts +26 -0
- package/dist/tools/gitingest.js +41 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/list-child-sessions.d.ts +9 -0
- package/dist/tools/list-child-sessions.js +24 -0
- package/dist/tools/prompt-session.d.ts +19 -0
- package/dist/tools/prompt-session.js +39 -0
- package/dist/tools/reply-child.d.ts +19 -0
- package/dist/tools/reply-child.js +42 -0
- package/images/logo.png +0 -0
- package/package.json +4 -2
- package/command/commit.md +0 -18
package/README.md
CHANGED
|
@@ -1,51 +1,391 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="images/logo.png" alt="opencode-froggy logo" width="300">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/smartfrog/opencode-froggy/actions"><img src="https://github.com/smartfrog/opencode-froggy/workflows/CI/badge.svg" alt="CI"></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/opencode-froggy"><img src="https://badge.fury.io/js/opencode-froggy.svg" alt="npm version"></a>
|
|
8
|
+
</p>
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
It can automatically simplify changes when the session becomes idle, if files were modified
|
|
7
|
-
via `write` or `edit`. Resources are loaded automatically from `agent/`, `command/`, and `skill/`.
|
|
8
|
-
Hooks are loaded from OpenCode configuration directories (global and project-level).
|
|
10
|
+
Plugin providing Claude Code–style hooks, specialized agents (doc-writer, code reviewer, architect, partner, etc.), dedicated commands such as simplify-code and review-pr, and tools such as gitingest.
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
---
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [Commands](#commands)
|
|
18
|
+
- [Agents](#agents)
|
|
19
|
+
- [Tools](#tools)
|
|
20
|
+
- [gitingest](#gitingest)
|
|
21
|
+
- [diff-summary](#diff-summary)
|
|
22
|
+
- [prompt-session](#prompt-session)
|
|
23
|
+
- [list-child-sessions](#list-child-sessions)
|
|
24
|
+
- [Blockchain](#blockchain)
|
|
25
|
+
- [eth-transaction](#eth-transaction)
|
|
26
|
+
- [eth-address-balance](#eth-address-balance)
|
|
27
|
+
- [eth-address-txs](#eth-address-txs)
|
|
28
|
+
- [eth-token-transfers](#eth-token-transfers)
|
|
29
|
+
- [Hooks](#hooks)
|
|
30
|
+
- [Configuration Locations](#configuration-locations)
|
|
31
|
+
- [Configuration File Format](#configuration-file-format)
|
|
32
|
+
- [Supported Events](#supported-events)
|
|
33
|
+
- [Conditions](#conditions)
|
|
34
|
+
- [Supported Actions](#supported-actions)
|
|
35
|
+
- [Execution Behavior](#execution-behavior)
|
|
36
|
+
- [Example Hook Configurations](#example-hook-configurations)
|
|
37
|
+
- [Configuration Options](#configuration-options)
|
|
38
|
+
- [License](#license)
|
|
13
39
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### From npm (recommended)
|
|
45
|
+
|
|
46
|
+
Add the plugin to your OpenCode configuration file (`opencode.json`):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"$schema": "https://opencode.ai/config.json",
|
|
51
|
+
"plugin": ["opencode-froggy"]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
19
54
|
|
|
20
|
-
###
|
|
55
|
+
### From local files
|
|
56
|
+
|
|
57
|
+
Alternatively, clone or copy the plugin files to one of these directories:
|
|
58
|
+
|
|
59
|
+
- **Project-local**: `.opencode/plugin/opencode-froggy/`
|
|
60
|
+
- **Global**: `~/.config/opencode/plugin/opencode-froggy/`
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
21
65
|
|
|
22
66
|
| Command | Description | Agent |
|
|
23
67
|
|---------|-------------|-------|
|
|
24
|
-
| `/commit` |
|
|
68
|
+
| `/commit-push` | Stage, commit, and push changes with user confirmation | `build` |
|
|
69
|
+
| `/doc-changes` | Update documentation based on uncommitted changes (new features only) | `doc-writer` |
|
|
25
70
|
| `/review-changes` | Review uncommitted changes (staged + unstaged, including untracked files) | `code-reviewer` |
|
|
26
71
|
| `/review-pr <source> <target>` | Review changes from source branch into target branch | `code-reviewer` |
|
|
72
|
+
| `/send-to [agent] <message>` | Send a message to a child session (subagent) to continue the conversation | - |
|
|
27
73
|
| `/simplify-changes` | Simplify uncommitted changes (staged + unstaged, including untracked files) | `code-simplifier` |
|
|
28
74
|
| `/tests-coverage` | Run the full test suite with coverage report and suggest fixes for failures | `build` |
|
|
29
75
|
|
|
30
|
-
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Agents
|
|
79
|
+
|
|
80
|
+
| Agent | Mode | Description |
|
|
81
|
+
|-------|------|-------------|
|
|
82
|
+
| `architect` | subagent | Strategic technical advisor providing high-leverage guidance on architecture, code structure, and complex engineering trade-offs. Read-only. |
|
|
83
|
+
| `code-reviewer` | subagent | Reviews code for quality, correctness, and security. Read-only with restricted git access. |
|
|
84
|
+
| `code-simplifier` | subagent | Simplifies recently modified code for clarity and maintainability while strictly preserving behavior. |
|
|
85
|
+
| `doc-writer` | subagent | Technical writer that crafts clear, comprehensive documentation (README, API docs, architecture docs, user guides). |
|
|
86
|
+
| `partner` | subagent | Strategic ideation partner that breaks frames, expands solution spaces, and surfaces non-obvious strategic options. Read-only. |
|
|
87
|
+
| `rubber-duck` | subagent | Strategic thinking partner for exploratory dialogue. Challenges assumptions, asks pointed questions, and sharpens thinking through conversational friction. Read-only. |
|
|
88
|
+
|
|
89
|
+
---
|
|
31
90
|
|
|
32
|
-
|
|
91
|
+
## Tools
|
|
33
92
|
|
|
34
|
-
|
|
93
|
+
### gitingest
|
|
35
94
|
|
|
95
|
+
Fetch a GitHub repository's full content via gitingest.com. Returns summary, directory tree, and file contents optimized for LLM analysis. Use when you need to understand an external repository's structure or code.
|
|
96
|
+
|
|
97
|
+
#### Parameters
|
|
98
|
+
|
|
99
|
+
| Parameter | Type | Required | Default | Description |
|
|
100
|
+
|-----------|------|----------|---------|-------------|
|
|
101
|
+
| `url` | `string` | Yes | - | The GitHub repository URL to fetch |
|
|
102
|
+
| `maxFileSize` | `number` | No | `50000` | Maximum file size in bytes to include |
|
|
103
|
+
| `pattern` | `string` | No | `""` | Glob pattern to filter files (e.g., `*.ts`, `src/**/*.py`) |
|
|
104
|
+
| `patternType` | `"include"` \| `"exclude"` | No | `"exclude"` | Whether to include or exclude files matching the pattern |
|
|
105
|
+
|
|
106
|
+
#### Usage Examples
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Fetch entire repository
|
|
110
|
+
gitingest({ url: "https://github.com/user/repo" })
|
|
111
|
+
|
|
112
|
+
// Only TypeScript files
|
|
113
|
+
gitingest({
|
|
114
|
+
url: "https://github.com/user/repo",
|
|
115
|
+
pattern: "*.ts",
|
|
116
|
+
patternType: "include"
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Exclude test files
|
|
120
|
+
gitingest({
|
|
121
|
+
url: "https://github.com/user/repo",
|
|
122
|
+
pattern: "*.test.ts",
|
|
123
|
+
patternType: "exclude"
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// Increase max file size to 100KB
|
|
127
|
+
gitingest({
|
|
128
|
+
url: "https://github.com/user/repo",
|
|
129
|
+
maxFileSize: 100000
|
|
130
|
+
})
|
|
36
131
|
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
132
|
+
|
|
133
|
+
#### Limitations
|
|
134
|
+
|
|
135
|
+
- Content is truncated to 300k characters (server-side limit from gitingest.com)
|
|
136
|
+
- For large repositories, use pattern filtering to focus on relevant files
|
|
137
|
+
- The `maxFileSize` parameter controls individual file size, not total output size
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### diff-summary
|
|
142
|
+
|
|
143
|
+
Generate a structured summary of git diffs. Use for reviewing branch comparisons or working tree changes. Returns stats, commits, files changed, and full diff in a structured markdown format.
|
|
144
|
+
|
|
145
|
+
#### Parameters
|
|
146
|
+
|
|
147
|
+
| Parameter | Type | Required | Default | Description |
|
|
148
|
+
|-----------|------|----------|---------|-------------|
|
|
149
|
+
| `source` | `string` | No | - | Source branch to compare (e.g., `feature-branch`). If omitted, analyzes working tree changes. |
|
|
150
|
+
| `target` | `string` | No | `main` | Target branch to compare against |
|
|
151
|
+
| `remote` | `string` | No | `origin` | Git remote name |
|
|
152
|
+
|
|
153
|
+
#### Usage Examples
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Analyze working tree changes (staged, unstaged, and untracked files)
|
|
157
|
+
diffSummary({})
|
|
158
|
+
|
|
159
|
+
// Compare feature branch against main
|
|
160
|
+
diffSummary({ source: "feature-branch" })
|
|
161
|
+
|
|
162
|
+
// Compare feature branch against develop
|
|
163
|
+
diffSummary({
|
|
164
|
+
source: "feature-branch",
|
|
165
|
+
target: "develop"
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
// Compare branches on a different remote
|
|
169
|
+
diffSummary({
|
|
170
|
+
source: "feature-branch",
|
|
171
|
+
target: "main",
|
|
172
|
+
remote: "upstream"
|
|
173
|
+
})
|
|
40
174
|
```
|
|
41
175
|
|
|
42
|
-
|
|
176
|
+
#### Output Structure
|
|
177
|
+
|
|
178
|
+
**For branch comparisons:**
|
|
179
|
+
- Stats Overview: Summary of changes (insertions, deletions)
|
|
180
|
+
- Commits to Review: List of commits in the range
|
|
181
|
+
- Files Changed: List of modified files
|
|
182
|
+
- Full Diff: Complete diff with context
|
|
183
|
+
|
|
184
|
+
**For working tree changes:**
|
|
185
|
+
- Status Overview: Git status output
|
|
186
|
+
- Staged Changes: Stats, files, and diff for staged changes
|
|
187
|
+
- Unstaged Changes: Stats, files, and diff for unstaged changes
|
|
188
|
+
- Untracked Files: List and diffs for new untracked files
|
|
189
|
+
|
|
190
|
+
#### Notes
|
|
191
|
+
|
|
192
|
+
- When comparing branches, the tool fetches from the remote before generating the diff
|
|
193
|
+
- Diffs include 5 lines of context and function context for better readability
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### prompt-session
|
|
198
|
+
|
|
199
|
+
Send a message to a child session (subagent) to continue the conversation. Useful for iterating with subagents without creating new sessions.
|
|
200
|
+
|
|
201
|
+
#### Parameters
|
|
202
|
+
|
|
203
|
+
| Parameter | Type | Required | Default | Description |
|
|
204
|
+
|-----------|------|----------|---------|-------------|
|
|
205
|
+
| `message` | `string` | Yes | - | The message to send to the child session |
|
|
206
|
+
| `sessionId` | `string` | No | - | The child session ID to target. If omitted, targets the last child session. |
|
|
43
207
|
|
|
44
|
-
|
|
208
|
+
#### Usage Examples
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// Send a message to the last child session
|
|
212
|
+
promptSession({ message: "Please also add unit tests for the new function" })
|
|
213
|
+
|
|
214
|
+
// Send a message to a specific child session
|
|
215
|
+
promptSession({
|
|
216
|
+
message: "Can you clarify the error handling approach?",
|
|
217
|
+
sessionId: "abc123"
|
|
218
|
+
})
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Behavior
|
|
222
|
+
|
|
223
|
+
- If `sessionId` is not provided, the tool automatically targets the most recently created child session
|
|
224
|
+
- Returns the text response from the child session
|
|
225
|
+
- Returns an error message if no child session exists for the current session
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### list-child-sessions
|
|
230
|
+
|
|
231
|
+
List all child sessions (subagents) of the current session. Useful for finding specific sessions to target with `prompt-session`.
|
|
232
|
+
|
|
233
|
+
#### Parameters
|
|
234
|
+
|
|
235
|
+
This tool takes no parameters.
|
|
236
|
+
|
|
237
|
+
#### Usage Examples
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// List all child sessions
|
|
241
|
+
listChildSessions()
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Output
|
|
245
|
+
|
|
246
|
+
Returns a formatted list of child sessions with:
|
|
247
|
+
- Session ID
|
|
248
|
+
- Session title
|
|
249
|
+
- Created and updated timestamps
|
|
250
|
+
|
|
251
|
+
Example output:
|
|
252
|
+
```
|
|
253
|
+
Child sessions (2):
|
|
254
|
+
|
|
255
|
+
1. [abc123] Code Review Session
|
|
256
|
+
Created: 2024-01-15T10:30:00Z | Updated: 2024-01-15T10:35:00Z
|
|
257
|
+
|
|
258
|
+
2. [def456] Architecture Discussion
|
|
259
|
+
Created: 2024-01-15T11:00:00Z | Updated: 2024-01-15T11:15:00Z
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### Blockchain
|
|
265
|
+
|
|
266
|
+
Tools for querying Ethereum and EVM-compatible blockchains via Etherscan APIs.
|
|
267
|
+
|
|
268
|
+
All blockchain tools support multiple chains via the `chainId` parameter:
|
|
269
|
+
|
|
270
|
+
| Chain ID | Network |
|
|
271
|
+
|----------|---------|
|
|
272
|
+
| `1` | Ethereum (default) |
|
|
273
|
+
| `137` | Polygon |
|
|
274
|
+
| `56` | BSC |
|
|
275
|
+
| `42161` | Arbitrum |
|
|
276
|
+
| `10` | Optimism |
|
|
277
|
+
| `8453` | Base |
|
|
278
|
+
| `43114` | Avalanche |
|
|
279
|
+
| `250` | Fantom |
|
|
280
|
+
| `324` | zkSync |
|
|
281
|
+
|
|
282
|
+
#### eth-transaction
|
|
283
|
+
|
|
284
|
+
Get Ethereum transaction details by transaction hash. Returns status, block, addresses, gas costs, and log count.
|
|
285
|
+
|
|
286
|
+
##### Parameters
|
|
287
|
+
|
|
288
|
+
| Parameter | Type | Required | Default | Description |
|
|
289
|
+
|-----------|------|----------|---------|-------------|
|
|
290
|
+
| `hash` | `string` | Yes | - | Transaction hash (0x...) |
|
|
291
|
+
| `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
|
|
292
|
+
|
|
293
|
+
##### Usage Examples
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// Get transaction on Ethereum mainnet
|
|
297
|
+
ethTransaction({ hash: "0x123abc..." })
|
|
298
|
+
|
|
299
|
+
// Get transaction on Polygon
|
|
300
|
+
ethTransaction({
|
|
301
|
+
hash: "0x123abc...",
|
|
302
|
+
chainId: "137"
|
|
303
|
+
})
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### eth-address-balance
|
|
307
|
+
|
|
308
|
+
Get the ETH balance of an Ethereum address. Returns balance in both ETH and Wei.
|
|
309
|
+
|
|
310
|
+
##### Parameters
|
|
311
|
+
|
|
312
|
+
| Parameter | Type | Required | Default | Description |
|
|
313
|
+
|-----------|------|----------|---------|-------------|
|
|
314
|
+
| `address` | `string` | Yes | - | Ethereum address (0x...) |
|
|
315
|
+
| `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
|
|
316
|
+
|
|
317
|
+
##### Usage Examples
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// Get balance on Ethereum mainnet
|
|
321
|
+
ethAddressBalance({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
|
|
322
|
+
|
|
323
|
+
// Get balance on Arbitrum
|
|
324
|
+
ethAddressBalance({
|
|
325
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
326
|
+
chainId: "42161"
|
|
327
|
+
})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### eth-address-txs
|
|
331
|
+
|
|
332
|
+
List Ethereum transactions for an address. Shows incoming and outgoing transactions with values, timestamps, and status.
|
|
333
|
+
|
|
334
|
+
##### Parameters
|
|
335
|
+
|
|
336
|
+
| Parameter | Type | Required | Default | Description |
|
|
337
|
+
|-----------|------|----------|---------|-------------|
|
|
338
|
+
| `address` | `string` | Yes | - | Ethereum address (0x...) |
|
|
339
|
+
| `limit` | `number` | No | `20` | Maximum number of transactions to return |
|
|
340
|
+
| `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
|
|
341
|
+
|
|
342
|
+
##### Usage Examples
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// List recent transactions on Ethereum mainnet
|
|
346
|
+
ethAddressTxs({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
|
|
347
|
+
|
|
348
|
+
// List last 50 transactions on Base
|
|
349
|
+
ethAddressTxs({
|
|
350
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
351
|
+
limit: 50,
|
|
352
|
+
chainId: "8453"
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### eth-token-transfers
|
|
357
|
+
|
|
358
|
+
List ERC-20 token transfers for an Ethereum address. Shows token names, symbols, values, and transaction details.
|
|
359
|
+
|
|
360
|
+
##### Parameters
|
|
361
|
+
|
|
362
|
+
| Parameter | Type | Required | Default | Description |
|
|
363
|
+
|-----------|------|----------|---------|-------------|
|
|
364
|
+
| `address` | `string` | Yes | - | Ethereum address (0x...) |
|
|
365
|
+
| `limit` | `number` | No | `20` | Maximum number of transfers to return |
|
|
366
|
+
| `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
|
|
367
|
+
|
|
368
|
+
##### Usage Examples
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// List recent token transfers on Ethereum mainnet
|
|
372
|
+
ethTokenTransfers({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
|
|
373
|
+
|
|
374
|
+
// List last 100 token transfers on Optimism
|
|
375
|
+
ethTokenTransfers({
|
|
376
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
377
|
+
limit: 100,
|
|
378
|
+
chainId: "10"
|
|
379
|
+
})
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Hooks
|
|
45
385
|
|
|
46
386
|
Hooks run actions on session events. Configuration is loaded from standard OpenCode configuration directories.
|
|
47
387
|
|
|
48
|
-
|
|
388
|
+
### Configuration Locations
|
|
49
389
|
|
|
50
390
|
Hooks are loaded from these locations (in order, merged together):
|
|
51
391
|
|
|
@@ -59,11 +399,11 @@ On Windows, `~/.config` is preferred for cross-platform consistency. If hooks ex
|
|
|
59
399
|
|
|
60
400
|
Global hooks run first, then project hooks are added. Hooks from both sources are combined (not overridden).
|
|
61
401
|
|
|
62
|
-
|
|
402
|
+
### Configuration File Format
|
|
63
403
|
|
|
64
|
-
- YAML frontmatter must include a `hooks` list
|
|
65
|
-
- Each hook defines `event`, `actions`, and optional `conditions
|
|
66
|
-
- Hooks for the same event run in declaration order
|
|
404
|
+
- YAML frontmatter must include a `hooks` list
|
|
405
|
+
- Each hook defines `event`, `actions`, and optional `conditions`
|
|
406
|
+
- Hooks for the same event run in declaration order
|
|
67
407
|
|
|
68
408
|
Example `hooks.md`:
|
|
69
409
|
|
|
@@ -77,7 +417,7 @@ hooks:
|
|
|
77
417
|
---
|
|
78
418
|
```
|
|
79
419
|
|
|
80
|
-
|
|
420
|
+
### Supported Events
|
|
81
421
|
|
|
82
422
|
| Event | Description |
|
|
83
423
|
|-------|-------------|
|
|
@@ -89,17 +429,19 @@ hooks:
|
|
|
89
429
|
| `tool.after.*` | Emitted after any tool executes |
|
|
90
430
|
| `tool.after.<name>` | Emitted after a specific tool (e.g., `tool.after.edit`) |
|
|
91
431
|
|
|
92
|
-
|
|
432
|
+
#### Tool Hook Execution Order
|
|
433
|
+
|
|
93
434
|
1. `tool.before.*` (all tools)
|
|
94
435
|
2. `tool.before.<name>` (specific tool)
|
|
95
436
|
3. *(tool executes)*
|
|
96
437
|
4. `tool.after.*` (all tools)
|
|
97
438
|
5. `tool.after.<name>` (specific tool)
|
|
98
439
|
|
|
99
|
-
|
|
440
|
+
#### Blocking Tools with Exit Code 2
|
|
441
|
+
|
|
100
442
|
For `tool.before.*` and `tool.before.<name>` hooks, a bash action returning exit code 2 will block the tool from executing. The stderr output is displayed to the user as the block reason.
|
|
101
443
|
|
|
102
|
-
|
|
444
|
+
### Conditions
|
|
103
445
|
|
|
104
446
|
| Condition | Description |
|
|
105
447
|
|-----------|-------------|
|
|
@@ -108,115 +450,126 @@ For `tool.before.*` and `tool.before.<name>` hooks, a bash action returning exit
|
|
|
108
450
|
|
|
109
451
|
All listed conditions must pass for the hook to run.
|
|
110
452
|
|
|
111
|
-
Code extensions treated as "code"
|
|
453
|
+
**Code extensions treated as "code":**
|
|
454
|
+
|
|
112
455
|
`ts`, `tsx`, `js`, `jsx`, `mjs`, `cjs`, `json`, `yml`, `yaml`, `toml`, `css`, `scss`, `sass`, `less`, `html`, `vue`, `svelte`, `go`, `rs`, `c`, `h`, `cpp`, `cc`, `cxx`, `hpp`, `java`, `py`, `rb`, `php`, `sh`, `bash`, `kt`, `kts`, `swift`, `m`, `mm`, `cs`, `fs`, `scala`, `clj`, `hs`, `lua`.
|
|
113
456
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
457
|
+
### Supported Actions
|
|
458
|
+
|
|
459
|
+
#### Command Action
|
|
460
|
+
|
|
461
|
+
Execute a plugin command.
|
|
462
|
+
|
|
463
|
+
```yaml
|
|
464
|
+
# Short form
|
|
465
|
+
- command: simplify-changes
|
|
466
|
+
|
|
467
|
+
# With arguments
|
|
468
|
+
- command:
|
|
469
|
+
name: review-pr
|
|
470
|
+
args: "main feature"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
If the command exists in config, the plugin reuses its `agent` and `model`.
|
|
474
|
+
|
|
475
|
+
#### Tool Action
|
|
476
|
+
|
|
477
|
+
Prompt the session to use a tool with specific arguments.
|
|
478
|
+
|
|
479
|
+
```yaml
|
|
480
|
+
- tool:
|
|
481
|
+
name: bash
|
|
482
|
+
args: { command: "echo done" }
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
#### Bash Action
|
|
486
|
+
|
|
487
|
+
Execute a shell command directly without involving the LLM. Useful for running linters, formatters, build scripts, or custom automation.
|
|
488
|
+
|
|
489
|
+
**Configuration:**
|
|
490
|
+
|
|
491
|
+
```yaml
|
|
492
|
+
# Short form
|
|
493
|
+
- bash: "npm run lint"
|
|
494
|
+
|
|
495
|
+
# Long form with custom timeout
|
|
496
|
+
- bash:
|
|
497
|
+
command: "$OPENCODE_PROJECT_DIR/.opencode/hooks/init.sh"
|
|
498
|
+
timeout: 30000 # milliseconds (default: 60000)
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Environment Variables:**
|
|
502
|
+
|
|
503
|
+
The plugin injects these variables into the child process environment:
|
|
504
|
+
|
|
505
|
+
| Variable | Value | Use case |
|
|
506
|
+
|----------|-------|----------|
|
|
507
|
+
| `OPENCODE_PROJECT_DIR` | Absolute path to the project (e.g., `/home/user/project`) | Reference project files from scripts located elsewhere |
|
|
508
|
+
| `OPENCODE_SESSION_ID` | The OpenCode session identifier | Logging, tracing, or conditioning actions based on session |
|
|
509
|
+
|
|
510
|
+
**Stdin JSON Context:**
|
|
511
|
+
|
|
512
|
+
The command receives a JSON object via stdin with session context:
|
|
513
|
+
|
|
514
|
+
```json
|
|
515
|
+
{
|
|
516
|
+
"session_id": "abc123",
|
|
517
|
+
"event": "session.idle",
|
|
518
|
+
"cwd": "/path/to/project",
|
|
519
|
+
"files": ["src/index.ts", "src/utils.ts"]
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
The `files` array is only present for `session.idle` events and contains paths modified via `write` or `edit`.
|
|
524
|
+
|
|
525
|
+
For tool hooks (`tool.before.*`, `tool.after.*`), additional fields are provided:
|
|
526
|
+
|
|
527
|
+
```json
|
|
528
|
+
{
|
|
529
|
+
"session_id": "abc123",
|
|
530
|
+
"event": "tool.before.write",
|
|
531
|
+
"cwd": "/path/to/project",
|
|
532
|
+
"tool_name": "write",
|
|
533
|
+
"tool_args": { "filePath": "src/index.ts", "content": "..." }
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Environment Variables vs Stdin JSON:**
|
|
538
|
+
|
|
539
|
+
- **Environment variables**: Direct access via `$VAR`, convenient for simple values like paths and IDs
|
|
540
|
+
- **Stdin JSON**: Contains richer context (event type, working directory, modified files), requires parsing with `jq` or similar
|
|
541
|
+
|
|
542
|
+
Both mechanisms are complementary. Use environment variables for quick access to project path and session ID; use stdin JSON when you need event details or the list of modified files.
|
|
543
|
+
|
|
544
|
+
**Exit Codes:**
|
|
545
|
+
|
|
546
|
+
| Code | Behavior |
|
|
547
|
+
|------|----------|
|
|
548
|
+
| `0` | Success, continue to next action |
|
|
549
|
+
| `2` | Blocking error, stop remaining actions in this hook |
|
|
550
|
+
| Other | Non-blocking error, log warning and continue |
|
|
551
|
+
|
|
552
|
+
**Result Feedback:**
|
|
553
|
+
|
|
554
|
+
Bash hook results are automatically sent back to your session:
|
|
555
|
+
|
|
556
|
+
```
|
|
557
|
+
[BASH HOOK ✓] npm run lint
|
|
558
|
+
Exit: 0 | Duration: 1234ms
|
|
559
|
+
Stdout: All files passed linting
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
The feedback includes a status icon (✓ success, ✗ failure), exit code, execution duration, and stdout/stderr output (truncated to 500 characters). This message appears in your session but does not trigger a response from the assistant.
|
|
563
|
+
|
|
564
|
+
### Execution Behavior
|
|
565
|
+
|
|
566
|
+
- Action errors are logged and do not stop later actions
|
|
567
|
+
- `session.idle` only fires if files were modified via `write` or `edit`; the session's modified file list is cleared after the hook runs
|
|
568
|
+
- The main session is set on `session.created` with no parent, or on the first `session.idle` if needed
|
|
569
|
+
|
|
570
|
+
### Example Hook Configurations
|
|
571
|
+
|
|
572
|
+
#### Basic Multi-Hook Setup
|
|
220
573
|
|
|
221
574
|
```markdown
|
|
222
575
|
---
|
|
@@ -238,9 +591,8 @@ hooks:
|
|
|
238
591
|
---
|
|
239
592
|
```
|
|
240
593
|
|
|
241
|
-
####
|
|
594
|
+
#### Simple Lint-on-Idle Hook
|
|
242
595
|
|
|
243
|
-
**Simple lint-on-idle hook:**
|
|
244
596
|
```yaml
|
|
245
597
|
hooks:
|
|
246
598
|
- event: session.idle
|
|
@@ -249,7 +601,10 @@ hooks:
|
|
|
249
601
|
- bash: "npm run lint --fix"
|
|
250
602
|
```
|
|
251
603
|
|
|
252
|
-
|
|
604
|
+
#### Custom Initialization Script
|
|
605
|
+
|
|
606
|
+
`.opencode/hooks/init.sh`:
|
|
607
|
+
|
|
253
608
|
```bash
|
|
254
609
|
#!/bin/bash
|
|
255
610
|
set -e
|
|
@@ -269,7 +624,8 @@ echo "Project: $OPENCODE_PROJECT_DIR"
|
|
|
269
624
|
exit 0
|
|
270
625
|
```
|
|
271
626
|
|
|
272
|
-
|
|
627
|
+
#### Conditional Blocking Based on Lint Errors
|
|
628
|
+
|
|
273
629
|
```bash
|
|
274
630
|
#!/bin/bash
|
|
275
631
|
# Run linter and block if critical errors found
|
|
@@ -281,9 +637,8 @@ else
|
|
|
281
637
|
fi
|
|
282
638
|
```
|
|
283
639
|
|
|
284
|
-
####
|
|
640
|
+
#### Block Modifications to Sensitive Files
|
|
285
641
|
|
|
286
|
-
**Block modifications to sensitive files:**
|
|
287
642
|
```yaml
|
|
288
643
|
hooks:
|
|
289
644
|
- event: tool.before.write
|
|
@@ -305,7 +660,8 @@ hooks:
|
|
|
305
660
|
fi
|
|
306
661
|
```
|
|
307
662
|
|
|
308
|
-
|
|
663
|
+
#### Auto-Format TypeScript Files After Write
|
|
664
|
+
|
|
309
665
|
```yaml
|
|
310
666
|
hooks:
|
|
311
667
|
- event: tool.after.write
|
|
@@ -317,7 +673,8 @@ hooks:
|
|
|
317
673
|
fi
|
|
318
674
|
```
|
|
319
675
|
|
|
320
|
-
|
|
676
|
+
#### Log All Tool Executions
|
|
677
|
+
|
|
321
678
|
```yaml
|
|
322
679
|
hooks:
|
|
323
680
|
- event: tool.before.*
|
|
@@ -328,112 +685,17 @@ hooks:
|
|
|
328
685
|
echo "[$(date)] Tool: $tool" >> /tmp/opencode-tools.log
|
|
329
686
|
```
|
|
330
687
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
Add the plugin to your OpenCode configuration file at `~/.config/opencode/opencode.json`:
|
|
334
|
-
|
|
335
|
-
```json
|
|
336
|
-
{
|
|
337
|
-
"plugin": {
|
|
338
|
-
"froggy": {
|
|
339
|
-
"path": "/path/to/opencode-froggy"
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
Or if published to npm:
|
|
346
|
-
|
|
347
|
-
```json
|
|
348
|
-
{
|
|
349
|
-
"plugin": {
|
|
350
|
-
"froggy": {
|
|
351
|
-
"module": "opencode-froggy"
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
## Usage
|
|
358
|
-
|
|
359
|
-
### Review uncommitted changes
|
|
360
|
-
|
|
361
|
-
```
|
|
362
|
-
/review-changes
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
Reviews all staged, unstaged, and untracked changes in the working tree.
|
|
366
|
-
|
|
367
|
-
### Review a pull request
|
|
368
|
-
|
|
369
|
-
```
|
|
370
|
-
/review-pr feature-branch main
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
Fetches and reviews changes from `origin/feature-branch` into `origin/main`.
|
|
374
|
-
|
|
375
|
-
### Simplify uncommitted changes
|
|
376
|
-
|
|
377
|
-
```
|
|
378
|
-
/simplify-changes
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
Analyzes and simplifies all uncommitted changes while preserving behavior.
|
|
382
|
-
|
|
383
|
-
### Commit and push
|
|
384
|
-
|
|
385
|
-
```
|
|
386
|
-
/commit
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
Creates a branch (if on main/master), commits with an appropriate message, and pushes.
|
|
390
|
-
|
|
391
|
-
### Run tests with coverage
|
|
392
|
-
|
|
393
|
-
```
|
|
394
|
-
/tests-coverage
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
Runs the test suite with coverage and suggests fixes for failures.
|
|
688
|
+
---
|
|
398
689
|
|
|
399
690
|
## Configuration Options
|
|
400
691
|
|
|
401
|
-
The plugin does not require additional configuration. Agents, commands, and skills are loaded automatically from the `agent/`, `command/`, and `skill/` directories within the plugin. Hooks are loaded from the standard OpenCode configuration directories (see Hooks section
|
|
692
|
+
The plugin does not require additional configuration. Agents, commands, and skills are loaded automatically from the `agent/`, `command/`, and `skill/` directories within the plugin. Hooks are loaded from the standard OpenCode configuration directories (see [Hooks](#hooks) section).
|
|
402
693
|
|
|
403
694
|
### Supported Code File Extensions
|
|
404
695
|
|
|
405
|
-
The `hasCodeChange` condition checks file extensions against the default set listed in the
|
|
406
|
-
|
|
407
|
-
## Development
|
|
408
|
-
|
|
409
|
-
### Prerequisites
|
|
410
|
-
|
|
411
|
-
- Node.js 18+
|
|
412
|
-
- npm
|
|
413
|
-
|
|
414
|
-
### Setup
|
|
696
|
+
The `hasCodeChange` condition checks file extensions against the default set listed in the [Conditions](#conditions) section. Hooks without any conditions still trigger on any modified file paths tracked via `write` or `edit` in the current session.
|
|
415
697
|
|
|
416
|
-
|
|
417
|
-
npm install
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Build
|
|
421
|
-
|
|
422
|
-
```bash
|
|
423
|
-
npm run build
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Run tests
|
|
427
|
-
|
|
428
|
-
```bash
|
|
429
|
-
npm test
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
### Type checking
|
|
433
|
-
|
|
434
|
-
```bash
|
|
435
|
-
npm run typecheck
|
|
436
|
-
```
|
|
698
|
+
---
|
|
437
699
|
|
|
438
700
|
## License
|
|
439
701
|
|