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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +508 -246
  3. package/agent/architect.md +91 -0
  4. package/agent/partner.md +143 -0
  5. package/agent/rubber-duck.md +129 -0
  6. package/command/commit-push.md +21 -0
  7. package/command/doc-changes.md +45 -0
  8. package/command/review-changes.md +1 -21
  9. package/command/review-pr.md +1 -22
  10. package/command/send-to.md +21 -0
  11. package/command/simplify-changes.md +2 -20
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +27 -52
  14. package/dist/index.test.js +29 -8
  15. package/dist/loaders.d.ts +9 -5
  16. package/dist/loaders.js +5 -1
  17. package/dist/tools/blockchain/eth-address-balance.d.ts +20 -0
  18. package/dist/tools/blockchain/eth-address-balance.js +37 -0
  19. package/dist/tools/blockchain/eth-address-txs.d.ts +23 -0
  20. package/dist/tools/blockchain/eth-address-txs.js +41 -0
  21. package/dist/tools/blockchain/eth-token-transfers.d.ts +23 -0
  22. package/dist/tools/blockchain/eth-token-transfers.js +41 -0
  23. package/dist/tools/blockchain/eth-transaction.d.ts +20 -0
  24. package/dist/tools/blockchain/eth-transaction.js +40 -0
  25. package/dist/tools/blockchain/etherscan-client.d.ts +25 -0
  26. package/dist/tools/blockchain/etherscan-client.js +156 -0
  27. package/dist/tools/blockchain/etherscan-client.test.d.ts +1 -0
  28. package/dist/tools/blockchain/etherscan-client.test.js +211 -0
  29. package/dist/tools/blockchain/formatters.d.ts +10 -0
  30. package/dist/tools/blockchain/formatters.js +147 -0
  31. package/dist/tools/blockchain/index.d.ts +10 -0
  32. package/dist/tools/blockchain/index.js +10 -0
  33. package/dist/tools/blockchain/tools.test.d.ts +1 -0
  34. package/dist/tools/blockchain/tools.test.js +208 -0
  35. package/dist/tools/blockchain/types.d.ts +90 -0
  36. package/dist/tools/blockchain/types.js +8 -0
  37. package/dist/tools/diff-summary.d.ts +20 -0
  38. package/dist/tools/diff-summary.js +111 -0
  39. package/dist/tools/gitingest.d.ts +26 -0
  40. package/dist/tools/gitingest.js +41 -0
  41. package/dist/tools/index.d.ts +5 -0
  42. package/dist/tools/index.js +5 -0
  43. package/dist/tools/list-child-sessions.d.ts +9 -0
  44. package/dist/tools/list-child-sessions.js +24 -0
  45. package/dist/tools/prompt-session.d.ts +19 -0
  46. package/dist/tools/prompt-session.js +39 -0
  47. package/dist/tools/reply-child.d.ts +19 -0
  48. package/dist/tools/reply-child.js +42 -0
  49. package/images/logo.png +0 -0
  50. package/package.json +4 -2
  51. package/command/commit.md +0 -18
package/README.md CHANGED
@@ -1,51 +1,391 @@
1
- # opencode-froggy
1
+ <p align="center">
2
+ <img src="images/logo.png" alt="opencode-froggy logo" width="300">
3
+ </p>
2
4
 
3
- ## Overview
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
- opencode-froggy is an OpenCode plugin that adds agents, commands, skills, and a hook system.
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
- ## Features
12
+ ---
11
13
 
