@te-river/opencode-team-mode 1.7.7 → 1.7.8

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.
Files changed (39) hide show
  1. package/README.md +1010 -1010
  2. package/README.zh-CN.md +907 -907
  3. package/dist/host/v2-browser-gate.js +2 -2
  4. package/dist/host/v2-offload.js +6 -6
  5. package/dist/host/v2-retry.d.ts +9 -1
  6. package/dist/host/v2-retry.d.ts.map +1 -1
  7. package/dist/host/v2-retry.js +10 -2
  8. package/dist/host/v2-retry.js.map +1 -1
  9. package/dist/prompts/specialists.js +286 -286
  10. package/dist/task-offload.js +1 -1
  11. package/dist/tm/config-layers.d.ts +5 -2
  12. package/dist/tm/config-layers.d.ts.map +1 -1
  13. package/dist/tm/config-layers.js +9 -6
  14. package/dist/tm/config-layers.js.map +1 -1
  15. package/dist/tm/config.d.ts.map +1 -1
  16. package/dist/tm/config.js +7 -1
  17. package/dist/tm/config.js.map +1 -1
  18. package/dist/tm/ledger.js +5 -5
  19. package/dist/tm/memory.js +9 -9
  20. package/dist/tm/search.d.ts +3 -0
  21. package/dist/tm/search.d.ts.map +1 -1
  22. package/dist/tm/search.js +67 -15
  23. package/dist/tm/search.js.map +1 -1
  24. package/dist/tm/tools.js +3 -3
  25. package/dist/tm/webfetch.d.ts +94 -5
  26. package/dist/tm/webfetch.d.ts.map +1 -1
  27. package/dist/tm/webfetch.js +285 -64
  28. package/dist/tm/webfetch.js.map +1 -1
  29. package/docs/installation.md +505 -505
  30. package/docs/research/agent-data-exchange.md +117 -117
  31. package/docs/research/browser-pane.md +94 -94
  32. package/docs/research/host-http-api.md +132 -132
  33. package/docs/research/host-subagent-injection.md +187 -187
  34. package/docs/research/plugin-loader-contract.md +261 -261
  35. package/docs/research/v2-builtin-tools.md +447 -447
  36. package/docs/v2-port-notes.md +121 -78
  37. package/index.js +7 -7
  38. package/package.json +64 -64
  39. package/scripts/lib/config-surgery.cjs +239 -239
