opencode-ultra 0.4.0 → 0.5.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/README.md CHANGED
@@ -1,30 +1,52 @@
1
1
  # opencode-ultra
2
2
 
3
- [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) をベースにした OpenCode 1.2.x プラグイン。
4
- マルチエージェントオーケストレーション・キーワード駆動モード切替・ルール注入を軽量な単一プラグインで実現する。
5
-
6
- ## oh-my-opencode との違い
7
-
8
- | | oh-my-opencode | opencode-ultra |
9
- |---|---|---|
10
- | 構成 | フルスタック (LSP, AST-Grep, MCP, Hook 25+, Ralph Loop, Comment Checker...) | **オーケストレーション特化** — 同等機能を軽量に再実装 |
11
- | エージェント表 | ハードコード | **設定から動的生成** — `oh-my-opencode.json` のオーバーライドが Sisyphus のプロンプトに自動反映 |
12
- | プラン承認 | なし (即実行) | **Plan-First Protocol** — spawn_agent 前に Phase 形式のプランを提示、ユーザー承認を待つ |
13
- | 並列制御 | バックグラウンドタスク API | **Semaphore ベース** — グローバル/プロバイダー/モデル単位で同時実行制限 |
14
- | Categories | ハードコード | **設定可能** カテゴリでモデル/バリアントを一括切替 |
15
- | Ralph Loop | 外部ツール依存 | **ビルトインツール** — `<promise>DONE</promise>` マーカーで完了検知 |
16
- | Comment Checker | 外部バイナリ (AST-Grep) | **正規表現ベース** — AIスロップパターン検知 |
17
- | Todo Enforcer | `tool.execute.after` 方式 | **`session.idle` イベント方式** セッション idle 時に未完了 TODO を検査 |
18
- | MCP | Exa, Context7, grep_app | **Context7 のみ** (API キー不要で動作、キーありでレートリミット緩和) |
19
- | 依存 | 多数 (Exa, tmux...) | **最小限** (`@opencode-ai/plugin`, `jsonc-parser`, `zod`) |
20
- | 設定形式 | JSON | **JSONC** (コメント・末尾カンマ対応) |
3
+ [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) をベースに、micode / opencode-skillful の良い部分を取り込んだ OpenCode 1.2.x プラグイン。
4
+ マルチエージェントオーケストレーション・キーワード駆動モード切替・ルール注入・セッション継続・AST検索を軽量な単一プラグインで実現する。
5
+
6
+ ## 機能一覧
7
+
8
+ ### ツール (7)
9
+
10
+ | ツール | 説明 |
11
+ |--------|------|
12
+ | `spawn_agent` | 並列エージェント実行 (ConcurrencyPool 制御付き) |
13
+ | `ralph_loop` | 自律ループ実行 (`<promise>DONE</promise>` で完了検知) |
14
+ | `cancel_ralph` | 実行中の Ralph Loop をキャンセル |
15
+ | `batch_read` | 複数ファイル並列読み込み (最大20) |
16
+ | `ledger_save` | Continuity Ledger の保存 (.opencode/ledgers/) |
17
+ | `ledger_load` | Continuity Ledger の読み込み (名前指定 or 最新) |
18
+ | `ast_search` | AST-aware コード検索 (ast-grep/sg バイナリ使用、未インストール時は自動スキップ) |
19
+
20
+ ### フック (9)
21
+
22
+ | フック | hook ポイント | 説明 |
23
+ |--------|-------------|------|
24
+ | `keyword-detector` | chat.message | ultrawork/search/analyze/think キーワード検知 |
25
+ | `rules-injector` | system.transform | .opencode/rules.md を system prompt に注入 |
26
+ | `context-injector` | system.transform | ARCHITECTURE.md / CODE_STYLE.md を自動注入 |
27
+ | `fragment-injector` | system.transform | エージェント毎のカスタムプロンプト断片注入 |
28
+ | `prompt-renderer` | system.transform | モデル別 system prompt フォーマット最適化 (markdown/xml/json) |
29
+ | `comment-checker` | tool.execute.after | Write/Edit 後の AI スロップコメント検知 |
30
+ | `token-truncation` | tool.execute.after | 30000文字超のツール出力を先頭40%+末尾40%に圧縮 |
31
+ | `todo-enforcer` | event (session.idle) | 未完了 TODO を検知して強制継続 |
32
+ | `session-compaction` | experimental.session.compacting | セッション圧縮時に structured summary 生成 |
33
+
34
+ ### その他
35
+
36
+ | 機能 | 説明 |
37
+ |------|------|
38
+ | **Built-in Agent Demotion** | OpenCode 標準エージェント (build/plan/triage/docs) を subagent に降格 |
39
+ | **MCP 自動登録** | Context7 を自動登録 (API キー任意) |
40
+ | **Plan-First Protocol** | spawn_agent 前に Phase 形式のプランを提示、ユーザー承認を待つ |
41
+ | **Categories** | spawn_agent の category パラメータでモデル/バリアントを一括切替 |
42
+ | **Concurrency Pool** | Semaphore ベースの global/provider/model 三層並列制御 |
21
43
 
22
44
  ## アーキテクチャ
23
45
 
