@te-river/opencode-team-mode 1.5.0 → 1.5.2

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 (54) hide show
  1. package/README.md +157 -53
  2. package/README.zh-CN.md +137 -53
  3. package/dist/agents.d.ts.map +1 -1
  4. package/dist/agents.js +128 -26
  5. package/dist/agents.js.map +1 -1
  6. package/dist/approval-gate.d.ts +147 -0
  7. package/dist/approval-gate.d.ts.map +1 -0
  8. package/dist/approval-gate.js +471 -0
  9. package/dist/approval-gate.js.map +1 -0
  10. package/dist/commands.js +3 -3
  11. package/dist/commands.js.map +1 -1
  12. package/dist/envprotect.d.ts +234 -0
  13. package/dist/envprotect.d.ts.map +1 -0
  14. package/dist/envprotect.js +820 -0
  15. package/dist/envprotect.js.map +1 -0
  16. package/dist/index.d.ts +5 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +112 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/tm/config.d.ts +105 -0
  21. package/dist/tm/config.d.ts.map +1 -0
  22. package/dist/tm/config.js +118 -0
  23. package/dist/tm/config.js.map +1 -0
  24. package/dist/tm/guard.d.ts +56 -0
  25. package/dist/tm/guard.d.ts.map +1 -0
  26. package/dist/tm/guard.js +249 -0
  27. package/dist/tm/guard.js.map +1 -0
  28. package/dist/tm/index.d.ts +41 -0
  29. package/dist/tm/index.d.ts.map +1 -0
  30. package/dist/tm/index.js +93 -0
  31. package/dist/tm/index.js.map +1 -0
  32. package/dist/tm/preview.d.ts +46 -0
  33. package/dist/tm/preview.d.ts.map +1 -0
  34. package/dist/tm/preview.js +354 -0
  35. package/dist/tm/preview.js.map +1 -0
  36. package/dist/tm/ptc.d.ts +279 -0
  37. package/dist/tm/ptc.d.ts.map +1 -0
  38. package/dist/tm/ptc.js +839 -0
  39. package/dist/tm/ptc.js.map +1 -0
  40. package/dist/tm/refs.d.ts +37 -0
  41. package/dist/tm/refs.d.ts.map +1 -0
  42. package/dist/tm/refs.js +58 -0
  43. package/dist/tm/refs.js.map +1 -0
  44. package/dist/tm/store.d.ts +95 -0
  45. package/dist/tm/store.d.ts.map +1 -0
  46. package/dist/tm/store.js +222 -0
  47. package/dist/tm/store.js.map +1 -0
  48. package/dist/tm/tools.d.ts +84 -0
  49. package/dist/tm/tools.d.ts.map +1 -0
  50. package/dist/tm/tools.js +710 -0
  51. package/dist/tm/tools.js.map +1 -0
  52. package/dist/types.d.ts +155 -0
  53. package/dist/types.d.ts.map +1 -1
  54. package/package.json +3 -2
package/README.md CHANGED
@@ -55,73 +55,40 @@ Instead of one agent trying to do everything, you get:
55
55
 
56
56
  ### Install TeamMode
57
57
 
58
- **Option A — One-line installer (recommended):**
58
+ **Option A — One-line installer:**
59
59
 
60
60
  macOS / Linux (bash):
61
61
  ```bash
62
- curl -fsSL "https://gh-proxy.com/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh" | bash
62
+ curl -fsSL https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
63
63
  ```
64
64
 
65
65
  Windows (PowerShell):
66
66
  ```powershell
67
- irm "https://gh-proxy.com/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1" | iex
67
+ irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
68
68
  ```
69
69
 
70
- If gh-proxy is unavailable, try jsdelivr or GitHub raw:
71
- ```bash
72
- # macOS / Linux — jsdelivr
73
- curl -fsSL "https://cdn.jsdelivr.net/gh/Te-River/Opencode-TeamMode@main/scripts/install.sh" | bash
74
-
75
- # Windows — jsdelivr
76
- irm "https://cdn.jsdelivr.net/gh/Te-River/Opencode-TeamMode@main/scripts/install.ps1" | iex
77
-
78
- # macOS / Linux — GitHub raw
79
- curl -fsSL https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
80
-
81
- # Windows — GitHub raw
82
- irm https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
83
- ```
84
-
85
- These scripts install the npm package and automatically register the plugin in your `opencode.jsonc`.
70
+ **Option B — Manual config:**
86
71
 