12
- ### Agents
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
- | Agent | Mode | Description |
15
- |-------|------|-------------|
16
- | `code-reviewer` | subagent | Reviews code for quality, correctness, and security. Read-only with restricted git access. |
17
- | `code-simplifier` | subagent | Simplifies recently modified code for clarity and maintainability while strictly preserving behavior. |
18
- | `doc-writer` | subagent | Technical writer that crafts clear, comprehensive documentation (README, API docs, architecture docs, user guides). |
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
- ### Commands
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` | Create a commit with appropriate message, create branch if on main/master, and push | `build` |
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
- ### Skills
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
- The plugin supports skills loaded from `skill/<name>/SKILL.md` within the plugin directory. No skills are included by default. The plugin exposes a `skill` tool that lists available skills and returns their instructions.
91
+ ## Tools
33
92
 
34
- To add your own skills, create a directory structure like:
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
- skill/
38
- my-skill/
39
- SKILL.md
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
- The `SKILL.md` file supports YAML frontmatter with `name` and `description` fields. The name defaults to the directory name if not specified.
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
- ### Hooks
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
- #### Configuration locations
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
- #### Configuration file
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
- #### Supported events
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
- **Tool hook execution order:**
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
- **Blocking tools with exit code 2:**
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
- #### Conditions
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" by default:
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
- #### Supported actions
115
-
116
- - **Command**
117
- - Short form: `command: simplify-changes`
118
- - With args:
119
- - `command:`
120
- - `name: review-pr`
121
- - `args: "main feature"`
122
- - If the command exists in config, the plugin reuses its `agent` and `model`.
123
- - **Skill**
124
- - `skill: my-skill`
125
- - The name must match a loaded skill. The plugin prompts the session to call the `skill` tool for that skill.
126
- - **Tool**
127
- - `tool:`
128
- - `name: bash`
129
- - `args: { command: "echo done" }`
130
- - The plugin prompts the session to use the tool with these arguments.
131
- - **Bash**
132
- Executes a shell command directly without involving the LLM. Useful for running linters, formatters, build scripts, or custom automation.
133
-
134
- **Configuration:**
135
- ```yaml
136
- # Short form
137
- - bash: "npm run lint"
138
-
139
- # Long form with custom timeout
140
- - bash:
141
- command: "$OPENCODE_PROJECT_DIR/.opencode/hooks/init.sh"
142
- timeout: 30000 # milliseconds (default: 60000)
143
- ```
144
-
145
- **Environment variables:**
146
-
147
- The plugin injects these variables into the child process environment before executing the command:
148
-
149
- | Variable | Value | Use case |
150
- |----------|-------|----------|
151
- | `OPENCODE_PROJECT_DIR` | Absolute path to the project (e.g., `/home/user/project`) | Reference project files from scripts located elsewhere |
152
- | `OPENCODE_SESSION_ID` | The OpenCode session identifier | Logging, tracing, or conditioning actions based on session |
153
-
154
- Example usage in a script:
155
- ```bash
156
- #!/bin/bash
157
- # Access variables directly
158
- echo "Project: $OPENCODE_PROJECT_DIR"
159
- echo "Session: $OPENCODE_SESSION_ID"
160
-
161
- # Access a project file
162
- cat "$OPENCODE_PROJECT_DIR/package.json"
163
-
164
- # Log with session ID
165
- echo "[$OPENCODE_SESSION_ID] Hook executed" >> /tmp/opencode.log
166
- ```
167
-
168
- **Stdin JSON context:**
169
- The command receives a JSON object via stdin with session context:
170
- ```json
171
- {
172
- "session_id": "abc123",
173
- "event": "session.idle",
174
- "cwd": "/path/to/project",
175
- "files": ["src/index.ts", "src/utils.ts"]
176
- }
177
- ```
178
- The `files` array is only present for `session.idle` events and contains paths modified via `write` or `edit`.
179
-
180
- For tool hooks (`tool.before.*`, `tool.after.*`), additional fields are provided:
181
- ```json
182
- {
183
- "session_id": "abc123",
184
- "event": "tool.before.write",
185
- "cwd": "/path/to/project",
186
- "tool_name": "write",
187
- "tool_args": { "filePath": "src/index.ts", "content": "..." }
188
- }
189
- ```
190
-
191
- **Environment variables vs stdin JSON:**
192
- - **Environment variables**: Direct access via `$VAR`, convenient for simple values like paths and IDs
193
- - **Stdin JSON**: Contains richer context (event type, working directory, modified files), requires parsing with `jq` or similar
194
-
195
- 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.
196
-
197
- **Exit codes:**
198
- | Code | Behavior |
199
- |------|----------|
200
- | `0` | Success, continue to next action |
201
- | `2` | Blocking error, stop remaining actions in this hook |
202
- | Other | Non-blocking error, log warning and continue |
203
-
204
- **Result feedback:**
205
- Bash hook results are automatically sent back to your session, so you can see what happened:
206
- ```
207
- [BASH HOOK ✓] npm run lint
208
- Exit: 0 | Duration: 1234ms
209
- Stdout: All files passed linting
210
- ```
211
- 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.
212
-
213
- #### Execution behavior
214
-
215
- - Action errors are logged and do not stop later actions.
216
- - `session.idle` only fires if files were modified via `write` or `edit`; the session's modified file list is cleared after the hook runs.
217
- - The main session is set on `session.created` with no parent, or on the first `session.idle` if needed.
218
-
219
- Example with multiple hooks:
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
- #### Example bash hook scripts
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
- **Custom initialization script (`.opencode/hooks/init.sh`):**
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
- **Conditional blocking based on lint errors:**
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
- #### Example tool hooks
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
- **Auto-format TypeScript files after write:**
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
- **Log all tool executions:**
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
- ## Installation
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 above).
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 Hooks section. Hooks without any conditions still trigger on any modified file paths tracked via `write` or `edit` in the current session.
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
- ```bash
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