24
46
  ```
25
47
  User
26
48
 
27
- │ "ultrawork" / "ulw" キーワード
49
+ │ "ultrawork" / "ulw" / "think hard" キーワード
28
50
 
29
51
 
30
52
  ┌──────────────────────────────────────────────┐
@@ -32,27 +54,37 @@ User
32
54
  │ │
33
55
  │ chat.message hook │
34
56
  │ ├─ keyword-detector │
35
- │ │ └─ ultrawork / search / analyze
57
+ │ │ └─ ultrawork / search / analyze / think
36
58
  │ └─ ultrawork → variant: "max" │
37
59
  │ │
38
60
  │ system.transform hook │
39
61
  │ ├─ keyword message injection │
40
- └─ rules-injector (.opencode/rules.md) │
62
+ ├─ rules-injector (.opencode/rules.md) │
63
+ │ ├─ context-injector (ARCHITECTURE/CODE_STYLE)│
64
+ │ ├─ fragment-injector (per-agent fragments) │
65
+ │ └─ prompt-renderer (markdown/xml/json) │
41
66
  │ │
42
67
  │ tool.execute.after hook │
43
- └─ comment-checker (Write/Edit 後に検査) │
68
+ ├─ comment-checker (Write/Edit 後に検査) │
69
+ │ └─ token-truncation (30000文字超を圧縮) │
70
+ │ │
71
+ │ session.compacting hook │
72
+ │ └─ session-compaction (structured summary) │
44
73
  │ │
45
74
  │ event hook │
46
75
  │ ├─ session cleanup │
47
76
  │ └─ todo-enforcer (session.idle 時に検査) │
48
77
  │ │
49
78
  │ config hook │
50
- └─ register agents to OpenCode │
79
+ ├─ register agents to OpenCode │
80
+ │ └─ demote built-in agents to subagent │
51
81
  │ │
52
82
  │ tools │
53
83
  │ ├─ spawn_agent (並列実行 + 並列制御) │
54
- │ ├─ ralph_loop (自律ループ実行)
55
- └─ cancel_ralph (ループキャンセル)
84
+ │ ├─ ralph_loop / cancel_ralph
85
+ ├─ batch_read (複数ファイル並列読み込み)
86
+ │ ├─ ledger_save / ledger_load (文脈継続) │
87
+ │ └─ ast_search (構文木検索, optional) │
56
88
  │ │
57
89
  │ MCP registration │
58
90
  │ └─ context7 (自動登録) │
@@ -72,13 +104,13 @@ User
72
104
 
73
105
  ## エージェント構成
74
106
 
75
- Sisyphus (オーケストレーター) が直接ツールを使わず、全てを spawn_agent 経由でサブエージェントに委任する。
107
+ Sisyphus (オーケストレーター) が直接コードを読み、実装はサブエージェントに委任する。
76
108
 
77
109
  ### ビルトインデフォルト
78
110
 
79
111
  | Agent | 役割 | デフォルトモデル | モード |
80
112
  |-------|------|-----------------|--------|
81
- | **sisyphus** | オーケストレーター — 分析・計画・委任 | anthropic/claude-opus-4-5 | primary |
113
+ | **sisyphus** | オーケストレーター — 読み込み+分析+計画+委任 | openai-codex/gpt-5.3-codex | primary |
82
114
  | **oracle** | 設計・デバッグ・アーキテクチャ判断 | openai/gpt-5.2 | subagent |
83
115
  | **explore** | 高速コードベース偵察 | anthropic/claude-haiku-4-5 | subagent |
84
116
  | **librarian** | ドキュメント・ベストプラクティス調査 | anthropic/claude-sonnet-4-5 | subagent |
@@ -88,314 +120,175 @@ Sisyphus (オーケストレーター) が直接ツールを使わず、全て
88
120
  | **atlas** | タスク管理・進捗追跡 | anthropic/claude-sonnet-4-5 | subagent |
89
121
  | **multimodal-looker** | 画像・スクリーンショット解析 | anthropic/claude-sonnet-4-5 | subagent |
90
122
 
91
- **全てのモデルは `oh-my-opencode.json` でオーバーライド可能。** Sisyphus のプロンプト内エージェント表にはオーバーライド後の実際のモデル名が動的に埋め込まれる。
92
-
93
- ### Sisyphus の制約
123
+ 全てのモデルは `oh-my-opencode.json` でオーバーライド可能。
94
124
 
95
- Sisyphus は以下のツールが**物理的に無効化**されている:
125
+ ### Sisyphus のツール権限
96
126
 
97
127
  ```
98
- Grep: false, Glob: false, Read: false,
99
- Write: false, Edit: false, Bash: false
128
+ Grep: true, Glob: true, Read: true ← 直接読み込み可能
129
+ Write: false, Edit: false, Bash: false ← サブエージェントに委任
100
130
  ```
101
131
 
102
- 使えるのは `spawn_agent`、`ralph_loop`、`cancel_ralph` と TODO 系ツールのみ。これにより高コストな Orchestrator トークンの浪費を防ぎ、適切なモデルへの委任を強制する。
103
-
104
- ## Plan-First Protocol
132
+ ## Continuity Ledger
105
133
 
106
- Sisyphus は spawn_agent を呼ぶ前に、必ず以下の形式でプランを提示する:
107
-
108
- ```
109
- ## Execution Plan
110
-
111
- ### Phase 1: 偵察 (parallel)
112
- - [ ] API ルート探索 → explore (gpt-5.3-codex-spark)
113
- - [ ] フレームワーク仕様調査 → librarian (glm-4.7)
114
-
115
- ### Phase 2: 実装 (after Phase 1)
116
- - [ ] エンドポイント実装 → hephaestus (gpt-5.2)
117
-
118
- ### Phase 3: Review
119
- - [ ] コードレビュー → momus (gpt-5.3-codex)
120
-
121
- Estimated agents: 4 | Phases: 3
122
- ```
123
-
124
- - 独立タスクは同一 Phase にグループ化 (並列実行)
125
- - 依存関係があるタスクは別 Phase
126
- - エージェント名 + 実際のモデル名を表示
127
- - **「このプランで進めますか?」で承認待ち — OK するまで実行しない**
128
-
129
- ## spawn_agent ツール
130
-
131
- Sisyphus が使う並列エージェント実行ツール。
134
+ セッション間の文脈を引き継ぐマークダウンドキュメント。`.opencode/ledgers/` に保存される。
132
135
 
133
136
  ```typescript