87
- **Option B — Manual npm install:**
88
-
89
- ```bash
90
- # 1. Install the plugin package
91
- npm install -g @te-river/opencode-team-mode
92
-
93
- # 2. Add the plugin to your opencode.jsonc
94
- # (see "Configuration" below)
95
- ```
96
-
97
- **Option C — Local dev install (from this repo):**
98
-
99
- ```bash
100
- git clone https://github.com/Te-River/Opencode-TeamMode.git
101
- cd Opencode-TeamMode
102
- npm install
103
- npm run build
104
- npm link
105
- ```
106
-
107
- ---
108
-
109
- ## ⚙️ Configuration
110
-
111
- After installing, add the plugin to your `opencode.jsonc`:
72
+ Add the plugin to your `opencode.jsonc`:
112
73
 
113
74
  ```jsonc
114
75
  {
115
76
  "$schema": "https://opencode.ai/config.json",
116
77
  "plugin": [
117
- "@te-river/opencode-team-mode@1.4.9"
78
+ "@te-river/opencode-team-mode@latest"
118
79
  ]
119
80
  }
120
81
  ```
121
82
 
122
- That's it. The plugin automatically injects all team agents and commands when OpenCode starts. **No need to manually copy agent files or command definitions.**
83
+ OpenCode will automatically install the plugin on startup.
84
+
85
+ > **Tip:** After modifying `opencode.json`, **restart OpenCode Desktop** for changes to take effect.
123
86
 
124
- > 💡 **Tip:** After modifying `opencode.json`, **restart OpenCode Desktop** for changes to take effect.
87
+ ---
88
+
89
+ ## ⚙️ Configuration
90
+
91
+ The plugin automatically injects all team agents and commands when OpenCode starts. **No need to manually copy agent files or command definitions.**
125
92
 
126
93
  > ⚠️ **Model choice matters.** Every judgment in the workflow — triage,
127
94
  > decomposition, dispatch briefs, synthesis, review-loop verdicts — flows
@@ -139,7 +106,7 @@ To enable TeamMode in every project, add the plugin to your global config:
139
106
  {
140
107
  "$schema": "https://opencode.ai/config.json",
141
108
  "plugin": [
142
- "@te-river/opencode-team-mode@1.4.9"
109
+ "@te-river/opencode-team-mode@latest"
143
110
  ]
144
111
  }
