@te-river/opencode-team-mode 1.6.0 → 1.6.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 +80 -15
- package/README.zh-CN.md +67 -18
- package/dist/host/note.d.ts +7 -0
- package/dist/host/note.d.ts.map +1 -0
- package/dist/host/note.js +28 -0
- package/dist/host/note.js.map +1 -0
- package/dist/host/v1.d.ts +14 -0
- package/dist/host/v1.d.ts.map +1 -0
- package/dist/host/v1.js +340 -0
- package/dist/host/v1.js.map +1 -0
- package/dist/host/v2-browser-gate.d.ts +45 -0
- package/dist/host/v2-browser-gate.d.ts.map +1 -0
- package/dist/host/v2-browser-gate.js +319 -0
- package/dist/host/v2-browser-gate.js.map +1 -0
- package/dist/host/v2-capabilities.d.ts +68 -0
- package/dist/host/v2-capabilities.d.ts.map +1 -0
- package/dist/host/v2-capabilities.js +146 -0
- package/dist/host/v2-capabilities.js.map +1 -0
- package/dist/host/v2-client.d.ts +53 -0
- package/dist/host/v2-client.d.ts.map +1 -0
- package/dist/host/v2-client.js +193 -0
- package/dist/host/v2-client.js.map +1 -0
- package/dist/host/v2-events.d.ts +56 -0
- package/dist/host/v2-events.d.ts.map +1 -0
- package/dist/host/v2-events.js +158 -0
- package/dist/host/v2-events.js.map +1 -0
- package/dist/host/v2-guard.d.ts +101 -0
- package/dist/host/v2-guard.d.ts.map +1 -0
- package/dist/host/v2-guard.js +199 -0
- package/dist/host/v2-guard.js.map +1 -0
- package/dist/host/v2-offload.d.ts +148 -0
- package/dist/host/v2-offload.d.ts.map +1 -0
- package/dist/host/v2-offload.js +288 -0
- package/dist/host/v2-offload.js.map +1 -0
- package/dist/host/v2-permissions.d.ts +123 -0
- package/dist/host/v2-permissions.d.ts.map +1 -0
- package/dist/host/v2-permissions.js +190 -0
- package/dist/host/v2-permissions.js.map +1 -0
- package/dist/host/v2-probe.d.ts +85 -0
- package/dist/host/v2-probe.d.ts.map +1 -0
- package/dist/host/v2-probe.js +268 -0
- package/dist/host/v2-probe.js.map +1 -0
- package/dist/host/v2-scope.d.ts +51 -0
- package/dist/host/v2-scope.d.ts.map +1 -0
- package/dist/host/v2-scope.js +58 -0
- package/dist/host/v2-scope.js.map +1 -0
- package/dist/host/v2-session-client.d.ts +74 -0
- package/dist/host/v2-session-client.d.ts.map +1 -0
- package/dist/host/v2-session-client.js +171 -0
- package/dist/host/v2-session-client.js.map +1 -0
- package/dist/host/v2-session.d.ts +85 -0
- package/dist/host/v2-session.d.ts.map +1 -0
- package/dist/host/v2-session.js +171 -0
- package/dist/host/v2-session.js.map +1 -0
- package/dist/host/v2-subagent.d.ts +157 -0
- package/dist/host/v2-subagent.d.ts.map +1 -0
- package/dist/host/v2-subagent.js +286 -0
- package/dist/host/v2-subagent.js.map +1 -0
- package/dist/host/v2-tool.d.ts +67 -0
- package/dist/host/v2-tool.d.ts.map +1 -0
- package/dist/host/v2-tool.js +209 -0
- package/dist/host/v2-tool.js.map +1 -0
- package/dist/host/v2-transcript.d.ts +73 -0
- package/dist/host/v2-transcript.d.ts.map +1 -0
- package/dist/host/v2-transcript.js +151 -0
- package/dist/host/v2-transcript.js.map +1 -0
- package/dist/host/v2-types.d.ts +229 -0
- package/dist/host/v2-types.d.ts.map +1 -0
- package/dist/host/v2-types.js +17 -0
- package/dist/host/v2-types.js.map +1 -0
- package/dist/host/v2.d.ts +42 -0
- package/dist/host/v2.d.ts.map +1 -0
- package/dist/host/v2.js +706 -0
- package/dist/host/v2.js.map +1 -0
- package/dist/index.d.ts +23 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -366
- 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 +452 -426
- package/dist/prompts/lead.js.map +1 -1
- package/dist/prompts/shared.d.ts +2 -2
- package/dist/prompts/shared.d.ts.map +1 -1
- package/dist/prompts/shared.js +30 -10
- 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 +7 -6
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/task-offload.d.ts +16 -0
- package/dist/task-offload.d.ts.map +1 -1
- package/dist/task-offload.js +51 -0
- package/dist/task-offload.js.map +1 -1
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +41 -10
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/dispatch.d.ts +47 -0
- package/dist/tm/dispatch.d.ts.map +1 -1
- package/dist/tm/dispatch.js +230 -31
- package/dist/tm/dispatch.js.map +1 -1
- package/dist/tm/dupe-guard.d.ts +16 -3
- package/dist/tm/dupe-guard.d.ts.map +1 -1
- package/dist/tm/dupe-guard.js +27 -7
- package/dist/tm/dupe-guard.js.map +1 -1
- package/dist/tm/index.d.ts +40 -1
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +40 -11
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/ledger.d.ts +114 -0
- package/dist/tm/ledger.d.ts.map +1 -0
- package/dist/tm/ledger.js +308 -0
- package/dist/tm/ledger.js.map +1 -0
- package/dist/tm/perm-ask.d.ts +1 -3
- package/dist/tm/perm-ask.d.ts.map +1 -1
- package/dist/tm/perm-ask.js +10 -1
- package/dist/tm/perm-ask.js.map +1 -1
- package/dist/tm/preview.d.ts +55 -0
- package/dist/tm/preview.d.ts.map +1 -1
- package/dist/tm/preview.js +225 -0
- package/dist/tm/preview.js.map +1 -1
- package/dist/tm/search.d.ts.map +1 -1
- package/dist/tm/search.js +40 -10
- package/dist/tm/search.js.map +1 -1
- package/dist/tm/serp-loop.d.ts +45 -0
- package/dist/tm/serp-loop.d.ts.map +1 -0
- package/dist/tm/serp-loop.js +80 -0
- package/dist/tm/serp-loop.js.map +1 -0
- package/dist/tm/stats.d.ts +10 -0
- package/dist/tm/stats.d.ts.map +1 -1
- package/dist/tm/stats.js +160 -0
- package/dist/tm/stats.js.map +1 -1
- package/dist/tm/webfetch.d.ts +4 -0
- package/dist/tm/webfetch.d.ts.map +1 -1
- package/dist/tm/webfetch.js +75 -8
- package/dist/tm/webfetch.js.map +1 -1
- package/docs/installation-v2.md +436 -0
- package/docs/installation.md +12 -0
- package/docs/research/agent-data-exchange.md +117 -0
- package/docs/research/browser-pane.md +89 -0
- package/docs/research/host-http-api.md +132 -0
- package/docs/research/host-subagent-injection.md +187 -0
- package/docs/research/plugin-loader-contract.md +261 -0
- package/docs/research/v2-builtin-tools.md +447 -0
- package/docs/v2-port-notes.md +315 -0
- package/index.js +7 -0
- package/package.json +64 -61
- package/scripts/gen-v2-config.mjs +304 -0
- package/scripts/lib/config-surgery.cjs +239 -0
- package/scripts/lib/fake-ctx.mjs +146 -0
package/README.md
CHANGED
|
@@ -19,9 +19,12 @@
|
|
|
19
19
|
> **The lazy path:** paste this to any coding agent and let it do the work:
|
|
20
20
|
>
|
|
21
21
|
> ```text
|
|
22
|
-
> Install the OpenCode plugin @te-river/opencode-team-mode
|
|
23
|
-
> https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
24
|
-
>
|
|
22
|
+
> Install the OpenCode plugin @te-river/opencode-team-mode. First run `opencode --version`:
|
|
23
|
+
> 1.18.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
24
|
+
> 2.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation-v2.md
|
|
25
|
+
> (on 2.x a plugin cannot create an agent, so the six roles and six `/team-*` commands come
|
|
26
|
+
> from a generator step in that guide — that step is not optional.) Then verify the install
|
|
27
|
+
> using the checks in that guide.
|
|
25
28
|
> ```
|
|
26
29
|
>
|
|
27
30
|
> **The one command to remember afterwards:** `/team-run <task>` — the Team Lead
|
|
@@ -48,7 +51,7 @@ TeamMode's answer to each:
|
|
|
48
51
|
| 🐌 **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
52
|
| 🕳️ **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
53
|
| 🌫️ **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
|
|
54
|
+
| 🧭 **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 renderer's supported set is measured rather than assumed, and the prompts carry the negative half of that measurement — footnotes, `==highlight==`, a bare `---` rule and `$…$` math reach you as literal text, so agents are told not to use them, while `mermaid` diagrams are offered because this host does draw them. |
|
|
52
55
|
| 🎯 **Goal drift** | The lead opens with `GOAL:` in your own words plus checkable `ACCEPTANCE:` criteria, and the run does not end while a criterion lacks evidence — the only legitimate stops are named (blocked on you, or provably unachievable). When a round settles with items still open on the host's todo list, `tm_join` says 目标未达成 and lists them, and the goal is carried through context compaction so a summarized transcript cannot redefine it. |
|
|
53
56
|
|
|
54
57
|
| 🗣️ **Replies in a language you never chose** | The governed tools answer in Chinese, and an agent left to its own devices mirrors that straight back at you. Every role now carries a reply-language rule: your own language wins, and a Chinese string is quoted verbatim only where it IS the evidence (a close verdict, a refusal line) — translating a verdict is how an unchecked claim starts looking checked. |
|
|
@@ -87,9 +90,12 @@ orchestrator (opt-out in [Configuration](#-configuration)).
|
|
|
87
90
|
Copy this into any coding agent — it will edit your config, restart-remind you, and verify:
|
|
88
91
|
|
|
89
92
|
```text
|
|
90
|
-
Install the OpenCode plugin @te-river/opencode-team-mode
|
|
91
|
-
https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
92
|
-
|
|
93
|
+
Install the OpenCode plugin @te-river/opencode-team-mode. First run `opencode --version`:
|
|
94
|
+
1.18.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
95
|
+
2.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation-v2.md
|
|
96
|
+
(on 2.x a plugin cannot create an agent, so the six roles and six `/team-*` commands come from
|
|
97
|
+
a generator step in that guide — that step is not optional.)
|
|
98
|
+
(If a URL is unreachable — common on mainland-China networks — retry with
|
|
93
99
|
the mirror prefix: https://ghproxy.net/ + the same path.)
|
|
94
100
|
Then verify the install using the checks in that guide.
|
|
95
101
|
```
|
|
@@ -127,6 +133,12 @@ Add the plugin to your `opencode.jsonc`:
|
|
|
127
133
|
|
|
128
134
|
OpenCode installs the plugin on next startup.
|
|
129
135
|
|
|
136
|
+
> **On OpenCode 2.x the key is `plugins` (plural)** — a 2.x host never reads the singular
|
|
137
|
+
> `plugin` key, and it installs the package itself from the entry at startup. See
|
|
138
|
+
> [docs/installation-v2.md](./docs/installation-v2.md) for the 2.x flow (a plugin cannot
|
|
139
|
+
> create an agent there, so the six roles and six commands are generated config files);
|
|
140
|
+
> `docs/research/plugin-loader-contract.md` has the host's own loader code.
|
|
141
|
+
|
|
130
142
|
### ⚠️ Read this once, save yourself an hour later
|
|
131
143
|
|
|
132
144
|
- **Restart to activate.** After touching `opencode.json`, fully quit and restart OpenCode (Desktop: quit from tray, not just the window).
|
|
@@ -261,17 +273,60 @@ through with `tm_fetch` when it genuinely needs the payload.
|
|
|
261
273
|
|
|
262
274
|
| Tool | What it does | Roles |
|
|
263
275
|
|---|---|---|
|
|
264
|
-
| `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 |
|
|
276
|
+
| `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 — **except on OpenCode 2.x, where the first three are not registered; see the note under this table** |
|
|
265
277
|
| `tm_memory` | Session + project + global memory store (Markdown + frontmatter): add / search / list / forget / compact | all six agents |
|
|
266
278
|
| `tm_board_write` | **The blackboard's write side**: places ONE new Markdown file at `<board-root>/<session-key>/<task-slug>/NN-<role>-<topic>[-rN].md` and chooses the name itself — a revision is a new round-suffixed file, never an overwrite, and the reply carries the path plus the byte count, never the content. It exists because the board used to need a file tool, and `architect` / `researcher` own none (no `write`, no `edit`, no `bash` even to stamp the session folder), so every oversized deliverable from those roles came back as `BLACKBOARD WRITE FAILED` plus the whole document pasted inline — the reply shape this team mandates was un-followable exactly where it mattered. Scope is enforced rather than asked: segments sanitized, target realpath-verified against the board root (a symlinked task dir is refused), the name always ends in `.md` so no `.env`/rc file can be produced, caps via `TM_BOARD_MAX_CHARS` + a per-session file limit | All six agents |
|
|
267
279
|
| `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 |
|
|
268
280
|
| `tm_search` | Multi-engine web search with extracted, deduplicated, RRF-fused hit lists | Lead + Researcher |
|
|
269
281
|
| `tm_webfetch` | Single governed GET of an allowlisted page (search pages auto-extracted). Manual redirects, re-checked per hop, and a refusal names the WHOLE chain (`跳转链: a → b(停在第 2 跳)`) — an allowlisted shortener that bounces off-site used to report only the off-site host, which read as "that site will not fetch" and sent the agent back to retry the entry URL it had just watched fail. A 429/503 carries its own `Retry-After` when the server sends delta-seconds (an HTTP-date is deliberately not laundered into a countdown), so "come back later" never looks like "no content here". The page GET also asks for Markdown first (`Accept: text/markdown,…`) — measured on `learn.microsoft.com`: 60,778 B of HTML becomes 11,449 B of Markdown, and every other host tried returns the same document either way, so the preference is free where it is ignored | Lead + Researcher |
|
|
270
|
-
| `
|
|
271
|
-
| `
|
|
282
|
+
| `tm_ledger` | **The lead's task ledger** (`add` / `doing` / `done` / `blocked` / `list`), stored in the host's own `ctx.storage` per session — the landing spot for the LEDGER rule on OpenCode 2.x, which gives a plugin no `todowrite`. A repeated ask is ONE item, an id that matches two is refused with both printed, `blocked` carries the reason, and a write that did not reach storage is reported as a failure rather than as recorded. **v2 only** — v1 keeps the host's `todowrite` | Lead only |
|
|
283
|
+
| `tm_join` | **Sub-agent collection** — there is no plugin-side dispatcher any more (`tm_dispatch` is removed: a child a plugin creates is a session the user can neither open nor stop from the interface). Delegation goes through the host's own `task` / `task { background: true }`, and `tm_join` is the read side: a status snapshot, a bounded `waitMs`, `cancel:true` to abort, and `claimNamedChild` so `tm_join { ids: ["ses_…"] }` pulls one child's WHOLE reply back through the offload pipeline (handle + ≤80-token preview) instead of kilotokens inline. It also rebuilds its registry from the host session tree after a restart, so leftover children are 接管 rather than lost. **On 2.x it also registers the children the host's own `subagent` tool created** (the ack's `metadata.sessionID` is the seam), so a background dispatch is never reported as "nothing to collect" while the user watches it run — and such a row says where its reply actually arrives (the host's injected message) and whether it settled by event or by inference | Lead only |
|
|
284
|
+
| `tm_pty` (**v1 only** — v2 registers nothing: the plugin ctx has no pty domain) | **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 |
|
|
272
285
|
| `tm_stats` | **The plugin reads its own trajectory back**: tokens kept out of the context window by offloading (net of the preview that arrived), seconds saved by dispatch overlap (serial cost minus the wall window the children actually used), PTC internals, governance counts (blocked subresources, refused `tm_pty` starts, clamped bash timeouts, cache hits, redactions) — plus the **host capability matrix** (`已验证/存在未用/待观察/缺失/需人眼` per host surface). Read-only over files this plugin wrote; run it first after an OpenCode upgrade. `{ recent: 20 }` appends a call-by-call recap — handle + payload path for every offloaded result, which is how you see what a governed tool actually returned (the host gives plugin tools no expandable card) | All agents |
|
|
273
286
|
| `tm_browser` | Interactive browser session (**your default browser**): 18 Playwright verbs (snapshot-first `take_snapshot` → uid-addressed `click`/`fill`/`drag`/…, **including multi-tab `new_page` / `close_page`** so you can hold two pages at once) + 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. **One browser per agent**: `open` returns an id (`b1`) and every reply is tagged with it — that window, its uid numbering and its dialog-approved hosts belong to YOUR session; another agent's id is refused with the owner named (an id is a name, not a key), and `close { id:"all" }` closes only your own. `click` reports what the PAGE did, not merely that a mouse event was sent: it reads the target's observable state before and after (`aria-expanded`, URL, DOM node count) and answers `已点击 … · aria-expanded: false → true`, retries once if the page had not finished loading — the measured cause of a click that lands on a node with no handler — and says 页面没有任何可观测变化 rather than implying success. `close` will not say 已确认关闭 until the browser's OS process is gone — it waits on the pid, terminates it once if it lingers, and prints the pid either way, because a dropped connection is not a closed browser; when no pid could be resolved it says 进程未核验 rather than borrowing that sentence. A browser this process launched but could not reap is recorded in a per-workspace ledger (pid, owner pid, executable) and reclaimed by the next boot — only entries whose owner process is dead *and* whose pid still is that executable, terminated as a whole tree (`taskkill /T` on Windows), never another window's live tab. **A blank page now explains itself**: `same-site` cannot know that a site's own bundle lives on a brand-unrelated CDN (Baidu serves its scripts from `bdimg.com`), so when a page comes back with `0 个可寻址节点` while a script host was blocked, the reply says the blankness is **our gate**, names the host, and offers `allow_host { host }` — one official dialog for one bare domain, for your browser only, for this session, nothing written to config (re-navigate afterwards, the gate decides per request). A page that is really a human-verification wall (百度安全验证 / Cloudflare / access denied) is reported as a wall, because the move there is another source, not another retry | Lead + Researcher + Tester (UI verification) |
|
|
274
287
|
|
|
288
|
+
> **On OpenCode 2.x, five of those tools are deliberately not registered.**
|
|
289
|
+
> `tm_read` / `tm_grep` / `tm_bash` are replaced by the host's own `read` / `grep` /
|
|
290
|
+
> `glob` / `shell`, and `tm_ptc_run` by the host's `execute` (Code Mode) — the same
|
|
291
|
+
> job, one fewer tool for the model to choose between. The governance did NOT
|
|
292
|
+
> disappear with them: an oversized native result is offloaded through
|
|
293
|
+
> `tool.execute.after` (measured: `shell` 12,902 tokens arriving as a 78-token
|
|
294
|
+
> preview), and the address red line plus R6's per-command classification ride the
|
|
295
|
+
> host's `permission.evaluate`. `tm_ledger` is the one tool that exists ONLY on v2 (the lead's list needs a home where
|
|
296
|
+
> `todowrite` does not).
|
|
297
|
+
> **Nothing we change reaches outside Team.** Every v2 hook fires for every session on
|
|
298
|
+
> the host, so the tool-surface trim, the 0.2 temperature, the blackboard note, the offload
|
|
299
|
+
> of native results, the R6/address strictening and the forced-background dispatch all ask
|
|
300
|
+
> "is this one of our six roles?" first — `build`, `plan` and your own agents stay as a
|
|
301
|
+
> fresh install leaves them. Calls whose owner the host did not tell us are left alone too,
|
|
302
|
+
> and counted (`tm_stats` prints `作用域:我们 · 他人 · 未判定`).
|
|
303
|
+
> The installer writes the v2 variants of the six
|
|
304
|
+
> role prompts, which name `read` / `grep` / `shell` instead of the aliases.
|
|
305
|
+
> Everything above this note describes the v1 (1.18.x) surface, which still ships
|
|
306
|
+
> all thirteen.
|
|
307
|
+
|
|
308
|
+
> **On OpenCode 2.x, interactive browsing is the host's, and it stays ours.** The
|
|
309
|
+
> desktop renders a browser in its side panel, and that panel attaches to the
|
|
310
|
+
> server's own browser service — a plugin cannot register a page of its own into it
|
|
311
|
+
> (forensics: `docs/research/browser-pane.md`). So the three roles with network
|
|
312
|
+
> grants (lead, researcher, tester) are pointed at the host's `browser_*` tools
|
|
313
|
+
> first, and `tm_browser` remains the governed door for hosts with no desktop
|
|
314
|
+
> browser attached (CLI, standalone). Handing browsing over did not mean handing
|
|
315
|
+
> governance over: `permission.evaluate` was observed NOT firing for `browser_*`, so
|
|
316
|
+
> our gate sits on `tool.execute.before` instead — it classifies the URL of every
|
|
317
|
+
> navigate/open, the path of every `browser_preview`, and every browser URL named
|
|
318
|
+
> inside an `execute` program, refuses the ones out of policy, and if the host runs a
|
|
319
|
+
> refused call anyway it replaces the page with the same refusal, so no
|
|
320
|
+
> out-of-policy content reaches the context, the store or the trajectory. What we
|
|
321
|
+
> cannot do is un-make a request the host already performed, and the reply says so
|
|
322
|
+
> rather than claiming a block; `tm_stats` prints the two numbers apart (refused /
|
|
323
|
+
> leaked past the refusal). One exception to the offload rule lives here: a
|
|
324
|
+
> `browser_snapshot` is an addressing table, not a document, so it is CAPPED (every
|
|
325
|
+
> `[ref=…]` line kept, static text dropped, budget `TM_NATIVE_SNAPSHOT_MAX_TOKENS`
|
|
326
|
+
> default 1 200 — the same budget `tm_browser` runs at) rather than replaced by a
|
|
327
|
+
> handle. Measured on a 261-ref page: a head cut keeps 118 refs, this keeps 261 of
|
|
328
|
+
> them using 1 044 of 11 326 tokens.
|
|
329
|
+
|
|
275
330
|
> **Fixed tool priority ladder (every task): ① the user's own MCP/plugin
|
|
276
331
|
> tools → ② TeamMode governed tools (`tm_*`) → ③ the model's own reasoning.**
|
|
277
332
|
> It doubles as the fallback chain: when a tool errors (no browser on this
|
|
@@ -565,6 +620,14 @@ for overrides, extra agents and disabling roles.
|
|
|
565
620
|
| Env var | Default | Purpose |
|
|
566
621
|
|---|---|---|
|
|
567
622
|
| `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` (off also disarms the approval timer) |
|
|
623
|
+
| `TM_R6_FINE_ASK` | classifier (v2 only) | On **v2** the command line is judged per-call by the host's `permission.evaluate` hook, so an ordinary `git status` asks nothing and an env dump still does. `off` falls back to asking about EVERY shell command — which is also what happens automatically on a host that does not expose the hook, and the boot note says which of the two caused it. v1 is unaffected: it classifies in the tool-call hook either way |
|
|
624
|
+
| `TM_V2_CODEMODE` | catalog (opt-in `direct`) — **v2 only** | How our tools reach the model. OpenCode 2.x decides tool visibility with `options.codemode`. We used to send `codemode:false` by default and claim direct delivery — **a live 2.0.16 desktop session disproved it**: with the flag sent, every `tm_*` still arrived inside the host's Code Mode catalog ("They cannot be called directly…"), and the model's own callable list was the nine native tools. So the default now sends nothing, and `direct` is an experiment for a build that honours it. The observable truth is `tools_in_request` in the shutdown record (rendered by `tm_stats` as `请求内实际可见=…`), never the flag we sent |
|
|
625
|
+
| `TM_LEDGER_MAX_ITEMS` | 200 | Ceiling on `tm_ledger` items per session. The host's `ctx.storage` has no TTL and no quota (measured), so the list refuses to grow past this instead of quietly dropping the oldest asks — and a refusal is something the lead can act on, while a silent truncation is a claim nobody can re-check |
|
|
626
|
+
| `TM_V2_PROBE` | — (v2 only) | Path to a JSONL file where the surface probe records the host's real tool ids, permission action names and argument key names. Names and counts only — never a command line, path, URL or env value. It is how "does the host actually have X?" gets answered from the running build instead of from a doc; without it the same name sets still ride the trajectory so `tm_stats` can show them |
|
|
627
|
+
| `TM_PRIVATE_SPACE` | `ask` on v1 · `deny` on **v2** | What private space (loopback, RFC1918, ULA, CGNAT, `.localhost`) does through our tools: `ask` routes it to the host dialog (v1 can raise one), `allow` opens the class, `deny` refuses it. v2 defaults to `deny` because a plugin there cannot raise a dialog — telling the agent to wait for a window that will never open is not a gate with a procedure — so the refusal prints both operator exits instead (`allow`, or that one hostname in `TM_WEBFETCH_ALLOWED_DOMAINS`). Never conflated with the FORBIDDEN ranges: cloud-metadata / link-local / reserved are refused under every setting and every allowlist, with no consent path |
|
|
628
|
+
| `TM_V2_BROWSER_GATE` | on — **v2 only** | The gate over the host's `browser_*` catalog (URLs and preview paths at `execute.before`, plus the browser URLs named inside an `execute` program). `off` restores the host's ungoverned browsing; the boot line and `tm_stats` say which world is running |
|
|
629
|
+
| `TM_NATIVE_REPORT_MAX_TOKENS` | 1600 — **v2 only** | The budget a report-shaped native result (anything carrying a Markdown table — `tm_stats` via Code Mode, a `tm_join` summary) keeps in context. Table lines and their headings win the space and the prose between them is what gets dropped, because a table with a hole in it is not a table; the full text still rides the handle |
|
|
630
|
+
| `TM_NATIVE_SNAPSHOT_MAX_TOKENS` | 1200 — **v2 only** | The budget a native `browser_snapshot` / `browser_find` keeps in context. Addressing lines win it before static text does; past `budget × 4` the reply states how many ref lines did not fit, and kept + dropped always equals the total |
|
|
568
631
|
| `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). Every governed tool ALSO ends the wait itself at this + 15 s, because the gate is only armed when R6 is on and the client can reply — and a tool that waits forever reads as a hang, not as a request for your attention |
|
|
569
632
|
| `TM_ASK_TIMEOUT_FLOOR_MIN` | `1` | minimum enforced for the ask timeout above |
|
|
570
633
|
| `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex; always hard block, never dialog-governed) |
|
|
@@ -579,7 +642,7 @@ for overrides, extra agents and disabling roles.
|
|
|
579
642
|
| `TM_BOARD_MAX_FILES` | `200` | tm_board_write: markdown files allowed per session folder; the TTL sweeper is the only reclaim path, so the refusal names it and the `ttlDays` option |
|
|
580
643
|
| `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
|
|
581
644
|
| `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) |
|
|
582
|
-
| `TM_WEBFETCH_ALLOWED_DOMAINS` | the 24 seeded hosts | tm_webfetch / tm_search / tm_browser allowlist (`"*"` opens all; empty = deny all; a custom list REPLACES the seed — keep the engine hosts). A site's own asset CDN has to be seeded or `tm_browser` renders it blank — `bdimg.com` is there for exactly that reason; per-session gaps go through `tm_browser { action:"allow_host", host }` instead of an env edit. `"*"` does **not** cover private space: loopback / RFC1918 / CGNAT / `.localhost` still need the dialog on every use, and non-routable ranges (169.254.0.0/16 metadata, 0.0.0.0/8, multicast, reserved, plus the IPv4-mapped and DNS64 spellings of the same target) are a hard red line no setting can open |
|
|
645
|
+
| `TM_WEBFETCH_ALLOWED_DOMAINS` | the 24 seeded hosts on v1; `"*"` on **v2** | tm_webfetch / tm_search / tm_browser allowlist (`"*"` opens all; empty = deny all; a custom list REPLACES the seed — keep the engine hosts). A site's own asset CDN has to be seeded or `tm_browser` renders it blank — `bdimg.com` is there for exactly that reason; per-session gaps go through `tm_browser { action:"allow_host", host }` instead of an env edit. `"*"` does **not** cover private space: loopback / RFC1918 / CGNAT / `.localhost` still need the dialog on every use, and non-routable ranges (169.254.0.0/16 metadata, 0.0.0.0/8, multicast, reserved, plus the IPv4-mapped and DNS64 spellings of the same target) are a hard red line no setting can open |
|
|
583
646
|
| `TM_BROWSER_PATH` | auto-detect | tm_browser executable override (default: your DEFAULT browser when Chromium-family, else Edge/Chrome probes) |
|
|
584
647
|
| `TM_BROWSER_HEADLESS` | `auto` | `1` headless (CI) / `0` headful / `auto` (headless only on display-less Linux) |
|
|
585
648
|
| `TM_BROWSER_ENGINE` | `playwright` | `playwright` (needs Node ≥ 20; any import failure auto-degrades) / `cdp-legacy` (zero-dep CDP pipe, core verbs only) |
|
|
@@ -598,7 +661,7 @@ for overrides, extra agents and disabling roles.
|
|
|
598
661
|
| `TM_PTY_MAX` | `4` | concurrent `tm_pty` terminal sessions this plugin may keep running at once |
|
|
599
662
|
| `TM_JOIN_MAX_WAIT_MS` | `60000` | ceiling on `tm_join { waitMs }`. Was 300 000, and a lead parked in it twice in a row (19 min of nothing) while its children worked — waiting is not parallelism, so the default now says "check, then work". A second consecutive wait after nothing settled is cut to 10 s and answered with what to do instead |
|
|
600
663
|
| `TM_STORE_RECLAIM` | `on` | at boot, reclaim what an upgrade left behind: a per-workspace store shard idle past the TTL, and the pre-shard `blackboard/` + `trajectory/` under the temp-dir fallback (503 MB of expired runs on one real machine, with no sweeper pointed at them any more). Only TTL-expired entries are ever removed — a fresh run dir survives, because a session started before the upgrade may still be writing there. `off` leaves the disk exactly as found (the test runner sets it) |
|
|
601
|
-
| `TM_TASK_OFFLOAD` | `on` | keep the HOST's background sub-agent inside the context budget: when `task { background: true }` finishes, the host injects the child's full reply into your session; this replaces an oversized body with a preview + a `tm_fetch`-style pointer (`tm_join { ids: [...] }`), touching ONLY synthetic parts that carry the host's own `<task id=… state="completed">` envelope and exceed the text offload threshold. Nothing is copied to disk — the text stays where it was written (the child session). `off` restores the host's verbatim injection |
|
|
664
|
+
| `TM_TASK_OFFLOAD` | `on` | keep the HOST's background sub-agent inside the context budget: when `task { background: true }` finishes, the host injects the child's full reply into your session; this replaces an oversized body with a preview + a `tm_fetch`-style pointer (`tm_join { ids: [...] }`), touching ONLY synthetic parts that carry the host's own `<task id=… state="completed">` envelope and exceed the text offload threshold. Nothing is copied to disk — the text stays where it was written (the child session). `off` restores the host's verbatim injection. **On OpenCode 2.x this half does not apply**: a v2 plugin is never handed the injected message before it is persisted, and we deliberately do NOT rewrite outgoing messages (a wrong guess about that layer's shape deletes evidence silently — the v1 `experimental.chat.messages.transform` path is left unimplemented on purpose). The compensation there is contractual, not a rewrite: the child's oversized deliverable goes to the blackboard file and its reply carries the path, so the lead reads the summary and pulls the whole thing with `tm_join` |
|
|
602
665
|
| `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) |
|
|
603
666
|
| `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 |
|
|
604
667
|
| `TM_COMPACTION_CONTEXT` | `on` | on the host's pre-compaction hook, add the must-survive list (reply skeleton, offload handles, open sub-agent session ids, provenance, board paths). Additive — the host's own summarizer prompt is never replaced |
|
|
@@ -727,7 +790,7 @@ self-approves — the only side it can take is yours or nobody's.
|
|
|
727
790
|
|
|
728
791
|
## 🗑️ Uninstall
|
|
729
792
|
|
|
730
|
-
1. Remove the entry from the `"plugin"` array in your config file.
|
|
793
|
+
1. Remove the entry from the `"plugin"` array in your config file — **`"plugins"` (plural) on OpenCode 2.x**, which is also where the 2.x installers write; if you installed on 2.x, delete the generated `~/.config/opencode/agents/*.md` and `commands/team-*.md` too, and any `default_agent: "team"` you no longer want.
|
|
731
794
|
2. Delete the cache dir (table in [Install](#-read-this-once-save-yourself-an-hour-later)) if you want the disk space back.
|
|
732
795
|
3. Restart OpenCode. The agents, commands and tools are gone; the stores under `<repo>/.git/opencode-team/` (and `~/.opencode-team/` for global memories) are plain files you can delete whenever.
|
|
733
796
|
|
|
@@ -750,7 +813,8 @@ opencode-team-mode/
|
|
|
750
813
|
│ ├── tm/ ← Governed tools: pipelines / store / preview / guard / refs /
|
|
751
814
|
│ │ webfetch / search / memory / browser / shell-bridge / ptc/ (9 modules)
|
|
752
815
|
│ └── types.ts ← Loader-contract types (1.18.x)
|
|
753
|
-
├── docs/installation.md ← The agent-consumable install guide
|
|
816
|
+
├── docs/installation.md ← The agent-consumable install guide (1.18.x)
|
|
817
|
+
├── docs/installation-v2.md ← The 2.x install guide (roles arrive as generated config files)
|
|
754
818
|
├── scripts/ ← One-line installers (bash / PowerShell)
|
|
755
819
|
├── pt07/ ← PT-07 baseline suite (seeded A/B token measurement)
|
|
756
820
|
└── README.*.md ← You are here (twice)
|
|
@@ -782,7 +846,8 @@ are intentionally loose but not psychic).
|
|
|
782
846
|
## 🔗 Links
|
|
783
847
|
|
|
784
848
|
- [npm Package](https://www.npmjs.com/package/@te-river/opencode-team-mode) — `@te-river/opencode-team-mode`
|
|
785
|
-
- [Installation guide](./docs/installation.md) — the complete manual / agent-consumable procedure
|
|
849
|
+
- [Installation guide, 1.18.x](./docs/installation.md) — the complete manual / agent-consumable procedure
|
|
850
|
+
- [Installation guide, **OpenCode 2.x**](./docs/installation-v2.md) — a different install: a 2.x plugin cannot create an agent, so the six roles and six commands are generated into the config directory
|
|
786
851
|
- [OpenCode Desktop](https://opencode.ai) — Official website & download
|
|
787
852
|
- [OpenCode Docs](https://opencode.ai/docs) — Configuration & plugin documentation
|
|
788
853
|
- [OpenCode Plugin API](https://opencode.ai/docs/plugins) — Build your own plugins
|
package/README.zh-CN.md
CHANGED
|
@@ -19,9 +19,11 @@
|
|
|
19
19
|
> **懒人路径:** 把下面这段话粘给任意编码 agent,让它替你装:
|
|
20
20
|
>
|
|
21
21
|
> ```text
|
|
22
|
-
> 安装 OpenCode 插件 @te-river/opencode-team-mode
|
|
23
|
-
> https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
24
|
-
>
|
|
22
|
+
> 安装 OpenCode 插件 @te-river/opencode-team-mode:先跑 `opencode --version` 判断版本。
|
|
23
|
+
> 1.18.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
24
|
+
> 2.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation-v2.md
|
|
25
|
+
> (2.x 的插件不能创建 agent,六个角色和六条 `/team-*` 命令要靠那份指南里的生成步骤落到
|
|
26
|
+
> 配置目录——这一步不是可选的。)然后按该指南里的检查项验证。
|
|
25
27
|
> ```
|
|
26
28
|
>
|
|
27
29
|
> **装好后只需要记住一条命令:** `/team-run <任务>` —— Team Lead 会先出计划、
|
|
@@ -47,9 +49,8 @@ TeamMode 对每一个的回应:
|
|
|
47
49
|
| 🐌 **回合开销** | `tm_ptc_run`:agent 写**一个程序**,单回合内发起 N 次受治理调用。运行期间零 LLM 回合。 |
|
|
48
50
|
| 🕳️ **静默副作用** | R6/R2 审批门禁:环境变量读取和危险操作走 OpenCode 官方确认弹窗,1 分钟没人理自动拒绝。插件从不代替你批准——它只会拒绝。 |
|
|
49
51
|
| 🌫️ **幻觉式调研** | 联网是双角色的授权 + 白名单受治理工具链。抓不到的事实就报告为缺口——绝不编造。 |
|
|
50
|
-
| 🧭 **纯文本墙** | 回复被引导成宿主渲染得最快的形状:逐文件 / 逐用例 / 逐条发现用 markdown 表格,diff
|
|
52
|
+
| 🧭 **纯文本墙** | 回复被引导成宿主渲染得最快的形状:逐文件 / 逐用例 / 逐条发现用 markdown 表格,diff 和配置用围栏代码块,浏览器截图只在你明确要求时才内联附上。宿主支持哪些语法是实测出来的、不是照着 CommonMark 猜的,提示词里带着这份实测的否定清单——脚注 `[^1]`、`==高亮==`、单独的 `---` 分隔线和 `$…$` 数学会以字面量形式出现在你面前,所以 agent 被明确告知不要用;而 `mermaid` 图是可以用的,因为这个宿主确实会画。 |
|
|
51
53
|
| 🎯 **目标漂移** | lead 开局必须用你自己的措辞写下 `GOAL:` 和可验证的 `ACCEPTANCE:` 判据,判据没有证据支撑这一轮就不算结束——合法的停止只有两种(卡在你这里,或有证据地证明做不到)。一轮收完但宿主 todolist 上还有未完成项时,`tm_join` 会直接说"目标未达成"并列出条目;目标本身随上下文压缩一起存活,摘要不能悄悄把它换掉。 |
|
|
52
|
-
|
|
53
54
|
| 🗣️ **用你没选的语言回话** | 受治理工具回复的是中文,agent 放任自己就会把这份中文原样反射给你。现在每个角色都带一条回复语言规则:**你用的语言优先**;中文句子只在"它本身就是证据"时逐字引用(close 的三种裁决、拒绝语)——把裁决词翻译掉,正是未经核实的结论看起来像核实过的开始。 |
|
|
54
55
|
| ⏱️ **为了"看起来很认真"而烧掉的轮次** | 效率至上写进了 lead 和五个专家:一次宽调用代替三次窄调用、互不依赖的调用并到同一轮、≥3 个探测合成一次 `tm_ptc_run`、不许为了"再看它绿一遍"重跑同一个检查。同时把边界写死:效率不能拿去赎回证据规则——一个没验证过的"done"会让你赔上那一轮 **加上** 那个 bug。 |
|
|
55
56
|
|
|
@@ -85,10 +86,12 @@ TeamMode 对每一个的回应:
|
|
|
85
86
|
把这段话粘给任意编码 agent——它会改配置、提醒你重启、并完成验证:
|
|
86
87
|
|
|
87
88
|
```text
|
|
88
|
-
安装 OpenCode 插件 @te-river/opencode-team-mode
|
|
89
|
-
https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
安装 OpenCode 插件 @te-river/opencode-team-mode:先跑 `opencode --version` 判断版本。
|
|
90
|
+
1.18.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation.md
|
|
91
|
+
2.x → https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/docs/installation-v2.md
|
|
92
|
+
(2.x 的插件不能创建 agent,六个角色和六条 `/team-*` 命令要靠那份指南里的生成步骤落到配置
|
|
93
|
+
目录——这一步不是可选的。)按该指南里的检查项验证。
|
|
94
|
+
(若 URL 无法访问——中国大陆网络常见——改用镜像前缀重试:
|
|
92
95
|
https://ghproxy.net/ + 原路径。)
|
|
93
96
|
```
|
|
94
97
|
|
|
@@ -124,6 +127,12 @@ irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-Team
|
|
|
124
127
|
|
|
125
128
|
OpenCode 下次启动时装好。
|
|
126
129
|
|
|
130
|
+
> **OpenCode 2.x 上键名是 `plugins`(复数)**——2.x 宿主完全不读单数的 `plugin`,而且它会
|
|
131
|
+
> 在启动时按这个条目自己装包。2.x 的装法见
|
|
132
|
+
> [docs/installation-v2.md](./docs/installation-v2.md)(那里插件不能创建 agent,六个角色和
|
|
133
|
+
> 六条命令是生成的配置文件);宿主装载器的原始代码在
|
|
134
|
+
> `docs/research/plugin-loader-contract.md`。
|
|
135
|
+
|
|
127
136
|
### ⚠️ 现在读一遍,以后省一小时
|
|
128
137
|
|
|
129
138
|
- **改完配置要重启。** 碰了 `opencode.json` 之后,完全退出再启动 OpenCode(桌面版从托盘退出,不是只关窗口)。
|
|
@@ -252,17 +261,44 @@ HMAC 句柄,agent 真需要 payload 时用 `tm_fetch` 分页取。
|
|
|
252
261
|
|
|
253
262
|
| 工具 | 功能 | 角色 |
|
|
254
263
|
|---|---|---|
|
|
255
|
-
| `tm_read` / `tm_grep` / `tm_bash` / `tm_fetch` | 受治理的文件读 / 正则搜索 / 只读 shell(白名单)/ 句柄分页(JSON 句柄支持 `fields` 点路径投影——刻意小的 jq 子集,如 `items[].name`) | 全部六个 agent |
|
|
264
|
+
| `tm_read` / `tm_grep` / `tm_bash` / `tm_fetch` | 受治理的文件读 / 正则搜索 / 只读 shell(白名单)/ 句柄分页(JSON 句柄支持 `fields` 点路径投影——刻意小的 jq 子集,如 `items[].name`) | 全部六个 agent——**但在 OpenCode 2.x 上前三个不注册,见本表下方说明** |
|
|
256
265
|
| `tm_memory` | 会话 + 项目 + 全局三层记忆库(Markdown + frontmatter):add / search / list / forget / compact | 全部六个 agent |
|
|
257
266
|
| `tm_board_write` | **黑板的写入侧**:只在 `<board-root>/<session-key>/<task-slug>/NN-<role>-<topic>[-rN].md` 放下一个**新**的 Markdown 文件,文件名由工具自己决定——修订是一个带 `-rN` 的新文件,绝不覆写;回复只给路径和字节数,绝不回传正文。它存在的理由是:落黑板原本需要一个文件工具,而 `architect` / `researcher` 一个都没有(没有 `write`、没有 `edit`、连用来给会话目录打时间戳的 `bash` 都没有),于是这两类角色的超长交付每次都以 `BLACKBOARD WRITE FAILED` + 整篇文档内联回来收场——本项目最看重的那个回复形态,恰恰在最需要的角色身上无法执行。范围是强制的:路径段做规整、目标用 realpath 对齐黑板根(符号链接的任务目录直接拒写)、文件名永远以 `.md` 结尾(所以造不出 `.env`/rc 文件)、正文受 `TM_BOARD_MAX_CHARS` 与会话文件数上限约束 | 全部六个 agent |
|
|
258
267
|
| `tm_ptc_run` | 批量编排:一个程序、N 次受治理调用、零 LLM 回合;联网角色还能在程序里调 `tm.search` / `tm.webfetch` | 全部六个 agent |
|
|
259
268
|
| `tm_search` | 多引擎网络搜索,返回提取、去重、RRF 融合后的命中列表 | Lead + Researcher |
|
|
260
269
|
| `tm_webfetch` | 白名单页面的单次受治理 GET(搜索页自动提取)。重定向逐跳手动过检,被拒时会把**整条链**报出来(`跳转链: a → b(停在第 2 跳)`)——以前只会报最后一个主机,一个在白名单内的短链跳到站外时,读起来像"这个站点抓不到",于是 agent 又回去重试它刚眼睁睁失败的入口 URL。429/503 若带 delta-seconds 的 `Retry-After` 会一并报出(HTTP-date 形式刻意不折算成倒计时),所以"待会儿再来"不会被当成"这里没东西"。读页面时还会优先要 Markdown(`Accept: text/markdown,…`)——实测 `learn.microsoft.com`:60 778 B 的 HTML 变成 11 449 B 的 Markdown,其余站点两种请求返回同一份文档,所以在不支待的地方这个偏好是零成本的 | Lead + Researcher |
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
270
|
+
| `tm_ledger` | **领队的任务清单**(`add` / `doing` / `done` / `blocked` / `list`),存在宿主自己的 `ctx.storage` 里、按会话分开——OpenCode 2.x 不给插件 `todowrite`,LEDGER 规则从此有了落点。同一个要求重复提出只算一条;编号撞上两条会拒绝并把两条都列出来;`blocked` 带上卡住的原因;写不进存储就报失败,不会说成「已记录」。**仅 v2**——v1 继续用宿主的 `todowrite` | 仅领队 |
|
|
271
|
+
| `tm_join` | **子代理回收**——插件侧的派发器已经没有了(`tm_dispatch` 被移除:插件创建的子会话,用户既打不开也停不掉)。派活统一走宿主自己的 `task` / `task { background: true }`,`tm_join` 是它的读端:不带参数=状态快照,`waitMs`=有界等待,`cancel:true` 取消跑飞的子任务,`tm_join { ids: ["ses_…"] }` 则把某个子代理的**整篇**回复经卸载管线取回(句柄 + ≤80 token 预览),而不是几千 token 直接压进上下文。插件重启后它还会从宿主会话树重建登记,遗留的子代理被"接管"而不是丢失。**2.x 上它还会登记宿主自己的 `subagent` 工具派出去的子会话**(凭据就是那句确认里的 `metadata.sessionID`),所以用户明明在屏幕上看着子代理跑、`tm_join` 却说"没有待收集的派发"这种事不会再发生;这类行同时说清自己的正文是从哪儿到的(宿主的注入消息),以及它是靠事件结算的还是靠推断结算的 | 仅 Lead |
|
|
272
|
+
| `tm_pty`(**仅 v1**——v2 不注册:插件上下文没有 pty 域)| 在宿主自己的终端会话上**非阻塞执行命令**(`start`/`status`/`list`/`kill`):独立的构建与测试各自一个会话并行跑,不再串成一条 120 秒的 bash 调用。它不抓输出(命令自己 tee 日志,用 `tm_read` 读),且每次启动都先过 R6 分类器、R2 危险面 glob,再走官方确认窗,才真的建进程 | 仅 Lead |
|
|
263
273
|
| `tm_stats` | **插件把自己的 trajectory 读回来**:卸载挡在上下文之外的 token(扣掉确实回来的预览)、派发重叠省下的秒数(串行代价减去子代理实际占用的墙钟)、PTC 内部量、治理计数(被拦子资源、`tm_pty` 拒绝、bash 超时夹顶、缓存命中、脱敏次数)——外加**宿主能力矩阵**(每个宿主接口标 `已验证/存在未用/待观察/缺失/需人眼`)。只读本插件自己写的文件;OpenCode 升级后第一个跑它。`{ recent: 20 }` 追加一份逐条调用清单——每次卸载结果的句柄和落盘路径都在里面,这就是"看看刚才那个工具到底返回了什么"的办法(宿主不给插件工具卡片留展开位) | 全角色 |
|
|
264
274
|
| `tm_browser` | 交互式浏览器会话(**驱动你的默认浏览器**):18 个 Playwright 动词(快照优先:`take_snapshot` → 按 uid 寻址的 `click`/`fill`/`drag`…,**并新增多标签页 `new_page` / `close_page`**,可同时持有两个页面)+ 5 个旧版兼容动词(open/navigate/read/screenshot/close);Playwright 引擎需 Node ≥ 20,不满足或导入失败时自动降级到旧版 CDP 引擎。它开的是**你自己的默认浏览器渠道**(默认装 Edge Beta 就开 Beta),除操作者设 `TM_BROWSER_HEADLESS` 外保持有头;页面自家图片/CSS/JS 靠 `same-site` 子资源策略正常加载;`take_screenshot { image:true }` 会附一张 JPEG,让模型真能看见画面。**一个 agent 一个浏览器**:`open` 返回一个 id(`b1`),之后每条回复都带着它——那个窗口、它的 uid 编号、它经对话框批准过的主机,都属于**你的**会话;用别人的 id 会被拒绝并点名属主(id 是名字,不是钥匙),`close { id:"all" }` 只关你自己的。`click` 报的是**页面做了什么**,而不只是"我发出了鼠标事件":它点击前后各读一次目标的可观测状态(`aria-expanded`、URL、DOM 节点数),回答形如 `已点击 … · aria-expanded: false → true`;页面还没加载完时会有界重试一次——这正是实测中"点击落在没有 handler 的节点上"的成因;仍然没有变化就说"页面没有任何可观测变化",而不是暗示成功。`close` 在浏览器的操作系统进程真正退出之前不会说“已确认关闭”——它等 pid、必要时补一次终止,两种结果都会把 pid 写在回复里,因为连接断开不等于浏览器关了;万一拿不到 pid,它会说“进程未核验”,而不是借用那句已确认。本进程启动过却没能收掉的浏览器会记进按工作区隔离的账本(pid、属主 pid、可执行文件),由下一次启动回收——只回收属主进程已死**且**该 pid 现在仍是那个可执行文件的条目,并按整棵进程树终止(Windows 上 `taskkill /T`),绝不动另一个窗口的活标签。**空白页现在会自己解释原因**:`same-site` 无从知道一个站点把自己的脚本包放在与品牌无关的 CDN 上(百度把脚本发在 `bdimg.com`),所以当一页返回 `0 个可寻址节点` 而同时有脚本域名被拦时,回复会直接说明这片空白是**我们的门禁**造成的、点名该域名,并给出 `allow_host { host }`——一个域名一次官方确认窗,只对你的浏览器、只在本次会话,不写任何配置文件(批准后要重新导航,门禁在请求时判定)。而真的需要人工验证的页面(百度安全验证 / Cloudflare / access denied)会被说成一道验证墙,因为对它的正确动作是换来源,不是再试一次 | Lead + Researcher + Tester(仅 UI 验证) |
|
|
265
275
|
|
|
276
|
+
> **在 OpenCode 2.x 上,其中五个工具是刻意不注册的。**
|
|
277
|
+
> `tm_read` / `tm_grep` / `tm_bash` 由宿主自己的 `read` / `grep` / `glob` / `shell`
|
|
278
|
+
> 接管,`tm_ptc_run` 由宿主的 `execute`(Code Mode)接管——同一件工作,少给模型一个
|
|
279
|
+
> 要挑的工具。治理没有跟着消失:超大的原生结果照样被 `tool.execute.after` 卸载
|
|
280
|
+
> (实测:`shell` 的 12,902 token 变成 78 token 的预览),地址红线和 R6 的按命令分类
|
|
281
|
+
> 都跑在宿主的 `permission.evaluate` 上。> `tm_ledger` 是唯一一个只存在于 v2 的工具(在 `todowrite` 不存在的地方,领队的清单需要一个家)。
|
|
282
|
+
> **我们改的一切都不会溢到 Team 之外。** v2 的每个钩子对宿主上所有会话都会触发,所以工具面
|
|
283
|
+
> 裁剪、0.2 温度、黑板注记、原生结果卸载、R6 与地址红线的收紧、强制后台派发,全都会先问一句
|
|
284
|
+
> "这是我们六个角色吗"——`build`、`plan` 和你自己的 agent 保持刚装好时的原样。宿主没告诉我们会话
|
|
285
|
+
> 归属的调用同样不碰,并且会计数(`tm_stats` 里是 `作用域:我们 · 他人 · 未判定`)。
|
|
286
|
+
> 安装器写出的六个角色提示词是 v2 变体,
|
|
287
|
+
> 里面点名的是 `read` / `grep` / `shell` 而不是这些别名。
|
|
288
|
+
> 上面这张表描述的是 v1(1.18.x)的工具面,那一份仍然十三个都在。
|
|
289
|
+
|
|
290
|
+
> **在 OpenCode 2.x 上,交互式浏览交给宿主,治理仍在我们手里。** 桌面端侧边栏挂的是**服务端自己的**浏览器
|
|
291
|
+
> 服务——插件没法把自己的页面注册进去(取证:`docs/research/browser-pane.md`)。所以三个有联网授权的角色
|
|
292
|
+
> (领队 / researcher / tester)优先用宿主的 `browser_*` 工具,`tm_browser` 退为"宿主没接桌面浏览器时"
|
|
293
|
+
> (CLI / standalone)的受治理通道。交出去的是浏览器,不是治理:活体观测里 `browser_*` **不触发**
|
|
294
|
+
> `permission.evaluate`,所以门禁改挂在 `tool.execute.before` 上——判定每次 navigate/open 的 URL、每次
|
|
295
|
+
> `browser_preview` 的路径,以及写在 `execute` 程序里的浏览器 URL;不合规则就拒绝,而宿主若把已拒绝的调用
|
|
296
|
+
> 照样跑了,就把页面换成同一段拒绝语,越权内容不会进上下文、store 或轨迹。宿主已发出的请求我们撤回不了,
|
|
297
|
+
> 这照实说,不谎称拦住过;`tm_stats` 把两个数分开给(拒绝 N 次 / 被放过去 M 次)。卸载规则在此有一条例外:
|
|
298
|
+
> `browser_snapshot` 是**寻址表**不是文档,所以它是**截断**(每行 `[ref=…]` 都留、丢静态文字,预算
|
|
299
|
+
> `TM_NATIVE_SNAPSHOT_MAX_TOKENS` 默认 1 200,与 `tm_browser` 同口径)而不是换成句柄。261 个 ref 的页面实测:
|
|
300
|
+
> 从头截断只剩 118 个 ref,这种方式 261 个全留,11 326 token 里只占 1 044。
|
|
301
|
+
|
|
266
302
|
> **固定工具优先级阶梯(每个任务都适用):① 用户自己的 MCP/插件工具
|
|
267
303
|
> → ② TeamMode 受治理工具(`tm_*`) → ③ 模型自己的推理。** 它同时是回退链:某个受治理
|
|
268
304
|
> 工具报错(这台机器没浏览器、主机被拦),agent 会说明情况降到下一级,
|
|
@@ -500,7 +536,15 @@ Team Lead 自己从不删黑板,你可以随时审计任何一次运行。
|
|
|
500
536
|
|
|
501
537
|
| 环境变量 | 默认 | 用途 |
|
|
502
538
|
|---|---|---|
|
|
503
|
-
| `TM_ENV_PROTECT` | `strict` | R6 模式:`strict` / `standard` / `off`(off 同时解除审批计时器)
|
|
539
|
+
| `TM_ENV_PROTECT` | `strict` | R6 模式:`strict` / `standard` / `off`(off 同时解除审批计时器)
|
|
540
|
+
| `TM_R6_FINE_ASK` | 按命令行判定(仅 v2) | 在 **v2** 上,命令行由宿主的 `permission.evaluate` 钩子逐次判定,所以普通 `git status` 什么都不问、导出环境变量照样问。`off` 退回"每条 shell 命令都问"——宿主不提供该钩子时也会自动走这条路,而且启动日志会说是哪一个原因造成的。v1 不受影响:它本来就在工具调用钩子里判定 |
|
|
541
|
+
| `TM_V2_CODEMODE` | catalog(`direct` 需显式开启)——**仅 v2** | 我们的工具怎么送到模型面前。OpenCode 2.x 用 `options.codemode` 决定可见性。我们曾默认发 `codemode:false` 并宣称"以真实定义交付"——**一次 2.0.16 桌面端活体会话把它推翻了**:发了那个标志之后,十个 `tm_*` 仍然只出现在宿主的 Code Mode 目录里(原文:"They cannot be called directly…"),模型可直接调用的是那九个原生工具。所以默认什么都不发,`direct` 留给可能认它的构建做实验。能核对的只有关停记录里的 `tools_in_request`(`tm_stats` 渲染成"请求内实际可见=…"),不是我们发出的标志 |
|
|
542
|
+
| `TM_PRIVATE_SPACE` | v1 `ask` · **v2 `deny`** | 私网(回环、RFC1918、ULA、CGNAT、`.localhost`)经我们工具时的行为:`ask` 走宿主确认窗(v1 弹得出),`allow` 放开整段,`deny` 拒绝。v2 默认 `deny`,因为插件在那儿弹不出窗子——"等用户批准"在一台给不出确认框的宿主上不是闸门,是让 agent 干等。所以 v2 的拒绝语会印出两条操作者自己走得通的出口(`TM_PRIVATE_SPACE=allow`,或把这一台主机名写进 `TM_WEBFETCH_ALLOWED_DOMAINS`)。元数据 / 链路本地 / 保留段不在这个开关管辖内:任何设置都拒,也没有批准路径 |
|
|
543
|
+
| `TM_V2_BROWSER_GATE` | 开——**仅 v2** | 对宿主 `browser_*` 目录的门禁(`execute.before` 判 URL 与 `browser_preview` 路径,也扫 `execute` 程序里出现的浏览器 URL)。`off` 恢复宿主无治理的浏览;启动行与 `tm_stats` 会说清当前是哪种 |
|
|
544
|
+
| `TM_NATIVE_SNAPSHOT_MAX_TOKENS` | 1200——**仅 v2** | 原生 `browser_snapshot` / `browser_find` 在上下文里保留的预算。带 ref 的行优先占位,静态文字先被删;超过 `预算 × 4` 时回复会说明有多少 ref 行没装下,kept + dropped 恒等于总行数 |
|
|
545
|
+
| `TM_NATIVE_REPORT_MAX_TOKENS` | 1600——**仅 v2** | 报告形原生结果(带 Markdown 表格的那种:经 Code Mode 回来的 `tm_stats`、`tm_join` 汇总)在上下文里保留的预算。表格行和小标题优先占位,被删的是表格之间的散文——缺一行的表格就不是表格;全文仍在句柄里 |
|
|
546
|
+
| `TM_LEDGER_MAX_ITEMS` | 200 | 每个会话 `tm_ledger` 的条数上限。宿主的 `ctx.storage` 没有 TTL 也没有配额(实测),所以清单到顶就**拒绝新增**,而不是悄悄丢掉最早的条目——拒绝是领队能据此行动的信号,静默截断则是一条没人能复核的主张 |
|
|
547
|
+
| `TM_V2_PROBE` | —(仅 v2) | 表面探针的 JSONL 输出路径,记录宿主真实给出的工具 id、权限动作名、参数键名。只记名字与计数——绝不记命令行、路径、URL、环境变量值。它是"宿主到底有没有 X"这个问句的取证入口(问运行中的构建,而不是问文档);不设这个变量时,同一批名字集合仍会进轨迹,`tm_stats` 照样能看 | |
|
|
504
548
|
| `TM_ASK_TIMEOUT_MIN` | `1` | 无人应答弹窗自动拒绝前等待的分钟数(地板 1 分钟——安全:抢跑应答良性记为 `already-closed`;宿主应答事件到插件晚约 120 秒是事件总线投递延迟,非点击解析延迟)。此外每个受治理工具都会在"这个值 + 15 秒"处自己结束等待——审批闸只在 R6 开启且宿主能回复时才武装,而一个永不返回的工具在界面上读起来就是卡死,不是在请你确认 |
|
|
505
549
|
| `TM_ASK_TIMEOUT_FLOOR_MIN` | `1` | 上述自动拒绝的强制最小时长 |
|
|
506
550
|
| `TM_ENV_PROTECT_EXTRA_DENY` | — | 额外拦截模式(正则;永远硬拦截,不走弹窗) |
|
|
@@ -529,14 +573,14 @@ Team Lead 自己从不删黑板,你可以随时审计任何一次运行。
|
|
|
529
573
|
| `TM_PTY_MAX` | `4` | 本插件同时最多保持多少个 `tm_pty` 终端会话 |
|
|
530
574
|
| `TM_JOIN_MAX_WAIT_MS` | `60000` | `tm_join { waitMs }` 的上限。过去是 300 000,于是有了一次"连续两次各等 5 分钟、期间 lead 什么都没做"的实测——等待不是并行,所以默认改成"看一眼就去干活"。上一次没等到任何结算时,第二次等待被截到 10 秒并附替代动作 |
|
|
531
575
|
| `TM_STORE_RECLAIM` | `on` | 启动时回收“升级留下的遗产”:超过 TTL 没动静的分片,以及临时目录回退点上分片之前的 `blackboard/` + `trajectory/`(一台真实机器上实测滞留 503 MB 过期 run,而搬家后没有任何清扫器指向那里)。只删超过 TTL 的条目——新鲜的 run 一定留着,因为升级前起来的会话可能还在往里写。设 `off` 就完全不碰磁盘(测试执行器会设它) |
|
|
532
|
-
| `TM_TASK_OFFLOAD` | `on` | 把宿主的后台子代理压在 token 预算内:`task { background: true }` 完成时宿主会把子代理全文注入你的会话,这里把超限的正文换成预览 + 取回指针(`tm_join { ids: [...] }`)。**只碰**同时满足三条的 part:`synthetic === true`、正文精确匹配宿主自己的 `<task id=… state="completed">` 信封、且超过文本卸载阈值;任一不满足就原样放过。不往磁盘复制任何东西——全文本来就写在子会话里。`off`
|
|
576
|
+
| `TM_TASK_OFFLOAD` | `on` | 把宿主的后台子代理压在 token 预算内:`task { background: true }` 完成时宿主会把子代理全文注入你的会话,这里把超限的正文换成预览 + 取回指针(`tm_join { ids: [...] }`)。**只碰**同时满足三条的 part:`synthetic === true`、正文精确匹配宿主自己的 `<task id=… state="completed">` 信封、且超过文本卸载阈值;任一不满足就原样放过。不往磁盘复制任何东西——全文本来就写在子会话里。`off` 恢复宿主原样注入。**OpenCode 2.x 上这一半不适用**:v2 不会把注入后的消息在落盘前交给插件,而我们刻意不改写发出的消息(对那一层形状猜错就是静默删证据,v1 的 `experimental.chat.messages.transform` 就是因此一直没实现)。v2 的补偿是契约而不是改写:超限交付写进黑板文件、回复里带路径,领队读摘要、用 `tm_join` 取全文 |
|
|
533
577
|
| `TM_TOOL_HINTS` | `on` | 通过 `tool.definition` 把本插件的调用点纪律追加到内置 `bash` / `task` 的**描述**后面(只追加、幂等,绝不替换宿主原文) |
|
|
534
578
|
| `TM_AGENT_TEMPERATURE` | `off` | `on` 时按角色分档采样(architect 0.35 / researcher 0.3 / reviewer 0.1 / 其余 0.2)经 `chat.params` 生效;也可写 `reviewer=0.05;team=0.4`。默认关闭=守住"所有 agent 0.2"这条既定原则 |
|
|
535
579
|
| `TM_COMPACTION_CONTEXT` | `on` | 在宿主压缩前追加"必须存活清单"(回复骨架、offload 句柄、未回收的子会话 id、出处、板上路径)。只做追加——宿主自己的压缩提示词不被替换 |
|
|
536
580
|
| `TM_COMPACTION_AUTOCONTINUE` | `on` | 设 `off` 则压缩后不让宿主静默续跑,先由人复核状态 |
|
|
537
581
|
| `TM_SHELL_NO_COLOR` | `on` | 经 `shell.env` 给每个子 shell 注入 `NO_COLOR`/`TERM=dumb`(ANSI 进度条纯属上下文税)。绝不覆盖宿主已设的值 |
|
|
538
582
|
| `TM_SHELL_ENV` | — | 显式 `KEY=VALUE;KEY2=VALUE2` 透传进子 shell——刻意用白名单,避免这个钩子变成父环境泄露通道 |
|
|
539
|
-
| `TM_WEBFETCH_ALLOWED_DOMAINS` | 24
|
|
583
|
+
| `TM_WEBFETCH_ALLOWED_DOMAINS` | v1:24 个种子主机;**v2 默认 `"*"`** | tm_webfetch / tm_search / tm_browser 白名单(`"*"` 全开;空 = 全拒;自定义值**替换**种子——保留引擎主机)。站点自己的资源 CDN 必须进种子,否则 `tm_browser` 打开就是白屏——`bdimg.com` 就是因为这个才在种子里;临时缺口走 `tm_browser { action:"allow_host", host }`,不用改环境变量。`"*"` **不覆盖私网**:回环 / RFC1918 / CGNAT / `.localhost` 仍然每次都要弹确认窗;不可路由段(169.254.0.0/16 元数据端点、0.0.0.0/8、组播、保留段,以及这些地址的 IPv4-mapped 与 DNS64 写法)是不可被任何配置打开的硬红线 |
|
|
540
584
|
| `TM_BROWSER_PATH` | 自动探测 | tm_browser 可执行文件覆盖(默认用你的默认浏览器——Chromium 系时;否则回退 Edge/Chrome 探测) |
|
|
541
585
|
| `TM_BROWSER_HEADLESS` | `auto` | `1` 无头(CI)/ `0` 有头 / `auto`(仅无显示的 Linux 用无头) |
|
|
542
586
|
| `TM_BROWSER_ENGINE` | `playwright` | `playwright`(需 Node ≥ 20;导入失败自动降级)/ `cdp-legacy`(零依赖 CDP pipe,仅核心动词) |
|
|
@@ -653,7 +697,10 @@ OpenCode 按 spec 字符串缓存插件,从不重新解析 `@latest`(上游
|
|
|
653
697
|
|
|
654
698
|
## 🗑️ 卸载
|
|
655
699
|
|
|
656
|
-
1. 从配置文件的 `"plugin"`
|
|
700
|
+
1. 从配置文件的 `"plugin"` 数组里移除该条目——**OpenCode 2.x 上是 `"plugins"`(复数)**,2.x
|
|
701
|
+
的安装器也写在那里;如果你是在 2.x 上装的,还要删掉生成的
|
|
702
|
+
`~/.config/opencode/agents/*.md` 与 `commands/team-*.md`,以及你不再需要的
|
|
703
|
+
`default_agent: "team"`。
|
|
657
704
|
2. 想回收磁盘就删缓存目录(见[安装](#-现在读一遍以后省一小时)里的表格)。
|
|
658
705
|
3. 重启 OpenCode。agent、命令、工具全部消失;`<repo>/.git/opencode-team/`
|
|
659
706
|
下的存储(全局记忆在 `~/.opencode-team/`)都是普通文件,随时可删。
|
|
@@ -677,7 +724,8 @@ opencode-team-mode/
|
|
|
677
724
|
│ ├── tm/ ← 受治理工具:pipelines / store / preview / guard / refs /
|
|
678
725
|
│ │ webfetch / search / memory / browser / shell-bridge / ptc/(9 模块)
|
|
679
726
|
│ └── types.ts ← 加载器契约类型(1.18.x)
|
|
680
|
-
├── docs/installation.md ← agent
|
|
727
|
+
├── docs/installation.md ← agent 可消费的安装指南(1.18.x)
|
|
728
|
+
├── docs/installation-v2.md ← 2.x 安装指南(角色以生成的配置文件形式落地)
|
|
681
729
|
├── scripts/ ← 一行安装脚本(bash / PowerShell)
|
|
682
730
|
├── pt07/ ← PT-07 基线套件(种子化 A/B token 测量)
|
|
683
731
|
└── README.*.md ← 你在这里(有两个版本)
|
|
@@ -706,7 +754,8 @@ opencode-team-mode/
|
|
|
706
754
|
## 🔗 链接
|
|
707
755
|
|
|
708
756
|
- [npm 包](https://www.npmjs.com/package/@te-river/opencode-team-mode) — `@te-river/opencode-team-mode`
|
|
709
|
-
- [
|
|
757
|
+
- [安装指南(1.18.x)](./docs/installation.md) — 完整的手动 / agent 可消费流程
|
|
758
|
+
- [安装指南(**OpenCode 2.x**)](./docs/installation-v2.md) — 装法不同:2.x 插件不能创建 agent,六个角色和六条命令要生成到配置目录
|
|
710
759
|
- [OpenCode Desktop](https://opencode.ai) — 官网与下载
|
|
711
760
|
- [OpenCode 文档](https://opencode.ai/docs) — 配置与插件文档
|
|
712
761
|
- [OpenCode 插件 API](https://opencode.ai/docs/plugins) — 开发你自己的插件
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime prompt addendum both plugin personalities hand to the team
|
|
3
|
+
* agent. It lives here rather than inside a personality because the board
|
|
4
|
+
* root and the TTL sweeper are the same regardless of host generation.
|
|
5
|
+
*/
|
|
6
|
+
export declare function blackboardNote(root: string, ttlDays: number): string;
|
|
7
|
+
//# sourceMappingURL=note.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note.d.ts","sourceRoot":"","sources":["../../src/host/note.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAqBpE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime prompt addendum both plugin personalities hand to the team
|
|
3
|
+
* agent. It lives here rather than inside a personality because the board
|
|
4
|
+
* root and the TTL sweeper are the same regardless of host generation.
|
|
5
|
+
*/
|
|
6
|
+
export function blackboardNote(root, ttlDays) {
|
|
7
|
+
return [
|
|
8
|
+
"",
|
|
9
|
+
"",
|
|
10
|
+
"## Team Blackboard — resolved for this workspace",
|
|
11
|
+
`Root directory: \`${root}\``,
|
|
12
|
+
`- Hybrid channel: specialist replies (the STATUS/CHANGES/FINDINGS/EVIDENCE/HANDOFF`,
|
|
13
|
+
` skeleton) are the PRIMARY transport — normal work needs no files at all.`,
|
|
14
|
+
`- Board files exist ONLY for oversized deliverables (>~50 lines), and they`,
|
|
15
|
+
` go through \`tm_board_write { task, topic, content, session? }\` — the board's`,
|
|
16
|
+
` write side, carried by every role including the ones with no file tool. It`,
|
|
17
|
+
` places \`<root>/<session-key>/<task-slug>/NN-<role>-<topic>[-rN].md\`, never`,
|
|
18
|
+
` overwrites, and answers with the PATH (never the content).`,
|
|
19
|
+
` On the FIRST board write of this conversation pass a session folder made from`,
|
|
20
|
+
` a compact clock timestamp (PowerShell: \`Get-Date -Format yyyyMMdd-HHmmss\`;`,
|
|
21
|
+
` POSIX: \`date +%Y%m%d-%H%M%S\`) and reuse it for every later task; omit it and`,
|
|
22
|
+
` the tool stamps one — that is how a role with no bash reaches the board at`,
|
|
23
|
+
` all. Never write into another conversation's session folder.`,
|
|
24
|
+
`- Auto-cleanup: the plugin sweeps task directories idle for more than ${ttlDays} days (at startup and hourly).`,
|
|
25
|
+
` This is the ONLY cleanup path — never delete task or session directories yourself.`,
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=note.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note.js","sourceRoot":"","sources":["../../src/host/note.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAe;IAC1D,OAAO;QACL,EAAE;QACF,EAAE;QACF,kDAAkD;QAClD,qBAAqB,IAAI,IAAI;QAC7B,oFAAoF;QACpF,4EAA4E;QAC5E,4EAA4E;QAC5E,kFAAkF;QAClF,+EAA+E;QAC/E,gFAAgF;QAChF,8DAA8D;QAC9D,iFAAiF;QACjF,gFAAgF;QAChF,kFAAkF;QAClF,8EAA8E;QAC9E,iEAAiE;QACjE,yEAAyE,OAAO,gCAAgC;QAChH,sFAAsF;KACvF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The v1 personality: everything this plugin does through the OpenCode 1.18.x
|
|
3
|
+
* `server(input, options)` hook object. Moved out of `src/index.ts` verbatim
|
|
4
|
+
* for the v2 port (see docs plan) — no behaviour change is allowed here; a v1
|
|
5
|
+
* host must observe byte-identical hooks, and the ~1700 assertions in
|
|
6
|
+
* test-*.mjs are the oracle that keeps that promise.
|
|
7
|
+
*
|
|
8
|
+
* v1-only by construction: the single composed `tool.execute.before` slot, the
|
|
9
|
+
* permission-event approval gate, the `{"*": "ask"}` bash escalation object,
|
|
10
|
+
* and `tui.showToast` notification.
|
|
11
|
+
*/
|
|
12
|
+
import type { PluginInput, Hooks } from "../types.js";
|
|
13
|
+
export declare function createV1Personality(input: PluginInput, options?: Record<string, unknown>): Promise<Hooks>;
|
|
14
|
+
//# sourceMappingURL=v1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v1.d.ts","sourceRoot":"","sources":["../../src/host/v1.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAA8C,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAqCjG,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,KAAK,CAAC,CA4UhB"}
|