134
- spawn_agent({
135
- agents: [
136
- { agent: "explore", prompt: "Find all API routes in src/", description: "Route discovery" },
137
- { agent: "librarian", prompt: "Research Express middleware best practices", description: "Middleware docs" },
138
- { agent: "hephaestus", prompt: "Implement the feature", description: "Implementation", category: "deep" }
139
- ]
140
- })
141
- ```
142
-
143
- - 複数エージェントは **Promise.all で並列実行**(ConcurrencyPool による同時実行制御付き)
144
- - 各エージェントは**エフェメラルセッション**で起動 — 完了後に自動削除
145
- - 内部セッションには `internalSessions` フラグを付与し、**フックの再帰を防止**
146
- - 進捗は `toolCtx.metadata({ title })` でステータスバーに表示
147
- - Toast 通知で個別エージェントの完了を通知
148
- - **`category` パラメータ**でモデル/バリアントをカテゴリから自動解決
137
+ // 保存
138
+ ledger_save({ name: "auth-refactor", content: "## Context\n..." })
139
+ // Saved to .opencode/ledgers/auth-refactor.md
149
140
 
150
- ### 並列制御 (Concurrency)
141
+ // 読み込み (名前指定)
142
+ ledger_load({ name: "auth-refactor" })
151
143
 
152
- `background_task` が設定されていると、Semaphore ベースの並列制御が有効になる。
153
-
154
- ```
155
- spawn_agent に 5 エージェント渡す
156
- → defaultConcurrency: 3 なら同時 3 個まで
157
- → 残りは空きを待って順次実行
144
+ // 読み込み (最新)
145
+ ledger_load({})
158
146
  ```
159
147
 
160
- | 設定フィールド | 目的 | 動作 |
161
- |---------------|------|------|
162
- | `defaultConcurrency` | 全体の同時実行上限 | 全エージェント合計で N 個まで同時実行 |
163
- | `providerConcurrency` | プロバイダー別上限 (例: openai: 8) | 同一プロバイダーのエージェントを N 個に制限 |
164
- | `modelConcurrency` | モデル別上限 (例: gpt-5.2: 2) | 同一モデルのエージェントを N 個に制限 |
148
+ ## Fragment Injection
165
149
 
166
- セマフォは model → provider → global の順で acquire し、global → provider → model の順で release する。エラー時も確実に release される。
167
-
168
- `background_task` 未設定の場合は制限なし(従来通り全エージェント同時発火)。
169
-
170
- ## Categories
171
-
172
- spawn_agent の `category` パラメータでモデル/バリアントを一括切替できる。
173
-
174
- ### ビルトインカテゴリ
175
-
176
- | カテゴリ | 用途 | デフォルトモデル | バリアント |
177
- |---------|------|-----------------|-----------|
178
- | `visual-engineering` | フロントエンド/UI実装 | google/gemini-3-pro | — |
179
- | `ultrabrain` | 最高精度タスク | openai/gpt-5.3-codex | xhigh |
180
- | `deep` | 深い分析・複雑ロジック | openai/gpt-5.3-codex | medium |
181
- | `quick` | 高速・低コストタスク | anthropic/claude-haiku-4-5 | — |
182
- | `writing` | ドキュメント・文章 | zai-coding-plan/glm-4.7 | — |
183
-
184
- 設定ファイルでカスタムカテゴリの追加やビルトインの上書きが可能:
150
+ エージェント毎にカスタムプロンプト断片を注入する。
185
151
 
186
152
  ```jsonc
