@te-river/opencode-team-mode 1.5.11 → 1.5.13
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 +154 -57
- package/README.zh-CN.md +126 -47
- package/dist/agents.d.ts +5 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +37 -11
- package/dist/agents.js.map +1 -1
- package/dist/approval-gate.d.ts +54 -16
- package/dist/approval-gate.d.ts.map +1 -1
- package/dist/approval-gate.js +163 -42
- package/dist/approval-gate.js.map +1 -1
- package/dist/host-hooks.d.ts +115 -0
- package/dist/host-hooks.d.ts.map +1 -0
- package/dist/host-hooks.js +270 -0
- package/dist/host-hooks.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -4
- package/dist/index.js.map +1 -1
- package/dist/prompts/lead.d.ts +1 -1
- package/dist/prompts/lead.d.ts.map +1 -1
- package/dist/prompts/lead.js +88 -6
- package/dist/prompts/lead.js.map +1 -1
- package/dist/prompts/shared.d.ts +1 -1
- package/dist/prompts/shared.d.ts.map +1 -1
- package/dist/prompts/shared.js +203 -119
- package/dist/prompts/shared.js.map +1 -1
- package/dist/prompts/specialists.d.ts +2 -2
- package/dist/prompts/specialists.d.ts.map +1 -1
- package/dist/prompts/specialists.js +73 -23
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/tm/args-schema.d.ts +31 -1
- package/dist/tm/args-schema.d.ts.map +1 -1
- package/dist/tm/args-schema.js +155 -39
- package/dist/tm/args-schema.js.map +1 -1
- package/dist/tm/bash-timeout.d.ts +72 -0
- package/dist/tm/bash-timeout.d.ts.map +1 -0
- package/dist/tm/bash-timeout.js +100 -0
- package/dist/tm/bash-timeout.js.map +1 -0
- package/dist/tm/browser.d.ts +250 -20
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +1200 -143
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/config.d.ts +129 -0
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js +117 -1
- package/dist/tm/config.js.map +1 -1
- package/dist/tm/dispatch.d.ts +95 -0
- package/dist/tm/dispatch.d.ts.map +1 -0
- package/dist/tm/dispatch.js +369 -0
- package/dist/tm/dispatch.js.map +1 -0
- package/dist/tm/index.d.ts +32 -7
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +74 -5
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/memory.d.ts +88 -10
- package/dist/tm/memory.d.ts.map +1 -1
- package/dist/tm/memory.js +881 -99
- package/dist/tm/memory.js.map +1 -1
- package/dist/tm/pipelines.d.ts +26 -3
- package/dist/tm/pipelines.d.ts.map +1 -1
- package/dist/tm/pipelines.js +167 -11
- package/dist/tm/pipelines.js.map +1 -1
- package/dist/tm/ptc/budgets.d.ts +22 -1
- package/dist/tm/ptc/budgets.d.ts.map +1 -1
- package/dist/tm/ptc/budgets.js +87 -8
- package/dist/tm/ptc/budgets.js.map +1 -1
- package/dist/tm/ptc/contract.d.ts +49 -9
- package/dist/tm/ptc/contract.d.ts.map +1 -1
- package/dist/tm/ptc/contract.js +41 -3
- package/dist/tm/ptc/contract.js.map +1 -1
- package/dist/tm/ptc/driver.d.ts +5 -2
- package/dist/tm/ptc/driver.d.ts.map +1 -1
- package/dist/tm/ptc/driver.js +47 -15
- package/dist/tm/ptc/driver.js.map +1 -1
- package/dist/tm/ptc/engines.d.ts +15 -4
- package/dist/tm/ptc/engines.d.ts.map +1 -1
- package/dist/tm/ptc/engines.js +281 -28
- package/dist/tm/ptc/engines.js.map +1 -1
- package/dist/tm/ptc/index.d.ts +4 -4
- package/dist/tm/ptc/index.d.ts.map +1 -1
- package/dist/tm/ptc/index.js +2 -2
- package/dist/tm/ptc/index.js.map +1 -1
- package/dist/tm/ptc/pscan.d.ts +20 -1
- package/dist/tm/ptc/pscan.d.ts.map +1 -1
- package/dist/tm/ptc/pscan.js +328 -14
- package/dist/tm/ptc/pscan.js.map +1 -1
- package/dist/tm/ptc/summary.d.ts.map +1 -1
- package/dist/tm/ptc/summary.js +23 -1
- package/dist/tm/ptc/summary.js.map +1 -1
- package/dist/tm/ptc/tool.d.ts +34 -3
- package/dist/tm/ptc/tool.d.ts.map +1 -1
- package/dist/tm/ptc/tool.js +117 -20
- package/dist/tm/ptc/tool.js.map +1 -1
- package/dist/tm/pty.d.ts +70 -0
- package/dist/tm/pty.d.ts.map +1 -0
- package/dist/tm/pty.js +242 -0
- package/dist/tm/pty.js.map +1 -0
- package/dist/tm/search.d.ts +128 -15
- package/dist/tm/search.d.ts.map +1 -1
- package/dist/tm/search.js +556 -47
- package/dist/tm/search.js.map +1 -1
- package/dist/tm/shell-bridge.d.ts +14 -1
- package/dist/tm/shell-bridge.d.ts.map +1 -1
- package/dist/tm/shell-bridge.js +57 -10
- package/dist/tm/shell-bridge.js.map +1 -1
- package/dist/tm/webfetch.d.ts +29 -7
- package/dist/tm/webfetch.d.ts.map +1 -1
- package/dist/tm/webfetch.js +117 -15
- package/dist/tm/webfetch.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/installation.md +216 -17
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -44,10 +44,11 @@ TeamMode's answer to each:
|
|
|
44
44
|
|
|
45
45
|
| Pain | TeamMode's answer |
|
|
46
46
|
|---|---|
|
|
47
|
-
| 🔥 **Context flooding** | Every governed tool output over 2000 tokens is offloaded to a local run store and replaced by an 80-token preview + an HMAC handle. The agent pages through what it needs — the window never drowns. |
|
|
47
|
+
| 🔥 **Context flooding** | Every governed tool output over its content-class offload threshold (prose 4000 / data 2000 tokens, CJK-aware) is offloaded to a local run store and replaced by an 80-token preview + an HMAC handle. The agent pages through what it needs — the window never drowns. |
|
|
48
48
|
| 🐌 **Round-trip overhead** | `tm_ptc_run`: the agent writes ONE program that makes N governed calls in a single turn. Zero LLM round-trips during the run. |
|
|
49
|
-
| 🕳️ **Silent side effects** | R6/R2 approval gate: env-var reads and dangerous ops route through OpenCode's official confirmation dialog, auto-rejected after
|
|
49
|
+
| 🕳️ **Silent side effects** | R6/R2 approval gate: env-var reads and dangerous ops route through OpenCode's official confirmation dialog, auto-rejected after 1 unanswered minute (default). The plugin never approves on its own — it only ever rejects. |
|
|
50
50
|
| 🌫️ **Hallucinated research** | Web access is a two-role grant with an allowlisted, governed tool chain. A fact that couldn't be fetched is reported as a gap — never fabricated. |
|
|
51
|
+
| 🧭 **Walls of text** | Replies are steered into the shape the host renders fastest: a markdown table for per-file / per-case / per-finding results, fenced code for diffs and configs, a browser screenshot attached as an inline image only when you ask for one. The host does not draw mermaid, so no agent pretends it does. |
|
|
51
52
|
|
|
52
53
|
And the workflow discipline underneath: deterministic routing, a ≤30-line plan
|
|
53
54
|
you approve before ≥2 dispatches execute, structured `STATUS/CHANGES/FINDINGS/
|
|
@@ -127,10 +128,12 @@ OpenCode installs the plugin on next startup.
|
|
|
127
128
|
- **Restart to activate.** After touching `opencode.json`, fully quit and restart OpenCode (Desktop: quit from tray, not just the window).
|
|
128
129
|
- **Plugin updates: re-run the installer.** It is idempotent — a re-run re-patches the config (no-op when present), purges the stale plugin cache, and re-resolves any npm-installed copy. This exists because OpenCode caches plugins by spec string and does NOT re-resolve `@latest` when a new version publishes (upstream limitation). Manual recipe, if you prefer:
|
|
129
130
|
|
|
130
|
-
| OS |
|
|
131
|
+
| OS | Purge command — recursive, covers BOTH cache layouts |
|
|
131
132
|
|---|---|
|
|
132
|
-
| macOS / Linux | `
|
|
133
|
-
| Windows | `
|
|
133
|
+
| macOS / Linux | `find ~/.cache/opencode/packages -type d -name '*opencode-team-mode*' -prune -exec rm -rf {} +` |
|
|
134
|
+
| Windows (PowerShell) | `foreach ($r in "$HOME\.cache\opencode\packages", "$env:LOCALAPPDATA\opencode\cache\packages") { if (Test-Path $r) { Get-ChildItem $r -Directory -Recurse -Filter '*opencode-team-mode*' -EA SilentlyContinue | Sort-Object { $_.FullName.Length } | Remove-Item -Recurse -Force -EA SilentlyContinue } }` |
|
|
135
|
+
|
|
136
|
+
⚠️ OpenCode loads the plugin from `~/.cache/opencode/packages/` — possibly nested inside the scoped `@te-river/` directory — **not** from `~/.config/opencode/node_modules`, which is why the delete must recurse (a top-level-only `rm -rf` silently misses the scoped copy).
|
|
134
137
|
|
|
135
138
|
If you also npm-installed the plugin into `~/.config/opencode`, its package-lock pins the version — run `npm install @te-river/opencode-team-mode@latest` there too. Full recipe (including an agent-driven update prompt): [installation guide, Updating](./docs/installation.md).
|
|
136
139
|
- **Prerequisites:** [OpenCode](https://opencode.ai) (Desktop or CLI) and Node ≥ 18.
|
|
@@ -201,19 +204,24 @@ as a structured skeleton — nothing landed in your repo, nothing was guessed.
|
|
|
201
204
|
## 🧰 Governed tools & security
|
|
202
205
|
|
|
203
206
|
Every tool TeamMode adds runs under ONE governance pipeline: outputs above
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
the offload threshold never enter the context window — the boundary is
|
|
208
|
+
content-class aware (`TM_OFFLOAD_THRESHOLD_TEXT` = 4000 for prose:
|
|
209
|
+
text/log/markdown; `TM_OFFLOAD_THRESHOLD_DATA` = 2000 for json/csv/code/
|
|
210
|
+
binary; an unknown class falls back to the global `TM_OFFLOAD_THRESHOLD`) —
|
|
211
|
+
and oversized results are offloaded to a run store and replaced by a
|
|
212
|
+
content-aware preview plus an HMAC-signed handle that the agent pages
|
|
213
|
+
through with `tm_fetch` when it genuinely needs the payload.
|
|
208
214
|
|
|
209
215
|
| Tool | What it does | Roles |
|
|
210
216
|
|---|---|---|
|
|
211
|
-
| `tm_read` / `tm_grep` / `tm_bash` / `tm_fetch` | Governed file read / regex search / read-only shell (allowlist) / paged handle retrieval | all six agents |
|
|
212
|
-
| `tm_memory` |
|
|
213
|
-
| `tm_ptc_run` | Batch orchestration: one program, N governed calls, zero LLM round-trips | all six agents |
|
|
214
|
-
| `tm_search` | Multi-engine web search with extracted, deduplicated hit lists | Lead + Researcher |
|
|
217
|
+
| `tm_read` / `tm_grep` / `tm_bash` / `tm_fetch` | Governed file read / regex search / read-only shell (allowlist) / paged handle retrieval (JSON handles take a `fields` dot-path projection — a deliberately small jq subset like `items[].name`) | all six agents |
|
|
218
|
+
| `tm_memory` | Session + project + global memory store (Markdown + frontmatter): add / search / list / forget / compact | all six agents |
|
|
219
|
+
| `tm_ptc_run` | Batch orchestration: one program, N governed calls, zero LLM round-trips; web roles also get `tm.search` / `tm.webfetch` inside the program | all six agents |
|
|
220
|
+
| `tm_search` | Multi-engine web search with extracted, deduplicated, RRF-fused hit lists | Lead + Researcher |
|
|
215
221
|
| `tm_webfetch` | Single governed GET of an allowlisted page (search pages auto-extracted) | Lead + Researcher |
|
|
216
|
-
| `
|
|
222
|
+
| `tm_dispatch` / `tm_join` | **Async sub-agent dispatch**: `tm_dispatch` starts a specialist in its own child session and returns the id immediately (the built-in `task` tool blocks you until it finishes), `tm_join` collects — status snapshot, bounded `waitMs`, `cancel:true` to abort a runaway child; collected replies ride the offload pipeline, so five fat reports arrive as handles + previews instead of multiplying your context. Lead-only, and a child never dispatches | Lead only |
|
|
223
|
+
| `tm_pty` | **Non-blocking command execution** on the host's own terminal sessions (`start`/`status`/`list`/`kill`) — independent builds and test suites overlap instead of queueing behind one 120 s bash call. Captures no output (the command tees its own log; read it with `tm_read`), and every start passes the R6 classifier, the R2 danger-face globs **and** the official confirmation dialog before a process exists | Lead only |
|
|
224
|
+
| `tm_browser` | Interactive browser session (**your default browser**): 16 Playwright verbs (snapshot-first `take_snapshot` → uid-addressed `click`/`fill`/`drag`/…) + 5 legacy compat verbs (open/navigate/read/screenshot/close); Playwright engine needs Node ≥ 20, below that (or on any import failure) it auto-degrades to the legacy CDP engine. It drives YOUR default browser channel (an Edge Beta default opens Edge Beta), stays headful unless the operator sets `TM_BROWSER_HEADLESS`, loads a page's own images/CSS/JS via the `same-site` subresource policy, and `take_screenshot { image:true }` attaches a JPEG so the model can actually see the screen | Lead + Researcher + Tester (UI verification) |
|
|
217
225
|
|
|
218
226
|
> **Fixed tool priority ladder (every task): ① TeamMode governed tools
|
|
219
227
|
> (`tm_*`) → ② user MCP/plugin tools → ③ the model's own reasoning.**
|
|
@@ -228,26 +236,48 @@ its own step id and its own payload, and nothing cross-contaminates
|
|
|
228
236
|
### Context governance: offload, handles, previews
|
|
229
237
|
|
|
230
238
|
Large tool outputs are context cost's main driver — every step re-sends the
|
|
231
|
-
whole window. So results above
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
whole window. So results above the content-class offload boundary (prose →
|
|
240
|
+
`TM_OFFLOAD_THRESHOLD_TEXT`, structured data → `TM_OFFLOAD_THRESHOLD_DATA`,
|
|
241
|
+
unknown → global `TM_OFFLOAD_THRESHOLD`) are written to a local run store
|
|
242
|
+
(`<repo>/.git/opencode-team/`, never your working tree) and replaced by a
|
|
243
|
+
handle with a content-aware preview: JSON keys / CSV header + shape / log
|
|
244
|
+
ERROR×N stats / code signatures / binary metadata, hard-capped at 80 tokens.
|
|
245
|
+
When the agent actually needs the payload, it pages through with `tm_fetch`
|
|
246
|
+
using an HMAC-signed, run-scoped, expiring handle — and on a JSON handle it
|
|
247
|
+
can ask for a `fields` dot-path projection instead (a deliberately small jq
|
|
248
|
+
subset: `items[].name`, `[].stargazers_count`), so a big API dump narrows to
|
|
249
|
+
just the values needed without the raw body ever entering the window.
|
|
250
|
+
`tm_bash` only allows read-only commands (allowlist), and failures come back
|
|
251
|
+
as structured errors instead of raw dumps.
|
|
252
|
+
|
|
253
|
+
### Session + project + global memory (tm_memory)
|
|
241
254
|
|
|
242
255
|
Durable facts — build commands, environment quirks, architecture decisions,
|
|
243
|
-
your conventions — live as human-editable Markdown with frontmatter
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
- **`
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
256
|
+
your conventions — live as human-editable Markdown with frontmatter, in
|
|
257
|
+
THREE tiers:
|
|
258
|
+
|
|
259
|
+
- **`session`**: this conversation's transients only — in-process, TTL-swept
|
|
260
|
+
(`TM_MEMORY_SESSION_TTL_MIN`, default 240 min), invisible to other
|
|
261
|
+
sessions; ephemeral unless `TM_MEMORY_SESSION_PERSIST=1` writes them under
|
|
262
|
+
`memories/sessions/<sid>/`.
|
|
263
|
+
- **`project`** (default): `<repo>/.git/opencode-team/memories/…` — per checkout, git-adjacent. Facts about THIS repo: build commands, environment quirks, architecture decisions.
|
|
264
|
+
- **`global`**: `~/.opencode-team/memories/global/` (override `TM_MEMORY_GLOBAL_DIR`) — **follows you across ALL projects**. User-level conventions: preferred package manager, commit style, tooling habits.
|
|
265
|
+
|
|
266
|
+
Actions: `add` / `search` (deterministic keyword scoring) / `list` / `forget` /
|
|
267
|
+
`compact`; 4000 chars per memory. `search` walks ALL tiers with **session >
|
|
268
|
+
project > global precedence** — project entries get a +2 near-tie weight and a
|
|
269
|
+
same-title higher-layer twin shadows the lower one (it never surfaces).
|
|
270
|
+
Near-duplicates never pile up: an `add` that hits an existing entry in the same
|
|
271
|
+
tier and category (dedup key, or title+keywords Jaccard ≥ 0.6) **folds into
|
|
272
|
+
it** — new content wins, keywords union, the old slug moves to `supersedes:`,
|
|
273
|
+
and the answer says 已合并 (that is normal; don't re-add under a variant title).
|
|
274
|
+
When a tier reaches `TM_MEMORY_MAX_ENTRIES` (200 per scope) the add fails on
|
|
275
|
+
purpose: run `compact` first — it dry-runs the merge plan by default, and
|
|
276
|
+
re-running with `apply:true` performs it after copying every original to a
|
|
277
|
+
timestamped `.compact-backup` tree (the rollback path). Entries older than
|
|
278
|
+
`TM_MEMORY_STALE_DAYS` (30) surface tagged `[stale Nd]` in search. Agents
|
|
279
|
+
are prompted to search before assuming conventions and to save hard-won
|
|
280
|
+
facts for the next conversation.
|
|
251
281
|
|
|
252
282
|
### 🌐 Web search that actually works (in China)
|
|
253
283
|
|
|
@@ -258,18 +288,22 @@ sees raw SERP chrome.
|
|
|
258
288
|
|
|
259
289
|
| Engine | Notes |
|
|
260
290
|
|---|---|
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
263
|
-
| `
|
|
291
|
+
| `auto` (default) | Classifies the query, fans the matching engines out **in parallel** (every route has ≥2 legs), dedupes by host+path and fuses them with weighted RRF into a top-10 list tagged with each hit's source engine(s). Ranking is scaled by real query-token overlap (floor `TM_SEARCH_RELEVANCE_FLOOR`), so a trusted engine's off-topic junk no longer outranks another engine's best hit. Routing: errors / camelCase APIs → `stackoverflow`+`github`+`bing`; dev-ecosystem (releases, frameworks, open source) → `hn`+`github`+`npm`; Chinese → `bing`+`moegirl`+`stackoverflow`+`hn`; other → `bing`+`stackoverflow`+`hn`+`github`. Pin another default via `TM_SEARCH_DEFAULT_ENGINE` |
|
|
292
|
+
| `bing` | cn.bing.com — the only live CN HTML SERP; multi-word CJK queries get their phrase boundary protected (quoted) so markup shuffle can't split the result list |
|
|
293
|
+
| `stackoverflow` | api.stackexchange.com question search (no key, 300/day/IP) → numbered questions with composite snippets; `auto` tracks the quota and swaps in `bing` once spent |
|
|
294
|
+
| `hn` | Hacker News via Algolia API (no key) → story titles + snippets with direct article URLs |
|
|
264
295
|
| `bilibili` | video search |
|
|
265
296
|
| `moegirl` | MediaWiki search API — entry titles + snippets, structured |
|
|
266
297
|
| `npm` | registry search → name@version + description, structured |
|
|
267
|
-
| `github` | repo search API → stars + description, structured |
|
|
298
|
+
| `github` | repo search API → stars + description, structured; `org:` / `user:` / `stars:` / `language:` qualifiers fold into the query (e.g. `vector db stars:>500 language:rust`) |
|
|
268
299
|
|
|
269
|
-
All
|
|
270
|
-
every one of them sits on the seeded domain allowlist.
|
|
271
|
-
(
|
|
272
|
-
|
|
300
|
+
All seven engines are reachable from mainland China **without API keys**, and
|
|
301
|
+
every one of them sits on the seeded domain allowlist. The previous CN HTML
|
|
302
|
+
SERPs (`sogou` / `so` / `baidu` / `bing-int`) were **removed** — a live
|
|
303
|
+
benchmark (2026-09-14) showed them serving anti-bot shells or 100% empty
|
|
304
|
+
results; they are not even manually selectable. On an empty result,
|
|
305
|
+
the error names the alternative engines instead of leaving the agent stuck.
|
|
306
|
+
Two more channels complete the surface:
|
|
273
307
|
|
|
274
308
|
- `tm_webfetch` — a known URL, one governed GET. Search-engine pages it
|
|
275
309
|
fetches are auto-extracted to hit lists too. JSON endpoints like
|
|
@@ -277,9 +311,28 @@ leaving the agent stuck. Two more channels complete the surface:
|
|
|
277
311
|
- `tm_browser` — JS-rendered pages: **your DEFAULT browser** (Windows
|
|
278
312
|
registry / Linux `xdg-settings`; Chromium-family only — Firefox falls back
|
|
279
313
|
to the Edge/Chrome probe order because CDP is Chromium-proprietary;
|
|
280
|
-
`TM_BROWSER_PATH` overrides), headful
|
|
281
|
-
**domain allowlist enforced at the network layer** per request
|
|
282
|
-
|
|
314
|
+
`TM_BROWSER_PATH` overrides), headful by default, isolated temp profile,
|
|
315
|
+
**domain allowlist enforced at the network layer** per request and per
|
|
316
|
+
redirect hop. The action surface is chrome-devtools-mcp aligned: **16
|
|
317
|
+
Playwright verbs** (`navigate_page` · `take_snapshot` · `click` · `fill` ·
|
|
318
|
+
`hover` · `drag` · `press_key` · `select_page` · `upload_file` · `wait_for`
|
|
319
|
+
· `evaluate_script` · `list_console_messages` · `list_network_requests` ·
|
|
320
|
+
`list_pages` · `take_screenshot` · `handle_dialog`) plus 5 legacy compat
|
|
321
|
+
verbs (`open` / `navigate` / `read` / `screenshot` / `close`).
|
|
322
|
+
Snapshot-first: `take_snapshot` returns the aria snapshot with injected
|
|
323
|
+
`[uid=eN]` tokens, follow-up actions address nodes by uid instead of
|
|
324
|
+
guessed locators; snapshots are hard-capped by
|
|
325
|
+
`TM_BROWSER_SNAPSHOT_MAX_TOKENS` (default 1200).
|
|
326
|
+
**Engine split:** the primary engine is `playwright-core` (an optional
|
|
327
|
+
dependency — needs **Node ≥ 20**; on older Node, or if the import fails,
|
|
328
|
+
the session auto-degrades per instance to the zero-dep `cdp-legacy`
|
|
329
|
+
engine, which keeps the core verbs only; pin either via
|
|
330
|
+
`TM_BROWSER_ENGINE=playwright|cdp-legacy`). No browser download is ever
|
|
331
|
+
involved — Playwright launches YOUR installed browser by path, so
|
|
332
|
+
`npx playwright install` is not part of the user flow (the dependency
|
|
333
|
+
itself resolves at npm install/publish time). Isolated temp profile by
|
|
334
|
+
default: persistent logins only if you explicitly set
|
|
335
|
+
`TM_BROWSER_USER_DATA_DIR`.
|
|
283
336
|
|
|
284
337
|
When a fetch still returns **403 after the real-Chrome headers**, the error
|
|
285
338
|
is a DIRECTIVE: the gate is JS-challenge / TLS-fingerprint based and only a
|
|
@@ -289,16 +342,18 @@ filter known noise: engine-internal wrappers (`so.com/link?`, `ai.so.com`)
|
|
|
289
342
|
and same-name-different-site domains (`maimai.cn` 脉脉 vs the maimai DX
|
|
290
343
|
game) never ride along — extend the hit blacklist with `TM_HIT_BLACKLIST`.
|
|
291
344
|
|
|
292
|
-
Seeded allowlist (
|
|
293
|
-
domains, so every sibling subdomain — baike.baidu.com,
|
|
294
|
-
space.bilibili.com — is covered):
|
|
345
|
+
Seeded allowlist (all three web tools; 23 hosts — baidu/moegirl/bilibili are
|
|
346
|
+
PARENT domains, so every sibling subdomain — baike.baidu.com,
|
|
347
|
+
mzh.moegirl.org.cn, space.bilibili.com — is covered):
|
|
295
348
|
`baidu.com`, `moegirl.org.cn`, `bilibili.com`, `www.sogou.com`, `www.so.com`,
|
|
296
349
|
`cn.bing.com`, `www.bing.com`, `zhihu.com`, `juejin.cn`, `csdn.net`,
|
|
297
350
|
`cnblogs.com`, `gitee.com`, `github.com`, `api.github.com`,
|
|
298
351
|
`raw.githubusercontent.com`, `gist.githubusercontent.com`, `ghproxy.net`
|
|
299
|
-
(mainland mirror for github raw), `stackoverflow.com`, `
|
|
300
|
-
|
|
301
|
-
`
|
|
352
|
+
(mainland mirror for github raw), `stackoverflow.com`, `api.stackexchange.com`
|
|
353
|
+
+ `hn.algolia.com` (the two JSON search engines), `npmjs.org`, `pypi.org`,
|
|
354
|
+
`learn.microsoft.com` — extend via
|
|
355
|
+
`TM_WEBFETCH_ALLOWED_DOMAINS` (`"*"` opens every host; a custom list REPLACES
|
|
356
|
+
the seed, so keep the engine hosts or `tm_search` loses its targets). Architect /
|
|
302
357
|
implementer / reviewer have NO network grant — web questions come back as a
|
|
303
358
|
reported gap, never simulated. The tester carries `tm_browser` ONLY, for
|
|
304
359
|
governed UI verification of the project (local dev servers, preview routes);
|
|
@@ -307,7 +362,7 @@ open web fetching stays with the two network roles.
|
|
|
307
362
|
**Out-of-allowlist targets are a gate, not a wall.** When a fetch / search /
|
|
308
363
|
browser-open points at a host outside the allowlist, the tool hands the URL
|
|
309
364
|
to OpenCode's **official confirmation dialog** — you decide, once per
|
|
310
|
-
target (an unanswered dialog is auto-rejected on the usual
|
|
365
|
+
target (an unanswered dialog is auto-rejected on the usual 1-minute timer,
|
|
311
366
|
and the plugin still never self-allows). Every dialog also fires a
|
|
312
367
|
**system toast notification**, so you know something is waiting even when
|
|
313
368
|
you're not staring at the screen. Env-file URLs and non-http(s) schemes
|
|
@@ -319,11 +374,21 @@ remain hard-rejected with no dialog — R6 red lines are never consentable.
|
|
|
319
374
|
environment variables silently. Env reads (`printenv`, `env`, `Get-ChildItem
|
|
320
375
|
env:`, …) and env files (`.env`, shell rc) route through OpenCode's official
|
|
321
376
|
confirmation dialog; unanswered prompts are **auto-rejected after
|
|
322
|
-
`TM_ASK_TIMEOUT_MIN` (default
|
|
377
|
+
`TM_ASK_TIMEOUT_MIN` (default 1 min)**. Env reads no wildcard can express
|
|
323
378
|
(embedded `$VAR` / `${VAR}` / `$env:` inside another command, command
|
|
324
379
|
substitution) and the `tm_*` wrapper channel stay a **hard block** — no dialog
|
|
325
380
|
to slip through. The audit log records only tool name + pattern category +
|
|
326
|
-
verdict — never command text, paths, variable names or values.
|
|
381
|
+
verdict — never command text, paths, variable names or values. Verdicts now
|
|
382
|
+
also explain a dialog that cannot be answered anymore: a reply that hits an
|
|
383
|
+
**already-closed** dialog (host 404 — the timer already auto-rejected) audits
|
|
384
|
+
as `already-closed` without degrading the gate, a plugin-side bad reply shape
|
|
385
|
+
audits as `rejected-shape-bug`, and a user reply that arrives *after* the
|
|
386
|
+
auto-reject is recorded as `late-<verdict>` for observability only (the
|
|
387
|
+
rejection stands — the plugin still never self-allows). The 1-minute auto-reject
|
|
388
|
+
floor is tunable via `TM_ASK_TIMEOUT_FLOOR_MIN`; the short default is safe
|
|
389
|
+
because a reply that races the timer audits as benign `already-closed` (host
|
|
390
|
+
404 on a closed dialog — no gate degrade), and the observed ~120 s is the
|
|
391
|
+
host-to-plugin event-bus *delivery* lag, not click-resolution latency.
|
|
327
392
|
|
|
328
393
|
**R2 dangerous operations (same dialog).** Delete, git publish, network
|
|
329
394
|
fetch, package install/publish, process/system, privilege changes — none are
|
|
@@ -390,24 +455,52 @@ for overrides, extra agents and disabling roles.
|
|
|
390
455
|
| Env var | Default | Purpose |
|
|
391
456
|
|---|---|---|
|
|
392
457
|
| `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` (off also disarms the approval timer) |
|
|
393
|
-
| `TM_ASK_TIMEOUT_MIN` | `
|
|
458
|
+
| `TM_ASK_TIMEOUT_MIN` | `1` | minutes before an unanswered dialog is auto-rejected (floored at 1 min — safe: a racing reply audits as benign `already-closed`; the host's reply event reaching the plugin ~120 s late is event-bus delivery lag, not a click delay) |
|
|
459
|
+
| `TM_ASK_TIMEOUT_FLOOR_MIN` | `1` | minimum enforced for the ask timeout above |
|
|
394
460
|
| `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex; always hard block, never dialog-governed) |
|
|
395
|
-
| `TM_OFFLOAD_THRESHOLD` | `2000` | offload
|
|
461
|
+
| `TM_OFFLOAD_THRESHOLD` | `2000` | global offload fallback (tokens, CJK-aware estimate) — used when the content class is unknown |
|
|
462
|
+
| `TM_OFFLOAD_THRESHOLD_TEXT` | `4000` | offload boundary for prose (text / log / markdown) |
|
|
463
|
+
| `TM_OFFLOAD_THRESHOLD_DATA` | `2000` | offload boundary for structured payloads (json / csv / code / binary) |
|
|
396
464
|
| `TM_PREVIEW_MAX_TOKENS` | `80` | preview hard cap |
|
|
397
465
|
| `TM_FETCH_MAX_LINES` | `2000` | tm_fetch page cap |
|
|
398
466
|
| `TM_BLACKBOARD_DIR` / `TM_TRAJECTORY_DIR` | `<repo>/.git/opencode-team/…` | offload store / trajectory ledger (tmpdir fallback; explicit = absolute or project-relative) |
|
|
399
467
|
| `TM_BLACKBOARD_TTL` | `7` | store retention (days) |
|
|
400
468
|
| `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
|
|
401
|
-
| `
|
|
469
|
+
| `TM_SEARCH_DEFAULT_ENGINE` | `auto` | tm_search engine when no `engine` arg is given (`auto` = classify + parallel fan-out + RRF fusion; any table name also pins a manual default) |
|
|
470
|
+
| `TM_WEBFETCH_ALLOWED_DOMAINS` | the 23 seeded hosts | tm_webfetch / tm_search / tm_browser allowlist (`"*"` opens all; empty = deny all; a custom list REPLACES the seed — keep the engine hosts) |
|
|
402
471
|
| `TM_BROWSER_PATH` | auto-detect | tm_browser executable override (default: your DEFAULT browser when Chromium-family, else Edge/Chrome probes) |
|
|
403
472
|
| `TM_BROWSER_HEADLESS` | `auto` | `1` headless (CI) / `0` headful / `auto` (headless only on display-less Linux) |
|
|
404
|
-
| `
|
|
473
|
+
| `TM_BROWSER_ENGINE` | `playwright` | `playwright` (needs Node ≥ 20; any import failure auto-degrades) / `cdp-legacy` (zero-dep CDP pipe, core verbs only) |
|
|
474
|
+
| `TM_BROWSER_SNAPSHOT_MAX_TOKENS` | `1200` | hard cap on `take_snapshot` payloads |
|
|
475
|
+
| `TM_BROWSER_SUBRESOURCE` | `same-site` | what a page may load after its navigation was allowed: `same-site` = images/media/fonts/stylesheets always, scripts/XHR only for a site this session actually opened; `passive` = only the passive types; `off` = the legacy every-request gate. Blocked requests surface as a "N 个子资源请求被拦截" note on the next snapshot |
|
|
476
|
+
| `TM_BROWSER_IDLE_MS` | `180000` | an untouched browser session closes itself after this many ms (0 disables) and tells the user — a window nobody owns is a user-facing bug |
|
|
477
|
+
| `TM_BROWSER_IMAGE_MAX_BYTES` | `400000` | ceiling on the JPEG `take_screenshot { image:true }` inlines into the model's context (above it the reply stays path-only and says why) |
|
|
478
|
+
| `TM_SEARCH_WEIGHTS` | unset | per-engine fusion weight overrides, e.g. `bing=0.3,hn=0.25`; anything unset keeps the built-in table |
|
|
479
|
+
| `TM_SEARCH_RELEVANCE_FLOOR` | `0.35` | weight fraction kept by a hit that shares no query token with its title/snippet/host (demotes junk without deleting an engine) |
|
|
480
|
+
| `TM_SEARCH_MAX_HITS` | `10` | hits kept per engine leg and in the fused list |
|
|
481
|
+
| `TM_SEARCH_DISABLED_ENGINES` | unset | engines removed from the roster AND from every `auto` route (`sogou,baidu` style) |
|
|
482
|
+
| `TM_BASH_TIMEOUT_PROBE_MS` | `60000` | ceiling forced onto a `timeout` the model set for a read-only probe command (0 disables) |
|
|
483
|
+
| `TM_BASH_TIMEOUT_MAX_MS` | `0` | optional global ceiling for every other bash command — off by default so a real build keeps the timeout it asked for |
|
|
484
|
+
| `TM_PTY_MAX` | `4` | concurrent `tm_pty` terminal sessions this plugin may keep running at once |
|
|
485
|
+
| `TM_TOOL_HINTS` | `on` | append TeamMode's call-site discipline to the built-in `bash` / `task` tool DESCRIPTIONS via `tool.definition` (append-only, idempotent — the host text is never replaced) |
|
|
486
|
+
| `TM_AGENT_TEMPERATURE` | `off` | `on` applies a per-role sampling table (architect 0.35 / researcher 0.3 / reviewer 0.1 / rest 0.2) via `chat.params`; or give it `reviewer=0.05;team=0.4`. Off = the documented "all agents at 0.2" invariant stands |
|
|
487
|
+
| `TM_COMPACTION_CONTEXT` | `on` | on the host's pre-compaction hook, add the must-survive list (reply skeleton, offload handles, dispatched child session ids, provenance, board paths). Additive — the host's own summarizer prompt is never replaced |
|
|
488
|
+
| `TM_COMPACTION_AUTOCONTINUE` | `on` | `off` stops the host from silently resuming the turn after a compaction, so a human re-reads state first |
|
|
489
|
+
| `TM_SHELL_NO_COLOR` | `on` | inject `NO_COLOR`/`TERM=dumb` into every child shell via `shell.env` (ANSI progress bars are pure context tax). Never overwrites a value the host already set |
|
|
490
|
+
| `TM_SHELL_ENV` | — | explicit `KEY=VALUE;KEY2=VALUE2` passthrough into child shells — deliberately allowlisted, so this hook can't become a side channel for the parent environment |
|
|
491
|
+
| `TM_BROWSER_USER_DATA_DIR` | — (isolated temp profile) | explicit persistent profile dir — the ONLY way logins survive between sessions |
|
|
492
|
+
| `TM_MEMORY_GLOBAL_DIR` | `~/.opencode-team/memories/global/` | tm_memory GLOBAL tier store |
|
|
493
|
+
| `TM_MEMORY_SESSION_TTL_MIN` | `240` | session-tier entry TTL (lazy + boot sweep) |
|
|
494
|
+
| `TM_MEMORY_MAX_ENTRIES` | `200` | per-scope entry cap; over it `add` fails on purpose — run `compact` |
|
|
495
|
+
| `TM_MEMORY_STALE_DAYS` | `30` | age after which search hits are tagged `[stale Nd]` (`0` disables) |
|
|
496
|
+
| `TM_MEMORY_SESSION_PERSIST` | — (ephemeral) | `1` also writes session entries under `memories/sessions/<sid>/` |
|
|
405
497
|
| `TM_HIT_BLACKLIST` | `maimai.cn` | extra domains never listed as search hits (comma/semicolon separated; same-name-different-site noise like 脉脉) |
|
|
406
498
|
| `TM_PTC_MAX_PROGRAM_CHARS` | `4000` | PTC program source cap |
|
|
407
499
|
| `TM_PTC_MAX_CALLS` | `20` | PTC per-run bridge-call budget (1–200) |
|
|
408
500
|
| `TM_PTC_MAX_ERRORS` | `3` | PTC per-run error budget (1–50) |
|
|
409
501
|
| `TM_PTC_TIMEOUT_MS` | `60000` | PTC per-run wall-clock timeout (5s–10min) |
|
|
410
502
|
| `TM_PTC_ENGINE` | `auto` | `auto` (worker→inline degrade) / `worker` / `inline` |
|
|
503
|
+
| `TM_PTC_WEB_BRIDGE` | `on` | expose `tm.search` / `tm.webfetch` to PTC programs (`off` removes them from the bridge set) |
|
|
411
504
|
|
|
412
505
|
---
|
|
413
506
|
|
|
@@ -427,6 +520,10 @@ not the rule: a deliverable over ~50 lines goes to ONE named board file under
|
|
|
427
520
|
routing bug.
|
|
428
521
|
- **Approval gate (count-based):** ≥2 dispatches → plan (≤30 lines) → **your
|
|
429
522
|
approval** → execute. Blocking questions are batched and asked immediately.
|
|
523
|
+
- **Concurrent dispatch:** independent dispatches batch into the SAME round
|
|
524
|
+
(parallel implementers with per-file ownership + verbatim contracts,
|
|
525
|
+
3-dimension reviews, split test suites); only the Team Lead dispatches —
|
|
526
|
+
specialists no longer hold `task`, so no sub-agent spawns a sub-agent.
|
|
430
527
|
- **Adaptive review:** one reviewer by default; three parallel dimensions
|
|
431
528
|
only for high-risk profiles (auth/security, cross-module contracts, public APIs).
|
|
432
529
|
- **Static verification:** build / typecheck / lint / tests. Improvised
|
|
@@ -506,7 +603,7 @@ the whole workflow are host-agnostic. On display-less Linux, `tm_browser`
|
|
|
506
603
|
runs headless automatically.
|
|
507
604
|
|
|
508
605
|
**What happens if I don't answer a confirmation dialog?**
|
|
509
|
-
It auto-rejects after `TM_ASK_TIMEOUT_MIN` (default
|
|
606
|
+
It auto-rejects after `TM_ASK_TIMEOUT_MIN` (default 1). The plugin never
|
|
510
607
|
self-approves — the only side it can take is yours or nobody's.
|
|
511
608
|
|
|
512
609
|
---
|