145
112
  ```
@@ -251,6 +218,139 @@ In **OpenCode Desktop**, you get additional UX benefits:
251
218
 
252
219
  ---
253
220
 
221
+ ## 🧯 Context governance (tm_* + R6 + R2) — new in v1.5.1
222
+
223
+ > ⚠️ Requires `@te-river/opencode-team-mode@1.5.1` or later (released
224
+ > 2026-09-08). If your config pins `@latest`, OpenCode upgrades on next start.
225
+
226
+ **JIT layer-2 tools (`tm_read` / `tm_grep` / `tm_bash` / `tm_fetch`).**
227
+ Large tool outputs are context cost's main driver: every step re-sends the
228
+ whole window. The tm_* tools run the built-in capability under governance
229
+ first: results above `TM_OFFLOAD_THRESHOLD` tokens never enter the window —
230
+ they are written to a local run store and replaced by a handle with a
231
+ content-aware preview (JSON keys / CSV header+shape / log ERROR×N stats /
232
+ code signatures / binary metadata, hard-capped at 80 tokens). When the agent
233
+ actually needs the payload it pages through it with `tm_fetch`, using an
234
+ HMAC-signed, run-scoped, expiring handle. `tm_bash` only allows read-only
235
+ commands (allowlist), and failures come back as structured errors instead of
236
+ raw dumps.
237
+
238
+ **R6 environment protection (now an approval gate).** With TeamMode active,
239
+ the model cannot read environment variables silently. Env-var reads
240
+ (`printenv`, `env`, `Get-ChildItem env:`, …) and env files (`.env`, shell rc
241
+ files) route through OpenCode's **official confirmation dialog**: you get a
242
+ native prompt to approve or deny, and an unanswered prompt is **auto-rejected
243
+ after `TM_ASK_TIMEOUT_MIN` (default 10 min)** — the plugin only ever rejects
244
+ on timeout, never approves on the model's behalf. Env reads that no wildcard
245
+ can express (embedded `$VAR` / `${VAR}` / `$env:` inside another command,
246
+ command substitution, subshell/escaped forms) and the `tm_*` wrapper channel
247
+ stay a **hard block** (no dialog to slip through). tm_* wrappers route through
248
+ the same checks (no backdoor via the wrappers). Audit lines record only tool
249
+ name + pattern category + the verdict (`ask` / `allowed-once` /
250
+ `allowed-always` / `rejected` / `timeout-rejected` / `degraded`) — never
251
+ command text, paths, variable names or values.
252
+
253
+ **R2 dangerous operations (same dialog).** Delete (`rm`/`del`/`Remove-Item`/
254
+ `rmdir`), git publishing (`git push`/`git commit`), network fetch (`curl`/
255
+ `wget`/`Invoke-WebRequest`/`Invoke-RestMethod`), package installs/publishes
256
+ (`npm install`/`npm publish`/`pip install`/`winget`/`choco`), process/system
257
+ (`taskkill`/`Stop-Process`/`kill`/`shutdown`/`format`) and privilege changes
258
+ (`chmod`/`takeown`/`icacls`) — none are silently allowed. They pop the same
259
+ official dialog and are auto-rejected if you don't answer within the timeout.
260
+ The normal verification stack (`npm test`, `tsc`, `git status`/`diff`) is NOT
261
+ gated, so day-to-day team work runs without interruption.
262
+
263
+ > ⚠️ **When you approve a dialog, pick "once" — not "always".** Verified on
264
+ > the live host, "always" records a far broader rule than the command you
265
+ > saw: approving `Get-ChildItem env:PATH` with "always" stores `Get-ChildItem
266
+ > *`, so every later `Get-ChildItem` runs with no dialog at all. Only the
267
+ > once-verdict keeps each gated operation individually human-checked.
268
+
269
+ > Deferral is per-session: env reads only route to the dialog in sessions
270
+ > running TeamMode's injected agents (or after such a session has shown one
271
+ > of these dialogs). In any other session (e.g. a stock `build`/`plan` chat)
272
+ > TeamMode's guard keeps hard-blocking env reads, since no dialog would back
273
+ > them there. Compound commands (`a; b`) are evaluated per segment by the
274
+ > host and approved through one dialog; the guard blocks them outright
275
+ > whenever any segment is an env read.
276
+
277
+ > The permission protocol was verified against a live `opencode serve` host
278
+ > (1.18.29) via SSE event capture; the Desktop dialog rendering itself is the
279
+ > one leg that still needs eyeballing in a real Desktop session. Headless
280
+ > `opencode run` auto-rejects an unanswered `ask` immediately (there is no
281
+ > human to prompt).
282
+
283
+ | Env var | Default | Purpose |
284
+ |---|---|---|
285
+ | `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` (off also disarms the approval timer) |
286
+ | `TM_ASK_TIMEOUT_MIN` | `10` | minutes before an unanswered R6/R2 confirmation dialog is auto-rejected; minimum 3 minutes (the host's `permission.replied` reaches the plugin ~120 s late on the event bus — shorter values would auto-reject a just-approved request) |
287
+ | `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex list; always a hard block, never dialog-governed) |
288
+ | `TM_OFFLOAD_THRESHOLD` | `2000` | offload threshold (tokens, chars/4 estimate) |
289
+ | `TM_PREVIEW_MAX_TOKENS` | `80` | preview hard cap |
290
+ | `TM_FETCH_MAX_LINES` | `2000` | tm_fetch page cap |
291
+ | `TM_BLACKBOARD_DIR` | `.blackboard/` | offloaded payload store |
292
+ | `TM_TRAJECTORY_DIR` | `.trajectory/` | append-only tool-call ledger |
293
+ | `TM_BLACKBOARD_TTL` | `7` | store retention (days) |
294
+ | `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
295
+ | `TM_PTC_MAX_PROGRAM_CHARS` | `4000` | PTC program source length cap (chars) |
296
+ | `TM_PTC_MAX_CALLS` | `20` | PTC per-run bridge-call budget (1–200) |
297
+ | `TM_PTC_MAX_ERRORS` | `3` | PTC per-run error budget (1–50) |
298
+ | `TM_PTC_TIMEOUT_MS` | `60000` | PTC per-run wall-clock timeout (5s–10min) |
299
+ | `TM_PTC_ENGINE` | `auto` | PTC engine: `auto` (worker→inline degrade) / `worker` / `inline` |
300
+
301
+ ---
302
+
303
+ ## ⚡ Batch orchestration (`tm_ptc_run`) — new in v1.5.2
304
+
305
+ > Shipped in **v1.5.2** (2026-09-10). Requires `@te-river/opencode-team-mode@1.5.2`
306
+ > or later.
307
+
308
+ `tm_ptc_run` lets a specialist agent write **one async program** that makes N
309
+ governed `tm_*` calls in a single turn — zero LLM round-trips during the run,
310
+ only an aggregation summary returns to context. It is designed for batch
311
+ read-only tasks: multi-file reconnaissance, bulk grep + read aggregation,
312
+ cross-referencing search results.
313
+
314
+ ### How it works
315
+
316
+ The agent writes a program body using `tm.read(args)`, `tm.grep(args)`,
317
+ `tm.bash(args)`, `tm.fetch(args)` — same args as the four governed tools.
318
+ Each call returns `{ok:true, data}` (governed: inline text or an offload
319
+ handle) or `{ok:false, error:{tool,phase,line?,message}}`. The program
320
+ `return`s a value; it is JSON-serialized into the aggregation summary.
321
+
322
+ Programs containing `require`, `import`, `process`, `globalThis`, `Deno`,
323
+ `Bun`, `fs`, `net`, or `child_process` are rejected before execution (static
324
+ pre-scan, auxiliary guard).
325
+
326
+ ### Budgets (tighten-only)
327
+
328
+ The caller may tighten `max_calls`, `max_errors`, and `timeout_ms` — values
329
+ above the `TM_PTC_*` ceilings are clamped down; values below the floor are
330
+ clamped up. Hitting any budget stops the whole run; produced output is NOT
331
+ lost.
332
+
333
+ ### Engine (`TM_PTC_ENGINE`)
334
+
335
+ | Mode | Behavior |
336
+ |---|---|
337
+ | `auto` (default) | Tries `worker_threads` first; on failure degrades to `node:vm` with a `degraded-engine` mark in the summary |
338
+ | `worker` | Forces the worker engine (engine-error on failure) |
339
+ | `inline` | Forces the `node:vm` engine (30s compile timeout for sync busy-loops; await-gap residual documented) |
340
+
341
+ The worker engine runs the program in a dedicated thread with `env:{}`
342
+ (process.env emptied), `resourceLimits`, and hard wall-clock `terminate()`.
343
+ All governance (P2 path scope, P3 allowlist, R6, threshold offload, TTL)
344
+ applies to every bridged call — PTC is not a bypass layer.
345
+
346
+ ### Access
347
+
348
+ Five specialist agents (`implementer`, `tester`, `architect`, `reviewer`,
349
+ `researcher`) have `tm_ptc_run` in their whitelist. The `team` lead does
350
+ not — it orchestrates, it does not run batch programs itself.
351
+
352
+ ---
353
+
254
354
  ## 🏗️ Architecture
255
355
 
256
356
  ```