187
153
  {
188
- "categories": {
189
- "quick": { "model": "openai/gpt-4o-mini" },
190
- "my-custom": { "model": "custom/model", "variant": "high" }
154
+ "fragments": {
155
+ "hephaestus": [".opencode/fragments/strict-coding.md"],
156
+ "sisyphus": [".opencode/fragments/planning-rules.md"]
191
157
  }
192
158
  }
193
159
  ```
194
160
 
195
- ## Ralph Loop
196
-
197
- 自律ループ実行ツール。エージェントが `<promise>DONE</promise>` を出力するか、最大イテレーション数に達するまで繰り返し実行する。
198
-
199
- ```typescript
200
- ralph_loop({
201
- prompt: "Implement all unit tests for the auth module",
202
- agent: "hephaestus", // default
203
- maxIterations: 10 // default
204
- })
205
- ```
206
-
207
- - 各イテレーションで前回の進捗をレビューし、続きから再開するよう指示
208
- - ステータスバーに `Ralph Loop [3/10] — hephaestus` のように進捗表示
209
- - `cancel_ralph` ツールで実行中のループを全てキャンセル可能
210
-
211
- ## Todo Enforcer
212
-
213
- セッションが idle になったとき、最後の assistant メッセージに未完了の TODO(`- [ ]`)がある場合、強制継続プロンプトを送信する。
214
-
215
- - **最大 5 回**(デフォルト)の強制で無限ループを防止
216
- - spawn_agent のサブセッションには適用されない
217
- - `disabled_hooks: ["todo-enforcer"]` で無効化可能
218
- - 設定で最大回数を変更可能: `"todo_enforcer": { "maxEnforcements": 3 }`
219
-
220
- ## Comment Checker
221
-
222
- Write / Edit ツール実行後に、書き込まれたファイルのコメント品質を検査する。
161
+ 指定ファイルの内容が該当エージェントの system prompt に追加される。
223
162
 
224
- ### 検出するパターン
163
+ ## Per-model Prompt Renderer
225
164
 
226
- - コメント比率が 30% を超えるファイル
227
- - 80 文字超の行コメント (`// This function does...`)
228
- - 説明的すぎる冒頭 (`// This`, `// The`, `// We`, `// Here`, `// Note:`)
229
- - AI プレースホルダー (`// TODO: implement`)
230
- - lint 回避コメント (`// eslint-disable`)
231
- - 300 文字超の巨大 JSDoc
232
-
233
- 閾値超えの場合、ツール出力に `[Comment Checker]` 警告を追加する。
165
+ モデルに応じて system prompt のフォーマットを最適化する。
234
166
 
235
167
  ```jsonc
236
168
  {
237
- "comment_checker": {
238
- "maxRatio": 0.3, // コメント比率閾値 (default: 0.3)
239
- "slopThreshold": 3 // AIスロップパターン数閾値 (default: 3)
240
- }
241
- }
242
- ```
243
-
244
- ## MCP 自動登録
245
-
246
- プラグイン初期化時に以下の MCP サーバーを自動登録する:
247
-
248
- | MCP | パッケージ | API キー |
249
- |-----|-----------|----------|
250
- | **Context7** | `@upstash/context7-mcp` | オプション(あるとレートリミット緩和) |
251
-
252
- API キーの渡し方:
253
-
254
- ```jsonc
255
- {
256
- "mcp_api_keys": {
257
- "context7": "ctx7sk-..."
169
+ "prompt_renderer": {
170
+ "default": "markdown",
171
+ "model_overrides": {
172
+ "anthropic/claude-sonnet-4-5": "xml",
173
+ "openai/gpt-5.2": "json"
174
+ }
258
175
  }
259
176
  }
260
177
  ```
261
178
 
262
- または環境変数 `CONTEXT7_API_KEY` を設定。
263
-
264
- `disabled_mcps: ["context7"]` で無効化可能。
179
+ | フォーマット | 出力例 |
180
+ |-------------|--------|
181
+ | `markdown` | そのまま (デフォルト) |
182
+ | `xml` | `<section name="Rules">...</section>` |
183
+ | `json` | `{"section":"Rules","content":"..."}` |
265
184
 
266
185
  ## キーワード検知
267
186
 
268
- ユーザーのプロンプトからキーワードを検知し、system prompt に動作モード指示を注入する。
269
- コードブロック (`` ``` `` / `` ` ``) 内のキーワードは無視する。
270
-
271
187
  | キーワード | モード | 効果 |
272
188
  |-----------|--------|------|
273
- | `ultrawork` / `ulw` | ultrawork | variant "max" に設定。全エージェント活用・並列実行・TODO 追跡を強制。ユーザーメッセージからキーワードを除去 |
274
- | `search` / `find` / `探して` / `検索` 等 | search | 複数 explore + librarian エージェントを並列起動。網羅的検索を強制 |
275
- | `analyze` / `調査` / `なぜ` / `debug` 等 | analyze | コンテキスト収集フェーズを実行。複雑な場合は Oracle に委任 |
189
+ | `ultrawork` / `ulw` | ultrawork | variant "max"、全エージェント活用 |
190
+ | `search` / `find` / `探して` 等 | search | 網羅的検索 |
191
+ | `analyze` / `調査` / `debug` 等 | analyze | コンテキスト収集 |
192
+ | `think hard` / `じっくり` / `熟考` 等 | think | Extended thinking 有効化 |
276
193
 
277
194
  日本語・中国語キーワードにも対応。
278
195
 
279
- ## ルール注入
280
-
281
- `<project>/.opencode/rules.md` が存在する場合、その内容を system prompt に `## Project Rules` として自動注入する。ファイルの mtime でキャッシュし、変更時のみ再読み込み。
282
-
283
196
  ## 設定
284
197
 
285
- 2 段階の設定マージ:
198
+ 2段階の設定マージ:
286
199
 
287
200
  1. **ユーザー設定**: `~/.config/opencode/oh-my-opencode.json[c]`
288
201
  2. **プロジェクト設定**: `<project>/.opencode/oh-my-opencode.json[c]`
289
202
 
290
- プロジェクト設定がユーザー設定をオーバーライドする。
291
-
292
203
  ### 設定スキーマ
293
204
 
294
205
  ```jsonc
295
206
  {
296
- // エージェントごとのモデル・プロンプトオーバーライド
207
+ // エージェントオーバーライド
297
208
  "agents": {
298
209
  "sisyphus": { "model": "openai/gpt-5.2" },
299
- "oracle": { "model": "zai-coding-plan/glm-5" },
300
- "explore": { "model": "openai/gpt-5.3-codex-spark" }
210
+ "oracle": { "model": "zai-coding-plan/glm-5" }
301
211
  },
302
212
 
303
- // カテゴリ (spawn_agent の category パラメータで使用)
213
+ // カテゴリ
304
214
  "categories": {
305
215
  "quick": { "model": "openai/gpt-4o-mini" }
306
216
  },
307
217
 
218
+ // Fragment Injection
219
+ "fragments": {
220
+ "hephaestus": [".opencode/fragments/strict.md"]
221
+ },
222
+
223
+ // Per-model Renderer
224
+ "prompt_renderer": {
225
+ "default": "markdown",
226
+ "model_overrides": {}
227
+ },
228
+
308
229
  // 無効化
309
230
  "disabled_agents": [],
310
- "disabled_hooks": ["keyword-detector", "rules-injector", "todo-enforcer", "comment-checker"],
311
- "disabled_tools": ["ralph_loop", "cancel_ralph", "spawn_agent"],
312
- "disabled_mcps": ["context7"],
231
+ "disabled_hooks": [], // keyword-detector, rules-injector, context-injector,
232
+ // fragment-injector, prompt-renderer, comment-checker,
233
+ // token-truncation, todo-enforcer, session-compaction
234
+ "disabled_tools": [], // spawn_agent, ralph_loop, cancel_ralph,
235
+ // batch_read, ledger_save, ledger_load, ast_search
236
+ "disabled_mcps": [], // context7
237
+
238
+ // Built-in Agent Demotion (default: true)
239
+ "demote_builtin": true,
313
240
 
314
241
  // 並列制御
315
242
  "background_task": {
316
243
  "defaultConcurrency": 3,
317
- "providerConcurrency": {
318
- "openai": 8,
319
- "zai-coding-plan": 10
320
- },
321
- "modelConcurrency": {
322
- "openai/gpt-5.2": 2
323
- }
244
+ "providerConcurrency": { "openai": 8 },
245
+ "modelConcurrency": { "openai/gpt-5.2": 2 }
324
246
  },
325
247
 
326
- // Comment Checker 設定
327
- "comment_checker": {
328
- "maxRatio": 0.3,
329
- "slopThreshold": 3
330
- },
248
+ // Token Truncation
249
+ "token_truncation": { "maxChars": 30000 },
331
250
 
332
- // Todo Enforcer 設定
333
- "todo_enforcer": {
334
- "maxEnforcements": 5
335
- },
251
+ // Comment Checker
252
+ "comment_checker": { "maxRatio": 0.3, "slopThreshold": 3 },
253
+
254
+ // Todo Enforcer
255
+ "todo_enforcer": { "maxEnforcements": 5 },
336
256
 
337
257
  // MCP API キー
338
- "mcp_api_keys": {
339
- "context7": "ctx7sk-..."
340
- }
258
+ "mcp_api_keys": { "context7": "ctx7sk-..." }
341
259
  }
342
260
  ```
343
261
 
344
- ### エージェントオーバーライドで使えるフィールド
345
-
346
- | フィールド | 型 | 説明 |
347
- |-----------|---|------|
348
- | `model` | string | 使用モデル (provider/model 形式) |
349
- | `description` | string | エージェントの説明 |
350
- | `prompt` | string | システムプロンプト全体を差し替え |
351
- | `prompt_append` | string | プロンプト末尾に追記 |
352
- | `disable` | boolean | 個別に無効化 |
353
- | `mode` | `"subagent"` / `"primary"` / `"all"` | 実行モード |
354
- | `maxTokens` | number | 最大出力トークン |
355
- | `thinking` | `{ type, budgetTokens }` | 思考トークン設定 |
356
- | `reasoningEffort` | `"low"` / `"medium"` / `"high"` / `"xhigh"` | 推論レベル |
357
- | `temperature` | number (0-2) | サンプリング温度 |
358
- | `top_p` | number (0-1) | Top-p |
359
- | `category` | string | デフォルトカテゴリ |
360
- | `variant` | string | モデルバリアント |
361
-
362
- ## フック再帰防止
363
-
364
- spawn_agent / ralph_loop で生成されたエフェメラルセッションは `internalSessions` Set で追跡される。`chat.message`、`system.transform`、`tool.execute.after`、`event` の各フックは内部セッションに対してスキップされ、キーワード検知・ルール注入・Comment Checker・Todo Enforcer がサブエージェントに二重適用されることを防ぐ。
365
-
366
262
  ## プロジェクト構成
367
263
 
368
264
  ```
369
265
  opencode-ultra/
370
266
  ├── src/
371
- │ ├── index.ts # プラグインエントリポイント (hook/tool/MCP 統合)
372
- │ ├── config.ts # 設定ロード・マージ・バリデーション (Zod)
267
+ │ ├── index.ts # プラグインエントリポイント
268
+ │ ├── config.ts # 設定ロード・マージ・バリデーション
373
269
  │ ├── agents/
374
- │ │ ├── types.ts # AgentDef 型定義
375
- │ │ └── index.ts # ビルトインエージェント定義 + 動的プロンプト生成
270
+ │ │ ├── types.ts # AgentDef 型定義
271
+ │ │ └── index.ts # ビルトインエージェント + 動的プロンプト生成
376
272
  │ ├── hooks/
377
- │ │ ├── keyword-detector.ts # ultrawork/search/analyze キーワード検知
378
- │ │ ├── rules-injector.ts # .opencode/rules.md 注入 (mtime キャッシュ)
379
- │ │ ├── todo-enforcer.ts # session.idle 時の未完了 TODO 強制継続
380
- │ │ └── comment-checker.ts # Write/Edit 後の AI スロップ検知
273
+ │ │ ├── keyword-detector.ts # ultrawork/search/analyze/think 検知
274
+ │ │ ├── rules-injector.ts # rules.md + ARCHITECTURE.md + CODE_STYLE.md 注入
275
+ │ │ ├── fragment-injector.ts # エージェント毎の断片注入
276
+ │ │ ├── prompt-renderer.ts # モデル別フォーマット変換
277
+ │ │ ├── comment-checker.ts # AI スロップコメント検知
278
+ │ │ ├── token-truncation.ts # ツール出力の賢い圧縮
279
+ │ │ ├── todo-enforcer.ts # 未完了 TODO 強制継続
280
+ │ │ └── session-compaction.ts # セッション圧縮サマリ生成
381
281
  │ ├── tools/
382
- │ │ ├── spawn-agent.ts # spawn_agent ツール (並列実行 + 並列制御 + カテゴリ)
383
- │ │ └── ralph-loop.ts # ralph_loop / cancel_ralph ツール (自律ループ)
384
- │ ├── concurrency/
385
- │ │ ├── semaphore.ts # 汎用セマフォ
386
- │ │ ├── pool.ts # ConcurrencyPool (global/provider/model 三層制御)
387
- │ └── index.ts # バレルエクスポート
388
- │ ├── categories/
389
- │ └── index.ts # ビルトインカテゴリ + resolveCategory
390
- ├── mcp/
391
- │ │ ├── servers.ts # ビルトイン MCP サーバー定義
392
- │ │ └── index.ts # MCP 登録ロジック
393
- │ └── shared/
394
- │ ├── paths.ts # XDG パス解決
395
- │ ├── jsonc.ts # JSONC パーサー
396
- │ ├── log.ts # [opencode-ultra] プレフィックスログ
397
- │ └── index.ts # バレルエクスポート
398
- ├── __test__/ # Bun テスト (70 tests)
282
+ │ │ ├── spawn-agent.ts # 並列エージェント実行
283
+ │ │ ├── ralph-loop.ts # 自律ループ実行
284
+ ├── batch-read.ts # 複数ファイル並列読み込み
285
+ │ │ ├── continuity-ledger.ts # セッション間文脈継続
286
+ │ │ └── ast-search.ts # AST-aware コード検索
287
+ ├── concurrency/ # Semaphore + ConcurrencyPool
288
+ │ ├── categories/ # ビルトインカテゴリ
289
+ ├── mcp/ # MCP サーバー登録
290
+ └── shared/ # ユーティリティ
291
+ ├── __test__/ # Bun テスト (92 tests, 20 files)
399
292
  ├── package.json
400
293
  ├── tsconfig.json
401
294
  └── .gitignore
@@ -404,13 +297,8 @@ opencode-ultra/
404
297
  ## ビルド・テスト
405
298
 
406
299
  ```bash
407
- # 依存インストール
408
300
  bun install
409
-
410
- # ビルド
411
- bun build src/index.ts --outdir dist --target bun --format esm
412
-
413
- # テスト
301
+ bun run build
414
302
  bun test
415
303
  ```
416
304
 
@@ -1,5 +1,5 @@
1
1
  export interface DetectedKeyword {
2
- type: "ultrawork" | "search" | "analyze" | "think";
2
+ type: "ultrawork" | "search" | "analyze" | "think" | "evolve";
3
3
  message: string;
4
4
  }
5
5
  export declare function removeCodeBlocks(text: string): string;
@@ -1,13 +1,14 @@
1
+ import type { ModelRef } from "../shared/types";
1
2
  export type PromptFormat = "markdown" | "xml" | "json";
2
3
  export type PromptRendererConfig = {
3
4
  default: PromptFormat;
4
5
  model_overrides: Record<string, PromptFormat>;
5
6
  };
6
- export declare function resolvePromptFormat(inputModel: any, config?: Partial<PromptRendererConfig>): PromptFormat;
7
+ export declare function resolvePromptFormat(inputModel: ModelRef | undefined, config?: Partial<PromptRendererConfig>): PromptFormat;
7
8
  export declare function formatSystemSection(format: PromptFormat, content: string): string;
8
9
  export declare function createPromptRendererHook(internalSessions: Set<string>, config?: Partial<PromptRendererConfig>): (input: {
9
10
  sessionID?: string;
10
- model?: unknown;
11
+ model?: ModelRef;
11
12
  }, output: {
12
13
  system: string[];
13
14
  }) => void;
@@ -11,7 +11,7 @@ type MessageLike = {
11
11
  };
12
12
  export declare function buildSessionSummary(messages: MessageLike[]): string;
13
13
  export declare function createSessionCompactionHook(ctx: {
14
- client: any;
14
+ client: Pick<import("../shared/types").ExtendedClient, "session">;
15
15
  }, internalSessions: Set<string>): (input: {
16
16
  sessionID: string;
17
17
  }, output: {
package/dist/index.js CHANGED
@@ -14369,6 +14369,49 @@ function log(message, data) {
14369
14369
  console.error(`${PREFIX} ${message}`);
14370
14370
  }
14371
14371
  }
14372
+ // src/shared/ttl-map.ts
14373
+ class TtlMap {
14374
+ map = new Map;
14375
+ maxSize;
14376
+ ttlMs;
14377
+ constructor(opts = {}) {
14378
+ this.maxSize = opts.maxSize ?? 1000;
14379
+ this.ttlMs = opts.ttlMs ?? 0;
14380
+ }
14381
+ get(key) {
14382
+ const entry = this.map.get(key);
14383
+ if (!entry)
14384
+ return;
14385
+ if (this.ttlMs > 0 && Date.now() - entry.createdAt > this.ttlMs) {
14386
+ this.map.delete(key);
14387
+ return;
14388
+ }
14389
+ return entry.value;
14390
+ }
14391
+ set(key, value) {
14392
+ if (this.map.has(key)) {
14393
+ this.map.delete(key);
14394
+ }
14395
+ if (this.map.size >= this.maxSize) {
14396
+ const oldest = this.map.keys().next().value;
14397
+ if (oldest !== undefined)
14398
+ this.map.delete(oldest);
14399
+ }
14400
+ this.map.set(key, { value, createdAt: Date.now() });
14401
+ }
14402
+ has(key) {
14403
+ return this.get(key) !== undefined;
14404
+ }
14405
+ delete(key) {
14406
+ return this.map.delete(key);
14407
+ }
14408
+ get size() {
14409
+ return this.map.size;
14410
+ }
14411
+ clear() {
14412
+ this.map.clear();
14413
+ }
14414
+ }
14372
14415
  // src/config.ts
14373
14416
  var AgentOverrideSchema = exports_external.object({
14374
14417
  model: exports_external.string().optional(),
@@ -14590,6 +14633,40 @@ var BUILTIN_AGENTS = {
14590
14633
  mode: "subagent",
14591
14634
  reasoningEffort: "medium",
14592
14635
  maxTokens: 64000
14636
+ },
14637
+ scout: {
14638
+ model: "anthropic/claude-sonnet-4-5",
14639
+ description: "Plugin ecosystem researcher \u2014 finds, analyzes, and compares OpenCode plugins for self-improvement",
14640
+ prompt: `You are Scout, an OpenCode plugin ecosystem researcher.
14641
+
14642
+ ## YOUR MISSION
14643
+ Search the web (npm, GitHub, OpenCode community) for OpenCode plugins and extensions.
14644
+ Analyze their features, architecture, and quality. Compare with opencode-ultra.
14645
+
14646
+ ## SEARCH STRATEGY
14647
+ 1. Search npm for "opencode-plugin", "opencode-ai", "@opencode" packages
14648
+ 2. Search GitHub for "opencode plugin", "opencode extension", "oh-my-opencode"
14649
+ 3. Look at package.json dependencies on @opencode-ai/plugin or @opencode-ai/sdk
14650
+ 4. Read README files and source code of discovered plugins
14651
+
14652
+ ## OUTPUT FORMAT
14653
+ For each plugin found, report:
14654
+ - **Name**: package name + repo URL
14655
+ - **Version**: latest version
14656
+ - **Features**: bullet list of capabilities
14657
+ - **Architecture**: hook types used, tool count, agent count
14658
+ - **Quality signals**: test count, TypeScript, last updated, download count
14659
+ - **Unique ideas**: features that opencode-ultra does NOT have
14660
+
14661
+ ## COMPARISON
14662
+ After listing plugins, generate a structured gap analysis:
14663
+ - Features others have that opencode-ultra lacks
14664
+ - Features opencode-ultra has that others lack (competitive advantages)
14665
+ - Improvement priority list (high/medium/low impact)
14666
+
14667
+ Be thorough but focused. Skip abandoned or trivial plugins.`,
14668
+ mode: "subagent",
14669
+ maxTokens: 32000
14593
14670
  }
14594
14671
  };
14595
14672
  function buildAgentTable(agents) {
@@ -14720,6 +14797,7 @@ var ULTRAWORK_PATTERN = /\b(ultrawork|ulw)\b/i;
14720
14797
  var THINK_PATTERN = /\b(think\s+hard|think\s+through|think\s+deeply|think\s+carefully)\b|\u3058\u3063\u304F\u308A|\u6DF1\u304F\u8003\u3048\u3066|\u719F\u8003/i;
14721
14798
  var SEARCH_PATTERN = /\b(search|find|locate|lookup|look\s*up|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all|\u691C\u7D22|\u63A2\u3057\u3066|\u898B\u3064\u3051\u3066|\u30B5\u30FC\u30C1|\u63A2\u7D22|\u30B9\u30AD\u30E3\u30F3|\u3069\u3053|\u767A\u898B|\u635C\u7D22|\u898B\u3064\u3051\u51FA\u3059|\u4E00\u89A7|\u641C\u7D22|\u67E5\u627E|\u5BFB\u627E|\u67E5\u8BE2|\u68C0\u7D22|\u5B9A\u4F4D|\u626B\u63CF|\u53D1\u73B0|\u5728\u54EA\u91CC|\u627E\u51FA\u6765|\u5217\u51FA/i;
14722
14799
  var ANALYZE_PATTERN = /\b(analyze|analyse|investigate|examine|research|study|deep[\s-]?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to|\u5206\u6790|\u8ABF\u67FB|\u89E3\u6790|\u691C\u8A0E|\u7814\u7A76|\u8A3A\u65AD|\u7406\u89E3|\u8AAC\u660E|\u691C\u8A3C|\u7CBE\u67FB|\u7A76\u660E|\u30C7\u30D0\u30C3\u30B0|\u306A\u305C|\u3069\u3046|\u4ED5\u7D44\u307F|\u8C03\u67E5|\u68C0\u67E5|\u5256\u6790|\u6DF1\u5165|\u8BCA\u65AD|\u89E3\u91CA|\u8C03\u8BD5|\u4E3A\u4EC0\u4E48|\u539F\u7406|\u641E\u6E05\u695A|\u5F04\u660E\u767D/i;
14800
+ var EVOLVE_PATTERN = /\b(evolve|self[\s-]?improve|self[\s-]?upgrade|plugin[\s-]?scout|ecosystem[\s-]?scan)\b|\u81EA\u5DF1\u6539\u5584|\u9032\u5316|\u30D7\u30E9\u30B0\u30A4\u30F3\u63A2\u7D22|\u30A8\u30B3\u30B7\u30B9\u30C6\u30E0|\u81EA\u6211\u8FDB\u5316|\u63D2\u4EF6\u641C\u7D22/i;
14723
14801
  function removeCodeBlocks(text) {
14724
14802
  return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "");
14725
14803
  }
@@ -14730,7 +14808,8 @@ var KEYWORD_DEFS = [
14730
14808
  { pattern: ULTRAWORK_PATTERN, type: "ultrawork", getMessage: () => ULTRAWORK_MESSAGE },
14731
14809
  { pattern: SEARCH_PATTERN, type: "search", getMessage: () => SEARCH_MESSAGE },
14732
14810
  { pattern: ANALYZE_PATTERN, type: "analyze", getMessage: () => ANALYZE_MESSAGE },
14733
- { pattern: THINK_PATTERN, type: "think", getMessage: () => THINK_MESSAGE }
14811
+ { pattern: THINK_PATTERN, type: "think", getMessage: () => THINK_MESSAGE },
14812
+ { pattern: EVOLVE_PATTERN, type: "evolve", getMessage: () => EVOLVE_MESSAGE }
14734
14813
  ];
14735
14814
  function detectKeywords(text) {
14736
14815
  const clean = removeCodeBlocks(text);
@@ -14820,11 +14899,38 @@ IF COMPLEX \u2014 DO NOT STRUGGLE ALONE. Consult specialists:
14820
14899
 
14821
14900
  SYNTHESIZE findings before proceeding.`;
14822
14901
  var THINK_MESSAGE = `Extended thinking enabled. Take your time to reason thoroughly.`;
14902
+ var EVOLVE_MESSAGE = `[evolve-mode] SELF-IMPROVEMENT CYCLE ACTIVATED.
14903
+
14904
+ ## MISSION
14905
+ Search the OpenCode plugin ecosystem, find what others have built, and identify gaps in opencode-ultra.
14906
+
14907
+ ## STEPS
14908
+ 1. **SCOUT** \u2014 Spawn the **scout** agent to search npm/GitHub for OpenCode plugins
14909
+ 2. **READ SELF** \u2014 Read opencode-ultra's own README.md and key source files to know current capabilities
14910
+ 3. **COMPARE** \u2014 Generate a structured gap analysis (what we have vs what we're missing)
14911
+ 4. **PRIORITIZE** \u2014 Rank missing features by impact (high/medium/low)
14912
+ 5. **PROPOSE** \u2014 Present improvement plan to the user
14913
+ 6. **SAVE** \u2014 Save findings to a continuity ledger via ledger_save for future reference
14914
+
14915
+ ## EXECUTION
14916
+ \`\`\`
14917
+ spawn_agent({
14918
+ agents: [
14919
+ {agent: "scout", prompt: "Search npm and GitHub for OpenCode 1.2.x plugins. Find all published plugins, analyze features, compare with opencode-ultra.", description: "Plugin ecosystem scan"},
14920
+ {agent: "explore", prompt: "Read opencode-ultra's README.md, src/index.ts, src/agents/index.ts to catalog current features", description: "Self-analysis"}
14921
+ ]
14922
+ })
14923
+ \`\`\`
14924
+
14925
+ After gathering results, synthesize into a gap analysis and present to the user.
14926
+ Save the analysis via: ledger_save({name: "evolve-scan-YYYY-MM-DD", content: "..."})
14927
+
14928
+ **This is how opencode-ultra gets better \u2014 by knowing what it doesn't know.**`;
14823
14929
 
14824
14930
  // src/hooks/rules-injector.ts
14825
14931
  import * as fs2 from "fs";
14826
14932
  import * as path2 from "path";
14827
- var cache = new Map;
14933
+ var cache = new TtlMap({ maxSize: 50, ttlMs: 10 * 60 * 1000 });
14828
14934
  function loadCachedFile(filePath) {
14829
14935
  try {
14830
14936
  if (!fs2.existsSync(filePath))
@@ -14882,7 +14988,7 @@ function loadCodeStyle(projectDir) {
14882
14988
  // src/hooks/fragment-injector.ts
14883
14989
  import * as fs3 from "fs";
14884
14990
  import * as path3 from "path";
14885
- var cache2 = new Map;
14991
+ var cache2 = new TtlMap({ maxSize: 100, ttlMs: 10 * 60 * 1000 });
14886
14992
  async function readCached(absPath) {
14887
14993
  try {
14888
14994
  const st = await fs3.promises.stat(absPath);
@@ -27322,7 +27428,8 @@ function resolveCategory(categoryName, configCategories) {
27322
27428
 
27323
27429
  // src/tools/spawn-agent.ts
27324
27430
  function showToast(ctx, title, message, variant = "info") {
27325
- ctx.client?.tui?.showToast?.({
27431
+ const client = ctx.client;
27432
+ client.tui?.showToast?.({
27326
27433
  body: { title, message, variant, duration: 2000 }
27327
27434
  })?.catch?.(() => {});
27328
27435
  }
@@ -27427,6 +27534,18 @@ spawn_agent({
27427
27534
  if (!agents || agents.length === 0) {
27428
27535
  return "No agents specified.";
27429
27536
  }
27537
+ for (let i = 0;i < agents.length; i++) {
27538
+ const t = agents[i];
27539
+ if (!t.agent || typeof t.agent !== "string" || t.agent.trim().length === 0) {
27540
+ return `Error: agents[${i}].agent is required (non-empty string)`;
27541
+ }
27542
+ if (!t.prompt || typeof t.prompt !== "string" || t.prompt.trim().length === 0) {
27543
+ return `Error: agents[${i}].prompt is required (non-empty string)`;
27544
+ }
27545
+ if (!t.description || typeof t.description !== "string") {
27546
+ return `Error: agents[${i}].description is required`;
27547
+ }
27548
+ }
27430
27549
  const agentNames = agents.map((a) => a.agent);
27431
27550
  log("spawn_agent", { count: agents.length, agents: agentNames });
27432
27551
  showToast(ctx, "spawn_agent", `${agents.length} agents: ${agentNames.join(", ")}`);
@@ -28190,6 +28309,8 @@ class Semaphore {
28190
28309
  });
28191
28310
  }
28192
28311
  release() {
28312
+ if (this.active <= 0)
28313
+ return;
28193
28314
  this.active--;
28194
28315
  const next = this.queue.shift();
28195
28316
  if (next)
@@ -28279,7 +28400,8 @@ async function registerMcps(ctx, disabled, apiKeys) {
28279
28400
  if (config3.env) {
28280
28401
  body.env = config3.env;
28281
28402
  }
28282
- await ctx.client.mcp?.add?.({ body });
28403
+ const client = ctx.client;
28404
+ await client.mcp?.add?.({ body });
28283
28405
  log(`MCP ${name} registered${apiKey ? " (with API key)" : ""}`);
28284
28406
  } catch (err) {
28285
28407
  log(`MCP ${name} registration failed: ${err}`);
@@ -28313,10 +28435,10 @@ var OpenCodeUltra = async (ctx) => {
28313
28435
  const todoEnforcer = createTodoEnforcer(ctx, internalSessions, pluginConfig.todo_enforcer?.maxEnforcements);
28314
28436
  const commentCheckerHook = createCommentCheckerHook(internalSessions, pluginConfig.comment_checker?.maxRatio, pluginConfig.comment_checker?.slopThreshold);
28315
28437
  const tokenTruncationHook = createTokenTruncationHook(internalSessions, pluginConfig.token_truncation?.maxChars);
28316
- const sessionCompactionHook = createSessionCompactionHook(ctx, internalSessions);
28438
+ const sessionCompactionHook = createSessionCompactionHook({ client: ctx.client }, internalSessions);
28317
28439
  const fragmentInjector = createFragmentInjector(ctx, internalSessions, pluginConfig.fragments);
28318
28440
  const promptRendererHook = createPromptRendererHook(internalSessions, pluginConfig.prompt_renderer);
28319
- const pendingKeywords = new Map;
28441
+ const pendingKeywords = new TtlMap({ maxSize: 200, ttlMs: 5 * 60 * 1000 });
28320
28442
  log("Config loaded", {
28321
28443
  agentCount: Object.keys(agents).length,
28322
28444
  disabledHooks: [...disabledHooks],
@@ -28397,7 +28519,8 @@ var OpenCodeUltra = async (ctx) => {
28397
28519
  if (output.message.variant === undefined) {
28398
28520
  output.message.variant = "max";
28399
28521
  }
28400
- ctx.client?.tui?.showToast?.({
28522
+ const client = ctx.client;
28523
+ client.tui?.showToast?.({
28401
28524
  body: {
28402
28525
  title: "ULTRAWORK MODE",
28403
28526
  message: "Maximum precision engaged. All agents at your disposal.",
@@ -1,3 +1,5 @@
1
1
  export { getConfigDir, getCacheDir, getDataDir } from "./paths";
2
2
  export { parseJsonc } from "./jsonc";
3
3
  export { log } from "./log";
4
+ export type { ExtendedClient, ModelRef, ToastOptions, SystemTransformInput } from "./types";
5
+ export { TtlMap } from "./ttl-map";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Simple Map with max size eviction (LRU-like: evicts oldest entry when full).
3
+ * Optionally supports TTL-based expiry.
4
+ */
5
+ export declare class TtlMap<K, V> {
6
+ private map;
7
+ private maxSize;
8
+ private ttlMs;
9
+ constructor(opts?: {
10
+ maxSize?: number;
11
+ ttlMs?: number;
12
+ });
13
+ get(key: K): V | undefined;
14
+ set(key: K, value: V): void;
15
+ has(key: K): boolean;
16
+ delete(key: K): boolean;
17
+ get size(): number;
18
+ clear(): void;
19
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Extended type definitions for OpenCode client APIs that are not (yet) in @opencode-ai/sdk types.
3
+ * These describe the actual runtime shape observed in OpenCode 1.2.x.
4
+ */
5
+ /** Model identifier as passed through hook input */
6
+ export interface ModelRef {
7
+ providerID?: string;
8
+ modelID?: string;
9
+ }
10
+ /** Toast notification (TUI-only, non-standard) */
11
+ export interface ToastOptions {
12
+ body: {
13
+ title: string;
14
+ message: string;
15
+ variant?: "info" | "success" | "warning" | "error";
16
+ duration?: number;
17
+ };
18
+ }
19
+ /** Extended OpenCode client with optional TUI and MCP methods */
20
+ export interface ExtendedClient {
21
+ session: {
22
+ create: (opts: {
23
+ body: Record<string, unknown>;
24
+ query?: {
25
+ directory?: string;
26
+ };
27
+ }) => Promise<{
28
+ data?: {
29
+ id?: string;
30
+ };
31
+ }>;
32
+ prompt: (opts: {
33
+ path: {
34
+ id: string;
35
+ };
36
+ body: {
37
+ parts: Array<{
38
+ type: string;
39
+ text: string;
40
+ }>;
41
+ agent?: string;
42
+ };
43
+ query?: {
44
+ directory?: string;
45
+ };
46
+ }) => Promise<unknown>;
47
+ messages: (opts: {
48
+ path: {
49
+ id: string;
50
+ };
51
+ query?: {
52
+ directory?: string;
53
+ };
54
+ }) => Promise<{
55
+ data?: Array<{
56
+ info?: {
57
+ role?: string;
58
+ };
59
+ parts?: Array<{
60
+ type: string;
61
+ text?: string;
62
+ }>;
63
+ }>;
64
+ }>;
65
+ delete: (opts: {
66
+ path: {
67
+ id: string;
68
+ };
69
+ query?: {
70
+ directory?: string;
71
+ };
72
+ }) => Promise<unknown>;
73
+ listMessages?: (opts: {
74
+ id: string;
75
+ }) => Promise<{
76
+ messages?: unknown[];
77
+ } | unknown[]>;
78
+ };
79
+ tui?: {
80
+ showToast?: (opts: ToastOptions) => Promise<void>;
81
+ };
82
+ mcp?: {
83
+ add?: (opts: {
84
+ body: Record<string, unknown>;
85
+ }) => Promise<void>;
86
+ };
87
+ }
88
+ /** System transform hook input */
89
+ export interface SystemTransformInput {
90
+ sessionID?: string;
91
+ model?: ModelRef;
92
+ agent?: string;
93
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-ultra",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Lightweight OpenCode 1.2.x plugin — ultrawork mode, multi-agent orchestration, rules injection",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",