dsh-plugin-teamflow 0.1.9 → 0.2.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/README.en.md CHANGED
@@ -20,51 +20,41 @@ requirement → PRD (based on existing patterns / product memory, archived to pr
20
20
 
21
21
  ## Screenshots
22
22
 
23
- 1. Pipeline viewstage serpentine lanes + node cards (status / duration / tokens / subagent session)
23
+ 1. Global panelthe 🏭 Team Workspace icon in the left sidebar (cross-session, product-line view: product list + run list + Backlog tab + overlay detail pane)
24
24
 
25
- ![Pipeline view](docs/screenshots/pipeline-view.png)
25
+ ![Global panel](docs/screenshots/en/global-panel.png)
26
26
 
27
- 2. Backlog boarddraggable lanes for requirements / tasks / defects
27
+ 2. Pipeline viewstage serpentine lanes + node cards (status / duration / tokens / subagent session)
28
28
 
29
- ![Backlog board](docs/screenshots/board.png)
29
+ ![Pipeline view](docs/screenshots/en/pipeline-view.png)
30
30
 
31
31
  3. Stage detail drawer — full stage artifacts + token breakdown + "🎬 jump to subagent session"
32
32
 
33
- ![Stage detail](docs/screenshots/stage-detail.png)
33
+ ![Stage detail](docs/screenshots/en/stage-detail.png)
34
34
 
35
- 4. Board task detail task-card drawer (requirement text / assignments / event timeline / subtasks / defects / tokens)
35
+ 4. Backlog boarddraggable lanes for requirements / tasks / defects
36
36
 
37
- ![Board task detail](docs/screenshots/board-task-detail.png)
37
+ ![Backlog board](docs/screenshots/en/board.png)
38
38
 
39
- 5. Team selector🏭 button + team dropdown
39
+ 5. Board task detail task-card drawer (requirement text / assignments / event timeline / subtasks / defects / tokens)
40
40
 
41
- ![Team selector](docs/screenshots/team-selector.png)
41
+ ![Board task detail](docs/screenshots/en/board-task-detail.png)
42
+
43
+ 6. Team selector — 🏭 button + team dropdown
44
+
45
+ ![Team selector](docs/screenshots/en/team-selector.png)
42
46
 
43
47
  ## Core Features
44
48
 
45
- - **Anti-fake-delivery**: Delivery is judged by **tiered signals** objective shape (non-empty + per-stage length floor) real-delivery signal (a `[Verification evidence]` block) **wording only as a fallback** (rejection phrases like "I cannot complete" count as undelivered **only when there is no evidence block**; a matched phrase with an evidence block is logged as a diagnostic and never vetoes — honestly reporting environment limits is no longer a false failure); Token circuit breaker new tokens accumulated per call (`input+cacheWrite+output`, cache hits excluded) beyond 200k stop retries and require human intervention; ③ Context-exhaustion failures are not retried (retrying the same prompt likely reproduces); Product-level concurrency lock — only one active pipeline per product at a time, preventing requirement state from stepping on itself; ⑤ Full stage outputs are retained (memory + disk) for the detail drawer and checkpoint resume.
46
- - **Auto completion report to main thread**: when a pipeline ends (success / failure / cancel / interrupt), it automatically delivers a summary (status / stage stats / total token / backlog / next-step guidance) to the initiating session's Agent — wakes on idle (followup), injects next-step context when busy (inject), using the same mechanism as DSH's background-task notifications (tool-jobs mode, but independently implemented and not dependent on the web-disabled tool-jobs). The user need not watch the panel; the model relays the result or continues per guidance (claim defects / transition / resume from checkpoint).
47
- - **Resume from checkpoint**: every stage checkpoint persists to `$DSH_HOME/teamflow/runs/<runId>.json` (LangGraph checkpointer semantics); after a process crash / restart it is auto-marked `interrupted`, and `teamflow_resume` / the panel's "↻ resume from checkpoint" continues from the first unfinished stage (skipping completed stages, reusing full stage outputs).
48
- - **Backlog persistence (workspace-isolated since v0.1.0)** under `$DSH_HOME/teamflow/<workspace>/backlog/` as `requirements.json` / `tasks.json` / `bugs.json`, surviving restarts; backlog is isolated per "workspace (project)" one workspace is one product line, and different workspaces each see their own Team Workspace.
49
- - **Single-task model **: one requirement = one rotating task card (no longer split by role); the task card records `devAssign` / `qaAssign` / acceptor, with state rotation: todo developing to-test testing to-accept accepted | bounced | needs-human; the delivered frontend page also shows each role's **real token usage** spent on that task.
50
- - **Artifact consolidation **: pipeline docs (PRD / design / architecture / tech spec / QA / memory / history) all consolidate into `docs/teamflow/`, command run logs are staged into `logs/teamflow/<runId>/` while the run is live, so the host `docs/<role>/` and project root are no longer polluted by TeamFlow.
51
- - **The log root lives in `$DSH_HOME`, not in your project (v0.1.9)**: sub-agents are confined by the DSH file sandbox (`workspace-write` can only write the session workspace), so they stage inside the project first; **as soon as the run ends the host archives what is worth keeping to `$DSH_HOME/teamflow/<workspace>/logs/<runId>/` and deletes the in-project copy** (the host's own event log `run.log` is written straight to the archive). **No output dumps are manufactured**: sub-agents are told *not* to redirect command/suite output into files — long output is already truncated to its tail by the host, which spills the full text to a temp path it reports (native DSH behaviour). What survives is therefore only your **checkers** (`scripts/`), **non-derivable payloads** (`captures.json`) and conclusion notes (`.md`); everything else (`*.log`/`*.out`/`*.txt`, source snapshots) is **dropped at archive time**. Measured on a real run, 93% of the bytes were rerunnable output or an exact copy of something already in git. A crashed/killed run leaves no residue (the next run in the same workspace applies the same rule — self-healing), and **each workspace keeps only the latest 20 runs**.
52
- - **Delivery surface vs. noise**: only **code + the `docs/teamflow/` task folder** go into the closing commit (one commit per run); `logs/teamflow/` is the plugin's own run log (including sub-agent scratch verification scripts) and is **not a deliverable** — before committing, the host appends that rule to the workspace `.gitignore` (idempotent, visible in the same commit) and, right after the whole-tree `git add`, **unstages the directory again** (`git rm -r --cached --ignore-unmatch` — index only, your files stay put), so **your project needs no pre-configured .gitignore** (these two guards cover the window where you commit yourself while a run is live). If a repo already committed that noise, run `git rm -r --cached logs/teamflow` there to untrack it (local files are kept).
53
- - **State machine + event log**: requirement (initiated → in-progress → to-accept → accepted), task (todo → developing → to-test → testing → to-accept → done | bounced | needs-human), defect (to-claim → in-progress → fixed-to-verify → closed).
54
- - **Bounce-back threshold**: 2 consecutive Agent failures in a single stage auto-retry; still failing → `needs-human`, requiring human intervention.
55
- - **Concurrency pool**: dev tasks run in parallel by `maxConcurrency` (default 3, max 8).
56
- - **QA defect registration**: the QA report outputs in a fixed table → auto-parsed into bugs entering the backlog.
57
- - **Token metering (official semantics)**: each stage records `usage` = **cache-miss input / cache-hit input / write-cache / output + call count** (accumulated per event by the sub-agent session) + **cache hit rate** (cacheRead / (input + cacheRead)). Workspace cards / task cards / completion reports all display in this basis — model-agnostic and consistent with the official bill.
58
- - **lite mode**: lightweight micro-features — `teamflow_start(lite:true)` skips the standalone tech-spec doc stage (PRD is the contract) and goes straight **PRD → dev → QA → acceptance**; with `needDesign:true` it **keeps the UI/UX design stage**. The point is trimming the stage set to match requirement size instead of running a full waterfall on a micro-feature (the `patch` tier is smaller still: single-point confirmation + dev).
59
- - **Token circuit breaker**: when the **new tokens** accumulated per call (`input + cacheWrite + output`, **cache hits excluded**) exceed `FRESH_TOKEN_BUDGET` (default 200k), retries stop and human intervention is required; reporting/display still uses the official billed basis (`totalTokensOf`). Cache hits are cheap replays — counting them here would mean "any single failure trips the breaker, making auto-retry dead code" (see `docs/devlog.md` entry 15).
60
- - **🏭 Team Workspace (Web tab)**: a session-header tab alongside chat / trace, containing:
61
- - Pipeline graph (stage swimlanes + node cards: status / duration / token / sub-agent session, 2s live refresh)
62
- - **Backlog drag-drop kanban** (requirement / task / defect three status swimlanes, cards dragged to transition, native HTML5 DnD zero-dep)
63
- - Cost center (per-stage token + total + runtime)
64
- - Human-intervention center (needs-human items aggregated + one-click terminal state)
65
- - History run switching + product switching
66
-
67
- - **Bilingual UI — Chinese / English (v0.1.9, P1 client surface)**: the workbench follows the host language (Settings → General → Language) and **switches live, no restart** — it rides the host `ctx.locale` service (the plugin registers dictionaries and declares `locale` on its slot entries, so every outlet re-renders on a switch) rather than a bespoke i18n layer. Status/phase/role/token-metering vocabularies and time formatting all go through one lookup table; all 247 keys are paired zh↔en, guarded by `test/smoke.js` (the two key sets must match, and no Chinese copy may remain in the client outside `console` diagnostics). **Scope boundary**: the **client display layer only**. Host-generated completion reports, tool results, pipeline logs and artifact documents (PRD/QA-REPORT/ACCEPTANCE…) remain Chinese — artifact language and the acceptance-verdict line are a host parsing contract, tracked as P3 (see `docs/TODO.md`).
49
+ - **One-line requirement accepted delivery**: requirement PRD technical design parallel developmentQAacceptance is orchestrated end to end; every stage gets a task card, artifacts and a verdict. Small mechanical changes can use the `patch` / `lite` tiers to trim the stage set instead of running a full waterfall.
50
+ - **Multi-agent team + parallel development**: the requirement is split into parallelizable tasks from the architecture blueprint (3 concurrent by default, 8 max), with product / architecture / dev / QA each working in their own isolated context.
51
+ - **Anti-fake-delivery**: delivery is judged by evidence, not wording a stage must provide a `[Verification evidence]` block (command + exit code + assertion count), QA runs its own adversarial probes, and acceptance only trusts an explicit verdict line (missing the pipeline stops for a human).
52
+ - **QA bounce-back loop**: P0–P2 defects are sent back for a fix and re-verified (≤2 rounds), each defect carrying its own check command and pass criterion; exceeding the limit hands over to a human instead of pretending the run is "done".
53
+ - **Resume + completion report**: after a crash or restart the pipeline continues from the first unfinished stage (completed stages reuse their artifacts); when a run ends, a summary (status / stages / tokens / next steps) is delivered back to the originating session.
54
+ - **Your repository stays clean**: pipeline docs live in the `docs/teamflow/` task folder and the plugin's own run logs are archived out of your project when the run ends the closing commit carries **code + the task folder only** (one commit per run, **no pre-configured `.gitignore` required**). If an older commit already swept in `logs/teamflow/`, untrack it in that repository with `git rm -r --cached logs/teamflow` (your local files stay).
55
+ - **🏭 Team workbench (two entry points)**: an in-session tab (pipeline graph, drag-and-drop kanban, cost centre, human-intervention centre) and an app-level panel (product-line view, usable across sessions); open any run to see its stages, tokens, verification evidence and artifacts. The UI is **bilingual (Chinese / English)** and follows the host language live; host replies, pipeline logs and pipeline artifacts follow it too (resolved once per run).
56
+ - **Token accounting you can audit**: every stage records its input (cache miss / hit), cache write, output and call count, plus the cache-hit rate, shown on the same basis in reports and in the workbench; mechanical stages automatically drop their reasoning effort and raise it again on retry.
57
+
68
58
 
69
59
  ## AGENTS.md minimal-invasion principle (important)
70
60
 
@@ -79,37 +69,37 @@ AGENTS.md is unconditionally injected into every session by the harness; it is *
79
69
 
80
70
  ```
81
71
  web profile host composition
82
- ├── teamflow-host (dsh-plugin-teamflow/host) Cordis service `teamflow`
83
- └── TeamflowService extends TypertRemoteService
84
- ├── ctx.typert.register(strict descriptors) 17 Remote methods
85
- ├── ctx.tools.register(teamflow_*)12 model tools
86
- └── node:fs $DSH_HOME/teamflow/...
87
- └── teamflow-client (dsh-plugin-teamflow/client, auto-scanned) ← package.json declares dsh.client,
88
- └── ctx.remote.$mount(TEAMFLOW_REMOTE_CONTRIBUTION) no patch line needed, clientModules auto-registers
89
- └── conversation.view tab "🏭 Team Workspace"
72
+ ├── teamflow-host (host/) Cordis service `teamflow`
73
+ ├── ctx.typert.register(strict descriptors) ← Remote methods (`descriptors.ts` pure data, shared by host / client)
74
+ ├── ctx.tools.register(teamflow_*) model tools
75
+ └── node:fs → $DSH_HOME/teamflow/…backlog / journal / archived logs
76
+ └── teamflow-client (client/) ← `package.json` declares `dsh.client`; the host composition scans and registers it
77
+ ├── conversation.view "🏭 Team Workspace" (in-session tab)
78
+ ├── sidebar.panellist + main/teamflow (global product-line panel)
79
+ └── sidebarRightTabs "teamflow-run" (right-sidebar run detail)
90
80
  ```
91
81
 
92
- **Why not the @Remote decorator**: host plugins are distributed as plain JS to avoid decorator syntax / TS compilation requirements; `ctx.typert.register` registers strict descriptors (`descriptors.js` pure data, shared by host/client, keeping endpoint and wire parameters consistent).
82
+ Two hard constraints shaped this (details in `AGENTS.md` §3): **no `@Remote` decorator** (plugins ship as plain JS, so Remote uses `ctx.typert.register`'s strict descriptors); **it must be a host-level plugin** (a dynamic plugin's `fs` is sandboxed to the runtime root and cannot write `$DSH_HOME`).
83
+
93
84
 
94
- **Why a host-level plugin (not a dynamic plugin)**: dynamic (in-session) plugins run in a restricted sandbox whose `fs` is hard-limited to the runtime root and cannot write to `$DSH_HOME` or the session workspace (observed `file access denied under workspace-write mode`). Only a formal plugin inside the host composition has real Node `fs`, able to land backlog in `$DSH_HOME`, and the client can register an independent tab.
95
85
 
96
86
  ## Directory structure
97
87
 
98
88
  ```
99
89
  dsh-plugin-teamflow/
100
- package.json # dsh.bundle.patch + dsh.client declarations; exports point to lib/ build output
101
- cordis.patch.yml # insert block; entry name uses package root (so clientModules can scan dsh.client)
102
- tsdown.config.ts # client build (ModuleLoader bundle → lib/client.js)
103
- tsdown.host.config.ts # host/store/descriptors build (ESM lib/*.mjs)
104
- descriptors.ts # Remote descriptors (pure data, shared by host/client)
105
- store.ts # persistence layer: atomic write / backup / corruption self-heal + journal serialize / load (independently testable)
106
- host/index.ts # TeamflowService (TS; built to lib/host.mjs for the host to load)
107
- client/index.tsx # Team Workspace (TSX; built to lib/client.js)
108
- test/smoke.js # dependency-free smoke test (descriptors / structure / security hardening)
109
- test/journal.test.js # journal behavior test (runs store.ts source directly)
90
+ package.json # dsh.bundle.patch + dsh.client declarations; exports point to lib/
91
+ cordis.patch.yml # plugin mount patch (insert block, entry uses the package root)
92
+ tsdown*.config.ts # builds: client → lib/client.js; host/store/descriptors → lib/*.mjs
93
+ host/ # TeamflowService + core/* (pipeline / backlog / runner / guard / triage / state…)
94
+ client/ # Web workbench (in-session tab + global panel + right-sidebar run detail)
95
+ store.ts # persistence layer (atomic write / backup / corruption self-heal + journal serialize)
96
+ descriptors.ts # Remote descriptors (pure data, shared by host / client)
97
+ test/ # dependency-free tests (node test/*.js, 14 suites)
98
+ docs/ # ADRs / dev log / benchmark corpus / release notes
110
99
  ```
111
100
 
112
- **TypeScript note**: the whole repo is TS/TSX. The host **must be built** (cannot rely on Node strip-types to run directly) — Node 22's type stripping does not apply to files under `node_modules` ("unsupported for files under node_modules"), while the host composition loads plugins from `profile/node_modules`. Consistent with the DSH ecosystem (the `@deepseek-ai/dsh-*` host packages' exports all point to lib/*.js). After changing source, run `pnpm bundle` to rebuild and sync the profile copy's `lib/`.
101
+ The whole repo is TS/TSX: **the host must be built** (Node's type stripping does not apply to files under `node_modules`, and the host loads plugins from the profile's `node_modules`), so run `pnpm bundle` after changing source and sync the profile copy's `lib/`. Per-file details and the dev environment are in `CONTRIBUTING.md`.
102
+
113
103
 
114
104
  ## Requirements
115
105
 
@@ -119,11 +109,16 @@ dsh-plugin-teamflow/
119
109
 
120
110
  ### Version anchor (dsh host compatibility)
121
111
 
122
- This plugin is developed and verified against **dsh v0.1.5-rc.2 (2026-09-10, tag `dsh-v0.1.5-rc.2`)**; on npm the `@deepseek-ai/dsh` package has `next`=0.1.5-rc.2 and `latest`=0.1.5-rc.1 (`latest` lags behind `next`do not use `latest` to judge the release line). `peerDependencies` stay at `*` (host-injected, deliberately loose), and `package.json` declares the compatibility window **`engines.dsh: ">=0.1.5-rc.2 <0.2.0"`** plus **`dsh.manifestVersion: 1`**dsh does not read or validate either field today (they exist as types only), so they are declarative author metadata.
112
+ This plugin is developed and verified against **dsh v0.1.7-alpha.1** (session format v4). **That is also the floor for running a pipeline**: every message the plugin injects must carry a producer-owned `source.kind` (`plugin:dsh-plugin-teamflow`), while a v3 host validates `source.kind` against a **closed vocabulary** (`SOURCE_KINDS` contains no `plugin:*`)the old form `{kind:'plugin', plugin:…}` is rejected outright by a v4 host, and the new form is equally illegal on a v3 host, so the two shapes are **mutually incompatible**; the plugin therefore no longer claims it can run back to v0.1.5-rc.2. The Remote descriptors still expose both `schema` and `create()` for hosts of either generation, see "typert descriptor contract" below. `package.json`'s `engines.dsh: ">=0.1.7-alpha.1 <0.2.0"` (**narrowed to this floor** see the measurement below) and `dsh.manifestVersion: 1` are declarative author metadata (the host neither reads nor validates them).
113
+
114
+ ⚠️ **How the prerelease-tuple rule interacts with this range** (verified 2026-09-23 with semver 7.7.4's `satisfies`): a prerelease only matches a range carrying a prerelease on the **same `[major,minor,patch]` tuple** — `>=0.1.7-alpha.1 <0.2.0` evaluates to **PASS for `0.1.7-alpha.1` / `0.1.7-alpha.2` / `0.1.7` / `0.1.8` / `0.1.9`** and **fail for `0.1.6-alpha.2` / `0.1.6` / `0.2.0-rc.1` / `0.2.0`** (exactly the v4 floor above). Note the old range `>=0.1.5-rc.2 <0.2.0` judged even the then-current `0.1.6-alpha.2` false under the same rule, so a field like this only states compatibility **against stable releases**; the host does not validate it anyway, and day to day you should go by **`next`**: `latest` lags behind it, so don't use `latest` to judge the release line.
115
+
116
+ **Breaking surface of v0.1.7-alpha.1 (this audit)**: the session event format moved to **v4** — before adopting an event the host validates every message's `source.kind` and **refuses the retired v3 plugin wrapper** (`{kind:'plugin', plugin:…}` → `format v4 message requires a producer-owned source kind`), requiring `kind:'plugin:<name>'` instead. All four injection sites (team context ×2 / completion report / guard reminder) still wrote the old wrapper, so a fresh run failed at the write step (the journal never even landed). They now emit `plugin:dsh-plugin-teamflow`. Every other surface re-checked (typert strict descriptors still require `create()`, `subagents.start`/`SubagentRun`, the `tokenUsage` four buckets + `sessionStats.steps`, `agent.inject/followup/steer`, the `settings.locale` read-only port, `remote.$mount`, `sessions.openSubagent`, `sidebarRight.openResource`) showed **no breakage**.
117
+
118
+ **Breaking surface of v0.1.6-alpha.2 (previous audit)**: the typert strict codec changed from `{ mode, typeSymbol, schema }` to `{ mode, typeSymbol, create: () => Schema }` (lazy materialisation — `materializeSchema` does `record.value ??= record.create()`); `validateCodec` **throws at registration** for a strict codec missing `create()` — `"strict codec has no create() factory"`. Combined with dsh-app-boot's policy (a required plugin failing to activate fails the whole profile with `startup failed`), the symptom is **"dsh won't start"** (`web boot: N entries did not activate`). A full diff of the other surfaces (client-modules / subagent / agent runtime / manifest / the tools llm projection) found no further breakage for this plugin, and the three UI slot packages have zero changes in `src/index.ts` → slot names are safe.
123
119
 
124
- Compatibility check of 2026-09-10 (dsh 0.1.5-rc.2): plugin panel slots (the old `conversation` root slot the `conversation` key under `main`), session format V3 + Session lifecycle (`SessionHandle`, async `agentLoop.create()`, session locks), removal of `ctx.agent` and typed Inbox, adjusted default tools for SDK/Headless/ACP, subprocess handles without pid **the plugin is compatible with all of them** (it uses none of the changed interfaces; the `conversation.view` / `conversation.input.right` declarations are unchanged and no slot was removed). One follow-up item:
120
+ If behaviour looks wrong after a dsh upgrade, check two things first: ① the session events this plugin injects (`tool-workflow/agent-start`, `user/message` with `source.kind='plugin:dsh-plugin-teamflow'`) must sit inside the host's event vocabulary **a v4 host only accepts producer-owned source kinds (the v3 `plugin` wrapper is retired)**, and a v3 host's closed vocabulary does not accept `plugin:*` either (hence the v4 floor); `tool-workflow/agent-start` carries no message/source slot and is outside that check. **New custom event types must carry `ignorable: true`**, and known types must not add keys outside it; metering reads the host **projection keys** (`tokenUsage` / `sessionStats`), so if the host renames them or bumps their state version, `host/core/metering.ts` has to be updated in step. Compatibility checks and open follow-ups are recorded in `CHANGELOG.md` (0.1.6–0.1.9) and `docs/TODO.md` (for example, repeat detection still reads the deprecated event readers).
125
121
 
126
- - **The synchronous session event readers are deprecated** (`session.eventAt()` / `snapshotEvents()` / `ownEvents()`; since 2026-09-09 the host allows existing calls but forbids new ones, aiming to stop keeping the full event sequence resident in memory): **token metering now prefers the official Session projection** (`ctx.sessionProjections.stateOf(session,'tokenUsage')` for the four buckets + `'sessionStats'.steps` for the call count), with event scanning degraded to a fallback for hosts without projections; **the guard reminder channel moved to the official `Agent.inject()` and the stall check to the official `subagentTiming` projection's `active.through`** (long silent tools are still exempted by the agent-activity guard). Only **repeat detection** still reads events (it needs streaming text; the official replacement — subscribing to `'session/event'` post-commit delivery — requires an equivalent predicate first, see `docs/TODO.md`).
127
122
 
128
123
  ## Install (for users)
129
124
 
@@ -137,7 +132,7 @@ dsh plugin --profile web add file:./plugins/dsh-plugin-teamflow
137
132
 
138
133
  After install, **restart** `dsh --profile web` for the host `teamflow-host` to take effect:
139
134
  - The model side gains 12 `teamflow_*` tools: `start / triage / status / backlog / claim / update / assign / cancel / resume / pause / resume_session / merge`;
140
- - The browser session header shows the "🏭 Team Workspace" tab;
135
+ - The browser session header shows the "🏭 Team Workspace" tab (in-session) **and the "Team Workspace" icon in the left sidebar** (the global panel: product-line view, cross-session);
141
136
  - Backlog is written to `$DSH_HOME/teamflow/<product>/backlog/*.json`.
142
137
 
143
138
  > Note: `@deepseek-ai/*` are host-private packages; running requires the DeepSeek Harness (dsh) host environment; this package is neither published standalone nor runnable alone.
@@ -146,7 +141,7 @@ After install, **restart** `dsh --profile web` for the host `teamflow-host` to t
146
141
 
147
142
  1. **Pick a team**: click the 🏭 button next to the input box and choose a team (or "no team" = chat directly, no pipeline);
148
143
  2. **Say the requirement**: just describe it — the model calls `teamflow_start` automatically (auto-triage: patch / lite / tech / medium / full); or force a mode, e.g. "run this in medium mode";
149
- 3. **Watch progress**: switch to the 🏭 Team Workspace tab in the session header — the pipeline graph live-refreshes (per-stage token / duration / sub-agent session), and the backlog kanban supports drag transitions and card detail drawers;
144
+ 3. **Watch progress**: switch to the 🏭 Team Workspace tab in the session header — the pipeline graph live-refreshes (per-stage token / duration / sub-agent session), and the backlog kanban supports drag transitions and card detail drawers; for a **cross-session / global** view, click the "Team Workspace" icon in the left sidebar (product-line perspective: product lines → runs + backlog), and hit "⏹ Stop" to cancel a live run (two-step confirm);
150
145
  4. **Get the result**: the pipeline reports back to the session automatically when done (status / stage stats / token / next steps); interrupted/failed runs can "↻ resume from checkpoint".
151
146
 
152
147
  > Note: after `teamflow_start`, the **main thread should not modify code or run verifications itself** — implementation, QA, and reporting are done by pipeline sub-agents (avoid fighting the pipeline over the workspace).
@@ -166,10 +161,10 @@ Optional cleanup (NOT done automatically; run as needed):
166
161
  ## Development & verification
167
162
 
168
163
  ```bash
169
- npm test # smoke (descriptors / structure / security) + journal (resume behavior)
170
- npm run typecheck # tsc --noEmit type check (same as VSCode, no drift)
164
+ pnpm test # smoke (descriptors / structure / security) + journal (resume behavior)
165
+ pnpm run typecheck # tsc --noEmit type check (needs the local dsh profile for @deepseek-ai/* types)
171
166
  node --check lib/host.mjs lib/client.js lib/store.mjs lib/descriptors.mjs
172
- npm run bundle # build client (tsdown → lib/client.js, __ModuleLoader__.load registers)
167
+ pnpm run bundle # build client (tsdown → lib/client.js, registered via __ModuleLoader__.load)
173
168
  ```
174
169
 
175
170
  **For plugin developers** (the local dev loop of THIS plugin): see [`AGENTS.md`](./AGENTS.md) and [`docs/adr/`](./docs/adr) in the repo — deployment sync (`node deploy.mjs` → restart `dsh --profile web`), the "running web loads the host from the profile deployment copy, building source alone does not take effect" caveat, design decision records (ADR-0001~0009) and benchmarks (`docs/benchmarks/`). All repo source is TS/TSX and must be built first (`pnpm bundle`) to run (`strip-types` does not apply under `node_modules`).
@@ -185,7 +180,7 @@ Note: `lib/` is excluded by `.gitignore` but must ship with the package (`files`
185
180
  | `teamflow_backlog` / `teamflow.backlog(product)` | View backlog (+ persistence path) |
186
181
  | `teamflow_claim` | Claim a task or defect |
187
182
  | `teamflow_update` / `teamflow.backlogUpdate(kind, id, to, product, reason)` | Manually transition state (handle needs-human) |
188
- | `teamflow_cancel` / `teamflow.cancel(runId)` | Cancel a run |
183
+ | `teamflow_cancel` / `teamflow.cancel(runId)` | Cancel a run (buttons in the workbench, the global panel's run row and run detail; two-step confirm; only effective while the run is live) |
189
184
  | `teamflow_resume` / `teamflow.resume(runId, sessionId)` | Resume from checkpoint (rerun from first unfinished stage) |
190
185
  | `teamflow_triage` | Requirement triage preview (start auto-triages by default; use only to pre-assess / force a mode) |
191
186
  | `teamflow_assign` | Assign owner of a task / defect (separate from claim: claim only changes state) |
package/README.md CHANGED
@@ -20,54 +20,41 @@ TeamFlow 团队研发流水线 —— DeepSeek Harness 可分发插件(`dsh pl
20
20
 
21
21
  ## 界面预览
22
22
 
23
- 1. 流水线视图——阶段蛇形泳道 + 节点卡片(状态/耗时/token/子代理会话)
23
+ 1. 全局面板——左侧边栏「🏭 团队工作台」图标(跨会话 / 产品线视角:产品线列表 + run 列表 + Backlog 标签页 + 覆盖式详情浮层)
24
24
 
25
- ![流水线视图](docs/screenshots/pipeline-view.png)
25
+ ![全局面板](docs/screenshots/global-panel.png)
26
26
 
27
- 2. Backlog 看板——需求/任务/缺陷拖拽泳道
27
+ 2. 流水线视图——阶段蛇形泳道 + 节点卡片(状态/耗时/token/子代理会话)
28
28
 
29
- ![Backlog 看板](docs/screenshots/board.png)
29
+ ![流水线视图](docs/screenshots/pipeline-view.png)
30
30
 
31
31
  3. 阶段详情抽屉——阶段性产物全文 + token 明细 +「🎬 跳转子代理会话」
32
32
 
33
33
  ![阶段详情](docs/screenshots/stage-detail.png)
34
34
 
35
- 4. 看板任务详情——任务卡抽屉(需求原文/分配/事件时间线/子卡/缺陷/token)
35
+ 4. Backlog 看板——需求/任务/缺陷拖拽泳道
36
+
37
+ ![Backlog 看板](docs/screenshots/board.png)
38
+
39
+ 5. 看板任务详情——任务卡抽屉(需求原文/分配/事件时间线/子卡/缺陷/token)
36
40
 
37
41
  ![看板任务详情](docs/screenshots/board-task-detail.png)
38
42
 
39
- 5. 团队选择——🏭 按钮 + 团队下拉
43
+ 6. 团队选择——🏭 按钮 + 团队下拉
40
44
 
41
45
  ![团队选择](docs/screenshots/team-selector.png)
42
46
 
43
47
  ## 核心特性
44
48
 
45
- - **防假交付**:① 交付判定按**信号分级**——客观形态(非空 + 阶段长度下限)→ 真交付信号(`[Verification evidence]` 证据块)→ **措辞兜底**(仅在**无证据块**时才把"我无法完成"等拒绝措辞视为未交付;命中措辞但已带证据块只记诊断、不否决——如实汇报环境限制不再被误杀);② token 熔断——单次调用累计**新增**消耗(`input+cacheWrite+output`,不含缓存命中)超 200k 停止重试转人工;③ 上下文耗尽类失败不重试(重试同一 prompt 大概率复现);④ 产品级并发锁——同一产品同时只允许一条活跃流水线,防需求状态互踩;⑤ 阶段产物全文保留(内存 + 磁盘,供详情抽屉与断点续跑读取)。
46
- - **完成汇总自动汇报主线程**:流水线结束(成功/失败/取消/中断)后自动把汇总(状态/阶段统计/token 总计/backlog/后续操作指引)投递给发起会话的 Agent——空闲时唤醒(followup),忙碌时注入下一步上下文(inject),与 DSH 后台任务通知同款机制(tool-jobs 模式,但独立实现,不依赖 web 面被禁用的 tool-jobs)。用户无需盯面板,模型会转述结果或按指引继续(认领缺陷/流转/断点重跑)。
47
- - **断点续跑**:每阶段 checkpoint 落盘 `$DSH_HOME/teamflow/runs/<runId>.json`(LangGraph checkpointer 语义);进程崩溃/重启后自动标记 `interrupted`,可用 `teamflow_resume` / 面板「↻ 从断点重跑」从第一个未完成阶段继续(跳过已完成阶段,复用阶段产物全文)。
48
- - **backlog 持久化(v0.1.0 起按工作区隔离)到 `$DSH_HOME/teamflow/<workspace>/backlog/`**
49
- `requirements.json` / `tasks.json` / `bugs.json`,跨重启不丢;backlog 按「工作区(项目)」隔离——一个工作区就是一条项目线,不同工作区各看各的团队工作台。
50
- - **单任务模型**:一个需求 = 一张轮转任务卡(不再按角色拆任务),任务卡记录 `devAssign` / `qaAssign` / 验收人,状态轮转:待办→开发中→待测试→测试中→待验收→已验收|打回|需人工;交付前端页面同时展示每个角色花在该任务上的**真实 token usage**。
51
- - **产物收口**:流水线文档(PRD/设计/架构/技术方案/QA/记忆/历史)全部收口到 `docs/teamflow/`,命令运行日志在 run 期间暂存到 `logs/teamflow/<runId>/`,宿主 `docs/<职责>/` 与项目根不再被 TeamFlow 污染。
52
- - **日志根在 `$DSH_HOME`,不在你的项目里(v0.1.9)**:子代理受 DSH 文件沙箱约束(`workspace-write` 只能写会话工作区),所以只能先在项目内暂存;**run 一结束 host 就把其中值得留的东西归档到 `$DSH_HOME/teamflow/<workspace>/logs/<runId>/` 并删掉项目内副本**(host 自身的事件日志 `run.log` 直接落归档位)。**不制造输出 dump**:子代理被要求**不要**把命令/套件输出重定向进文件——长输出本来就由宿主截成 tail、全文 spill 到它报告的临时路径(这是 DSH 原生能力),所以要留存的只有**检查脚本**(`scripts/`)、**不可重跑的命令载荷**(`captures.json`)与结论笔记(`.md`),其余(`*.log`/`*.out`/`*.txt`/源码快照)**归档时一律丢弃**。实测一次真实 run 里 93% 是可重跑输出或 git 里已有的副本。崩溃/被 kill 的 run 不留残渣:下次同工作区起跑按同一标准处理残留(自愈),**每个工作区只保留最近 20 次 run**。
53
- - **交付面与噪音隔离**:只有**代码 + `docs/teamflow/` 任务夹**进收口提交(一个 run 一个 commit);`logs/teamflow/` 是插件自己的运行日志(含子代理的临时验证脚本),**不属于交付物**——host 提交前先把这条规则**幂等写进工作区 `.gitignore`**(随本次提交可见),整树 `git add` 之后再**把该目录从索引里摘掉**(`git rm -r --cached --ignore-unmatch`,只动索引、不删你的文件),因此**目标项目不需要预先配置 .gitignore**(这两道防线覆盖的是「run 进行中你自己提交」的窗口)。若你的仓库已经提交过这批日志,可在目标仓库执行 `git rm -r --cached logs/teamflow` 移出(本地文件保留)。
54
- - **状态机 + 事件日志**:需求(立项→进行中→待验收→已验收)、任务(待办→开发中→待测试→测试中→待验收→完成|打回|需人工)、缺陷(待认领→处理中→已修复待验→已关闭)。
55
- - **打回阈值**:单阶段连续 2 次 Agent 失败自动重试,仍失败 → `needs-human`,需人工介入。
56
- - **并发池**:开发任务按 `maxConcurrency`(默认 3,最大 8)并行执行。
57
- - **QA 缺陷登记**:QA 报告按固定表格输出 → 自动解析成 Bug 进入 backlog。
58
- - **token 计量(官方口径)**:每阶段记录 `usage` = **输入(缓存未命中)/输入(缓存命中)/写缓存/输出 + 调用数**(由子代理会话逐事件累计)+ **缓存命中率**(cacheRead/(input+cacheRead))。工作台卡片/任务卡/完成汇报均按此口径展示,模型无关、与官方账单一致。
59
- - **lite 模式**:微功能轻量——`teamflow_start(lite:true)` 跳过独立技术方案文档阶段(PRD 即契约),直接 **PRD → 开发 → QA → 验收**;配套 `needDesign:true` 时**保留 UI/UX 设计阶段**。用「按需求规模裁剪阶段集」换流程重量,避免一个微功能套完整瀑布(`patch` 档更小:单点确认 + 开发)。
60
- - **token 熔断**:单次调用累计**新增**消耗(`input+cacheWrite+output`,**不含缓存命中**)超 `FRESH_TOKEN_BUDGET`(默认 200k)时停止重试、需人工介入;汇报/展示仍按官方 billed 口径(`totalTokensOf`)。缓存命中是廉价重放,把它计入熔断会让「任何任务失败一次就熔断、自动重试形同虚设」——见 `docs/devlog.md` 补 15。
61
- - **🏭 团队工作台(双入口)**:
62
- - **会话内 tab**:与 chat / 轨迹并列的会话头部 tab,含:
63
- - 流水线图形工作流(阶段泳道 + 节点卡片:状态/耗时/token/子代理会话,2s 实时刷新)
64
- - **Backlog 拖拽看板**(需求/任务/缺陷三组状态泳道,卡片拖拽流转,原生 HTML5 DnD 零依赖)
65
- - 成本中心(每阶段 token + 总计 + 运行时长)
66
- - 人工介入中心(needs-human 项聚合 + 一键终态)
67
- - 历史 run 切换 + 产品切换 + 「⇥ 右栏打开 run 详情」
68
- - **全局面板**(v0.1.8):侧边栏图标 → 中央主区整块切换为**产品线视角**——左栏产品线列表(`$DSH_HOME/teamflow/<key>`,含 run 计数/活跃数/最近需求与结论),右栏该产品线的 run 列表 + backlog 分组(不依附会话,跨会话可用)。点 run 在**面板内联**看详情(阶段/尝试/验证证据/产出/日志);要并排看产物就点 run 行的「对话右栏」= 切回对话并在右侧栏打开(**右侧栏的会话内容宿主只在对话视图渲染**,这是宿主设计,不是面板缺陷;任何一步不可用都会降级为面板内联并给出可见提示)
69
-
70
- - **界面中英双语(v0.1.9,P1 客户端面)**:工作台文案跟随宿主语言(设置 → 通用 → 语言)**实时切换、无需重启**——走宿主 `ctx.locale` 服务(插件注册词典 + slot 注册项声明 `locale`,宿主切语言时重渲染每个 outlet),不自建 i18n;状态/阶段/角色/token 口径/时间格式等词表统一查表,247 条 key 中英逐条对齐(`test/smoke.js` 断言守门:两侧 key 集合必须一致,且客户端除 console 诊断外不得残留中文字面量)。**范围边界**:仅**客户端展示层**;host 生成的完成汇报/工具返回/流水线日志与产物文档(PRD/QA-REPORT/ACCEPTANCE…)仍是中文——产物语言与「验收结论」是 host 解析契约,属 P3(见 `docs/TODO.md`)。
49
+ - **一句话需求 可验收的交付**:从需求到 PRD / 技术方案 / 并行开发 / QA / 验收全链路自动编排,每个阶段有任务卡、有产物、有结论;机械小改动可用 `patch` / `lite` 档裁剪阶段集,不必为一行改动跑完整瀑布。
50
+ - **多 Agent 团队 + 并行开发**:按架构蓝图把需求拆成可并行任务(默认 3 路并发,上限 8),产品 / 架构 / 开发 / QA 各自独立上下文,互不污染。
51
+ - **防假交付**:交付看证据不看措辞——阶段必须给出「命令 + 退出码 + 断言数」的验证证据,QA 有独立对抗探针,验收只认显式结论行(缺失即停线转人工)。
52
+ - **QA 打回闭环**:P0–P2 缺陷自动打回修复 → 复验(≤2 轮),每条缺陷都带「检测命令 + 通过判据」;超限转人工,不会伪装成「已完成」。
53
+ - **断点续跑 + 完成汇报**:进程崩溃 / 重启后从第一个未完成阶段继续(已完成阶段复用产物);流水线结束时自动把汇总(状态 / 阶段 / token / 后续指引)投递回发起会话。
54
+ - **你的仓库保持干净**:流水线文档收口在 `docs/teamflow/` 任务夹,插件自己的运行日志在 run 结束时归档出项目,收口提交只带**代码 + 任务夹**(一个 run 一个 commit,**不需要你预先配置 `.gitignore`**)。若历史提交里已经混进过 `logs/teamflow/`,在目标仓库执行 `git rm -r --cached logs/teamflow` 移出即可(本地文件保留)。
55
+ - **🏭 团队工作台(Web 双入口)**:会话内 tab(流水线图 + 拖拽看板 + 成本中心 + 人工介入中心)与应用级主面板(产品线视角,跨会话可用);点开 run 看阶段、token、验证证据与产物。**界面中英双语**,跟随宿主语言实时切换;host 侧的回复、流水线日志与产物文档同样跟随语言(run 起跑时定一次,同一条 run 内一致)。
56
+ - **token 有账可查**:按官方口径记录每个阶段的输入(未命中 / 命中)/ 写缓存 / 输出与调用数,并给出缓存命中率,汇报与看板同口径;机械阶段自动降档推理强度,重试时回升。
57
+
71
58
 
72
59
  ## AGENTS.md 最小侵入原则(重要)
73
60
 
@@ -82,48 +69,37 @@ AGENTS.md 会被 harness 无条件注入每个会话,是**团队资产**。Tea
82
69
 
83
70
  ```
84
71
  web profile 宿主组合
85
- ├── teamflow-host (dsh-plugin-teamflow/host) Cordis service `teamflow`
86
- └── TeamflowService extends TypertRemoteService
87
- ├── ctx.typert.register(strict descriptors) 22 个 Remote 方法
88
- ├── ctx.tools.register(teamflow_*)12 个模型工具
89
- └── node:fs $DSH_HOME/teamflow/...
90
- └── teamflow-client (dsh-plugin-teamflow/client,自动扫描) ← package.json 声明 dsh.client,
91
- └── ctx.remote.$mount(TEAMFLOW_REMOTE_CONTRIBUTION) 无需 patch 行,clientModules 自动注册
92
- ├── conversation.view tab「🏭 团队工作台」(会话内)
93
- ├── sidebar.panellist + main/teamflow(全局产品线面板)
94
- └── sidebarRightTabs「teamflow-run」(右栏 run 详情 tab)
72
+ ├── teamflow-host (host/) Cordis service `teamflow`
73
+ ├── ctx.typert.register(strict descriptors) ← Remote 方法(descriptors.ts 纯数据,host / client 共用)
74
+ ├── ctx.tools.register(teamflow_*) 模型工具
75
+ └── node:fs → $DSH_HOME/teamflow/…backlog / journal / 归档日志
76
+ └── teamflow-client (client/) ← package.json 声明 dsh.client,宿主组合自动扫描注册
77
+ ├── conversation.view「🏭 团队工作台」(会话内 tab)
78
+ ├── sidebar.panellist + main/teamflow(全局产品线面板)
79
+ └── sidebarRightTabs「teamflow-run」(右栏 run 详情)
95
80
  ```
96
81
 
97
- **为什么不用 @Remote 装饰器**:宿主插件以纯 JS 分发,避免装饰器语法/TS 编译要求;
98
- 用 `ctx.typert.register` 注册 strict 描述符(`descriptors.js` 纯数据,host/client 共用一份,
99
- 保证 endpoint 与 wire 参数一致)。
82
+ 两条硬约束决定了这个形态(详见 `AGENTS.md` §3):**不用 `@Remote` 装饰器**(插件以纯 JS 分发,Remote 走 `ctx.typert.register` 的严格描述符);**必须是宿主级插件**(动态插件的 `fs` 被沙箱限制在运行时根,写不了 `$DSH_HOME`)。
83
+
100
84
 
101
- **为什么是宿主级插件(而不是动态插件)**:动态(会话内)插件宿主运行在受限沙箱,
102
- 其 `fs` 被硬限制在运行时根,无法写入 `$DSH_HOME` 或会话工作区(实测
103
- `file access denied under workspace-write mode`)。只有宿主组合里的正式插件拥有真实
104
- Node `fs`,能把 backlog 落到 `$DSH_HOME`,且 client 能注册独立 tab。
105
85
 
106
86
  ## 目录结构
107
87
 
108
88
  ```
109
89
  dsh-plugin-teamflow/
110
- package.json # dsh.bundle.patch + dsh.client 声明;exports 指向 lib/ 构建产物
111
- cordis.patch.yml # insert 块;entry 名用包根(clientModules 才能扫到 dsh.client)
112
- tsdown.config.ts # client 构建(ModuleLoader bundle → lib/client.js
113
- tsdown.host.config.ts # host/store/descriptors 构建(ESM lib/*.mjs)
114
- descriptors.ts # Remote 描述符(纯数据,host/client 共用)
115
- store.ts # 持久化层:原子写/备份/损坏自愈 + journal 序列化/加载(可独立测试)
116
- host/index.ts # TeamflowService(TS;构建为 lib/host.mjs 供宿主加载)
117
- host/core/products.ts # 产品线装配(全局面板数据面:清单/摘要/地址)
118
- client/index.tsx # 会话内团队工作台 + 全部 slot 注册(TSX;构建为 lib/client.js)
119
- client/panel.tsx # 全局面板(sidebar.panellist + main)+ 右栏 run 详情 tab
120
- client/shared.tsx # 共享展示层(主题 token / 状态词表 / 格式化)
121
- test/smoke.js # 无依赖 smoke 测试(描述符/模块结构/安全加固)
122
- test/product-scope.test.js # 产品线装配测试(地址/白名单/过滤/摘要/空态)
123
- test/journal.test.js # journal 行为测试(直跑 store.ts 源码)
90
+ package.json # dsh.bundle.patch + dsh.client 声明;exports 指向 lib/ 构建产物
91
+ cordis.patch.yml # 插件挂载 patch(insert 块,entry 用包根)
92
+ tsdown*.config.ts # 构建:client → lib/client.js;host/store/descriptors → lib/*.mjs
93
+ host/ # TeamflowService + core/*(流水线 / backlog / runner / guard / triage / state…)
94
+ client/ # Web 工作台(会话内 tab + 全局面板 + 右栏 run 详情)
95
+ store.ts # 持久化层(原子写 / 备份 / 损坏自愈 + journal 序列化)
96
+ descriptors.ts # Remote 描述符(纯数据,host / client 共用)
97
+ test/ # 无依赖测试(node test/*.js,14 套件)
98
+ docs/ # ADR / 开发日志 / 评测语料 / release notes
124
99
  ```
125
100
 
126
- **TypeScript 说明**:全仓 TS/TSXhost 之所以**必须构建**(不能靠 Node strip-types 直跑)——Node 22 的 type stripping 对 `node_modules` 下的文件不生效("unsupported for files under node_modules"),而宿主组合从 profile/node_modules 加载插件。与 DSH 生态一致(`@deepseek-ai/dsh-*` 宿主包 exports 均指向 lib/*.js)。改动源码后需 `pnpm bundle` 重建并同步 profile 副本的 `lib/`。
101
+ 全仓 TS/TSX:**host 必须构建**(Node 的 type stripping 对 `node_modules` 下的文件不生效,而宿主从 profile `node_modules` 加载插件),改源码后跑 `pnpm bundle` 重建并同步 profile 副本的 `lib/`。逐文件说明与开发环境见 `CONTRIBUTING.md`。
102
+
127
103
 
128
104
  ## 环境要求
129
105
 
@@ -133,18 +109,16 @@ dsh-plugin-teamflow/
133
109
 
134
110
  ### 版本锚定(dsh 宿主兼容性)
135
111
 
136
- 本插件开发与验证基于 **dsh v0.1.5-rc.2(2026-09-10,tag `dsh-v0.1.5-rc.2`)**;npm `next`=0.1.5-rc.2、`latest`=0.1.5-rc.1(`latest` 常滞后于 `next`,勿以 latest 判断发布线)。`peerDependencies` 保持 `*`(宿主注入,宽松兼容),并在 `package.json` 声明兼容窗口 **`engines.dsh: ">=0.1.5-rc.2 <0.2.0"`** 与 **`dsh.manifestVersion: 1`**——当前 dsh 不读取/校验这两个字段(源码内仅有类型声明),属作者声明性元数据。
112
+ 本插件开发与验证基于 **dsh v0.1.7-alpha.1**(session 格式 v4)。**这也是「能跑流水线」的宿主下限**:插件注入的每条 message 必须带 producer-owned `source.kind`(`plugin:dsh-plugin-teamflow`),而 v3 宿主把 `source.kind` 校验为**封闭词表**(`SOURCE_KINDS` 不含 `plugin:*`)——旧写法 `{kind:'plugin', plugin:…}` 在 v4 宿主当场被拒,新写法在 v3 宿主同样非法,两种形态**互不兼容**,故不再声称可回退到 v0.1.5-rc.2 运行。Remote 描述符仍同时提供 `schema` `create()` 两个字段(供不同代际的宿主读取),见下「typert 描述符契约」。`package.json` `engines.dsh: ">=0.1.7-alpha.1 <0.2.0"`(**已随本次下限收窄**,见下条实测)与 `dsh.manifestVersion: 1` 是作者声明性元数据(宿主不读取/校验)。
113
+
114
+ ⚠️ **预发布 tuple 规则与本次区间的实测关系**(2026-09-23 用 semver 7.7.4 的 `satisfies` 实测):受「预发布版本只匹配同 `[major,minor,patch]` tuple 的区间」规则约束——`>=0.1.7-alpha.1 <0.2.0` 对 **`0.1.7-alpha.1` / `0.1.7-alpha.2` / `0.1.7` / `0.1.8` / `0.1.9` 判 PASS**,对 **`0.1.6-alpha.2` / `0.1.6` / `0.2.0-rc.1` / `0.2.0` 判 fail**(与上条 v4 下限恰好一致)。注意旧区间 `>=0.1.5-rc.2 <0.2.0` 在同一 rule 下连**当时正在用的 `0.1.6-alpha.2` 都判 false**,所以这类字段只表达**对正式版的兼容声明**;宿主既不校验它,日常应以 **`next`** 为准——`latest` 常滞后于 `next`,不要用 `latest` 判断发布线。
137
115
 
138
- 2026-09-10 兼容性核对(dsh 0.1.5-rc.2):插件面板 Slot(原 `conversation` slot `main` 下的 `conversation` key)、会话格式 V3 + Session 生命周期(`SessionHandle`、异步 `agentLoop.create()`、会话锁)、`ctx.agent` 移除与 Inbox 类型化、SDK/Headless/ACP 默认工具调整、subprocess handle 去除 pid——**插件全部兼容**(未使用被改动的接口;`conversation.view` / `conversation.input.right` 声明未变,slot 树无删除)。其中一项需要跟进:
116
+ **v0.1.7-alpha.1 breaking 面(本次核对)**:session 事件格式升到 **v4**——宿主在事件被 Session 采纳前校验每条 message 的 `source.kind`,**拒绝 v3 退役的 plugin wrapper**(`{kind:'plugin', plugin:…}` `format v4 message requires a producer-owned source kind`),要求 `kind:'plugin:<name>'`。插件原先四处注入(团队上下文 ×2 / 完成汇报 / 护栏提醒)写的都是旧 wrapper 新 run 在写入阶段即失败(journal 都落不了盘)。现已全部改为 `plugin:dsh-plugin-teamflow`。全量核对其余面(typert 严格描述符仍要 `create()`、`subagents.start`/`SubagentRun`、`tokenUsage` 四桶 + `sessionStats.steps`、`agent.inject/followup/steer`、`settings.locale` 只读端口、`remote.$mount`、`sessions.openSubagent`、`sidebarRight.openResource`)**均无破坏**。
139
117
 
140
- - **Session 同步事件读取器已弃用**(`session.eventAt()` / `snapshotEvents()` / `ownEvents()`,宿主 2026-09-09 起「存量可留、新调用禁止」,方向是不再把完整事件序列常驻内存):**token 计量已改为官方 Session 投影优先**(`ctx.sessionProjections.stateOf(session,'tokenUsage')` 取四桶 + `'sessionStats'.steps` 取调用数),事件扫描降级为无投影宿主的回退;**护栏的提醒通道已改官方 `Agent.inject()`、挂死判据已改用官方 `subagentTiming` 投影的 `active.through`**(长工具静默仍由 agent 活动守卫豁免),只剩**复读检测**仍在读事件(需要流式文本内容,官方替代=订阅 `'session/event'` post-commit 投递,需先定等价判据,见 `docs/TODO.md`)。
118
+ **v0.1.6-alpha.2 breaking 面(上次核对)**:typert strict codec 由 `{ mode, typeSymbol, schema }` 变为 `{ mode, typeSymbol, create: () => Schema }`(懒物化,`materializeSchema` `record.value ??= record.create()`);`validateCodec` 对缺 `create()` strict codec **注册即抛** `"strict codec has no create() factory"`。叠加 dsh-app-boot 的策略(required 插件 activate 失败 → 整个 profile `startup failed`),表现为**插件一挂就是「dsh 起不来」**(`web boot: N entries did not activate`)。全量 diff 其余面(client-modules / subagent / agent runtime / manifest / tools 的 llm 投影)对本插件无破坏,三个 UI slot 包的 `src/index.ts` 零变更 → slot 名安全。
141
119
 
142
- 2026-09-04 核对(dsh 0.1.3-alpha.1):session 持久化 v2(write-lease/JSONL 快照/版本化导出)、attachment/file-upload 收口、Windows 子进程隐藏、workspace 全限定路径硬化——全部兼容,插件无需调整。
120
+ 升级 dsh 后若行为异常,先核对两处:① 插件注入的 session 事件(`tool-workflow/agent-start`、`user/message` + `source.kind='plugin:dsh-plugin-teamflow'`)必须落在宿主事件词表内——**v4 宿主只收 producer-owned 的 source kind(`plugin` 这个 v3 wrapper 已退役)**,而 v3 宿主的封闭词表也不收 `plugin:*`(因此下限是 v4 宿主);`tool-workflow/agent-start` 不带 message/source 槽位,不在该校验范围内。**新增自定义事件类型要带 `ignorable: true`**、已知类型不要加词表外的键;② 计量读的是**宿主投影 key**(`tokenUsage` / `sessionStats`),宿主改 key 或 state 版本时需同步 `host/core/metering.ts`。历次兼容核对结论与待跟进项见 `CHANGELOG.md`(0.1.6–0.1.9 段)与 `docs/TODO.md`(例如复读检测仍读已弃用的事件读取器)。
143
121
 
144
- 插件侧契约约束(dsh 升级后若行为异常先核对本段;锚定版本变更会在此更新):
145
- - 插件注入的 session 事件(`tool-workflow/agent-start`、`user/message` 带 `source.kind='plugin'`)均在宿主 `known-event-types` 词表内;**未来新增自定义事件类型须带 `ignorable: true`**,已知类型载荷不加词表外键;
146
- - `@deepseek-ai/dsh-client-modules` 自 0.1.2-rc.1 起替代 `@deepseek-ai/dsh-client-runtime`(后者已从 monorepo 移除);
147
- - 计量读的是**宿主投影 key**(`tokenUsage` / `sessionStats`)而非插件自有格式:宿主若改 key 或 state 版本,此段与 `host/core/metering.ts` 同步更新。
148
122
 
149
123
  ## 安装(对使用者)
150
124
 
@@ -187,10 +161,10 @@ dsh plugin --profile web remove dsh-plugin-teamflow
187
161
  ## 开发与验证
188
162
 
189
163
  ```bash
190
- npm test # smoke(描述符/结构/安全)+ journal(断点续跑行为)
191
- npm run typecheck # tsc --noEmit 类型检查(需本机 dsh profile 提供 @deepseek-ai/* 类型)
164
+ pnpm test # smoke(描述符/结构/安全)+ journal(断点续跑行为)
165
+ pnpm run typecheck # tsc --noEmit 类型检查(需本机 dsh profile 提供 @deepseek-ai/* 类型)
192
166
  node --check lib/host.mjs lib/client.js lib/store.mjs lib/descriptors.mjs
193
- npm run bundle # 构建 client(tsdown → lib/client.js,__ModuleLoader__.load 注册)
167
+ pnpm run bundle # 构建 client(tsdown → lib/client.js,__ModuleLoader__.load 注册)
194
168
  ```
195
169
 
196
170
  **插件开发者**(本插件的本地开发链路)见仓库内 [`AGENTS.md`](./AGENTS.md) 与 [`docs/adr/`](./docs/adr)——含部署同步(`node deploy.mjs` → 重启 `dsh --profile web`)、生效前提(运行中 web 从 profile 部署副本加载 host,只构建源码不生效)、设计决策记录(ADR-0001~0009)与基准对比(`docs/benchmarks/`)。本仓库其余源码均为 TS/TSX,需先 `pnpm bundle` 构建后再运行(`node_modules` 下 strip-types 不生效)。
@@ -206,7 +180,7 @@ npm run bundle # 构建 client(tsdown → lib/client.js,__ModuleLoa
206
180
  | `teamflow_backlog` / `teamflow.backlog(product)` | 查看 backlog(+ persistence 落盘路径) |
207
181
  | `teamflow_claim` | 认领任务或缺陷 |
208
182
  | `teamflow_update` / `teamflow.backlogUpdate(kind, id, to, product, reason)` | 人工流转状态(处理 needs-human) |
209
- | `teamflow_cancel` / `teamflow.cancel(runId)` | 取消运行 |
183
+ | `teamflow_cancel` / `teamflow.cancel(runId)` | 取消运行(工作台 / 全局面板 run 行 / run 详情三处按钮,两段式确认;仅对正在跑的 run 生效) |
210
184
  | `teamflow_resume` / `teamflow.resume(runId, sessionId)` | 断点续跑(从第一个未完成阶段重跑) |
211
185
  | `teamflow_triage` | 需求分诊预览(默认 start 自动分诊,仅在想预评估/强制 mode 时使用) |
212
186
  | `teamflow_assign` | 指定任务/缺陷的负责人(与 claim 分离:claim 只改状态) |