@@ -258,14 +358,18 @@ opencode-team-mode/
258
358
  ├── package.json ← npm package definition
259
359
  ├── tsconfig.json ← TypeScript config
260
360
  ├── src/
261
- │ ├── index.ts ← Plugin entry (server() + config hook, id: "team-mode")
361
+ │ ├── index.ts ← Plugin entry (server(): config + R6 tool.execute.before + approval-gate event + tool segment)
262
362
  │ ├── agents.ts ← Agent definitions (prompts, modes, colors)
263
363
  │ ├── commands.ts ← Command definitions (templates, agent bindings)
264
364
  │ ├── blackboard.ts ← Shared blackboard + TTL auto-cleanup sweeper
365
+ │ ├── envprotect.ts ← R6 env-var read protection + R2 ask-pattern sets (dialog vs hard-block)
366
+ │ ├── approval-gate.ts ← Unified approval gate: host-dialog timeout auto-reject (never self-allows)
367
+ │ ├── tm/ ← JIT layer-2 tools (tm_read / tm_grep / tm_bash / tm_fetch / tm_ptc_run)
265
368
  │ └── types.ts ← Loader-contract type definitions (1.18.x)
266
369
  ├── scripts/
267
370
  │ ├── install.sh ← One-click installer (bash)
268
371
  │ └── install.ps1 ← One-click installer (PowerShell)
372
+ ├── pt07/ ← PT-07 baseline suite (seeded A/B token measurement)
269
373
  ├── LICENSE ← Apache 2.0
270
374
  ├── README.md ← English documentation
271
375
  └── README.zh-CN.md ← Chinese documentation
@@ -274,8 +378,8 @@ opencode-team-mode/
274
378
  ### How it works
275
379
 
276
380
  1. OpenCode Desktop starts and loads `opencode.json(c)`.
277
- 2. It sees `"@te-river/opencode-team-mode@1.4.9"` in the `plugin` array and loads the npm package.
278
- 3. The loader calls the plugin's `server(input, options)`, which registers a `config` hook; the hook injects 6 agents and 6 commands into the merged config.
381
+ 2. It sees `"@te-river/opencode-team-mode@latest"` in the `plugin` array and loads the npm package.
382
+ 3. The loader calls the plugin's `server(input, options)`, which registers a `config` hook; the hook injects 6 agents and 6 commands into the merged config. The same call installs the R6 `tool.execute.before` guard, arms the unified R6/R2 approval gate (official dialog + `TM_ASK_TIMEOUT_MIN` auto-reject, wired through an `event` hook), and registers the governed `tm_*` tools (see [Context governance](#-context-governance-tm--r6--r2--new-in-v151) below).
279
383
  4. The plugin's `id: "team-mode"` is displayed as the plugin name in the Desktop UI.
