triss-coworker 0.37.2 → 0.38.0
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/CHANGELOG.md +70 -0
- package/README.md +27 -15
- package/bin/triss.js +3 -3
- package/docs/configuration.md +18 -7
- package/docs/engines/opencode-zen.md +12 -5
- package/docs/engines/opencode2.md +60 -20
- package/docs/mcp.md +5 -1
- package/package.json +4 -3
- package/src/coder-credential-proxy.js +16 -4
- package/src/coder-engines/opencode2.js +222 -25
- package/src/coder-orchestration.js +15 -2
- package/src/coder-providers.js +238 -0
- package/src/coder-sandbox.js +1 -1
- package/src/commands/coder.js +821 -322
- package/src/commands/status.js +16 -8
- package/src/config.js +15 -2
- package/src/mcp/handlers.js +5 -3
- package/src/opencode2-preflight.js +57 -21
- package/src/usage.js +97 -18
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.38.0] — 2026-08-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Canonical OpenCode provider routing** — both `opencode` engines now resolve
|
|
15
|
+
Triss worker, Z.AI, OpenCode Zen, OpenCode Go, Moonshot, and Kimi for Coding
|
|
16
|
+
through one provider registry. Protected runs pin a transient provider in
|
|
17
|
+
`OPENCODE_CONFIG_CONTENT`, including model-specific Chat Completions,
|
|
18
|
+
Responses, and Anthropic transport metadata for audited Zen/Go models.
|
|
19
|
+
- **Explicit raw best-effort credential mode** — literal
|
|
20
|
+
`TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION=1` allows either OpenCode engine to
|
|
21
|
+
run every canonical provider, including ordinary plugins, agents, custom
|
|
22
|
+
tools, and shell policies, while reporting credential isolation as
|
|
23
|
+
unavailable and warning that the selected raw credential is visible to the
|
|
24
|
+
same-UID child.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- OpenCode 2 now installs from `@opencode-ai/cli@beta` and accepts compatible
|
|
29
|
+
releases at or above `0.0.0-beta-17793` when the required CLI capability
|
|
30
|
+
probe passes. `TRISS_CODER_OPENCODE2_VERSION` is a minimum-version override,
|
|
31
|
+
replacing the obsolete exact `next-*` pin.
|
|
32
|
+
- `triss coder init`, `coder run`, `coder models`, `triss status`, and the MCP
|
|
33
|
+
coder path use the same provider ownership, credential, endpoint, package,
|
|
34
|
+
header, and transport rules. One-shot main/small model routing is validated
|
|
35
|
+
as one provider pair; OpenCode 2 continues to report its small role as
|
|
36
|
+
unavailable.
|
|
37
|
+
- `triss-dsh-provider-bundle` is version-aligned and republished unchanged;
|
|
38
|
+
the routing and credential-mode behavior above belongs to the Triss runtime,
|
|
39
|
+
while the companion still exposes its existing OpenCode Zen, OpenCode Go,
|
|
40
|
+
and Z.AI catalogue routes.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- OpenCode 1 no longer sends Triss's run-scoped proxy token to the real
|
|
45
|
+
upstream because `OPENCODE_BASE_URL` was ignored. The transient provider
|
|
46
|
+
overlay now pins the credential proxy endpoint that the engine actually
|
|
47
|
+
uses, including the unprefixed `/responses` route.
|
|
48
|
+
- The bounded effective-config audit now mirrors the real launch mode:
|
|
49
|
+
one-shot runs probe and launch with `--pure`; ordinary runs do neither, so
|
|
50
|
+
managed, account, MDM, and disk policy layers are audited without disabling
|
|
51
|
+
the deny-first project policy.
|
|
52
|
+
- Protected credential-store checks now use the canonical local and global
|
|
53
|
+
Triss env paths (including `~/.config/triss/.env`), allow non-secret/control
|
|
54
|
+
entries, and reject readable stores containing provider credentials before
|
|
55
|
+
the engine starts.
|
|
56
|
+
- Worker routes verify the configured base URL through the final effective
|
|
57
|
+
provider projection, and Zen/Go protected runs fail closed for unaudited or
|
|
58
|
+
unsupported model transports instead of guessing Chat Completions.
|
|
59
|
+
|
|
60
|
+
### Security
|
|
61
|
+
|
|
62
|
+
- Protected mode rejects persistent collisions with Triss's transient provider
|
|
63
|
+
alias and verifies the final merged provider/model projection before any
|
|
64
|
+
credential-bearing child is spawned. Raw best-effort mode remains an
|
|
65
|
+
explicit risk acknowledgement and never claims proxy isolation.
|
|
66
|
+
|
|
67
|
+
### Artifact integrity (0.38.0)
|
|
68
|
+
|
|
69
|
+
- `triss-dsh-provider-bundle-0.38.0.tgz` — sha256
|
|
70
|
+
`bd9efaf1a692f82c15e49333c9a23071d9e30eee49e8e4576535dd91176fc71e`,
|
|
71
|
+
integrity
|
|
72
|
+
`sha512-sunelgV+I7TsL0OfkjDiv2XcnRQc+nQ4o3KjgfVZq390t8g2sVBTQTxPtNp+LU5IE41zm+fTqpXusAZzVQRuUg==`
|
|
73
|
+
(computed with the pinned release npm 11.6.2 via `npm pack`; `npm pack`
|
|
74
|
+
output is byte-deterministic).
|
|
75
|
+
- Root `triss-coworker-0.38.0.tgz` sha256 is reproducible via `npm pack` at
|
|
76
|
+
tag `v0.38.0` (the root tarball ships `CHANGELOG.md`, so its hash cannot be
|
|
77
|
+
recorded inside this file); registry verification compares the packed
|
|
78
|
+
artifact against the published tarball byte-for-byte.
|
|
79
|
+
|
|
10
80
|
## [0.37.2] — 2026-08-20
|
|
11
81
|
|
|
12
82
|
### Added
|
package/README.md
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
[](https://opensource.org/licenses/MIT)
|
|
12
12
|
[](CHANGELOG.md)
|
|
13
13
|
|
|
14
|
+
**Website:** [triss.work](https://triss.work/) · **Quickstart:**
|
|
15
|
+
[triss.work/docs/getting-started](https://triss.work/docs/getting-started/)
|
|
16
|
+
|
|
14
17
|
Triss is a small CLI (`triss`) that hands token-heavy I/O off to a cheap
|
|
15
18
|
DeepSeek model so your expensive primary agent (Claude Code, Codex, or
|
|
16
19
|
anything else that can run a shell/MCP tool) stays focused on reasoning and
|
|
@@ -48,7 +51,7 @@ tokens of tracker chatter into its own context. Adding a new provider
|
|
|
48
51
|
|
|
49
52
|
## Requirements
|
|
50
53
|
|
|
51
|
-
- **Node.js ≥ 22** (LTS). Check with `node --version`.
|
|
54
|
+
- **Node.js ≥ 22.12** (LTS). Check with `node --version`.
|
|
52
55
|
- Don't have it? Install via [nvm](https://github.com/nvm-sh/nvm), [fnm](https://github.com/Schniz/fnm), Homebrew (`brew install node`), or [nodejs.org](https://nodejs.org/).
|
|
53
56
|
- **npm** (ships with Node.js) — used only for the package-manager install path.
|
|
54
57
|
`pnpm` and `yarn` also work.
|
|
@@ -148,9 +151,9 @@ triss config wizard
|
|
|
148
151
|
|
|
149
152
|
The wizard first asks **Standard** vs **Advanced**:
|
|
150
153
|
|
|
151
|
-
- **Standard** — for most users.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
- **Standard** — for most users. Two prompts for API key + worker model
|
|
155
|
+
(writes the model into both `flash` and `pro` so `--model pro` works), then
|
|
156
|
+
asks which agent to wire up: **Claude / Codex / Both**. No questions about
|
|
154
157
|
Jira/Linear/base URL/etc. *Recommended starting point.*
|
|
155
158
|
- **Advanced** — full control: separate `flash`/`pro` presets, custom
|
|
156
159
|
base URL, integrations (Jira, Linear, …), default-preset choice.
|
|
@@ -206,7 +209,7 @@ top-level commands; `triss config <Tab>`, `triss jira <Tab>`,
|
|
|
206
209
|
|
|
207
210
|
| Mode in `triss config wizard` | What it does about your agent |
|
|
208
211
|
| ----------------------------- | ------------------------------ |
|
|
209
|
-
| **Standard** (default) |
|
|
212
|
+
| **Standard** (default) | After the two prompts, asks **Claude / Codex / Both** and installs MCP + global rules accordingly. |
|
|
210
213
|
| **Advanced** (`--advanced`) | Asks at the end: Both / MCP only / rules only / Skip. Default = Both. |
|
|
211
214
|
|
|
212
215
|
The two paths cooperate: MCP is primary, `CLAUDE.md` / `AGENTS.md` rules are
|
|
@@ -747,10 +750,12 @@ implicit persistent conversation), `result_retention`
|
|
|
747
750
|
/ `result_id` (`retained` only for isolated changed runs with enforced
|
|
748
751
|
result-store quota and a successful reservation), and `execution_capabilities`
|
|
749
752
|
(eight honest `enforced|best_effort|unavailable` values plus
|
|
750
|
-
`effective_isolation`).
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
`
|
|
753
|
+
`effective_isolation`). OpenCode 2 emits the same envelope v2 fields,
|
|
754
|
+
including `envelope_version`, lifecycle fields, activity, and
|
|
755
|
+
OpenCode best-effort raw runs explicitly report
|
|
756
|
+
`credential_isolation: "unavailable"` plus the stable downgrade warning;
|
|
757
|
+
Crush remains proxy-backed and reports the proxy's `best_effort` capability.
|
|
758
|
+
Non-isolated `files_changed` is `null`; the only
|
|
754
759
|
changes-expectation evidence is `run_files_changed`. Process completion and a
|
|
755
760
|
non-empty final text are not task satisfaction — use `--isolate`, check
|
|
756
761
|
`run_files_changed` in the envelope, and verify the retained worktree/diff
|
|
@@ -889,6 +894,14 @@ external plugins. Unreadable/JSONC/unknown layers fail closed. Concurrent
|
|
|
889
894
|
same-user config mutation between preflight and spawn remains outside this
|
|
890
895
|
guard's threat model.
|
|
891
896
|
|
|
897
|
+
Every OpenCode 1 run performs this final effective-config check before the
|
|
898
|
+
credential-bearing engine spawn, using a bounded `opencode debug config`
|
|
899
|
+
subprocess and a disposable probe credential. The probe mirrors the actual
|
|
900
|
+
run's plugin mode: explicit one-shot provider runs use `--pure` in both
|
|
901
|
+
processes; ordinary runs omit it in both, so their disk-backed deny-first bash
|
|
902
|
+
policy and later account/org, managed-directory, and macOS MDM layers remain
|
|
903
|
+
visible to the audit.
|
|
904
|
+
|
|
892
905
|
```bash
|
|
893
906
|
triss coder init --provider opencode-zen # guided: key + opencode.json
|
|
894
907
|
triss coder models --provider opencode-zen # see live Zen ids
|
|
@@ -959,7 +972,7 @@ Not every engine speaks every provider:
|
|
|
959
972
|
| Engine | Providers served |
|
|
960
973
|
| ---------- | ------------------------------------------------- |
|
|
961
974
|
| `opencode` | Triss worker, Z.AI GLM, OpenCode Zen, OpenCode Go, Moonshot, Kimi for Coding |
|
|
962
|
-
| `opencode2` | Same provider routing as V1 (
|
|
975
|
+
| `opencode2` | Same canonical provider routing as V1 (transient `OPENCODE_CONFIG_CONTENT` overlay; protected proxy by default; explicit literal-1 `TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION` enables raw best-effort with an honest downgrade warning; see [docs/engines/opencode2.md](docs/engines/opencode2.md)) |
|
|
963
976
|
| `crush` | Z.AI GLM (coding-plan only) |
|
|
964
977
|
|
|
965
978
|
`triss coder init` drives setup in that order — **engine, then provider,
|
|
@@ -1228,8 +1241,7 @@ OpenCode stores (quota usage on subscriptions, not necessarily cash paid).
|
|
|
1228
1241
|
### An earlier example week (the Triss worker)
|
|
1229
1242
|
|
|
1230
1243
|
One full week of real usage on this codebase, captured from the DeepSeek
|
|
1231
|
-
dashboard (May 6–13, 2026, all at list price
|
|
1232
|
-
would add another ~75% discount we did not use):
|
|
1244
|
+
dashboard (May 6–13, 2026, all at the list price then in effect):
|
|
1233
1245
|
|
|
1234
1246
|
| Metric | Pro | Flash | **Total** |
|
|
1235
1247
|
| -------------- | --------- | --------- | ---------- |
|
|
@@ -1257,9 +1269,9 @@ raw 5.8M input. That compounds across turns.
|
|
|
1257
1269
|
For reference, here is a single measured call of the kind that drives
|
|
1258
1270
|
the weekly numbers above:
|
|
1259
1271
|
|
|
1260
|
-
| Task | Source bytes | DeepSeek (pro,
|
|
1261
|
-
| ---- | ------------ |
|
|
1262
|
-
| `triss ask --urls --paths` over the original `claude-coworker-model` README + 12 of our source files (18.3K in / 2.4K out, structured 4-section report) | ≈ 65 KB | **\$0.
|
|
1272
|
+
| Task | Source bytes | DeepSeek (pro, list price) | Same job in Opus 4.x |
|
|
1273
|
+
| ---- | ------------ | -------------------------- | -------------------- |
|
|
1274
|
+
| `triss ask --urls --paths` over the original `claude-coworker-model` README + 12 of our source files (18.3K in / 2.4K out, structured 4-section report) | ≈ 65 KB | **\$0.040** | ≈ \$0.45 |
|
|
1263
1275
|
|
|
1264
1276
|
Real savings depend on which operations you delegate (bulk reads win
|
|
1265
1277
|
the most; tiny lookups break even); see `templates/claude.md` for the
|
package/bin/triss.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const [nodeMajor] = process.versions.node.split('.').map(Number);
|
|
3
|
-
if (nodeMajor < 22) {
|
|
2
|
+
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number);
|
|
3
|
+
if (nodeMajor < 22 || (nodeMajor === 22 && nodeMinor < 12)) {
|
|
4
4
|
process.stderr.write(
|
|
5
|
-
`triss requires Node.js >= 22 (you are on ${process.versions.node}).\n` +
|
|
5
|
+
`triss requires Node.js >= 22.12.0 (you are on ${process.versions.node}).\n` +
|
|
6
6
|
`Upgrade via nvm/fnm or https://nodejs.org/.\n`,
|
|
7
7
|
);
|
|
8
8
|
process.exit(1);
|
package/docs/configuration.md
CHANGED
|
@@ -272,7 +272,8 @@ self-hosted endpoints).
|
|
|
272
272
|
| `TRISS_CODER_SMALL_MODEL` | no | `zai-coding-plan/glm-5-turbo` | Small/fast **management/init intent** — written to `opencode.json` `small_model` by `init`/`triss coder model set`. **Not** a runtime override of an already-pinned small role (see precedence) |
|
|
273
273
|
| `TRISS_CODER_OPENCODE_VERSION` | no | `1.18.7` | Pin override for the `opencode-ai` npm install |
|
|
274
274
|
| `TRISS_CODER_ENGINE` | no | `opencode` | Coding engine: `opencode` (default), `opencode2` (beta — see [opencode2.md](engines/opencode2.md)), or `crush` |
|
|
275
|
-
| `TRISS_CODER_OPENCODE2_VERSION` | no | `0.0.0-
|
|
275
|
+
| `TRISS_CODER_OPENCODE2_VERSION` | no | `0.0.0-beta-17793` | Minimum accepted OpenCode 2 version; install from `@opencode-ai/cli@beta` (unsupported `next/dev/tui-v2` overrides fail closed) |
|
|
276
|
+
| `TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION` | no | unset | Only literal `1` enables OpenCode raw-credential best-effort mode; OpenCode reports credential isolation as unavailable and allows same-UID tools/plugins/shell to read the selected key. Crush continues to require its credential proxy. |
|
|
276
277
|
| `TRISS_CODER_CRUSH_VERSION` | no | `0.1.6` | Pin override for the `@phpcraftdream/crush` npm install (crush engine) |
|
|
277
278
|
| `TRISS_CODER_SESSION_CAP` | no | `4` | Persistent v2 session inventory cap per engine (fail closed) |
|
|
278
279
|
|
|
@@ -389,13 +390,23 @@ provider key, Triss audits the pinned version's full file graph: global
|
|
|
389
390
|
configs from the actual runtime directory to the Git root (or `/` for non-Git
|
|
390
391
|
directories). JSONC and unreadable layers fail closed. Because account/org,
|
|
391
392
|
managed-directory, and macOS MDM settings load after the in-memory overlay,
|
|
392
|
-
Triss also
|
|
393
|
-
|
|
393
|
+
Triss also validates the final merged config before every OpenCode 1 run under
|
|
394
|
+
the exact sanitized child environment, using a bounded `opencode debug config`
|
|
395
|
+
subprocess and a random canary instead of the real credential. The probe mirrors
|
|
396
|
+
the actual run: an explicit one-shot provider pair uses `--pure` for both probe
|
|
397
|
+
and run, while an ordinary run omits `--pure` for both so its disk-backed
|
|
398
|
+
deny-first bash policy and late managed layers remain visible. The final
|
|
394
399
|
main/small pair and selected provider must still match before the real key is
|
|
395
|
-
injected
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
400
|
+
injected. This includes inherited cwd and created or reused isolation worktrees.
|
|
401
|
+
Concurrent same-user mutation between preflight and spawn remains outside the
|
|
402
|
+
guard's threat model; unverified OpenCode versions fail closed.
|
|
403
|
+
|
|
404
|
+
For OpenCode 1, main and small models from the same provider may use different
|
|
405
|
+
audited transports. Triss then creates two transient provider aliases and two
|
|
406
|
+
model-scoped loopback proxy routes that share only the same one-run proxy token;
|
|
407
|
+
each route remains pinned to its own protocol, package, path, and model. OpenCode
|
|
408
|
+
2 validates an explicit small model as belonging to the selected provider but
|
|
409
|
+
does not configure or route it because that beta has no small-model role.
|
|
399
410
|
|
|
400
411
|
**Direct OpenCode `main` and `small`** (you run `opencode` yourself, not via
|
|
401
412
|
`triss coder run`): `opencode.json` is the source of truth — project
|
|
@@ -65,7 +65,8 @@ safety layer.
|
|
|
65
65
|
The Zen catalogue is **live and authoritative whenever it is reachable**.
|
|
66
66
|
Triss reads `GET https://opencode.ai/zen/v1/models` and treats whatever that
|
|
67
67
|
endpoint returns (authenticated) as the truth; the hardcoded priority list is
|
|
68
|
-
used only as the
|
|
68
|
+
used only as the offline availability fallback described below. Its ids still
|
|
69
|
+
need audited transport metadata before secure init can write them.
|
|
69
70
|
Discover the live catalogue on demand:
|
|
70
71
|
|
|
71
72
|
```bash
|
|
@@ -106,12 +107,18 @@ configuration are untouched, and GLM stays reachable through either engine (see
|
|
|
106
107
|
model. The priority list below is an **offline fallback only** — used when the
|
|
107
108
|
catalogue can't be fetched, and always labelled **not verified**:
|
|
108
109
|
|
|
109
|
-
| Role | Offline priority (first available wins;
|
|
110
|
+
| Role | Offline priority (first available wins; transport-audited ids only) |
|
|
110
111
|
|---|---|
|
|
111
|
-
| main | `deepseek-v4-flash-free` → `
|
|
112
|
-
| small | `deepseek-v4-flash-free` → `
|
|
112
|
+
| main | `deepseek-v4-flash-free` → `nemotron-3-ultra-free` → `mimo-v2.5-free` |
|
|
113
|
+
| small | `deepseek-v4-flash-free` → `mimo-v2.5-free` |
|
|
113
114
|
|
|
114
|
-
The
|
|
115
|
+
The offline path filters this list through Triss's audited transport registry;
|
|
116
|
+
catalogue-only ids such as `north-mini-code-free` are not written by secure
|
|
117
|
+
init when the live catalogue cannot be verified.
|
|
118
|
+
|
|
119
|
+
The secure interactive picker only offers live catalogue models with audited
|
|
120
|
+
transport metadata. Explicit unaudited ids remain available only through the
|
|
121
|
+
best-effort raw path described above.
|
|
115
122
|
For backward compatibility, Zen init keeps usable ids from a mixed response
|
|
116
123
|
even when unrelated entries are malformed; a response with no usable ids still
|
|
117
124
|
falls back as not verified. OpenCode Go intentionally uses a stricter all-entry
|
|
@@ -10,14 +10,23 @@ engine remains the default and is unchanged by installing or configuring V2.
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g @opencode-ai/cli@
|
|
13
|
+
npm install -g @opencode-ai/cli@beta # current V2 beta channel
|
|
14
14
|
triss coder init --engine opencode2
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
- The
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
- The supported floor is `0.0.0-beta-17793`. `TRISS_CODER_OPENCODE2_VERSION`
|
|
18
|
+
overrides the minimum accepted version; it is not an exact pin. `next-*`,
|
|
19
|
+
`dev-*`, and `tui-v2-*` overrides are unsupported.
|
|
20
|
+
- `triss status` reports the installed version against the effective minimum
|
|
21
|
+
and the required CLI capabilities (`--standalone`, `--format`, `--auto`,
|
|
22
|
+
`--model`).
|
|
23
|
+
- `triss coder init --engine opencode2` never spawns a V2 service; it probes
|
|
24
|
+
`opencode2 --version` and `opencode2 run --help` under isolated runtime
|
|
25
|
+
roots.
|
|
26
|
+
- When the host lacks a compatible `ps -axo` process snapshot (for example a
|
|
27
|
+
minimal BusyBox container), the required CLI flags and version still qualify
|
|
28
|
+
the engine. Init, status, and runs report that resident-service verification
|
|
29
|
+
is best effort instead of misdiagnosing the installed beta as incompatible.
|
|
21
30
|
|
|
22
31
|
## Shared config implications
|
|
23
32
|
|
|
@@ -25,15 +34,19 @@ V2 **shares** the V1 `opencode.json` (global and/or project) and the same env
|
|
|
25
34
|
pins — one config file, both engines. Consequences:
|
|
26
35
|
|
|
27
36
|
- The **shell policies of the two engines are NOT one policy**: the opencode2
|
|
28
|
-
beta requires deny-everything (`permission.bash = {"*":"deny"}`)
|
|
37
|
+
beta requires deny-everything (`permission.bash = {"*":"deny"}`) in protected
|
|
38
|
+
mode because the
|
|
29
39
|
credential sits in the child environment, while V1 init writes its
|
|
30
40
|
allowlist (`git status`, `git diff`, `npm test`, …) into the same shared
|
|
31
|
-
file. A fresh `coder init --engine opencode2` writes the deny-everything
|
|
41
|
+
file. A fresh protected `coder init --engine opencode2` writes the deny-everything
|
|
32
42
|
form (and warns that plain V1 `coder run` loses the allowlisted commands);
|
|
33
43
|
a tree initialized by V1 init is **rejected by V2** until the allow rules
|
|
34
44
|
are removed. Re-running plain `triss coder init` restores the V1 allowlist
|
|
35
45
|
— and makes the tree V2-incompatible again. This tension is inherent to
|
|
36
46
|
the shared-config beta and goes away only with real credential isolation.
|
|
47
|
+
Explicit best-effort mode (`TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION=1`)
|
|
48
|
+
accepts the raw-credential risk, so a fresh V2 config uses the normal V1
|
|
49
|
+
allowlist and an existing allow/ask policy remains byte-identical.
|
|
37
50
|
- `triss coder model set` / `triss coder models` show a shared-config notice
|
|
38
51
|
when the resolved engine is `opencode2`.
|
|
39
52
|
- Model transactions (`model set`, rollback) ride the same
|
|
@@ -49,6 +62,15 @@ reports `small_role_effective: false` for `opencode2`; the `small_model` value
|
|
|
49
62
|
in the shared config is an **OpenCode 1 compatibility value** and is shown as
|
|
50
63
|
such. There is no per-V2 small override.
|
|
51
64
|
|
|
65
|
+
Zen and Go protected runs use Triss's versioned, model-specific transport
|
|
66
|
+
metadata. Audited models may use Chat Completions, Responses, or Anthropic
|
|
67
|
+
Messages as indicated by that metadata; an unknown or Google/Gemini model is
|
|
68
|
+
rejected before spawn instead of being guessed as Chat. In explicit
|
|
69
|
+
`best_effort_raw` mode, an unknown Zen/Go model uses OpenCode's built-in
|
|
70
|
+
provider metadata while persistent provider overrides are still rejected. An
|
|
71
|
+
explicit `--small-model` is validated for provider ownership but does not
|
|
72
|
+
participate in V2 transport resolution and is reported as `used: false`.
|
|
73
|
+
|
|
52
74
|
## Usage gaps
|
|
53
75
|
|
|
54
76
|
Usage comes from per-step `step_finish` events (`usage_source: "opencode2"`).
|
|
@@ -59,12 +81,26 @@ maps `opencode2` into the same engine family as `opencode` (explicit
|
|
|
59
81
|
engines — the Go reseller's tariffs are not modeled (a
|
|
60
82
|
`TRISS_PRICE_OPENCODE_GO_<MODEL>` override prices it explicitly).
|
|
61
83
|
|
|
62
|
-
##
|
|
84
|
+
## Credential modes and executable surfaces
|
|
85
|
+
|
|
86
|
+
Protected mode is the default. It passes only a run-scoped proxy token to the
|
|
87
|
+
engine and keeps the strict deny-first executable-surface policy. Any
|
|
88
|
+
configured or discovered plugin, agent, or custom-tool source rejects before
|
|
89
|
+
the protected child starts.
|
|
90
|
+
|
|
91
|
+
Explicit best-effort mode is selected only by the literal environment value
|
|
92
|
+
`TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION=1`. It passes only the selected raw
|
|
93
|
+
provider credential, does not start the credential proxy, allows normal shell
|
|
94
|
+
policy and discovered agents/plugins/tools after config parse/shape checks,
|
|
95
|
+
and emits `TRISS_CODER_CREDENTIAL_ISOLATION_DOWNGRADED`. The envelope reports
|
|
96
|
+
`execution_capabilities.credential_isolation: "unavailable"`; same-UID code,
|
|
97
|
+
plugins, tools, and shell commands may read the credential. Endpoint, model,
|
|
98
|
+
package, header, and credential-binding pinning still applies.
|
|
63
99
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
100
|
+
The structural/config-shape checks apply in both modes. The executable-source
|
|
101
|
+
gate is mode-dependent: protected mode rejects these sources, while
|
|
102
|
+
best-effort mode inspects them and permits them after the shape checks. In
|
|
103
|
+
particular:
|
|
68
104
|
|
|
69
105
|
- `~/.config/opencode/plugins`, `.opencode/plugin`, configured plugin entries;
|
|
70
106
|
- `~/.config/opencode/agents/*`, `.opencode/agent/*`, configured agent
|
|
@@ -73,8 +109,10 @@ forwarded** — in both `coder init` and `coder run`:
|
|
|
73
109
|
`.opencode/tool`, and `.opencode/tools` custom-tool directories.
|
|
74
110
|
|
|
75
111
|
The error names the offending source path (never secrets). Remove or disable
|
|
76
|
-
the source,
|
|
77
|
-
|
|
112
|
+
the source for protected mode, or explicitly acknowledge best-effort risk.
|
|
113
|
+
One-shot provider selection is supported by both OpenCode engines; OpenCode 2
|
|
114
|
+
validates a supplied small model but reports that it has no separate small
|
|
115
|
+
role.
|
|
78
116
|
|
|
79
117
|
## Rollback
|
|
80
118
|
|
|
@@ -99,14 +137,16 @@ To fully remove V2: `npm uninstall -g @opencode-ai/cli` and delete
|
|
|
99
137
|
|
|
100
138
|
| Symptom | Cause / fix |
|
|
101
139
|
|---|---|
|
|
102
|
-
| `live-allow-rule (git status)` / `… not deny-everything` from `coder init --engine opencode2` | The existing (typically V1-authored) `opencode.json` carries live bash allow rules —
|
|
103
|
-
| V1 `coder run` lost `git status` / `npm test` after a V2 init | A fresh V2 init writes deny-everything into the SHARED `opencode.json` (init prints this warning). Export `TRISS_CODER_ENGINE=opencode2`, or re-run plain `triss coder init` to restore the V1 allowlist
|
|
104
|
-
| `unsupported plugin source "…"` / `unsupported agent source "…"` / `unsupported custom tool source "…"` |
|
|
140
|
+
| `live-allow-rule (git status)` / `… not deny-everything` from protected `coder init --engine opencode2` | The existing (typically V1-authored) `opencode.json` carries live bash allow rules — protected V2 cannot run while any exist. Protected init rejects **before writing anything**: remove the allow rules from `opencode.json` (V1 runs lose them too), or use the explicit best-effort acknowledgement if the raw-credential risk is acceptable. |
|
|
141
|
+
| V1 `coder run` lost `git status` / `npm test` after a protected V2 init | A fresh **protected** V2 init writes deny-everything into the SHARED `opencode.json` (init prints this warning). Export `TRISS_CODER_ENGINE=opencode2`, or re-run plain `triss coder init` to restore the V1 allowlist. A fresh best-effort V2 init writes the normal V1 allowlist and emits no false degradation warning. |
|
|
142
|
+
| `unsupported plugin source "…"` / `unsupported agent source "…"` / `unsupported custom tool source "…"` | In protected mode, the static preflight found an unverified source. Remove or disable it (see the path in the error), or explicitly opt into `TRISS_CODER_ALLOW_BEST_EFFORT_ISOLATION=1`; best-effort mode permits normal plugins, agents, and custom tools after the structural/config-shape checks and warns that the selected raw credential is exposed. |
|
|
105
143
|
| `Agent not found: "coder"` on an older Triss build | Older builds injected `--agent coder` into V2 runs; current builds use the engine's built-in primary agent when `--agent` is not passed. Update Triss. |
|
|
106
|
-
| `opencode2 not found` | Install the
|
|
107
|
-
| `
|
|
144
|
+
| `opencode2 not found` | Install the current beta channel: `npm install -g @opencode-ai/cli@beta`. |
|
|
145
|
+
| `below minimum` / `unsupported OpenCode 2 CLI contract` | Remove an obsolete `next-*` override or set a supported beta minimum at or above `0.0.0-beta-17793`; verify that `run --help` exposes the required flags. |
|
|
146
|
+
| `OPENCODE2_SERVICE_SNAPSHOT_UNAVAILABLE` | This host cannot run the optional `ps -axo` resident-service check. The verified `--standalone` CLI contract remains usable with best-effort service verification; use a host with compatible process inspection when a post-probe service proof is required. |
|
|
147
|
+
| `capability-probe-unavailable` | The isolated probe HOME/XDG root could not be created or inspected. Fix `TMPDIR`/filesystem permissions and retry; reinstalling OpenCode 2 does not repair this host error. |
|
|
108
148
|
| `usage_status: "missing"` | The run emitted no `step_finish`; counters are null by contract, not a bug. |
|
|
109
149
|
| `--session and --continue … ambiguous` | Pick one resume intent; they are mutually exclusive on V2. |
|
|
110
150
|
| Session slug not found across engines | By design: V1 and V2 keep separate session maps; a slug never cross-resumes. |
|
|
111
|
-
| `UnexpectedStatus` when resuming `--session ses_…` |
|
|
151
|
+
| `UnexpectedStatus` when resuming `--session ses_…` | An upstream beta compatibility issue. Capture the installed beta version and CLI capability output when reporting it; Triss does not roll back or maintain a future-beta denylist. |
|
|
112
152
|
| `provider.no-route: Model unavailable: opencode-go/…` | Transient provider-side catalogue failure — the same command succeeded minutes earlier. Retry; if it persists, check the Go subscription/status page. |
|
package/docs/mcp.md
CHANGED
|
@@ -503,7 +503,11 @@ the default), `OPENCODE_API_KEY` (OpenCode Zen or paid OpenCode Go — see
|
|
|
503
503
|
`debug config --pure` under the sanitized child environment and a random
|
|
504
504
|
canary instead of the real key. Late provider/model overrides, unauditable
|
|
505
505
|
JSONC, and unknown effective config fail closed; the actual run also uses
|
|
506
|
-
`--pure`.
|
|
506
|
+
`--pure`. All OpenCode 1 MCP runs perform the bounded final-config probe
|
|
507
|
+
before the credential-bearing spawn. Calls without `provider` omit `--pure`
|
|
508
|
+
from both probe and run, preserving their disk-backed deny-first bash policy
|
|
509
|
+
while keeping later account/org, managed-directory, and macOS MDM layers in
|
|
510
|
+
the audited view.
|
|
507
511
|
Without `provider`, `model` keeps its legacy main-only semantics. `model`
|
|
508
512
|
takes a `<provider>/<id>`
|
|
509
513
|
string — a Triss worker model (`triss-worker/deepseek-v4-flash`, reuses
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "triss-coworker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.0",
|
|
4
4
|
"description": "Give your AI coding agent a cheap DeepSeek coworker. Delegate bulk reads, boilerplate, and doc updates to save 60-70% of your token budget.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"docs/troubleshooting.md",
|
|
27
27
|
"docs/integrations/",
|
|
28
28
|
"docs/engines/",
|
|
29
|
+
"!docs/website/",
|
|
29
30
|
"README.md",
|
|
30
31
|
"CHANGELOG.md",
|
|
31
32
|
"LICENSE",
|
|
@@ -77,9 +78,9 @@
|
|
|
77
78
|
"bugs": {
|
|
78
79
|
"url": "https://github.com/ayleen/triss-coworker/issues"
|
|
79
80
|
},
|
|
80
|
-
"homepage": "https://
|
|
81
|
+
"homepage": "https://triss.work",
|
|
81
82
|
"engines": {
|
|
82
|
-
"node": ">=22"
|
|
83
|
+
"node": ">=22.12.0"
|
|
83
84
|
},
|
|
84
85
|
"packageManager": "npm@11.6.2",
|
|
85
86
|
"dependencies": {
|
|
@@ -79,7 +79,8 @@ function isValidOrigin(endpoint) {
|
|
|
79
79
|
* @param {string} opts.endpoint canonical upstream ORIGIN (https, no path)
|
|
80
80
|
* @param {string} opts.credential real provider credential (in-memory only)
|
|
81
81
|
* @param {string} [opts.pathPrefix='/v1'] OpenAI-compatible scope prefix
|
|
82
|
-
* @param {string} [opts.
|
|
82
|
+
* @param {string} [opts.protocol] 'openai_chat' | 'openai_responses' | 'anthropic_messages'
|
|
83
|
+
* @param {string} [opts.authStyle='bearer'] compatibility alias for protocol auth
|
|
83
84
|
* @param {string} [opts.token] pre-generated single-run token (tests)
|
|
84
85
|
* @param {number} [opts.maxRequests] request-count cap
|
|
85
86
|
* @param {number} [opts.maxBodyBytes] per-request body-byte cap
|
|
@@ -103,7 +104,10 @@ export async function startCoderCredentialProxy(opts = {}) {
|
|
|
103
104
|
const pathPrefix = typeof opts.pathPrefix === 'string' && opts.pathPrefix.startsWith('/')
|
|
104
105
|
? opts.pathPrefix.replace(/\/+$/, '') || '/'
|
|
105
106
|
: '/v1';
|
|
106
|
-
const
|
|
107
|
+
const protocol = ['openai_chat', 'openai_responses', 'anthropic_messages'].includes(opts.protocol)
|
|
108
|
+
? opts.protocol
|
|
109
|
+
: opts.authStyle === 'anthropic' ? 'anthropic_messages' : 'openai_chat';
|
|
110
|
+
const authStyle = protocol === 'anthropic_messages' ? 'anthropic' : 'bearer';
|
|
107
111
|
if (typeof provider !== 'string' || provider.length === 0) {
|
|
108
112
|
throw new TypeError('startCoderCredentialProxy: provider is required');
|
|
109
113
|
}
|
|
@@ -167,9 +171,9 @@ export async function startCoderCredentialProxy(opts = {}) {
|
|
|
167
171
|
// for the pinned protocol is forwarded — the whole prefix subtree is NOT
|
|
168
172
|
// open (other mutating or billed provider routes must be unreachable).
|
|
169
173
|
const allowedPaths = new Set(
|
|
170
|
-
|
|
174
|
+
protocol === 'anthropic_messages'
|
|
171
175
|
? [`${pathPrefix}/messages`]
|
|
172
|
-
: [`${pathPrefix}/chat/completions`],
|
|
176
|
+
: [protocol === 'openai_responses' ? `${pathPrefix}/responses` : `${pathPrefix}/chat/completions`],
|
|
173
177
|
);
|
|
174
178
|
|
|
175
179
|
function pathAllowed(url) {
|
|
@@ -218,6 +222,13 @@ export async function startCoderCredentialProxy(opts = {}) {
|
|
|
218
222
|
res.end(JSON.stringify({ error: { message: 'absolute-URI forward-proxy route denied' } }));
|
|
219
223
|
return;
|
|
220
224
|
}
|
|
225
|
+
// The proxy is an inference-only surface. Do not let a GET/PUT/etc.
|
|
226
|
+
// reach the body parser and get forwarded as POST upstream.
|
|
227
|
+
if (req.method !== 'POST') {
|
|
228
|
+
res.writeHead(405, { 'content-type': 'application/json', allow: 'POST' });
|
|
229
|
+
res.end(JSON.stringify({ error: { message: 'only POST is supported' } }));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
221
232
|
// Provider/model pinning: only the pinned OpenAI-compatible scope is
|
|
222
233
|
// forwarded; everything else is denied. The prefix match is
|
|
223
234
|
// boundary-exact — a `/v10` route must not pass a `/v1` pin.
|
|
@@ -437,6 +448,7 @@ export async function startCoderCredentialProxy(opts = {}) {
|
|
|
437
448
|
scopedBaseUrl: `http://${LOOPBACK_HOST}:${port}${pathPrefix}`,
|
|
438
449
|
provider,
|
|
439
450
|
model,
|
|
451
|
+
protocol,
|
|
440
452
|
revoke,
|
|
441
453
|
closed,
|
|
442
454
|
};
|