@te-river/opencode-team-mode 1.5.12 → 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 +27 -6
- package/README.zh-CN.md +25 -4
- package/dist/agents.d.ts +5 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +20 -0
- package/dist/agents.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 +71 -8
- 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 +51 -2
- package/dist/prompts/shared.js.map +1 -1
- package/dist/prompts/specialists.d.ts +1 -1
- package/dist/prompts/specialists.d.ts.map +1 -1
- package/dist/prompts/specialists.js +38 -17
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/tm/args-schema.d.ts +7 -1
- package/dist/tm/args-schema.d.ts.map +1 -1
- package/dist/tm/args-schema.js +9 -3
- 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 +66 -5
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +476 -89
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/config.d.ts +68 -0
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js +62 -0
- 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 +27 -4
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +38 -3
- package/dist/tm/index.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 +51 -7
- package/dist/tm/search.d.ts.map +1 -1
- package/dist/tm/search.js +151 -37
- package/dist/tm/search.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 +33 -5
- 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 +2 -2
package/README.md
CHANGED
|
@@ -46,8 +46,9 @@ TeamMode's answer to each:
|
|
|
46
46
|
|---|---|
|
|
47
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.
|
|
@@ -216,7 +219,9 @@ through with `tm_fetch` when it genuinely needs the payload.
|
|
|
216
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 |
|
|
217
220
|
| `tm_search` | Multi-engine web search with extracted, deduplicated, RRF-fused hit lists | Lead + Researcher |
|
|
218
221
|
| `tm_webfetch` | Single governed GET of an allowlisted page (search pages auto-extracted) | Lead + Researcher |
|
|
219
|
-
| `
|
|
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) |
|
|
220
225
|
|
|
221
226
|
> **Fixed tool priority ladder (every task): ① TeamMode governed tools
|
|
222
227
|
> (`tm_*`) → ② user MCP/plugin tools → ③ the model's own reasoning.**
|
|
@@ -283,7 +288,7 @@ sees raw SERP chrome.
|
|
|
283
288
|
|
|
284
289
|
| Engine | Notes |
|
|
285
290
|
|---|---|
|
|
286
|
-
| `auto` (default) | Classifies the query, fans
|
|
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` |
|
|
287
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 |
|
|
288
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 |
|
|
289
294
|
| `hn` | Hacker News via Algolia API (no key) → story titles + snippets with direct article URLs |
|
|
@@ -467,6 +472,22 @@ for overrides, extra agents and disabling roles.
|
|
|
467
472
|
| `TM_BROWSER_HEADLESS` | `auto` | `1` headless (CI) / `0` headful / `auto` (headless only on display-less Linux) |
|
|
468
473
|
| `TM_BROWSER_ENGINE` | `playwright` | `playwright` (needs Node ≥ 20; any import failure auto-degrades) / `cdp-legacy` (zero-dep CDP pipe, core verbs only) |
|
|
469
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 |
|
|
470
491
|
| `TM_BROWSER_USER_DATA_DIR` | — (isolated temp profile) | explicit persistent profile dir — the ONLY way logins survive between sessions |
|
|
471
492
|
| `TM_MEMORY_GLOBAL_DIR` | `~/.opencode-team/memories/global/` | tm_memory GLOBAL tier store |
|
|
472
493
|
| `TM_MEMORY_SESSION_TTL_MIN` | `240` | session-tier entry TTL (lazy + boot sweep) |
|
package/README.zh-CN.md
CHANGED
|
@@ -47,6 +47,7 @@ TeamMode 对每一个的回应:
|
|
|
47
47
|
| 🐌 **回合开销** | `tm_ptc_run`:agent 写**一个程序**,单回合内发起 N 次受治理调用。运行期间零 LLM 回合。 |
|
|
48
48
|
| 🕳️ **静默副作用** | R6/R2 审批门禁:环境变量读取和危险操作走 OpenCode 官方确认弹窗,1 分钟没人理自动拒绝。插件从不代替你批准——它只会拒绝。 |
|
|
49
49
|
| 🌫️ **幻觉式调研** | 联网是双角色的授权 + 白名单受治理工具链。抓不到的事实就报告为缺口——绝不编造。 |
|
|
50
|
+
| 🧭 **纯文本墙** | 回复被引导成宿主渲染得最快的形状:逐文件 / 逐用例 / 逐条发现用 markdown 表格,diff 和配置用围栏代码块,浏览器截图只在你明确要求时才内联附上。宿主不画 mermaid,所以没有 agent 会假装它在画。 |
|
|
50
51
|
|
|
51
52
|
底下还有流程纪律:确定性路由表、≥2 次派工先出 ≤30 行计划等你批、agent
|
|
52
53
|
之间用 `STATUS/CHANGES/FINDINGS/EVIDENCE/HANDOFF` 结构化交接、以及静态
|
|
@@ -126,8 +127,10 @@ OpenCode 下次启动时装好。
|
|
|
126
127
|
|
|
127
128
|
| 系统 | 缓存位置 |
|
|
128
129
|
|---|---|
|
|
129
|
-
| macOS / Linux | `
|
|
130
|
-
| Windows | `
|
|
130
|
+
| macOS / Linux | `find ~/.cache/opencode/packages -type d -name '*opencode-team-mode*' -prune -exec rm -rf {} +` |
|
|
131
|
+
| 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 } }` |
|
|
132
|
+
|
|
133
|
+
⚠️ OpenCode 是从 `~/.cache/opencode/packages/` 加载插件的(可能嵌套在 `@te-river/` 作用域目录里),**不是** `~/.config/opencode/node_modules`——所以删除必须递归:只删顶层会静默漏掉作用域式的缓存副本。
|
|
131
134
|
|
|
132
135
|
如果插件还被 npm 装进了 `~/.config/opencode`,package-lock 会钉住版本——在那里再跑一次 `npm install @te-river/opencode-team-mode@latest`。完整配方(含 agent 更新提示词)见[安装指南·更新](./docs/installation.md)。
|
|
133
136
|
- **前置条件:** [OpenCode](https://opencode.ai)(桌面版或 CLI)+ Node ≥ 18。
|
|
@@ -210,7 +213,9 @@ HMAC 句柄,agent 真需要 payload 时用 `tm_fetch` 分页取。
|
|
|
210
213
|
| `tm_ptc_run` | 批量编排:一个程序、N 次受治理调用、零 LLM 回合;联网角色还能在程序里调 `tm.search` / `tm.webfetch` | 全部六个 agent |
|
|
211
214
|
| `tm_search` | 多引擎网络搜索,返回提取、去重、RRF 融合后的命中列表 | Lead + Researcher |
|
|
212
215
|
| `tm_webfetch` | 白名单页面的单次受治理 GET(搜索页自动提取) | Lead + Researcher |
|
|
213
|
-
| `
|
|
216
|
+
| `tm_dispatch` / `tm_join` | **异步子代理派发**:`tm_dispatch` 在独立子会话里启动某个专员并立刻返回其 id(内置 `task` 会把你阻塞到子代理结束),`tm_join` 负责回收——不带参数=状态快照,`waitMs`=有界等待,`cancel:true` 取消跑飞的子任务;回收到的回复同样走卸载管线,五份长报告变成句柄+预览而不是压垮你的上下文 | 仅 Lead(子代理不得再派发) |
|
|
217
|
+
| `tm_pty` | 在宿主自己的终端会话上**非阻塞执行命令**(`start`/`status`/`list`/`kill`):独立的构建与测试各自一个会话并行跑,不再串成一条 120 秒的 bash 调用。它不抓输出(命令自己 tee 日志,用 `tm_read` 读),且每次启动都先过 R6 分类器、R2 危险面 glob,再走官方确认窗,才真的建进程 | 仅 Lead |
|
|
218
|
+
| `tm_browser` | 交互式浏览器会话(**驱动你的默认浏览器**):16 个 Playwright 动词(快照优先:`take_snapshot` → 按 uid 寻址的 `click`/`fill`/`drag`…)+ 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,让模型真能看见画面 | Lead + Researcher + Tester(仅 UI 验证) |
|
|
214
219
|
|
|
215
220
|
> **固定工具优先级阶梯(每个任务都适用):① TeamMode 受治理工具(`tm_*`)
|
|
216
221
|
> → ② 用户 MCP/插件工具 → ③ 模型自己的推理。** 它同时是回退链:某个受治理
|
|
@@ -264,7 +269,7 @@ agent 永远看不到原始搜索页的噪音。
|
|
|
264
269
|
|
|
265
270
|
| 引擎 | 说明 |
|
|
266
271
|
|---|---|
|
|
267
|
-
| `auto`(默认) |
|
|
272
|
+
| `auto`(默认) | 给查询分类,**并行**扇出匹配的引擎(每条路由至少 2 条腿),按 host+path 去重后做加权 RRF 融合,产出标有来源引擎的 top-10 列表。排序按命中与查询词的真实重叠度打折(地板 `TM_SEARCH_RELEVANCE_FLOOR`),高权重引擎的无关结果不再压过别的引擎最好的一条。路由:报错/camelCase API → `stackoverflow`+`github`+`bing`;开发生态(发布、框架、开源)→ `hn`+`github`+`npm`;中文 → `bing`+`moegirl`+`stackoverflow`+`hn`;其它 → `bing`+`stackoverflow`+`hn`+`github`。用 `TM_SEARCH_DEFAULT_ENGINE` 钉别的默认 |
|
|
268
273
|
| `bing` | cn.bing.com——唯一活着的中文 HTML SERP;多词 CJK 查询自动保护短语边界(加引号),markup 洗牌拆不散结果列表 |
|
|
269
274
|
| `stackoverflow` | api.stackexchange.com 问题搜索(免 Key,300 次/天/IP)→ 带复合摘要的编号问题列表;`auto` 跟踪配额,耗尽自动换 `bing` 顶上 |
|
|
270
275
|
| `hn` | Hacker News(Algolia API,免 Key)→ 帖子标题 + 摘要与原文链接 |
|
|
@@ -418,6 +423,22 @@ Team Lead 自己从不删黑板,你可以随时审计任何一次运行。
|
|
|
418
423
|
| `TM_BLACKBOARD_TTL` | `7` | 存储保留天数 |
|
|
419
424
|
| `TM_BASH_READONLY_ALLOWED` | 内置表 | tm_bash 白名单 |
|
|
420
425
|
| `TM_SEARCH_DEFAULT_ENGINE` | `auto` | tm_search 未显式给 `engine` 时的默认引擎(`auto` = 分类 + 并行扇出 + RRF 融合;也可钉表中任一引擎) |
|
|
426
|
+
| `TM_SEARCH_WEIGHTS` | 未设 | 按引擎覆盖融合权重,如 `bing=0.3,hn=0.25`;未列出的沿用内置表 |
|
|
427
|
+
| `TM_SEARCH_RELEVANCE_FLOOR` | `0.35` | 与查询词零重叠的命中只保留该比例的权重(压垃圾,不删引擎) |
|
|
428
|
+
| `TM_SEARCH_MAX_HITS` | `10` | 每引擎腿与融合列表保留的命中数 |
|
|
429
|
+
| `TM_SEARCH_DISABLED_ENGINES` | 未设 | 从引擎表与所有 `auto` 路由中移除的引擎(`sogou,baidu` 写法) |
|
|
430
|
+
| `TM_BROWSER_SUBRESOURCE` | `same-site` | 顶层导航过白名单后,页面子资源的策略:`same-site` = 图/媒体/字体/样式表一律放行,脚本/XHR 仅当属于本次会话真正打开过的站点;`passive` = 只放被动资源;`off` = 旧行为(逐请求过白名单)。被拦掉的请求会在下一次快照以"N 个子资源请求被拦截"告知 |
|
|
431
|
+
| `TM_BROWSER_IDLE_MS` | `180000` | 无人触碰的浏览器会话超过该毫秒数自动关闭并提示用户(0 关闭该回收)——没人负责的窗口是打扰用户的 bug |
|
|
432
|
+
| `TM_BROWSER_IMAGE_MAX_BYTES` | `400000` | `take_screenshot { image:true }` 内联给模型的 JPEG 上限;超过则只回路径并说明原因 |
|
|
433
|
+
| `TM_BASH_TIMEOUT_PROBE_MS` | `60000` | 对只读探针命令(P3 白名单内)强制夹顶模型自设的 `timeout`(0 关闭) |
|
|
434
|
+
| `TM_BASH_TIMEOUT_MAX_MS` | `0` | 其它 bash 命令的可选全局上限——默认关闭,真实构建保留它要的超时 |
|
|
435
|
+
| `TM_PTY_MAX` | `4` | 本插件同时最多保持多少个 `tm_pty` 终端会话 |
|
|
436
|
+
| `TM_TOOL_HINTS` | `on` | 通过 `tool.definition` 把本插件的调用点纪律追加到内置 `bash` / `task` 的**描述**后面(只追加、幂等,绝不替换宿主原文) |
|
|
437
|
+
| `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"这条既定原则 |
|
|
438
|
+
| `TM_COMPACTION_CONTEXT` | `on` | 在宿主压缩前追加"必须存活清单"(回复骨架、offload 句柄、未回收的子会话 id、出处、板上路径)。只做追加——宿主自己的压缩提示词不被替换 |
|
|
439
|
+
| `TM_COMPACTION_AUTOCONTINUE` | `on` | 设 `off` 则压缩后不让宿主静默续跑,先由人复核状态 |
|
|
440
|
+
| `TM_SHELL_NO_COLOR` | `on` | 经 `shell.env` 给每个子 shell 注入 `NO_COLOR`/`TERM=dumb`(ANSI 进度条纯属上下文税)。绝不覆盖宿主已设的值 |
|
|
441
|
+
| `TM_SHELL_ENV` | — | 显式 `KEY=VALUE;KEY2=VALUE2` 透传进子 shell——刻意用白名单,避免这个钩子变成父环境泄露通道 |
|
|
421
442
|
| `TM_WEBFETCH_ALLOWED_DOMAINS` | 23 个种子主机 | tm_webfetch / tm_search / tm_browser 白名单(`"*"` 全开;空 = 全拒;自定义值**替换**种子——保留引擎主机) |
|
|
422
443
|
| `TM_BROWSER_PATH` | 自动探测 | tm_browser 可执行文件覆盖(默认用你的默认浏览器——Chromium 系时;否则回退 Edge/Chrome 探测) |
|
|
423
444
|
| `TM_BROWSER_HEADLESS` | `auto` | `1` 无头(CI)/ `0` 有头 / `auto`(仅无显示的 Linux 用无头) |
|
package/dist/agents.d.ts
CHANGED
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
* high-risk profiles.
|
|
28
28
|
* - All agents run at temperature 0.2 for format discipline.
|
|
29
29
|
*/
|
|
30
|
-
import type { AgentConfig } from "./types.js";
|
|
30
|
+
import type { AgentConfig, AgentPermission } from "./types.js";
|
|
31
|
+
/** Grant the async levers to the lead only (issue #6 + #7). A child cannot
|
|
32
|
+
* dispatch or spawn processes: these matrix entries and the tools' own
|
|
33
|
+
* runtime `ctx.agent` checks are two independent locks. */
|
|
34
|
+
export declare function applyDispatcherPermission(permission: AgentPermission, isTeamLead: boolean): void;
|
|
31
35
|
export declare const agents: Record<string, AgentConfig>;
|
|
32
36
|
//# sourceMappingURL=agents.d.ts.map
|
package/dist/agents.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAkH9D;;4DAE4D;AAC5D,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAIhG;AAiLD,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAO9C,CAAA"}
|
package/dist/agents.js
CHANGED
|
@@ -116,8 +116,26 @@ const whitelist = (...granted) => {
|
|
|
116
116
|
permission["tm_webfetch"] = "deny";
|
|
117
117
|
permission["tm_search"] = "deny";
|
|
118
118
|
permission["tm_browser"] = "deny";
|
|
119
|
+
// Async dispatch (tm_dispatch / tm_join) is the LEAD's lever — the tm_*
|
|
120
|
+
// wildcard would otherwise hand every specialist the ability to spawn
|
|
121
|
+
// sub-agents, which is exactly the nesting T3 closed.
|
|
122
|
+
permission["tm_dispatch"] = "deny";
|
|
123
|
+
permission["tm_join"] = "deny";
|
|
124
|
+
// tm_pty starts a real process, so it must pop the OFFICIAL dialog on
|
|
125
|
+
// every use: the WEB_ASK_MAP shape is what makes PermissionV2's findLast
|
|
126
|
+
// resolve to `ask` instead of swallowing the ask under the tm_* allow.
|
|
127
|
+
// Default deny; the lead gets the ask-map (applyDispatcherPermission).
|
|
128
|
+
permission["tm_pty"] = "deny";
|
|
119
129
|
return permission;
|
|
120
130
|
};
|
|
131
|
+
/** Grant the async levers to the lead only (issue #6 + #7). A child cannot
|
|
132
|
+
* dispatch or spawn processes: these matrix entries and the tools' own
|
|
133
|
+
* runtime `ctx.agent` checks are two independent locks. */
|
|
134
|
+
export function applyDispatcherPermission(permission, isTeamLead) {
|
|
135
|
+
permission["tm_dispatch"] = isTeamLead ? "allow" : "deny";
|
|
136
|
+
permission["tm_join"] = isTeamLead ? "allow" : "deny";
|
|
137
|
+
permission["tm_pty"] = isTeamLead ? { ...WEB_ASK_MAP } : "deny";
|
|
138
|
+
}
|
|
121
139
|
/** Apply the tm_ptc_run grant to an agent's permission block. All six
|
|
122
140
|
* agents get `allow` (overrides the tm_* wildcard for explicit key priority). */
|
|
123
141
|
function applyPtcPermission(permission, _isTeamLead) {
|
|
@@ -261,12 +279,14 @@ for (const a of [architect, implementer, reviewer, tester, researcher]) {
|
|
|
261
279
|
if (teamLead.permission) {
|
|
262
280
|
applyPtcPermission(teamLead.permission, true);
|
|
263
281
|
applyNetworkPermission(teamLead.permission, true);
|
|
282
|
+
applyDispatcherPermission(teamLead.permission, true);
|
|
264
283
|
}
|
|
265
284
|
for (const a of [architect, implementer, reviewer, tester, researcher]) {
|
|
266
285
|
if (a.permission) {
|
|
267
286
|
applyPtcPermission(a.permission, false);
|
|
268
287
|
// tester: tm_browser only (UI verification); researcher: full web grant
|
|
269
288
|
applyNetworkPermission(a.permission, a === researcher, a === tester);
|
|
289
|
+
applyDispatcherPermission(a.permission, false);
|
|
270
290
|
}
|
|
271
291
|
}
|
|
272
292
|
/* ------------------------------------------------------------------ */
|
package/dist/agents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElE,wEAAwE;AACxE,sEAAsE;AACtE,wEAAwE;AACxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,aAAa,GAAG;IACpB,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,aAAa;IACb,UAAU;IACV,WAAW;IACX,WAAW;IACX,KAAK;IACL,OAAO;IACP,UAAU;CACF,CAAA;AAEV;;;;;;;;4DAQ4D;AAC5D,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,CAAU,CAAA;AAE3F;;;0DAG0D;AAC1D,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAU,CAAA;AAEpF;;;;;;uCAMuC;AACvC,MAAM,QAAQ,GAAG,YAAqB,CAAA;AAEtC,MAAM,SAAS,GAAG,CAChB,GAAG,OAAgD,EAClC,EAAE;IACnB,MAAM,UAAU,GAAoB,EAAE,CAAA;IACtC,KAAK,MAAM,IAAI,IAAI,aAAa;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAA;IAC3D,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;IAC9D,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,QAAQ;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA;IACvD,UAAU,CAAC,MAAM,CAAC,GAAG,OAAO,CAAA;IAC5B,yEAAyE;IACzE,sEAAsE;IACtE,sEAAsE;IACtE,wDAAwD;IACxD,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAAA;IAClC,UAAU,CAAC,WAAW,CAAC,GAAG,MAAM,CAAA;IAChC,UAAU,CAAC,YAAY,CAAC,GAAG,MAAM,CAAA;IACjC,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA;AAED;kFACkF;AAClF,SAAS,kBAAkB,CAAC,UAA2B,EAAE,WAAoB;IAC3E,UAAU,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;AAChC,CAAC;AAED;;;;;;;6DAO6D;AAC7D,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,KAAK,EAAW,CAAA;AAE3C;;;;;wCAKwC;AACxC,SAAS,sBAAsB,CAAC,UAA2B,EAAE,SAAkB,EAAE,QAAQ,GAAG,KAAK;IAC/F,UAAU,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;IACnE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;IACjE,UAAU,CAAC,YAAY,CAAC,GAAG,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;AAChF,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE,MAAM,QAAQ,GAAgB;IAC5B,IAAI,EAAE,SAAS;IACf,WAAW,EACT,4DAA4D;QAC5D,qEAAqE;QACrE,qEAAqE;QACrE,oEAAoE;QACpE,6DAA6D;QAC7D,4BAA4B;IAC9B,MAAM,EAAE,gBAAgB;IACxB,KAAK,EAAE,SAAS,EAAE,SAAS;IAC3B,kFAAkF;IAClF,yEAAyE;IACzE,4EAA4E;IAC5E,qEAAqE;IACrE,4CAA4C;IAC5C,UAAU,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC;IAC/E,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,SAAS,GAAgB;IAC7B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,2EAA2E;QAC3E,2EAA2E;QAC3E,0EAA0E;QAC1E,yCAAyC;IAC3C,MAAM,EAAE,gBAAgB;IACxB,KAAK,EAAE,SAAS,EAAE,WAAW;IAC7B,gEAAgE;IAChE,+DAA+D;IAC/D,sEAAsE;IACtE,iEAAiE;IACjE,wEAAwE;IACxE,0CAA0C;IAC1C,qEAAqE;IACrE,UAAU,EAAE,SAAS,EAAE;IACvB,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,WAAW,GAAgB;IAC/B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,uEAAuE;QACvE,0EAA0E;QAC1E,gEAAgE;IAClE,MAAM,EAAE,kBAAkB;IAC1B,KAAK,EAAE,SAAS,EAAE,QAAQ;IAC1B,0EAA0E;IAC1E,+DAA+D;IAC/D,2CAA2C;IAC3C,UAAU,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;IAC9C,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,QAAQ,GAAgB;IAC5B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,qEAAqE;QACrE,uEAAuE;QACvE,mEAAmE;QACnE,sEAAsE;QACtE,yBAAyB;IAC3B,MAAM,EAAE,eAAe;IACvB,KAAK,EAAE,SAAS,EAAE,SAAS;IAC3B,sEAAsE;IACtE,kEAAkE;IAClE,yEAAyE;IACzE,mDAAmD;IACnD,mEAAmE;IACnE,qEAAqE;IACrE,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC;IAC7B,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,MAAM,GAAgB;IAC1B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,qEAAqE;QACrE,yEAAyE;QACzE,wEAAwE;QACxE,uEAAuE;QACvE,oEAAoE;QACpE,gCAAgC;IAClC,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,SAAS,EAAE,OAAO;IACzB,iEAAiE;IACjE,6DAA6D;IAC7D,2EAA2E;IAC3E,6DAA6D;IAC7D,UAAU,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;IAC9C,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,UAAU,GAAgB;IAC9B,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,iEAAiE;QACjE,sEAAsE;QACtE,sEAAsE;QACtE,wEAAwE;QACxE,mEAAmE;QACnE,sEAAsE;QACtE,wDAAwD;IAC1D,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,SAAS,EAAE,SAAS;IAC3B,iEAAiE;IACjE,wEAAwE;IACxE,wEAAwE;IACxE,wEAAwE;IACxE,yEAAyE;IACzE,0BAA0B;IAC1B,UAAU,EAAE,SAAS,EAAE;IACvB,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,4EAA4E;AAC5E,KAAK,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;IACvE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,cAAc,GAAG,YAAY,CAAA;AAC7D,CAAC;AAED;;;qBAGqB;AACrB,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;IACxB,kBAAkB,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAC7C,sBAAsB,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-hook leverage beyond the tool surface (2026-09-18 audit follow-up).
|
|
3
|
+
*
|
|
4
|
+
* Everything here rides an ALREADY-PUBLISHED plugin hook — no host source is
|
|
5
|
+
* touched — and each knob is independently switchable, because this host's
|
|
6
|
+
* d.ts has promised surfaces the runtime never delivered (`permission.ask`
|
|
7
|
+
* is declared and never fires on 1.18.29/30). So: pure decisions in one
|
|
8
|
+
* place, adapters that never throw and never mutate unless the payload has
|
|
9
|
+
* the exact shape we verified.
|
|
10
|
+
*
|
|
11
|
+
* The four hooks implemented here:
|
|
12
|
+
* - `tool.definition` → append OUR discipline to a built-in
|
|
13
|
+
* tool's OWN description, where the model decides (a bash timeout rule
|
|
14
|
+
* buried in a system prompt loses to one printed next to the parameter);
|
|
15
|
+
* - `chat.params` → per-agent sampling overrides
|
|
16
|
+
* (off by default: "all agents at 0.2" is a documented project
|
|
17
|
+
* invariant, so changing it is the user's call, not ours);
|
|
18
|
+
* - `experimental.session.compacting`
|
|
19
|
+
* + `experimental.compaction.autocontinue` → keep the reply skeleton and
|
|
20
|
+
* the handle rules ALIVE across a compaction, instead of letting the
|
|
21
|
+
* summarizer invent its own contract;
|
|
22
|
+
* - `shell.env` → NO_COLOR/TERM=dumb for every child
|
|
23
|
+
* shell (ANSI escapes in npm/cargo/pytest output are pure context
|
|
24
|
+
* tokens), plus an explicit operator passthrough.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately NOT here: `experimental.chat.messages.transform`. Rewriting
|
|
27
|
+
* the outgoing message array means guessing the live shape of tool results
|
|
28
|
+
* at that layer; a wrong guess silently deletes the evidence the EVIDENCE
|
|
29
|
+
* line depends on. It needs a live host probe first, not a plausible patch.
|
|
30
|
+
*/
|
|
31
|
+
export declare const HOOK_ENV_DEFAULTS: {
|
|
32
|
+
readonly toolHints: "on";
|
|
33
|
+
readonly agentTemperature: "off";
|
|
34
|
+
readonly compactionContext: "on";
|
|
35
|
+
readonly compactionAutoContinue: "on";
|
|
36
|
+
readonly shellNoColor: "on";
|
|
37
|
+
};
|
|
38
|
+
type EnvLike = Record<string, string | undefined>;
|
|
39
|
+
/** The on/off switches the plugin entry needs before building adapters. */
|
|
40
|
+
export declare function hookSwitches(env?: EnvLike): {
|
|
41
|
+
toolHints: boolean;
|
|
42
|
+
compactionContext: boolean;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Footers appended to a built-in tool's description, keyed by tool id.
|
|
46
|
+
* Short, imperative, and about THIS plugin's guarantees — the point is that
|
|
47
|
+
* the model reads it at the call site, not thousands of tokens earlier.
|
|
48
|
+
*/
|
|
49
|
+
export declare const TOOL_HINTS: Record<string, string>;
|
|
50
|
+
/**
|
|
51
|
+
* The `tool.definition` adapter. Returns true when it appended (so the
|
|
52
|
+
* caller can log it). Idempotent: a re-issued description that already
|
|
53
|
+
* carries the marker is left byte-exact, and the host description is never
|
|
54
|
+
* replaced — only extended.
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyToolDefinition(input: unknown, output: unknown, enabled?: boolean): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Sampling per role, ONLY when the operator opts in. architect is the one
|
|
59
|
+
* role whose job (design alternatives) genuinely suffers at 0.2; the
|
|
60
|
+
* mechanical roles stay cold — a specialist that hallucinates a file path
|
|
61
|
+
* costs the whole team a round.
|
|
62
|
+
*/
|
|
63
|
+
export declare const AGENT_TEMPERATURES: Record<string, number>;
|
|
64
|
+
/**
|
|
65
|
+
* `TM_AGENT_TEMPERATURE` = off | on | `agent=value;agent=value`.
|
|
66
|
+
* Returns the temperature to force, or null to leave the host's value alone.
|
|
67
|
+
* A malformed table resolves to null rather than half-applying garbage.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolveAgentTemperature(agent: unknown, env?: EnvLike): number | null;
|
|
70
|
+
/** The `chat.params` adapter: only `temperature` is touched, and only when
|
|
71
|
+
* this agent has an override. */
|
|
72
|
+
export declare function applyChatParams(input: unknown, output: unknown, env?: EnvLike): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Context lines handed to the host's compaction summarizer
|
|
75
|
+
* (`experimental.session.compacting` → `output.context[]`). We ADD to the
|
|
76
|
+
* default prompt and never replace it: setting `output.prompt` would void
|
|
77
|
+
* whatever the host itself learns to preserve, and the summarizer would stop
|
|
78
|
+
* being the host's.
|
|
79
|
+
*
|
|
80
|
+
* Each line corresponds to a thing that, once summarized away, cannot be
|
|
81
|
+
* re-derived without spending a round to rediscover it:
|
|
82
|
+
* - the reply skeleton — prose instead of STATUS:/CHANGES/… makes the
|
|
83
|
+
* lead's machine check fail for the rest of the session;
|
|
84
|
+
* - offload handles (ref/access_token/expire_at) — they are the ONLY
|
|
85
|
+
* window onto a payload that never entered context;
|
|
86
|
+
* - child session ids from tm_dispatch — an uncollected dispatch is
|
|
87
|
+
* running work, and after a summary it looks indistinguishably like done
|
|
88
|
+
* work;
|
|
89
|
+
* - provenance (file:line / URL + confidence) — without it a finding
|
|
90
|
+
* degrades into model memory, the one thing this project refuses;
|
|
91
|
+
* - the todo list and board paths — the state lives there, not in chat.
|
|
92
|
+
*/
|
|
93
|
+
export declare const COMPACTION_CONTEXT: string[];
|
|
94
|
+
/** The `experimental.session.compacting` adapter — additive, idempotent. */
|
|
95
|
+
export declare function applySessionCompacting(output: unknown, enabled?: boolean): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* `experimental.compaction.autocontinue`. Left ALONE by default: the host
|
|
98
|
+
* resuming after a summary is what keeps a long pipeline moving, and
|
|
99
|
+
* stopping mid-flight without being asked is a worse surprise than a
|
|
100
|
+
* continued one. `TM_COMPACTION_AUTOCONTINUE=off` opts out — then the run
|
|
101
|
+
* pauses for the user to re-read state before anything touches files again.
|
|
102
|
+
*/
|
|
103
|
+
export declare function applyCompactionAutoContinue(output: unknown, env?: EnvLike): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Environment for every child shell. NO_COLOR/TERM=dumb is a token saving
|
|
106
|
+
* with no functional cost (an agent reading a progress bar reads nothing),
|
|
107
|
+
* and `TM_SHELL_ENV` is the explicit operator passthrough (`K=V;K2=V2`) —
|
|
108
|
+
* deliberately allowlisted rather than forwarding process env, so this hook
|
|
109
|
+
* can never become a side channel for secrets into a sub-agent's shell.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveShellEnv(env?: EnvLike): Record<string, string>;
|
|
112
|
+
/** The `shell.env` adapter. Never deletes an existing key the host set. */
|
|
113
|
+
export declare function applyShellEnv(output: unknown, env?: EnvLike): boolean;
|
|
114
|
+
export {};
|
|
115
|
+
//# sourceMappingURL=host-hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-hooks.d.ts","sourceRoot":"","sources":["../src/host-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,eAAO,MAAM,iBAAiB;;;;;;CAMpB,CAAA;AAEV,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAOjD,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,GAAE,OAAqB,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAK3G;AAID;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK7C,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,EACf,OAAO,UAAO,GACb,OAAO,CAeT;AAID;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOrD,CAAA;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,GAAE,OAAqB,GAAG,MAAM,GAAG,IAAI,CAkBjG;AAED;kCACkC;AAClC,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAE,OAAqB,GAAG,OAAO,CAWpG;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,kBAAkB,UAM9B,CAAA;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,UAAO,GAAG,OAAO,CAkB/E;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,GAAE,OAAqB,GAAG,OAAO,CAUhG;AAID;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,OAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBlF;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,GAAE,OAAqB,GAAG,OAAO,CAkBlF"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-hook leverage beyond the tool surface (2026-09-18 audit follow-up).
|
|
3
|
+
*
|
|
4
|
+
* Everything here rides an ALREADY-PUBLISHED plugin hook — no host source is
|
|
5
|
+
* touched — and each knob is independently switchable, because this host's
|
|
6
|
+
* d.ts has promised surfaces the runtime never delivered (`permission.ask`
|
|
7
|
+
* is declared and never fires on 1.18.29/30). So: pure decisions in one
|
|
8
|
+
* place, adapters that never throw and never mutate unless the payload has
|
|
9
|
+
* the exact shape we verified.
|
|
10
|
+
*
|
|
11
|
+
* The four hooks implemented here:
|
|
12
|
+
* - `tool.definition` → append OUR discipline to a built-in
|
|
13
|
+
* tool's OWN description, where the model decides (a bash timeout rule
|
|
14
|
+
* buried in a system prompt loses to one printed next to the parameter);
|
|
15
|
+
* - `chat.params` → per-agent sampling overrides
|
|
16
|
+
* (off by default: "all agents at 0.2" is a documented project
|
|
17
|
+
* invariant, so changing it is the user's call, not ours);
|
|
18
|
+
* - `experimental.session.compacting`
|
|
19
|
+
* + `experimental.compaction.autocontinue` → keep the reply skeleton and
|
|
20
|
+
* the handle rules ALIVE across a compaction, instead of letting the
|
|
21
|
+
* summarizer invent its own contract;
|
|
22
|
+
* - `shell.env` → NO_COLOR/TERM=dumb for every child
|
|
23
|
+
* shell (ANSI escapes in npm/cargo/pytest output are pure context
|
|
24
|
+
* tokens), plus an explicit operator passthrough.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately NOT here: `experimental.chat.messages.transform`. Rewriting
|
|
27
|
+
* the outgoing message array means guessing the live shape of tool results
|
|
28
|
+
* at that layer; a wrong guess silently deletes the evidence the EVIDENCE
|
|
29
|
+
* line depends on. It needs a live host probe first, not a plausible patch.
|
|
30
|
+
*/
|
|
31
|
+
export const HOOK_ENV_DEFAULTS = {
|
|
32
|
+
toolHints: "on",
|
|
33
|
+
agentTemperature: "off",
|
|
34
|
+
compactionContext: "on",
|
|
35
|
+
compactionAutoContinue: "on",
|
|
36
|
+
shellNoColor: "on",
|
|
37
|
+
};
|
|
38
|
+
const isOn = (raw, def) => {
|
|
39
|
+
const v = String(raw ?? "").trim().toLowerCase();
|
|
40
|
+
if (v === "")
|
|
41
|
+
return def === "on";
|
|
42
|
+
return !(v === "off" || v === "0" || v === "false" || v === "no");
|
|
43
|
+
};
|
|
44
|
+
/** The on/off switches the plugin entry needs before building adapters. */
|
|
45
|
+
export function hookSwitches(env = process.env) {
|
|
46
|
+
return {
|
|
47
|
+
toolHints: isOn(env.TM_TOOL_HINTS, HOOK_ENV_DEFAULTS.toolHints),
|
|
48
|
+
compactionContext: isOn(env.TM_COMPACTION_CONTEXT, HOOK_ENV_DEFAULTS.compactionContext),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/* ---------- tool.definition ---------- */
|
|
52
|
+
/**
|
|
53
|
+
* Footers appended to a built-in tool's description, keyed by tool id.
|
|
54
|
+
* Short, imperative, and about THIS plugin's guarantees — the point is that
|
|
55
|
+
* the model reads it at the call site, not thousands of tokens earlier.
|
|
56
|
+
*/
|
|
57
|
+
export const TOOL_HINTS = {
|
|
58
|
+
bash: "\n\n[OpenCode TeamMode] Time discipline: leave `timeout` out unless this step is genuinely slow — the default kill is 120 s and a bigger number only lengthens the silence, a read-only probe (ls/grep/rg/cat/Get-ChildItem) is never a 120-second command (values above the probe ceiling are clamped before the command runs). Independent steps do NOT belong chained with `;` into one call — separate calls, or one tm_ptc_run program.",
|
|
59
|
+
task: "\n\n[OpenCode TeamMode] This blocks your session until the child returns. For independent work that must overlap your own, prefer tm_dispatch (returns at once) + tm_join (collect) and keep the brief self-contained.",
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The `tool.definition` adapter. Returns true when it appended (so the
|
|
63
|
+
* caller can log it). Idempotent: a re-issued description that already
|
|
64
|
+
* carries the marker is left byte-exact, and the host description is never
|
|
65
|
+
* replaced — only extended.
|
|
66
|
+
*/
|
|
67
|
+
export function applyToolDefinition(input, output, enabled = true) {
|
|
68
|
+
if (!enabled)
|
|
69
|
+
return false;
|
|
70
|
+
try {
|
|
71
|
+
const toolID = String(input?.toolID ?? "").trim().toLowerCase();
|
|
72
|
+
const key = Object.keys(TOOL_HINTS).find((k) => toolID === k || toolID.endsWith(`:${k}`) || toolID.endsWith(`/${k}`));
|
|
73
|
+
if (!key)
|
|
74
|
+
return false;
|
|
75
|
+
const out = output;
|
|
76
|
+
if (!out || typeof out.description !== "string")
|
|
77
|
+
return false;
|
|
78
|
+
const marker = "[OpenCode TeamMode]";
|
|
79
|
+
if (out.description.includes(marker))
|
|
80
|
+
return false;
|
|
81
|
+
out.description = out.description + TOOL_HINTS[key];
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/* ---------- chat.params ---------- */
|
|
89
|
+
/**
|
|
90
|
+
* Sampling per role, ONLY when the operator opts in. architect is the one
|
|
91
|
+
* role whose job (design alternatives) genuinely suffers at 0.2; the
|
|
92
|
+
* mechanical roles stay cold — a specialist that hallucinates a file path
|
|
93
|
+
* costs the whole team a round.
|
|
94
|
+
*/
|
|
95
|
+
export const AGENT_TEMPERATURES = {
|
|
96
|
+
architect: 0.35,
|
|
97
|
+
researcher: 0.3,
|
|
98
|
+
team: 0.2,
|
|
99
|
+
implementer: 0.2,
|
|
100
|
+
reviewer: 0.1,
|
|
101
|
+
tester: 0.2,
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* `TM_AGENT_TEMPERATURE` = off | on | `agent=value;agent=value`.
|
|
105
|
+
* Returns the temperature to force, or null to leave the host's value alone.
|
|
106
|
+
* A malformed table resolves to null rather than half-applying garbage.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveAgentTemperature(agent, env = process.env) {
|
|
109
|
+
const raw = String(env.TM_AGENT_TEMPERATURE ?? HOOK_ENV_DEFAULTS.agentTemperature).trim().toLowerCase();
|
|
110
|
+
if (raw === "" || raw === HOOK_ENV_DEFAULTS.agentTemperature)
|
|
111
|
+
return null;
|
|
112
|
+
const name = String(agent ?? "").trim().toLowerCase();
|
|
113
|
+
if (!name)
|
|
114
|
+
return null;
|
|
115
|
+
if (raw === "on" || raw === "true" || raw === "1") {
|
|
116
|
+
const t = AGENT_TEMPERATURES[name];
|
|
117
|
+
return typeof t === "number" ? t : null;
|
|
118
|
+
}
|
|
119
|
+
const table = {};
|
|
120
|
+
for (const part of raw.split(/[;,]/)) {
|
|
121
|
+
const m = /^\s*([a-z0-9_-]{1,24})\s*=\s*(\d+(?:\.\d+)?)\s*$/.exec(part);
|
|
122
|
+
if (!m)
|
|
123
|
+
return null;
|
|
124
|
+
const value = Number(m[2]);
|
|
125
|
+
if (!Number.isFinite(value) || value < 0 || value > 2)
|
|
126
|
+
return null;
|
|
127
|
+
table[m[1]] = value;
|
|
128
|
+
}
|
|
129
|
+
return typeof table[name] === "number" ? table[name] : null;
|
|
130
|
+
}
|
|
131
|
+
/** The `chat.params` adapter: only `temperature` is touched, and only when
|
|
132
|
+
* this agent has an override. */
|
|
133
|
+
export function applyChatParams(input, output, env = process.env) {
|
|
134
|
+
try {
|
|
135
|
+
const t = resolveAgentTemperature(input?.agent, env);
|
|
136
|
+
if (t === null)
|
|
137
|
+
return false;
|
|
138
|
+
const out = output;
|
|
139
|
+
if (!out || typeof out.temperature !== "number")
|
|
140
|
+
return false;
|
|
141
|
+
out.temperature = t;
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/* ---------- compaction ---------- */
|
|
149
|
+
/**
|
|
150
|
+
* Context lines handed to the host's compaction summarizer
|
|
151
|
+
* (`experimental.session.compacting` → `output.context[]`). We ADD to the
|
|
152
|
+
* default prompt and never replace it: setting `output.prompt` would void
|
|
153
|
+
* whatever the host itself learns to preserve, and the summarizer would stop
|
|
154
|
+
* being the host's.
|
|
155
|
+
*
|
|
156
|
+
* Each line corresponds to a thing that, once summarized away, cannot be
|
|
157
|
+
* re-derived without spending a round to rediscover it:
|
|
158
|
+
* - the reply skeleton — prose instead of STATUS:/CHANGES/… makes the
|
|
159
|
+
* lead's machine check fail for the rest of the session;
|
|
160
|
+
* - offload handles (ref/access_token/expire_at) — they are the ONLY
|
|
161
|
+
* window onto a payload that never entered context;
|
|
162
|
+
* - child session ids from tm_dispatch — an uncollected dispatch is
|
|
163
|
+
* running work, and after a summary it looks indistinguishably like done
|
|
164
|
+
* work;
|
|
165
|
+
* - provenance (file:line / URL + confidence) — without it a finding
|
|
166
|
+
* degrades into model memory, the one thing this project refuses;
|
|
167
|
+
* - the todo list and board paths — the state lives there, not in chat.
|
|
168
|
+
*/
|
|
169
|
+
export const COMPACTION_CONTEXT = [
|
|
170
|
+
"OpenCode TeamMode contract survives compaction: every specialist reply keeps the STATUS / CHANGES / FINDINGS / EVIDENCE / HANDOFF skeleton and the lead machine-checks it — never summarize a reply into prose without those keys.",
|
|
171
|
+
"Offloaded payloads are addressed by handle (ref + access_token + expire_at) from tm_* results. Carry the handles forward VERBATIM; never re-run a tool to rediscover a payload a handle already names.",
|
|
172
|
+
"Async dispatches (tm_dispatch) and their child session ids must survive: an uncollected child is still-running work, not finished work.",
|
|
173
|
+
"Every finding keeps its source (file:line or URL) and confidence tag after compaction, otherwise it is unverifiable memory.",
|
|
174
|
+
"The todo list and the blackboard files are the state, not the transcript: keep task items and board paths, drop chit-chat and raw command echo.",
|
|
175
|
+
];
|
|
176
|
+
/** The `experimental.session.compacting` adapter — additive, idempotent. */
|
|
177
|
+
export function applySessionCompacting(output, enabled = true) {
|
|
178
|
+
if (!enabled)
|
|
179
|
+
return false;
|
|
180
|
+
try {
|
|
181
|
+
const out = output;
|
|
182
|
+
if (!out)
|
|
183
|
+
return false;
|
|
184
|
+
if (!Array.isArray(out.context))
|
|
185
|
+
out.context = [];
|
|
186
|
+
const list = out.context;
|
|
187
|
+
let added = 0;
|
|
188
|
+
for (const line of COMPACTION_CONTEXT) {
|
|
189
|
+
if (!list.includes(line)) {
|
|
190
|
+
list.push(line);
|
|
191
|
+
added++;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return added > 0;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* `experimental.compaction.autocontinue`. Left ALONE by default: the host
|
|
202
|
+
* resuming after a summary is what keeps a long pipeline moving, and
|
|
203
|
+
* stopping mid-flight without being asked is a worse surprise than a
|
|
204
|
+
* continued one. `TM_COMPACTION_AUTOCONTINUE=off` opts out — then the run
|
|
205
|
+
* pauses for the user to re-read state before anything touches files again.
|
|
206
|
+
*/
|
|
207
|
+
export function applyCompactionAutoContinue(output, env = process.env) {
|
|
208
|
+
try {
|
|
209
|
+
if (isOn(env.TM_COMPACTION_AUTOCONTINUE, HOOK_ENV_DEFAULTS.compactionAutoContinue))
|
|
210
|
+
return false;
|
|
211
|
+
const out = output;
|
|
212
|
+
if (!out || typeof out.enabled !== "boolean")
|
|
213
|
+
return false;
|
|
214
|
+
out.enabled = false;
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/* ---------- shell.env ---------- */
|
|
222
|
+
/**
|
|
223
|
+
* Environment for every child shell. NO_COLOR/TERM=dumb is a token saving
|
|
224
|
+
* with no functional cost (an agent reading a progress bar reads nothing),
|
|
225
|
+
* and `TM_SHELL_ENV` is the explicit operator passthrough (`K=V;K2=V2`) —
|
|
226
|
+
* deliberately allowlisted rather than forwarding process env, so this hook
|
|
227
|
+
* can never become a side channel for secrets into a sub-agent's shell.
|
|
228
|
+
*/
|
|
229
|
+
export function resolveShellEnv(env = process.env) {
|
|
230
|
+
const out = {};
|
|
231
|
+
if (isOn(env.TM_SHELL_NO_COLOR, HOOK_ENV_DEFAULTS.shellNoColor)) {
|
|
232
|
+
out.NO_COLOR = "1";
|
|
233
|
+
out.CLANG_COLOR_MODE = "never";
|
|
234
|
+
out.TERM = "dumb";
|
|
235
|
+
}
|
|
236
|
+
const raw = String(env.TM_SHELL_ENV ?? "").trim();
|
|
237
|
+
if (raw) {
|
|
238
|
+
for (const part of raw.split(/[;]/)) {
|
|
239
|
+
const m = /^\s*([A-Za-z_][A-Za-z0-9_]{0,40})\s*=\s*(.*)$/.exec(part);
|
|
240
|
+
if (!m)
|
|
241
|
+
continue;
|
|
242
|
+
out[m[1]] = m[2].replace(/\s+$/, "");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
/** The `shell.env` adapter. Never deletes an existing key the host set. */
|
|
248
|
+
export function applyShellEnv(output, env = process.env) {
|
|
249
|
+
try {
|
|
250
|
+
const patch = resolveShellEnv(env);
|
|
251
|
+
const out = output;
|
|
252
|
+
if (!out || Object.keys(patch).length === 0)
|
|
253
|
+
return false;
|
|
254
|
+
if (!out.env || typeof out.env !== "object")
|
|
255
|
+
out.env = {};
|
|
256
|
+
const target = out.env;
|
|
257
|
+
let added = 0;
|
|
258
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
259
|
+
if (target[k] === undefined) {
|
|
260
|
+
target[k] = v;
|
|
261
|
+
added++;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return added > 0;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=host-hooks.js.map
|