280
384
  5. Agents and commands are immediately available in the Desktop UI — no file copying needed. User-defined agents with the same name always win (the plugin never clobbers them).
281
385
 
@@ -381,7 +485,7 @@ Default is **5 days**. To choose your own, use the tuple plugin form in
381
485
  {
382
486
  "$schema": "https://opencode.ai/config.json",
383
487
  "plugin": [
384
- ["@te-river/opencode-team-mode@1.4.9", { "ttlDays": 7 }]
488
+ ["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
385
489
  ]
386
490
  }
387
491
  ```
@@ -405,7 +509,7 @@ team**):
405
509
  ```jsonc
406
510
  {
407
511
  "plugin": [
408
- ["@te-river/opencode-team-mode@1.4.9", { "defaultAgent": false }]
512
+ ["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
409
513
  ]
410
514
  }
411
515
  ```
package/README.zh-CN.md CHANGED
@@ -55,73 +55,40 @@ TeamMode 将 OpenCode 桌面版从一个单 Agent 编码助手,升级为**一
55
55
 
56
56
  ### 安装 TeamMode
57
57
 
58
- **方式 A — 一键安装脚本(推荐):**
58
+ **方式 A — 一键安装脚本:**
59
59
 
60
60
  macOS / Linux(bash):
61
61
  ```bash
62
- curl -fsSL "https://gh-proxy.com/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh" | bash
62
+ curl -fsSL https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
63
63
  ```
64
64
 
65
65
  Windows(PowerShell):
66
66
  ```powershell
67
- irm "https://gh-proxy.com/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1" | iex
67
+ irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
68
68
  ```
69
69
 
70
- 如果 gh-proxy 不可用,尝试 jsdelivr 或 GitHub 原始地址:
71
- ```bash
72
- # macOS / Linux — jsdelivr
73
- curl -fsSL "https://cdn.jsdelivr.net/gh/Te-River/Opencode-TeamMode@main/scripts/install.sh" | bash
74
-
75
- # Windows — jsdelivr
76
- irm "https://cdn.jsdelivr.net/gh/Te-River/Opencode-TeamMode@main/scripts/install.ps1" | iex
77
-
78
- # macOS / Linux — GitHub 原始地址
79
- curl -fsSL https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
80
-
81
- # Windows — GitHub 原始地址
82
- irm https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
83
- ```
84
-
85
- 脚本会自动安装 npm 包,并将插件注册到你的 `opencode.jsonc` 中。
70
+ **方式 B — 手动配置:**
86
71
 
87
- **方式 B — 手动 npm 安装:**
88
-
89
- ```bash
90
- # 1. 安装插件包
91
- npm install -g @te-river/opencode-team-mode
92
-
93
- # 2. 将插件添加到 opencode.jsonc
94
- # (见下方"配置"章节)
95
- ```
96
-
97
- **方式 C — 本地开发安装(从本仓库):**
98
-
99
- ```bash
100
- git clone https://github.com/Te-River/Opencode-TeamMode.git
101
- cd Opencode-TeamMode
102
- npm install
103
- npm run build
104
- npm link
105
- ```
106
-
107
- ---
108
-
109
- ## ⚙️ 配置
110
-
111
- 安装后,将插件添加到你的 `opencode.jsonc`:
72
+ 在你的 `opencode.jsonc` 中添加插件:
112
73
 
113
74
  ```jsonc
114
75
  {
115
76
  "$schema": "https://opencode.ai/config.json",
116
77
  "plugin": [
117
- "@te-river/opencode-team-mode@1.4.9"
78
+ "@te-river/opencode-team-mode@latest"
118
79
  ]
119
80
  }
120
81
  ```
121
82
 
122
- 就这么简单。插件会在 OpenCode 启动时自动注入所有团队 Agent 和命令,**无需手动复制任何 Agent 文件或命令定义**。
83
+ OpenCode 启动时会自动安装插件。
84
+
85
+ > **提示:** 修改 `opencode.json` 后,**重启 OpenCode Desktop** 使配置生效。
123
86
 
124
- > 💡 **提示:** 修改 `opencode.json` 后,请**重启 OpenCode 桌面版**使更改生效。
87
+ ---
88
+
89
+ ## ⚙️ 配置
90
+
91
+ 插件会在 OpenCode 启动时自动注入所有团队 Agent 和命令,**无需手动复制任何 Agent 文件或命令定义**。
125
92
 
126
93
  > ⚠️ **模型选择很重要。** 工作流里的每一个判断——分诊、拆解、派单、
127
94
  > 整合、审查/测试闭环裁决——都经过 **Team Lead**。这个位置上放弱模型,
@@ -137,7 +104,7 @@ npm link
137
104
  {
138
105
  "$schema": "https://opencode.ai/config.json",
139
106
  "plugin": [
140
- "@te-river/opencode-team-mode@1.4.9"
107
+ "@te-river/opencode-team-mode@latest"
141
108
  ]
142
109
  }
143
110
  ```
@@ -246,6 +213,119 @@ team 完成。
246
213
 
247
214
  ---
248
215
 
216
+ ## 🧯 上下文治理(tm_* + R6 + R2)—— v1.5.1 起提供
217
+
218
+ > ⚠️ 需 `@te-river/opencode-team-mode@1.5.1` 或更新(2026-09-08 发布)。
219
+ > 配置里钉 `@latest` 的用户,下次启动自动升级。
220
+
221
+ **JIT 层 2 工具(`tm_read` / `tm_grep` / `tm_bash` / `tm_fetch`)。**
222
+ 大体积工具输出是上下文成本的主要来源:智能体每走一步都要重发整个窗口。
223
+ tm_* 工具先用受治理的管线执行内置能力:超过 `TM_OFFLOAD_THRESHOLD`
224
+ token 的结果**不进窗口**——全量写入本地 run 存储,模型只拿一张句柄
225
+ “提货单”,附内容感知预览(JSON 键结构 / CSV 表头+形状 / 日志
226
+ ERROR×N 统计 / 代码签名清单 / 二进制元信息,硬上限 80 token)。
227
+ 确实需要全文时,用 HMAC 签名、限本 run、带有效期的句柄经 `tm_fetch`
228
+ 分段取回。`tm_bash` 仅放行只读命令白名单,失败以结构化错误返回。
229
+
230
+ **R6 环境变量保护(现已升级为审批门控)。** TeamMode 激活时,模型无法
231
+ 静默读取环境变量。env 导出命令(`printenv`、`env`、`Get-ChildItem env:`
232
+ 等)与环境文件(`.env`、shell rc 文件)会走 OpenCode **官方确认弹窗**:
233
+ 你会在桌面收到一次原生确认,超过 `TM_ASK_TIMEOUT_MIN`(默认 10 分钟)
234
+ 无人响应即**自动拒绝**——插件超时只会拒绝,绝不为模型自我放行。通配符
235
+ 表达不了的形态(命令里内嵌的 `$VAR` / `${VAR}` / `$env:`、命令替换、
236
+ 子 shell/转义写法)以及 `tm_*` 包装通道仍维持**代码级硬拦**(没有弹窗
237
+ 可钻)。tm_* 包装工具同样过这套检查(不给包装层留后门)。审计日志只记
238
+ 工具名 + 模式类别 + 裁决事件(`ask` / `allowed-once` / `allowed-always` /
239
+ `rejected` / `timeout-rejected` / `degraded`)——绝不记录命令文本、路径、
240
+ 变量名或值。
241
+
242
+ **R2 危险操作(同一个确认弹窗)。** 删除(`rm`/`del`/`Remove-Item`/
243
+ `rmdir`)、git 发布(`git push`/`git commit`)、网络(`curl`/`wget`/
244
+ `Invoke-WebRequest`/`Invoke-RestMethod`)、包安装与发布(`npm install`/
245
+ `npm publish`/`pip install`/`winget`/`choco`)、进程/系统(`taskkill`/
246
+ `Stop-Process`/`kill`/`shutdown`/`format`)、权限(`chmod`/`takeown`/
247
+ `icacls`)——都不再静默放行,而是弹同一个官方确认框,超时未响应即自动
248
+ 拒绝。日常验证栈(`npm test`、`tsc`、`git status`/`diff`)**不在**门控
249
+ 之列,团队协作照常无打扰运行。
250
+
251
+ > ⚠️ **批准弹窗时请选 once(仅此一次),不要选 always。** 真实宿主实测:
252
+ > always 记录的泛化规则远比当次命令宽——对 `Get-ChildItem env:PATH` 选
253
+ > always 会记下 `Get-ChildItem *`,此后所有 `Get-ChildItem` 都不再弹窗。
254
+ > 只有 once 能让每次危险操作继续单独过人手。
255
+
256
+ > 延后是**按会话**生效的:只有运行 TeamMode 注入角色的会话(或已弹过这类
257
+ > 确认框的会话)里的 env 读取才会被放行给弹窗;其他会话(如原生
258
+ > `build`/`plan`)里守护仍然直接硬拦——那里根本没有弹窗兜底。宿主对复合
259
+ > 命令(`a; b`)按段评估、单次弹窗批准整条;任一子段是 env 读取时守护整条
260
+ > 拦截。
261
+
262
+ > 权限协议已在真实 `opencode serve` 宿主(1.18.29)上经 SSE 事件捕获实测
263
+ > 核验;桌面弹窗的渲染本身仍需在真实 Desktop 会话里目视确认一次。非交互
264
+ > `opencode run` 下,无人应答的 `ask` 会被立即自动拒绝(没有人类可弹)。
265
+
266
+ | 环境变量 | 默认 | 作用 |
267
+ |---|---|---|
268
+ | `TM_ENV_PROTECT` | `strict` | R6 模式:`strict` / `standard` / `off`(off 同时解除审批计时器) |
269
+ | `TM_ASK_TIMEOUT_MIN` | `10` | R6/R2 确认弹窗无人应答后自动拒绝的分钟数;最小 3 分钟(宿主的 `permission.replied` 经事件总线到达插件约延迟 ~120 秒——更小的值会把刚获批的请求误拒) |
270
+ | `TM_ENV_PROTECT_EXTRA_DENY` | — | 追加拦截正则(分号分隔;始终硬拦,不走弹窗) |
271
+ | `TM_OFFLOAD_THRESHOLD` | `2000` | 卸载阈值(token,chars/4 估算) |
272
+ | `TM_PREVIEW_MAX_TOKENS` | `80` | 预览硬上限 |
273
+ | `TM_FETCH_MAX_LINES` | `2000` | tm_fetch 单段上限 |
274
+ | `TM_BLACKBOARD_DIR` | `.blackboard/` | 卸载载荷存储 |
275
+ | `TM_TRAJECTORY_DIR` | `.trajectory/` | 只追加工具调用账本 |
276
+ | `TM_BLACKBOARD_TTL` | `7` | 存储保留天数 |
277
+ | `TM_BASH_READONLY_ALLOWED` | 内置表 | tm_bash 只读白名单 |
278
+ | `TM_PTC_MAX_PROGRAM_CHARS` | `4000` | PTC 程序源码长度上限(字符) |
279
+ | `TM_PTC_MAX_CALLS` | `20` | PTC 单次运行桥接调用数上限(1–200) |
280
+ | `TM_PTC_MAX_ERRORS` | `3` | PTC 单次运行错误数上限(1–50) |
281
+ | `TM_PTC_TIMEOUT_MS` | `60000` | PTC 单次运行墙钟超时(5 秒–10 分钟) |
282
+ | `TM_PTC_ENGINE` | `auto` | PTC 引擎:`auto`(worker→inline 降级)/ `worker` / `inline` |
283
+
284
+ ---
285
+
286
+ ## ⚡ 批量编排(`tm_ptc_run`)—— v1.5.2 起提供
287
+
288
+ > 已随 **v1.5.2**(2026-09-10)发布。需 `@te-river/opencode-team-mode@1.5.2` 或更新。
289
+
290
+ `tm_ptc_run` 让专家代理编写**一个异步程序**,在单次回合中执行 N 次受治理的
291
+ `tm_*` 调用——运行期间零 LLM 往返,仅将聚合摘要返回上下文。设计用于批量
292
+ 只读任务:多文件侦察、批量 grep + read 聚合、交叉引用搜索结果。
293
+
294
+ ### 工作原理
295
+
296
+ 代理使用 `tm.read(args)`、`tm.grep(args)`、`tm.bash(args)`、`tm.fetch(args)`
297
+ 编写程序体——参数与四个受治理工具相同。每次调用返回 `{ok:true, data}`(已受
298
+ 治理:内联文本或卸载句柄)或 `{ok:false, error:{tool,phase,line?,message}}`。
299
+ 程序 `return` 一个值;它会被 JSON 序列化进聚合摘要。
300
+
301
+ 包含 `require`、`import`、`process`、`globalThis`、`Deno`、`Bun`、`fs`、`net`
302
+ 或 `child_process` 的程序会在执行前被拒绝(静态预扫描,辅助防护)。
303
+
304
+ ### 预算(仅收紧)
305
+
306
+ 调用方可收紧 `max_calls`、`max_errors` 和 `timeout_ms`——超过 `TM_PTC_*` 上限
307
+ 的值会被钳制到上限;低于下限的值会被钳制到下限。触达任一预算即整体停止运行;
308
+ 已产出的输出不会丢失。
309
+
310
+ ### 引擎(`TM_PTC_ENGINE`)
311
+
312
+ | 模式 | 行为 |
313
+ |---|---|
314
+ | `auto`(默认) | 优先尝试 `worker_threads`;失败时降级为 `node:vm`,摘要标记 `degraded-engine` |
315
+ | `worker` | 强制使用 worker 引擎(失败时返回 engine-error) |
316
+ | `inline` | 强制使用 `node:vm` 引擎(30 秒编译超时斩杀同步忙等;await 间隙残余已记录) |
317
+
318
+ worker 引擎在专用线程中运行程序,`env:{}` 清空 process.env、`resourceLimits`
319
+ 限量、硬墙钟 `terminate()`。所有治理(P2 路径范围、P3 白名单、R6、阈值卸载、
320
+ TTL)对每次桥接调用生效——PTC 不是绕过层。
321
+
322
+ ### 访问权限
323
+
324
+ 五个专家代理(`implementer`、`tester`、`architect`、`reviewer`、`researcher`)
325
+ 的白名单中包含 `tm_ptc_run`。`team` lead 不包含——它负责编排,不运行批量程序。
326
+
327
+ ---
328
+
249
329
  ## 🏗️ 架构
250
330
 
251
331
  ```
@@ -253,14 +333,18 @@ opencode-team-mode/
253
333
  ├── package.json ← npm 包定义
254
334
  ├── tsconfig.json ← TypeScript 配置
255
335
  ├── src/
256
- │ ├── index.ts ← 插件入口(server() + config hook,id: "team-mode")
336
+ │ ├── index.ts ← 插件入口(server():config + R6 tool.execute.before + 审批门 event 钩子 + tool 段)
257
337
  │ ├── agents.ts ← Agent 定义(prompts、模式、颜色)
258
338
  │ ├── commands.ts ← 命令定义(模板、Agent 绑定)
259
339
  │ ├── blackboard.ts ← 共享黑板 + TTL 自动清理清扫器
340
+ │ ├── envprotect.ts ← R6 环境变量读取保护 + R2 确认弹窗模式集(弹窗 vs 硬拦)
341
+ │ ├── approval-gate.ts ← 统一审批门:官方弹窗超时自动拒绝(绝不自我放行)
342
+ │ ├── tm/ ← JIT 层 2 工具(tm_read / tm_grep / tm_bash / tm_fetch / tm_ptc_run)
260
343
  │ └── types.ts ← 加载器契约类型定义(1.18.x)
261
344
  ├── scripts/
262
345
  │ ├── install.sh ← 一键安装脚本(bash)
263
346
  │ └── install.ps1 ← 一键安装脚本(PowerShell)
347
+ ├── pt07/ ← PT-07 基线任务集(种子化 A/B token 测量)
264
348
  ├── LICENSE ← Apache 2.0
265
349
  └── README.md ← 英文文档
266
350
  README.zh-CN.md ← 中文文档
@@ -269,8 +353,8 @@ opencode-team-mode/
269
353
  ### 工作原理
270
354
 
271
355
  1. OpenCode 桌面版启动,加载 `opencode.json(c)`
272
- 2. 检测到 `plugin` 数组中的 `"@te-river/opencode-team-mode@1.4.9"`,加载 npm 包
273
- 3. 加载器调用插件的 `server(input, options)`,注册 `config` hook;hook 向合并后的配置注入 6 个 Agent 和 6 个命令
356
+ 2. 检测到 `plugin` 数组中的 `"@te-river/opencode-team-mode@latest"`,加载 npm 包
357
+ 3. 加载器调用插件的 `server(input, options)`,注册 `config` hook;hook 向合并后的配置注入 6 个 Agent 和 6 个命令。同一次调用还会安装 R6 的 `tool.execute.before` 防护、武装 R6/R2 统一审批门(官方确认弹窗 + `TM_ASK_TIMEOUT_MIN` 超时自动拒绝,经 `event` 钩子驱动),并注册受治理的 `tm_*` 工具(见下文“上下文治理”)
274
358
  4. 插件的 `id: "team-mode"` 作为插件名显示在桌面版 UI
275
359
  5. Agent 和命令立即在桌面版 UI 中可用 —— 无需复制任何文件;同名 Agent 以用户自定义优先(插件绝不覆盖)
276
360
 
@@ -353,7 +437,7 @@ Team Lead 不再删除任务目录 —— 跑完的黑板原地留给你回看
353
437
  {
354
438
  "$schema": "https://opencode.ai/config.json",
355
439
  "plugin": [
356
- ["@te-river/opencode-team-mode@1.4.9", { "ttlDays": 7 }]
440
+ ["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
357
441
  ]
358
442
  }
359
443
  ```
@@ -372,7 +456,7 @@ TeamMode 默认**把 Team 设为你的默认代理**——新会话直接由团
372
456
  ```jsonc
373
457
  {
374
458
  "plugin": [
375
- ["@te-river/opencode-team-mode@1.4.9", { "defaultAgent": false }]
459
+ ["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
376
460
  ]
377
461
  }
378
462
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA0iB7C,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAO9C,CAAA"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAA;AAqpB9D,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAO9C,CAAA"}