@@ -497,83 +497,83 @@ survivors were written. Each is recorded here so the next reader does not re-der
497
497
  providerExecuted,cache,metadata,providerMetadata`; `media` → `type,media,filename,metadata`.
498
498
  The binary's union also names `compaction` and `effort`, which were never observed in a turn.
499
499
  This is why the prune layer's first version was inert: it accepted only `type:"text"`, and the
500
- bulk of a real request is `tool-result`/`tool-call`. `[L]`
501
-
502
- ### 2026-10-07 — the 1.7.1 cut: the 75% trigger is gone, and why the readers stayed `[L][R][D]`
503
-
504
- **Decision (user, 2026-10-07).** The early-compaction trigger shipped in 1.7.0 was removed
505
- outright: the host owns when a conversation is summarized, and a plugin that summarizes a live
506
- session on its own takes a context-losing action the user did not ask for. This is a
507
- `[D]`+product decision, not a measurement — recorded here because the *other* two facts below
508
- are measurements, and a future reader will otherwise look for a falsified claim that does not
509
- exist.
510
-
511
- **What was removed.** `src/host/v2-compaction.ts` (the whole layer: `applyV2EarlyCompaction`,
512
- `resolveCompactConfig`, `CompactReport`, the `session.hook("context")` registration and the
513
- `observeUsage` tap), the `onUsage` option on `applyV2EventFeed`, the `compact` input and the
514
- `ctx.session.compact` capability row in `v2-capabilities.ts`, the `compact_*` counters on both
515
- the `v2-surface` and `v2-shutdown` rows, the `v2-compact` trajectory line, the three
516
- file-overridable registry keys (`compactTrigger` / `compactAtPercent` / `compactMinMs`), and
517
- the `compact` seam on the test fake. An operator's `team-mode.jsonc` that still names those
518
- keys now collects them as UNKNOWN keys (a boot warning), which is the honest outcome: a knob
519
- whose feature is gone must not keep reading as if it did something. `[R]`
520
-
521
- **What was kept, and it is not sentiment.** The four pure usage readers (`readUsedTokens` /
522
- `readModelKey` / `lastUsageOf` / `percentOf`) moved to `src/host/v2-usage.ts` because
523
- `src/host/v2-prune.ts` still computes ITS OWN threshold from the same formula and the same
524
- `ctx.model.list()` → `limit.context` denominator. Copying them into the prune layer instead
525
- would have left two definitions of "how full is this window" free to drift, and the evidence
526
- below is the reason each branch of those readers exists. `[R]`
527
-
528
- **The evidence that shaped them (unchanged, re-stated so it is not lost with the module).**
529
- - Context usage lives ONLY in the `session.usage.updated` event. `session.hook("context")`
530
- hands over the assembled messages and those messages carry no token counts: a second turn
531
- that DID contain an assistant message still logged `source=no_usage messages=3` (run
532
- `r-20261005-235343-114738`). The denominator is `ctx.model.list()`'s `limit.context`; the
533
- numerator is the event. `[L]`
534
- - The readers therefore accept every location the host has actually used (`tokens` /
535
- `metadata.tokens` / `info.tokens` / `usage`) and return `null` — never `0` — when they
536
- find none, because "we did not find them" and "usage is zero" must not collapse into one
537
- number. A model the catalog does not describe gets `percentOf` = 0, never a guessed window. `[R]`
538
-
539
- **What 1.7.1 does NOT change.** The host's own compaction is still supported, not intercepted:
540
- `TM_COMPACTION_CONTEXT` (the survival list on `session.hook("compaction")`) and
541
- `TM_COMPACTION_AUTOCONTINUE` are untouched, `compaction_lines` still rides `tm_stats`, and the
542
- `ctx.session.compact` seam stays declared in `src/host/v2-types.ts` with a "DECLARED, NOT
543
- CALLED" note — a future layer would otherwise have to re-probe a seam the 2.0.23 probe already
544
- settled. Context Pruning (`TM_PRUNE`, default 70%) is a different mechanism: it rewrites settled
545
- message BODIES into pointers inside an outgoing request and never asks the host to summarize
546
- anything. `[R]`
547
-
548
- ### 2026-10-07 — the agent ID is the FILE NAME, and a case-only difference is not cosmetic `[L][R]`
549
-
550
- **Measured on 2.0.24 / 2026-10-07 (this machine).** The global config directory held
551
- `agents/team.md` — lowercase, left over from the pre-1.7 naming — while the generator had been
552
- "writing" `agents/Team.md` on every install since. The host was asked directly:
553
-
554
- - `opencode-cli run --standalone --agent Team --model nope/nope "x"` → `Agent not found: "Team"`
555
- - `opencode-cli run --standalone --agent team --model nope/nope "x"` → resolves (fails only on
556
- the fake model: `Model unavailable: nope/nope`)
557
- - `opencode-cli api get /api/agent?directory=…` → `{"id":"team","name":"team",…}` for the lead
558
-
559
- So the on-disk spelling IS the registered id, and the installer's own
560
- `default_agent: "Team"` named an agent that did not exist. Per the agents doc the fallback for
561
- an unresolvable default is `build` — silent, which is exactly the failure the installer's
562
- "write `default_agent` LAST, and read it back" rule exists to prevent; the read-back cannot see
563
- it, because the key IS on disk and the ID is what is wrong. `[L]`
564
-
565
- **Why every install failed to fix it.** `writeFileSync(<dir>/Team.md)` on a case-insensitive,
566
- case-PRESERVING filesystem opens the existing `team.md` and leaves that name alone — and the
567
- reclaim pass deliberately refused to delete the case-only entry (deleting it would delete the
568
- file just written: the #47/#48 guard). Nothing in the pipeline could ever change the spelling.
569
- The fix is an explicit two-step rename (`team.md` → temp → `Team.md`; a case-only `rename` on
570
- win32 is itself a no-op), performed ONLY on an entry the identity verdict has already PROVEN is
571
- the same file as a target, with a restore path if the second step throws. `[R]`
572
-
573
- **The lesson, stated in the general form.** "Is the tool loaded" and "is the file on disk" were
574
- both yes here — the two checks the installer prints. What no check covered was *which id the
575
- host derives from it*, and that is the difference between Team being the default and a silent
576
- `build`. A verifiable claim has to name the artefact the host actually keys on (the FILE NAME),
500
+ bulk of a real request is `tool-result`/`tool-call`. `[L]`
501
+
502
+ ### 2026-10-07 — the 1.7.1 cut: the 75% trigger is gone, and why the readers stayed `[L][R][D]`
503
+
504
+ **Decision (user, 2026-10-07).** The early-compaction trigger shipped in 1.7.0 was removed
505
+ outright: the host owns when a conversation is summarized, and a plugin that summarizes a live
506
+ session on its own takes a context-losing action the user did not ask for. This is a
507
+ `[D]`+product decision, not a measurement — recorded here because the *other* two facts below
508
+ are measurements, and a future reader will otherwise look for a falsified claim that does not
509
+ exist.
510
+
511
+ **What was removed.** `src/host/v2-compaction.ts` (the whole layer: `applyV2EarlyCompaction`,
512
+ `resolveCompactConfig`, `CompactReport`, the `session.hook("context")` registration and the
513
+ `observeUsage` tap), the `onUsage` option on `applyV2EventFeed`, the `compact` input and the
514
+ `ctx.session.compact` capability row in `v2-capabilities.ts`, the `compact_*` counters on both
515
+ the `v2-surface` and `v2-shutdown` rows, the `v2-compact` trajectory line, the three
516
+ file-overridable registry keys (`compactTrigger` / `compactAtPercent` / `compactMinMs`), and
517
+ the `compact` seam on the test fake. An operator's `team-mode.jsonc` that still names those
518
+ keys now collects them as UNKNOWN keys (a boot warning), which is the honest outcome: a knob
519
+ whose feature is gone must not keep reading as if it did something. `[R]`
520
+
521
+ **What was kept, and it is not sentiment.** The four pure usage readers (`readUsedTokens` /
522
+ `readModelKey` / `lastUsageOf` / `percentOf`) moved to `src/host/v2-usage.ts` because
523
+ `src/host/v2-prune.ts` still computes ITS OWN threshold from the same formula and the same
524
+ `ctx.model.list()` → `limit.context` denominator. Copying them into the prune layer instead
525
+ would have left two definitions of "how full is this window" free to drift, and the evidence
526
+ below is the reason each branch of those readers exists. `[R]`
527
+
528
+ **The evidence that shaped them (unchanged, re-stated so it is not lost with the module).**
529
+ - Context usage lives ONLY in the `session.usage.updated` event. `session.hook("context")`
530
+ hands over the assembled messages and those messages carry no token counts: a second turn
531
+ that DID contain an assistant message still logged `source=no_usage messages=3` (run
532
+ `r-20261005-235343-114738`). The denominator is `ctx.model.list()`'s `limit.context`; the
533
+ numerator is the event. `[L]`
534
+ - The readers therefore accept every location the host has actually used (`tokens` /
535
+ `metadata.tokens` / `info.tokens` / `usage`) and return `null` — never `0` — when they
536
+ find none, because "we did not find them" and "usage is zero" must not collapse into one
537
+ number. A model the catalog does not describe gets `percentOf` = 0, never a guessed window. `[R]`
538
+
539
+ **What 1.7.1 does NOT change.** The host's own compaction is still supported, not intercepted:
540
+ `TM_COMPACTION_CONTEXT` (the survival list on `session.hook("compaction")`) and
541
+ `TM_COMPACTION_AUTOCONTINUE` are untouched, `compaction_lines` still rides `tm_stats`, and the
542
+ `ctx.session.compact` seam stays declared in `src/host/v2-types.ts` with a "DECLARED, NOT
543
+ CALLED" note — a future layer would otherwise have to re-probe a seam the 2.0.23 probe already
544
+ settled. Context Pruning (`TM_PRUNE`, default 70%) is a different mechanism: it rewrites settled
545
+ message BODIES into pointers inside an outgoing request and never asks the host to summarize
546
+ anything. `[R]`
547
+
548
+ ### 2026-10-07 — the agent ID is the FILE NAME, and a case-only difference is not cosmetic `[L][R]`
549
+
550
+ **Measured on 2.0.24 / 2026-10-07 (this machine).** The global config directory held
551
+ `agents/team.md` — lowercase, left over from the pre-1.7 naming — while the generator had been
552
+ "writing" `agents/Team.md` on every install since. The host was asked directly:
553
+
554
+ - `opencode-cli run --standalone --agent Team --model nope/nope "x"` → `Agent not found: "Team"`
555
+ - `opencode-cli run --standalone --agent team --model nope/nope "x"` → resolves (fails only on
556
+ the fake model: `Model unavailable: nope/nope`)
557
+ - `opencode-cli api get /api/agent?directory=…` → `{"id":"team","name":"team",…}` for the lead
558
+
559
+ So the on-disk spelling IS the registered id, and the installer's own
560
+ `default_agent: "Team"` named an agent that did not exist. Per the agents doc the fallback for
561
+ an unresolvable default is `build` — silent, which is exactly the failure the installer's
562
+ "write `default_agent` LAST, and read it back" rule exists to prevent; the read-back cannot see
563
+ it, because the key IS on disk and the ID is what is wrong. `[L]`
564
+
565
+ **Why every install failed to fix it.** `writeFileSync(<dir>/Team.md)` on a case-insensitive,
566
+ case-PRESERVING filesystem opens the existing `team.md` and leaves that name alone — and the
567
+ reclaim pass deliberately refused to delete the case-only entry (deleting it would delete the
568
+ file just written: the #47/#48 guard). Nothing in the pipeline could ever change the spelling.
569
+ The fix is an explicit two-step rename (`team.md` → temp → `Team.md`; a case-only `rename` on
570
+ win32 is itself a no-op), performed ONLY on an entry the identity verdict has already PROVEN is
571
+ the same file as a target, with a restore path if the second step throws. `[R]`
572
+
573
+ **The lesson, stated in the general form.** "Is the tool loaded" and "is the file on disk" were
574
+ both yes here — the two checks the installer prints. What no check covered was *which id the
575
+ host derives from it*, and that is the difference between Team being the default and a silent
576
+ `build`. A verifiable claim has to name the artefact the host actually keys on (the FILE NAME),
577
577
  not the one we wrote (the path we computed). `[R]`
578
578
 
579
579
  ### 2026-10-18 — the request-layer `temperature` fill is gone, because a field we added broke other models `[L][R]`
@@ -608,4 +608,47 @@ overwrite path. `[R]`
608
608
  no-op because it is "only a default". The host assembled a request that worked; our fill made
609
609
  it a request some providers refuse. A plugin that improves determinism on one model can
610
610
  therefore remove compatibility on another, and the compatibility cost is invisible in our own
611
- logs — it shows up as somebody else's API error. `[R]`
611
+ logs — it shows up as somebody else's API error. `[R]`
612
+
613
+ ### 2026-10-21 — host 2.1.x: where its release notes actually live, and the #57260 contract renames that bind our seams `[D][L]`
614
+
615
+ **Where to look.** The desktop shipped 2.1.2 (`opencode-cli.version` = `2.1.2`; boot log
616
+ `msg="cli starting" version=2.1.2 channel=latest`). `api.github.com/repos/sst/opencode/releases/latest`
617
+ answers **v1.19.3** — the 2.x desktop line is not published as a GitHub release of that repo,
618
+ so `/releases/latest` (which also skips prereleases) is the wrong source and a search there
619
+ finds nothing. The authoritative notes are `https://opencode.ai/changelog`. `[D]`
620
+
621
+ **v2.1.0 is a BREAKING contract release (#57260)** — "intentional changes to public SDK, HTTP
622
+ message/event, and plugin contracts". The renames that touch our readers: tool parts lose
623
+ separate `providerState`/`providerResultState` — call and result data share `tool.native`
624
+ (success/failure events shallow-merge native into the call's native, result wins on duplicate
625
+ keys); `SessionCompactionResult.providerState` → `native`; compaction `recent` →
626
+ `metadata.keepID` reference; event names `session.tool.called` / `session.tool.success` /
627
+ `session.tool.failed` / `session.step.ended` / `session.step.failed` /
628
+ `session.compaction.started|ended`; `Credential.Key.configuration` removed (writes use
629
+ `metadata`). Our seams named in the risk list: `v2-offload.ts` (native-result shape measured as
630
+ `{content, metadata, output}` on 2.0.16), `v2-subagent.ts` (`result.metadata.sessionID` off the
631
+ ack), `v2-prune.ts` (parts-by-shape), `v2-events.ts` (whitelisted event NAMES — a renamed event
632
+ arrives as unrecognised and is counted, never forwarded on a guess), `v2-session.ts`
633
+ (compaction hook `output.context`). The design law caps the blast radius: an unrecognized shape
634
+ is left alone and COUNTED (`unknownParts`, `unmatched`, `scope_unknown`), so the expected failure
635
+ mode on a drifted field is silent degradation visible in `tm_stats`, not corruption.
636
+ Post-install checks owed on 2.1.2: the `v2-boot` row, a native `shell`/`read` result actually
637
+ offloading (`native:shell offloaded:true`), a background child settling via injection, and the
638
+ `v2-surface` counters' `unmatched`/`unknownParts` deltas. `[D]`
639
+
640
+ **v2.1.2 (#57146, #57589) adds `retryAfterMs` to structured session errors** and fixes retry
641
+ timing being dropped from quota/rate-limit/provider-internal errors. Our retry governor
642
+ (`v2-retry.ts`) parses `Retry-After` out of the error TEXT only — the structured field is a
643
+ follow-up read point (the 1.7.8 ladder is fixed 5s/10s/20s per the user's ask regardless, so
644
+ this is an enrichment, not a break). Also relevant: #54276 fixed Code Mode async jobs
645
+ interleaving (our `execute` programs), and #57416 keeps locations loaded while long tools run
646
+ (the new HTTP ladder's worst case is ~115 s single-URL, ~165 s across redirect hops).
647
+ v2.1.0's `experimental.todo` (a TUI `todowrite`) is config-gated and off by default —
648
+ `tm_ledger` remains our lead's ledger. `[D]`
649
+
650
+ **Live evidence, same day `[L]`:** this session ran on 2.1.2 with the installed 1.7.7 plugin —
651
+ three forced-background `subagent` dispatches each settled and their full bodies were collected
652
+ (the completion envelope injection path works on 2.1.2), and the boot probe against the real
653
+ config shows `loading plugin … @te-river/opencode-team-mode@latest` from the host cache with the
654
+ `[team-mode] v2 人格已启动` note and no load failure.
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
- // The host resolves a plugin DIRECTORY as `<dir>/index.js` (measured on 2.0.16:
2
- // `msg="loading plugin" … entrypoint=file:///…/team-mode/index.js`, while a directory that
3
- // only declares package.json#exports is skipped with no error at all). This shim is
4
- // therefore part of the contract, not a convenience: without it neither
5
- // `plugins: ["…/opencode-team-mode"]` in a config nor a node_modules install under that
6
- // key can load the plugin. The dual-personality shape itself lives in dist/index.js.
7
- export { default } from "./dist/index.js"
1
+ // The host resolves a plugin DIRECTORY as `<dir>/index.js` (measured on 2.0.16:
2
+ // `msg="loading plugin" … entrypoint=file:///…/team-mode/index.js`, while a directory that
3
+ // only declares package.json#exports is skipped with no error at all). This shim is
4
+ // therefore part of the contract, not a convenience: without it neither
5
+ // `plugins: ["…/opencode-team-mode"]` in a config nor a node_modules install under that
6
+ // key can load the plugin. The dual-personality shape itself lives in dist/index.js.
7
+ export { default } from "./dist/index.js"
package/package.json CHANGED
@@ -1,64 +1,64 @@
1
- {
2
- "name": "@te-river/opencode-team-mode",
3
- "version": "1.7.7",
4
- "description": "Team collaboration mode plugin for OpenCode Desktop — injects specialized agents (architect, reviewer, implementer, tester, researcher) and team workflow commands into your OpenCode workspace.",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- }
13
- },
14
- "files": [
15
- "dist",
16
- "index.js",
17
- "scripts/lib",
18
- "scripts/gen-v2-config.mjs",
19
- "README.md",
20
- "README.zh-CN.md",
21
- "LICENSE",
22
- "docs"
23
- ],
24
- "scripts": {
25
- "build": "tsc",
26
- "test": "node scripts/run-tests.mjs",
27
- "test:serial": "node scripts/run-tests.mjs --serial",
28
- "test:one": "node scripts/run-tests.mjs --no-build",
29
- "prepublishOnly": "tsc",
30
- "dev": "tsc --watch"
31
- },
32
- "keywords": [
33
- "opencode",
34
- "opencode-plugin",
35
- "plugin",
36
- "team-mode",
37
- "collaboration",
38
- "multi-agent",
39
- "desktop",
40
- "ai-coding"
41
- ],
42
- "author": "",
43
- "license": "Apache-2.0",
44
- "publishConfig": {
45
- "access": "public"
46
- },
47
- "optionalDependencies": {
48
- "playwright-core": "1.63.0"
49
- },
50
- "peerDependencies": {
51
- "@opencode-ai/plugin": ">=0.1.0"
52
- },
53
- "devDependencies": {
54
- "@types/node": "^26.4.0",
55
- "typescript": "^5.5.0"
56
- },
57
- "repository": {
58
- "type": "git",
59
- "url": "https://github.com/Te-River/Opencode-TeamMode.git"
60
- },
61
- "engines": {
62
- "node": ">=18.0.0"
63
- }
64
- }
1
+ {
2
+ "name": "@te-river/opencode-team-mode",
3
+ "version": "1.7.8",
4
+ "description": "Team collaboration mode plugin for OpenCode Desktop — injects specialized agents (architect, reviewer, implementer, tester, researcher) and team workflow commands into your OpenCode workspace.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "index.js",
17
+ "scripts/lib",
18
+ "scripts/gen-v2-config.mjs",
19
+ "README.md",
20
+ "README.zh-CN.md",
21
+ "LICENSE",
22
+ "docs"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "test": "node scripts/run-tests.mjs",
27
+ "test:serial": "node scripts/run-tests.mjs --serial",
28
+ "test:one": "node scripts/run-tests.mjs --no-build",
29
+ "prepublishOnly": "tsc",
30
+ "dev": "tsc --watch"
31
+ },
32
+ "keywords": [
33
+ "opencode",
34
+ "opencode-plugin",
35
+ "plugin",
36
+ "team-mode",
37
+ "collaboration",
38
+ "multi-agent",
39
+ "desktop",
40
+ "ai-coding"
41
+ ],
42
+ "author": "",
43
+ "license": "Apache-2.0",
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "optionalDependencies": {
48
+ "playwright-core": "1.63.0"
49
+ },
50
+ "peerDependencies": {
51
+ "@opencode-ai/plugin": ">=0.1.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^26.4.0",
55
+ "typescript": "^5.5.0"
56
+ },
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "https://github.com/Te-River/Opencode-TeamMode.git"
60
+ },
61
+ "engines": {
62
+ "node": ">=18.0.0"
63
+ }
64
+ }