@te-river/opencode-team-mode 1.5.0 → 1.5.1
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 +62 -53
- package/README.zh-CN.md +58 -53
- package/dist/envprotect.d.ts +123 -0
- package/dist/envprotect.d.ts.map +1 -0
- package/dist/envprotect.js +467 -0
- package/dist/envprotect.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/tm/config.d.ts +71 -0
- package/dist/tm/config.d.ts.map +1 -0
- package/dist/tm/config.js +97 -0
- package/dist/tm/config.js.map +1 -0
- package/dist/tm/guard.d.ts +56 -0
- package/dist/tm/guard.d.ts.map +1 -0
- package/dist/tm/guard.js +249 -0
- package/dist/tm/guard.js.map +1 -0
- package/dist/tm/index.d.ts +39 -0
- package/dist/tm/index.d.ts.map +1 -0
- package/dist/tm/index.js +63 -0
- package/dist/tm/index.js.map +1 -0
- package/dist/tm/preview.d.ts +46 -0
- package/dist/tm/preview.d.ts.map +1 -0
- package/dist/tm/preview.js +354 -0
- package/dist/tm/preview.js.map +1 -0
- package/dist/tm/refs.d.ts +37 -0
- package/dist/tm/refs.d.ts.map +1 -0
- package/dist/tm/refs.js +58 -0
- package/dist/tm/refs.js.map +1 -0
- package/dist/tm/store.d.ts +95 -0
- package/dist/tm/store.d.ts.map +1 -0
- package/dist/tm/store.js +222 -0
- package/dist/tm/store.js.map +1 -0
- package/dist/tm/tools.d.ts +68 -0
- package/dist/tm/tools.d.ts.map +1 -0
- package/dist/tm/tools.js +706 -0
- package/dist/tm/tools.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -1
- 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
|
|
58
|
+
**Option A — One-line installer:**
|
|
59
59
|
|
|
60
60
|
macOS / Linux (bash):
|
|
61
61
|
```bash
|
|
62
|
-
curl -fsSL
|
|
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
|
|
67
|
+
irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
|
|
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`.
|
|
86
|
-
|
|
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
|
-
---
|
|
70
|
+
**Option B — Manual config:**
|
|
108
71
|
|
|
109
|
-
|
|
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@
|
|
78
|
+
"@te-river/opencode-team-mode@latest"
|
|
118
79
|
]
|
|
119
80
|
}
|
|
120
81
|
```
|
|
121
82
|
|
|
122
|
-
|
|
83
|
+
OpenCode will automatically install the plugin on startup.
|
|
84
|
+
|
|
85
|
+
> **Tip:** After modifying `opencode.json`, **restart OpenCode Desktop** for changes to take effect.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚙️ Configuration
|
|
123
90
|
|
|
124
|
-
|
|
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@
|
|
109
|
+
"@te-river/opencode-team-mode@latest"
|
|
143
110
|
]
|
|
144
111
|
}
|
|
145
112
|
```
|
|
@@ -251,6 +218,45 @@ In **OpenCode Desktop**, you get additional UX benefits:
|
|
|
251
218
|
|
|
252
219
|
---
|
|
253
220
|
|
|
221
|
+
## 🧯 Context governance (tm_* + R6) — 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.** With TeamMode active, env-var reads by the
|
|
239
|
+
model are blocked at the tool layer: env dump commands (`printenv`,
|
|
240
|
+
`Get-ChildItem env:`, …), `$env:` / `$VAR` / `${VAR}` expansions, and env
|
|
241
|
+
files (`.env`, shell rc files). The model sees a structured refusal and can
|
|
242
|
+
ask the human instead; tm_* wrappers route through the same checks (no
|
|
243
|
+
backdoor via the wrappers). Audit lines record only tool name + pattern
|
|
244
|
+
category — never command text, paths, variable names or values.
|
|
245
|
+
|
|
246
|
+
| Env var | Default | Purpose |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` |
|
|
249
|
+
| `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex list) |
|
|
250
|
+
| `TM_OFFLOAD_THRESHOLD` | `2000` | offload threshold (tokens, chars/4 estimate) |
|
|
251
|
+
| `TM_PREVIEW_MAX_TOKENS` | `80` | preview hard cap |
|
|
252
|
+
| `TM_FETCH_MAX_LINES` | `2000` | tm_fetch page cap |
|
|
253
|
+
| `TM_BLACKBOARD_DIR` | `.blackboard/` | offloaded payload store |
|
|
254
|
+
| `TM_TRAJECTORY_DIR` | `.trajectory/` | append-only tool-call ledger |
|
|
255
|
+
| `TM_BLACKBOARD_TTL` | `7` | store retention (days) |
|
|
256
|
+
| `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
254
260
|
## 🏗️ Architecture
|
|
255
261
|
|
|
256
262
|
```
|
|
@@ -258,14 +264,17 @@ opencode-team-mode/
|
|
|
258
264
|
├── package.json ← npm package definition
|
|
259
265
|
├── tsconfig.json ← TypeScript config
|
|
260
266
|
├── src/
|
|
261
|
-
│ ├── index.ts ← Plugin entry (server() +
|
|
267
|
+
│ ├── index.ts ← Plugin entry (server(): config + R6 tool.execute.before + tool segment)
|
|
262
268
|
│ ├── agents.ts ← Agent definitions (prompts, modes, colors)
|
|
263
269
|
│ ├── commands.ts ← Command definitions (templates, agent bindings)
|
|
264
270
|
│ ├── blackboard.ts ← Shared blackboard + TTL auto-cleanup sweeper
|
|
271
|
+
│ ├── envprotect.ts ← R6 env-var read protection (pattern engine + hook)
|
|
272
|
+
│ ├── tm/ ← JIT layer-2 tools (tm_read / tm_grep / tm_bash / tm_fetch)
|
|
265
273
|
│ └── types.ts ← Loader-contract type definitions (1.18.x)
|
|
266
274
|
├── scripts/
|
|
267
275
|
│ ├── install.sh ← One-click installer (bash)
|
|
268
276
|
│ └── install.ps1 ← One-click installer (PowerShell)
|
|
277
|
+
├── pt07/ ← PT-07 baseline suite (seeded A/B token measurement)
|
|
269
278
|
├── LICENSE ← Apache 2.0
|
|
270
279
|
├── README.md ← English documentation
|
|
271
280
|
└── README.zh-CN.md ← Chinese documentation
|
|
@@ -274,8 +283,8 @@ opencode-team-mode/
|
|
|
274
283
|
### How it works
|
|
275
284
|
|
|
276
285
|
1. OpenCode Desktop starts and loads `opencode.json(c)`.
|
|
277
|
-
2. It sees `"@te-river/opencode-team-mode@
|
|
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.
|
|
286
|
+
2. It sees `"@te-river/opencode-team-mode@latest"` in the `plugin` array and loads the npm package.
|
|
287
|
+
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 and registers the governed `tm_*` tools (see [Context governance](#-context-governance-tm--r6--new-in-v151) below).
|
|
279
288
|
4. The plugin's `id: "team-mode"` is displayed as the plugin name in the Desktop UI.
|
|
280
289
|
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
290
|
|
|
@@ -381,7 +390,7 @@ Default is **5 days**. To choose your own, use the tuple plugin form in
|
|
|
381
390
|
{
|
|
382
391
|
"$schema": "https://opencode.ai/config.json",
|
|
383
392
|
"plugin": [
|
|
384
|
-
["@te-river/opencode-team-mode@
|
|
393
|
+
["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
|
|
385
394
|
]
|
|
386
395
|
}
|
|
387
396
|
```
|
|
@@ -405,7 +414,7 @@ team**):
|
|
|
405
414
|
```jsonc
|
|
406
415
|
{
|
|
407
416
|
"plugin": [
|
|
408
|
-
["@te-river/opencode-team-mode@
|
|
417
|
+
["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
|
|
409
418
|
]
|
|
410
419
|
}
|
|
411
420
|
```
|
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
|
|
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
|
|
67
|
+
irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
|
|
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` 中。
|
|
86
|
-
|
|
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
|
-
## ⚙️ 配置
|
|
70
|
+
**方式 B — 手动配置:**
|
|
110
71
|
|
|
111
|
-
|
|
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@
|
|
78
|
+
"@te-river/opencode-team-mode@latest"
|
|
118
79
|
]
|
|
119
80
|
}
|
|
120
81
|
```
|
|
121
82
|
|
|
122
|
-
|
|
83
|
+
OpenCode 启动时会自动安装插件。
|
|
84
|
+
|
|
85
|
+
> **提示:** 修改 `opencode.json` 后,**重启 OpenCode Desktop** 使配置生效。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚙️ 配置
|
|
123
90
|
|
|
124
|
-
|
|
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@
|
|
107
|
+
"@te-river/opencode-team-mode@latest"
|
|
141
108
|
]
|
|
142
109
|
}
|
|
143
110
|
```
|
|
@@ -246,6 +213,41 @@ team 完成。
|
|
|
246
213
|
|
|
247
214
|
---
|
|
248
215
|
|
|
216
|
+
## 🧯 上下文治理(tm_* + R6)—— 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`、`Get-ChildItem env:` 等)、
|
|
232
|
+
`$env:` / `$VAR` / `${VAR}` 展开、环境文件(`.env`、shell rc 文件)。
|
|
233
|
+
模型收到结构化拒绝提示,需要变量值时向人类申请;tm_* 包装工具同样
|
|
234
|
+
过这套检查(不给包装层留后门)。审计日志只记工具名+模式类别——
|
|
235
|
+
绝不记录命令文本、路径、变量名或值。
|
|
236
|
+
|
|
237
|
+
| 环境变量 | 默认 | 作用 |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| `TM_ENV_PROTECT` | `strict` | R6 模式:`strict` / `standard` / `off` |
|
|
240
|
+
| `TM_ENV_PROTECT_EXTRA_DENY` | — | 追加拦截正则(分号分隔) |
|
|
241
|
+
| `TM_OFFLOAD_THRESHOLD` | `2000` | 卸载阈值(token,chars/4 估算) |
|
|
242
|
+
| `TM_PREVIEW_MAX_TOKENS` | `80` | 预览硬上限 |
|
|
243
|
+
| `TM_FETCH_MAX_LINES` | `2000` | tm_fetch 单段上限 |
|
|
244
|
+
| `TM_BLACKBOARD_DIR` | `.blackboard/` | 卸载载荷存储 |
|
|
245
|
+
| `TM_TRAJECTORY_DIR` | `.trajectory/` | 只追加工具调用账本 |
|
|
246
|
+
| `TM_BLACKBOARD_TTL` | `7` | 存储保留天数 |
|
|
247
|
+
| `TM_BASH_READONLY_ALLOWED` | 内置表 | tm_bash 只读白名单 |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
249
251
|
## 🏗️ 架构
|
|
250
252
|
|
|
251
253
|
```
|
|
@@ -253,14 +255,17 @@ opencode-team-mode/
|
|
|
253
255
|
├── package.json ← npm 包定义
|
|
254
256
|
├── tsconfig.json ← TypeScript 配置
|
|
255
257
|
├── src/
|
|
256
|
-
│ ├── index.ts ← 插件入口(server() +
|
|
258
|
+
│ ├── index.ts ← 插件入口(server():config + R6 tool.execute.before 钩子 + tool 段)
|
|
257
259
|
│ ├── agents.ts ← Agent 定义(prompts、模式、颜色)
|
|
258
260
|
│ ├── commands.ts ← 命令定义(模板、Agent 绑定)
|
|
259
261
|
│ ├── blackboard.ts ← 共享黑板 + TTL 自动清理清扫器
|
|
262
|
+
│ ├── envprotect.ts ← R6 环境变量读取保护(模式引擎 + 钩子)
|
|
263
|
+
│ ├── tm/ ← JIT 层 2 工具(tm_read / tm_grep / tm_bash / tm_fetch)
|
|
260
264
|
│ └── types.ts ← 加载器契约类型定义(1.18.x)
|
|
261
265
|
├── scripts/
|
|
262
266
|
│ ├── install.sh ← 一键安装脚本(bash)
|
|
263
267
|
│ └── install.ps1 ← 一键安装脚本(PowerShell)
|
|
268
|
+
├── pt07/ ← PT-07 基线任务集(种子化 A/B token 测量)
|
|
264
269
|
├── LICENSE ← Apache 2.0
|
|
265
270
|
└── README.md ← 英文文档
|
|
266
271
|
README.zh-CN.md ← 中文文档
|
|
@@ -269,8 +274,8 @@ opencode-team-mode/
|
|
|
269
274
|
### 工作原理
|
|
270
275
|
|
|
271
276
|
1. OpenCode 桌面版启动,加载 `opencode.json(c)`
|
|
272
|
-
2. 检测到 `plugin` 数组中的 `"@te-river/opencode-team-mode@
|
|
273
|
-
3. 加载器调用插件的 `server(input, options)`,注册 `config` hook;hook 向合并后的配置注入 6 个 Agent 和 6
|
|
277
|
+
2. 检测到 `plugin` 数组中的 `"@te-river/opencode-team-mode@latest"`,加载 npm 包
|
|
278
|
+
3. 加载器调用插件的 `server(input, options)`,注册 `config` hook;hook 向合并后的配置注入 6 个 Agent 和 6 个命令。同一次调用还会安装 R6 的 `tool.execute.before` 防护,并注册受治理的 `tm_*` 工具(见下文“上下文治理”)
|
|
274
279
|
4. 插件的 `id: "team-mode"` 作为插件名显示在桌面版 UI
|
|
275
280
|
5. Agent 和命令立即在桌面版 UI 中可用 —— 无需复制任何文件;同名 Agent 以用户自定义优先(插件绝不覆盖)
|
|
276
281
|
|
|
@@ -353,7 +358,7 @@ Team Lead 不再删除任务目录 —— 跑完的黑板原地留给你回看
|
|
|
353
358
|
{
|
|
354
359
|
"$schema": "https://opencode.ai/config.json",
|
|
355
360
|
"plugin": [
|
|
356
|
-
["@te-river/opencode-team-mode@
|
|
361
|
+
["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
|
|
357
362
|
]
|
|
358
363
|
}
|
|
359
364
|
```
|
|
@@ -372,7 +377,7 @@ TeamMode 默认**把 Team 设为你的默认代理**——新会话直接由团
|
|
|
372
377
|
```jsonc
|
|
373
378
|
{
|
|
374
379
|
"plugin": [
|
|
375
|
-
["@te-river/opencode-team-mode@
|
|
380
|
+
["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
|
|
376
381
|
]
|
|
377
382
|
}
|
|
378
383
|
```
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R6 — code-level environment-variable read protection for Team mode.
|
|
3
|
+
*
|
|
4
|
+
* HUMAN-approved feature: in Team mode, EVERY path the model can use to
|
|
5
|
+
* read environment variables / env files is intercepted in code, before
|
|
6
|
+
* the tool runs, independent of prompt compliance. This hook throws inside
|
|
7
|
+
* `tool.execute.before`, which opencode (verified live on 1.18.29) turns
|
|
8
|
+
* into a failed tool call whose error text is returned to the model — so
|
|
9
|
+
* the block is hard, not advisory.
|
|
10
|
+
*
|
|
11
|
+
* Surfaces covered (bash + PowerShell dialects, matched against the bash
|
|
12
|
+
* tool's `args.command`, and against path-class args of the read / grep /
|
|
13
|
+
* glob / list tools):
|
|
14
|
+
* 1. explicit env commands: `env` — a dump whenever no outside command
|
|
15
|
+
* word follows: flags/assignments only (`env -0`, `env -u HOME`,
|
|
16
|
+
* `env FOO=bar`) or a command word that is itself `env`/`printenv`
|
|
17
|
+
* (`env printenv`); a real launcher (`env node app.js`, `env -i node
|
|
18
|
+
* app.js`) passes — `printenv`, bare `set` (sh context only —
|
|
19
|
+
* PowerShell `Set-*` cmdlets are never matched), `declare -p` and
|
|
20
|
+
* its dump synonyms `typeset -p` / `export -p` / `local -p` (flags
|
|
21
|
+
* may be split: `declare -x -p FOO`), and the PowerShell `env:`
|
|
22
|
+
* drive via Get-ChildItem / gci / dir / ls / Get-Item / gi /
|
|
23
|
+
* Get-Content / gc / cat / type (flags and optional quotes allowed
|
|
24
|
+
* between cmdlet and drive: `Get-Content 'env:HOME'`). The same
|
|
25
|
+
* statement heads are caught behind statement noise: subshells and
|
|
26
|
+
* groups (`(env)`, `{ env; }`), escaped commands (`\env`), the `time`
|
|
27
|
+
* keyword prefix, and command substitution (`$(printenv)`, backticks).
|
|
28
|
+
* 2. `$env:` / `${env:...}` expansion (PowerShell);
|
|
29
|
+
* 3. strict mode only: `${VAR}` and `$ALLCAPS_VAR` expansion;
|
|
30
|
+
* 4. env-file paths: `.env`, `.env.*`, `*.env`, `.bashrc`,
|
|
31
|
+
* `.bash_profile`, `.profile`, `.zshrc`, `.zprofile`, `.zshenv`
|
|
32
|
+
* (checked-in template copies like `.env.example` are exempt, and
|
|
33
|
+
* code identifiers like `process.env` are not files).
|
|
34
|
+
*
|
|
35
|
+
* TeamMode's own tm_* tools (tm_read / tm_grep / tm_bash) are aliased onto
|
|
36
|
+
* read/grep/bash in `inspectToolCall`, so this interception covers them
|
|
37
|
+
* identically — the plugin tools can never serve as an R6 bypass.
|
|
38
|
+
*
|
|
39
|
+
* Known limitation (accepted, documented): interpreter execution paths —
|
|
40
|
+
* `bash -c "env"`, `node -e 'process.env'`, `python -c "import os; ..."` —
|
|
41
|
+
* are NOT intercepted; the pattern surface stops at the command line
|
|
42
|
+
* itself. One decode pass covers URL-encoded names (`/%2Eenv`); a double
|
|
43
|
+
* encoding (`/%252Eenv`) and a quoted dump head behind `env`
|
|
44
|
+
* (`env 'printenv'`) stay ahead of the matcher by design.
|
|
45
|
+
*
|
|
46
|
+
* Configuration (read by the PLUGIN at startup — this is program-level
|
|
47
|
+
* configuration of the tool itself, the same category as the ttlDays
|
|
48
|
+
* option below; it is NOT what R6 defends against, which is the MODEL
|
|
49
|
+
* reading environment variables through tool calls at runtime):
|
|
50
|
+
* - `TM_ENV_PROTECT` = "strict" (default) | "standard" | "off";
|
|
51
|
+
* unknown values fail closed into strict.
|
|
52
|
+
* - `TM_ENV_PROTECT_EXTRA_DENY` = semicolon-separated user regexes,
|
|
53
|
+
* applied to every scanned string in any non-off mode.
|
|
54
|
+
*
|
|
55
|
+
* Audit red line (HUMAN privacy constraint): every interception is logged
|
|
56
|
+
* via `client.app.log()` (level "warn", service "team-mode-env-protect")
|
|
57
|
+
* recording ONLY the tool name and the pattern category. Command text,
|
|
58
|
+
* paths, variable names and values are NEVER logged — the audit trail must
|
|
59
|
+
* answer "what class of read was blocked", and must not become a place
|
|
60
|
+
* where secrets accumulate.
|
|
61
|
+
*/
|
|
62
|
+
/** Audit log service identifier (also the query key for "what was blocked"). */
|
|
63
|
+
export declare const ENV_PROTECT_SERVICE = "team-mode-env-protect";
|
|
64
|
+
/**
|
|
65
|
+
* Fixed structured message returned to the model on every block. The
|
|
66
|
+
* category is appended as a machine-readable suffix; tests pin both.
|
|
67
|
+
*/
|
|
68
|
+
export declare const ENV_PROTECT_MESSAGE = "TeamMode R6 env protection: \u73AF\u5883\u53D8\u91CF\u8BFB\u53D6\u5DF2\u88AB\u62E6\u622A\u3002\u9700\u8981\u53D8\u91CF\u503C\u8BF7\u5411 HUMAN \u7533\u8BF7\u3002";
|
|
69
|
+
/** Pattern categories surfaced in the block message and the audit log. */
|
|
70
|
+
export declare const CATEGORY_BASH_ENV_COMMAND = "bash-env-command";
|
|
71
|
+
export declare const CATEGORY_BASH_ENV_EXPANSION = "bash-env-expansion";
|
|
72
|
+
export declare const CATEGORY_ENV_FILE_PATH = "env-file-path";
|
|
73
|
+
export declare const CATEGORY_EXTRA_DENY = "extra-deny";
|
|
74
|
+
export type EnvProtectMode = "strict" | "standard" | "off";
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the protection mode. Only exact "standard" / "off" switch those
|
|
77
|
+
* modes on; everything else (unset, typos, wrong case) fails CLOSED into
|
|
78
|
+
* strict — a mistyped opt-out must never disable the red line.
|
|
79
|
+
*/
|
|
80
|
+
export declare function resolveEnvProtectMode(raw: unknown): EnvProtectMode;
|
|
81
|
+
/**
|
|
82
|
+
* Parse `TM_ENV_PROTECT_EXTRA_DENY` (semicolon-separated regex bodies).
|
|
83
|
+
* Invalid regexes are skipped rather than crashing plugin startup; the
|
|
84
|
+
* remaining rules still apply. Empty/absent input yields no extra rules.
|
|
85
|
+
*/
|
|
86
|
+
export declare function parseExtraDeny(raw: unknown): RegExp[];
|
|
87
|
+
/** The block error handed back to the model (fixed text + category tag). */
|
|
88
|
+
export declare function envProtectError(category: string): Error;
|
|
89
|
+
/**
|
|
90
|
+
* True when the value points at an env file. Matches on the BASENAME with
|
|
91
|
+
* both separators handled; URL query/fragment tails are cut first so
|
|
92
|
+
* `https://x/.env?raw=1` matches the same basename as a plain path, and
|
|
93
|
+
* asterisks are stripped so glob patterns like "*.env" or a recursive deep
|
|
94
|
+
* form of ".env.local" are caught by the same matcher as real paths.
|
|
95
|
+
* (Note: glob spellings are written without backticks here — a double-star
|
|
96
|
+
* + slash inside JSDoc would close the comment block early.)
|
|
97
|
+
*/
|
|
98
|
+
export declare function isEnvFilePath(raw: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Classify a bash/PowerShell command string. Returns the pattern category
|
|
101
|
+
* when the command must be blocked, null when it may pass. `off` is
|
|
102
|
+
* handled by the caller; user extra-deny rules take precedence.
|
|
103
|
+
*/
|
|
104
|
+
export declare function classifyBashCommand(command: string, mode: EnvProtectMode, extra?: RegExp[]): string | null;
|
|
105
|
+
/**
|
|
106
|
+
* Classify the path-class arguments of a file tool. Returns the pattern
|
|
107
|
+
* category when the call must be blocked, null when it may pass.
|
|
108
|
+
*/
|
|
109
|
+
export declare function classifyPathFields(args: Record<string, unknown> | undefined, mode: EnvProtectMode, extra?: RegExp[]): string | null;
|
|
110
|
+
/**
|
|
111
|
+
* Top routing: tool name + tool args -> category to block, or null to pass.
|
|
112
|
+
* `off` always passes (the hook stays installed but is a no-op).
|
|
113
|
+
*/
|
|
114
|
+
export declare function inspectToolCall(tool: string, args: Record<string, unknown> | undefined, mode: EnvProtectMode, extra?: RegExp[]): string | null;
|
|
115
|
+
/**
|
|
116
|
+
* Build the `tool.execute.before` hook. The hook is installed in every
|
|
117
|
+
* mode; with mode "off" it returns immediately and everything passes.
|
|
118
|
+
* When a block triggers, the audit entry is written first, then the fixed
|
|
119
|
+
* structured error is thrown so opencode surfaces it to the model as the
|
|
120
|
+
* failed tool result.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createEnvProtectHook(client: unknown, mode: EnvProtectMode, extra?: RegExp[]): (input: unknown, output: unknown) => Promise<void>;
|
|
123
|
+
//# sourceMappingURL=envprotect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envprotect.d.ts","sourceRoot":"","sources":["../src/envprotect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAEH,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,0BAA0B,CAAA;AAE1D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,sKAC4B,CAAA;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,yBAAyB,qBAAqB,CAAA;AAC3D,eAAO,MAAM,2BAA2B,uBAAuB,CAAA;AAC/D,eAAO,MAAM,sBAAsB,kBAAkB,CAAA;AACrD,eAAO,MAAM,mBAAmB,eAAe,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,CAAA;AAE1D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAIlE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAarD;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAEvD;AAyBD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAiClD;AAiJD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,cAAc,EACpB,KAAK,GAAE,MAAM,EAAO,GACnB,MAAM,GAAG,IAAI,CAgCf;AAYD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,IAAI,EAAE,cAAc,EACpB,KAAK,GAAE,MAAM,EAAO,GACnB,MAAM,GAAG,IAAI,CAWf;AAoBD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,IAAI,EAAE,cAAc,EACpB,KAAK,GAAE,MAAM,EAAO,GACnB,MAAM,GAAG,IAAI,CAYf;AA0CD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,cAAc,EACpB,KAAK,GAAE,MAAM,EAAO,GACnB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAUpD"}
|