@mstar-harness/dsh 3.8.1 → 3.8.2

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 (36) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +16 -6
  3. package/README.zh.md +16 -6
  4. package/dist/client/panel/engine-status-client.d.ts +84 -6
  5. package/dist/client/panel/graph/project-graph.d.ts +26 -13
  6. package/dist/client/panel/guards.d.ts +41 -1
  7. package/dist/client/panel/locale.d.ts +1 -1
  8. package/dist/client/panel/pages/AgentListPage.d.ts +1 -1
  9. package/dist/client/panel/sidebar.d.ts +3 -2
  10. package/dist/client/panel/state-section.d.ts +25 -3
  11. package/dist/client/panel/use-mstar-engine-status.d.ts +28 -4
  12. package/dist/client.js +346 -48
  13. package/dist/engine-status-endpoint.d.ts +85 -8
  14. package/dist/engine-status-store.d.ts +91 -1
  15. package/dist/engine-status-wire.d.ts +9 -0
  16. package/dist/gates/_shared.d.ts +61 -9
  17. package/dist/gates/adapter.d.ts +32 -2
  18. package/dist/gates/agent-flow.d.ts +312 -60
  19. package/dist/gates/catalog.d.ts +58 -37
  20. package/dist/gates/dispatch.d.ts +11 -2
  21. package/dist/gates/goal-bridge.d.ts +10 -130
  22. package/dist/gates/plan-mode-bridge.d.ts +20 -11
  23. package/dist/gates/role-persona.d.ts +16 -0
  24. package/dist/gates/steering.d.ts +41 -0
  25. package/dist/gates/workflow-ledger.d.ts +31 -4
  26. package/dist/gates/workflow-selection.d.ts +41 -20
  27. package/dist/index.js +1206 -392
  28. package/dist/types.d.ts +36 -11
  29. package/harness-commands/amazing-pr-review.md +2 -0
  30. package/harness-commands/codebase-audit.md +2 -0
  31. package/harness-skills/mstar-host/SKILL.md +3 -1
  32. package/harness-skills/mstar-host/references/dsh-workflow-scripts.md +424 -0
  33. package/harness-skills/mstar-host/references/dsh.md +170 -43
  34. package/harness-skills/mstar-roles/references/project-manager.md +2 -0
  35. package/harness-skills/mstar-sdd/SKILL.md +2 -0
  36. package/package.json +2 -2
@@ -138,6 +138,7 @@ or a custom profile).
138
138
  | dsh tool | Harness use |
139
139
  |----------|-------------|
140
140
  | **`subagent`** | Primary dispatch — the model-facing delegation tool the dispatch gate matches (default `toolName`; a renamed instance must be declared via Config `dispatchTools`) |
141
+ | **`workflow`** | Read-only N≥3 fan-out — one run, one conversation `workflow-run` node (§ Read-only fan-out via the `workflow` tool; scripts → `references/dsh-workflow-scripts.md`) |
141
142
  | **`mstar_iteration_gate`** | Evaluate the iteration phase gate in-app (`evaluatePhaseGate` — `mstar iteration gate` parity) |
142
143
  | **`mstar_sdd_workspace`** / **`mstar_sdd_task_brief`** | SDD workspace resolve + task brief extraction (`mstar sdd …` parity) |
143
144
  | **`mstar_*_validate`** | On-demand seam validators (design-md / audit / compound / roles) |
@@ -208,59 +209,107 @@ tab's `EventLogPage` log page are pure consumers of this evidence.
208
209
  `beforeDispatch` followed by the identical text as an in-loop subagent tool
209
210
  call) records two dispatch events — the surfaces are mutually exclusive by
210
211
  design; the double record is documented, not deduplicated.
211
- - **File / bounds**: events append to `{HARNESS_DIR}/agent-flow.jsonl` (JSON
212
- Lines, one event per line; harness dirs are gitignored by convention). The
213
- ledger assumes ONE dsh process writes each harness dir (single-writer):
214
- concurrent dsh sessions on the same repo can lose events (the append itself
215
- is near-atomic O_APPEND, but truncation is a read-modify-write) — the loss
216
- only under-reports actual flow in the panel, never a gate impact. After each
217
- append the file truncates to the most recent **500** events; truncation is
218
- size-gated (≈500 lines' typical size — small files stay append-only) and
219
- performed as an atomic temp-file rename. The catalog read returns the
220
- latest-first view with a default window of **50** and a role × outcome
221
- summary. A MISSING file reads as the empty view ("no actual dispatches yet"
222
- — recording starts at plan merge); an unreadable file is absent evidence;
223
- malformed lines are skipped, never fatal.
212
+ - **File / bounds**: events append to the ACTIVE workflow dir —
213
+ `{HARNESS_DIR}/workflows/<id>/agent-flow.jsonl` (JSON Lines, one event per
214
+ line; harness dirs are gitignored by convention) — never the harness root:
215
+ with no active lifecycle the record is SKIPPED with a one-time warn. The
216
+ append and the size-gated truncating read-modify-write form ONE critical
217
+ section behind a per-workflow lockdir, so a second dsh session sharing the
218
+ active lifecycle cannot silently drop the other writer's lines (steady state
219
+ stays one writer per workflow dir); any loss only under-reports actual flow
220
+ in the panel, never a gate impact. After each append the file truncates to
221
+ the most recent **500** events; truncation is size-gated (≈500 lines'
222
+ typical size — small files stay append-only) and performed as an atomic
223
+ temp-file rename. The catalog read returns the latest-first view with a
224
+ default window of **50** and a role × outcome summary. A MISSING file reads
225
+ as the empty view ("no actual dispatches yet" — recording starts at plan
226
+ merge); an unreadable file is absent evidence; malformed lines are skipped,
227
+ never fatal.
224
228
  - **Settle = real completion pairing, never faked**: `tools/post-execute`
225
229
  IS part of the
226
230
  verified dsh-tools registry surface (`runPostExecute` dispatches the
227
231
  waterfall for every tool call — verified against the upstream source and
228
232
  pinned by a real-call probe). The pairing listener matches dispatch TOOLS
229
- (Config `dispatchTools`, default `['subagent']`), looks up the exec's
230
- `callId` in the apply-scoped pairing store, and branches on the verified
231
- result shapes:
232
- - `{ kind: 'background', taskId }` → store `taskId → dispatchRef`; the REAL
233
- settle arrives via `ctx.tasks.onTaskDone` (terminal mapping
234
- completed → ok / killed → denied / failed → error, `durationMs` when
235
- available), wired through `ctx.inject(['tasks'])`.
233
+ (Config `dispatchTools`, default `['subagent', 'subagent_fork']`), looks up
234
+ the exec's agent-namespaced call key in the apply-scoped pairing store, and
235
+ branches on the verified result shapes:
236
+ - `{ kind: 'background', jobId }` (the registry job id, `<kind>-N`) → store
237
+ `jobId → dispatchRef` and the bounded job id as the ref's `taskRef`; the
238
+ REAL settle arrives via `ctx.inject(['jobs'])` → `jobs.onJobDone`
239
+ (terminal mapping completed → ok / killed → denied / failed → error,
240
+ `durationMs` when available). A background value without a valid `jobId` →
241
+ nothing mappable (no settle).
236
242
  - `{ kind: 'continuable', subagentId }` → no terminal signal this round →
237
- no settle (documented limit — the child owns its turns).
243
+ no settle (documented limit — the child owns its turns); the value
244
+ authorizes the child-identity join below and nothing is copied onto a
245
+ settle.
238
246
  - any other successful value (foreground included) → settle `ok`; a failed
239
- result (`isError`) → settle `error`.
247
+ result (`isError` or an `error` payload) → settle `error`. A returned
248
+ foreground `runId` is the settle's `childId`, extracted independently of
249
+ the outcome (an error settle keeps its identity without becoming `ok`).
240
250
  Pairing is apply-scoped (in-memory `callId → dispatchRef` /
241
- `taskId → dispatchRef` maps created in the entry `apply`; an HMR restart
251
+ `jobId → dispatchRef` maps created in the entry `apply`; an HMR restart
242
252
  resets them, and completions outside the window stay unpaired). Every
243
253
  PAIRED settle carries the paired dispatch's identity (`role`/`planId`/
244
254
  `taskId` — same field names + semantics as the dispatch event; the registry
245
- background-task id is never written as `taskId`, `taskRef` is reserved for
246
- it). Unpaired payloads (non-dispatch tools, calls outside the pairing
247
- window) record NOTHING — the ledger stays dispatch-only, never a
248
- fabricated settle.
255
+ job id is never written as `taskId` — `taskId` stays the Assignment `Task N`
256
+ tag, `taskRef` is reserved for the registry id). Unpaired payloads
257
+ (non-dispatch tools, calls outside the pairing window) record NOTHING — the
258
+ ledger stays dispatch-only, never a fabricated settle.
259
+ - **Child identity (`subagent-link`, nonterminal)**: the child session id is
260
+ published upstream as a PARENT-OWNED `subagent/catalog` session event
261
+ (`{ version: 0, childId, childCreatedAt, mode, label }`; `label` = the
262
+ delegation `description`), appended by the tool body — for the continuable
263
+ path BEFORE the tool returns. The join spans a per-dispatch CALL WINDOW: the
264
+ pre-execute reserves the first raw-label slot under the live parent Session
265
+ object and captures its `seq` as the window start; a valid `background` /
266
+ `continuable` result at `tools/post-execute` makes that exact candidate
267
+ eligible (every other outcome retires it to a tombstone; a duplicate label
268
+ was already refused a candidate at reservation). Eligibility walks
269
+ `eventAt(seq)` over `[fromSeq, end)`, where `end` is the session's `seq`
270
+ CAPTURED when the candidate became eligible — recovering a catalog appended
271
+ before the tool returned — while ONE root-context `session/event` observer
272
+ feeds the same matcher for later arrivals against the session's CURRENT
273
+ `seq`: only that live observer follows the session forward, so a catalog
274
+ appended after eligibility still joins through it (the catch-up scan stays
275
+ frozen at its captured endpoint). A matched
276
+ candidate is consumed once and appends `{ v: 1, ts, kind: 'subagent-link',
277
+ agent?, childId, label, role, planId?, taskId?, taskRef? }` to the
278
+ DISPATCH's own workflow dir (`ts` = observation time), correlating the
279
+ catalog child back to the dispatch identity mstar recorded. It is an
280
+ IDENTITY record, NOT a completion: no `outcome`, no `verdict`, no `paired`
281
+ marker. A background one-shot link also carries its registry `taskRef`; a
282
+ continuable link omits it. Settle rows carry an optional `childId` — a
283
+ foreground `runId`, or for background only when the join has already
284
+ supplied one.
285
+ - **Join bounds (honest degrade)**: NO row when the label is missing/empty,
286
+ the dispatch unpaired, a background result carries no valid `jobId` (the
287
+ reserved candidate is retired — nothing mappable: no settle, no link),
288
+ the catalog version unknown, the mode not matching the result kind,
289
+ a continuable catalog naming a different child than the tool returned,
290
+ the slot map at capacity (500 labels per parent Session), or the slot
291
+ already consumed. The join is apply-scoped: no whole-history cold
292
+ scan and no `session/created` backfill — a catalog written before apply
293
+ (constructor seeds) can never label a new dispatch. Duplicate labels are
294
+ deterministic best-effort (first reservation + first matching catalog wins),
295
+ NOT proof of unique ownership. Not every provider emits a catalog — a remote
296
+ run without a `localAgent` produces none, so a dispatch may legitimately
297
+ have no link row.
249
298
  - **Catalog**: `state.agentFlow` carries the ledger view (`events` ≤ 50,
250
299
  latest-first, + `summary`); the model-facing `<mstar_engine_status>` text
251
300
  renders ONE compact `agent flow: …` line only when events > 0 (role totals
252
301
  top-5 + latest dispatch with HH:MM — the event detail lives in the
253
- structured source, never the model text). A ledger record (dispatch/settle)
254
- invalidates the affected workspace's TTL cache entry IMMEDIATELY
255
- (apply-scoped `harnessDir → cache key` reverse map + invalidation closure)
256
- → the next pre-step rebuilds and (digest
257
- text change) re-injects the row — the 60 s TTL no longer bounds
258
- ledger-change latency; it still bounds non-ledger staleness.
302
+ structured source, never the model text). A ledger record
303
+ (dispatch/settle/link) invalidates the affected workspace's TTL cache entry
304
+ IMMEDIATELY (apply-scoped `harnessDir → cache key` reverse map +
305
+ invalidation closure) → the next pre-step rebuilds and (digest text change)
306
+ re-injects the row — the 60 s TTL no longer bounds ledger-change latency; it
307
+ still bounds non-ledger staleness.
259
308
  - **Maintainer view**: change the ledger shape (event schema, bounds, settle
260
309
  seam) and update the projections together — `gates/agent-flow.ts` (record /
261
- read / settle listener), `gates/catalog.ts` (agent-flow line + `source`
262
- view) and `client/panel/graph/project-graph.ts` (the ZoneView flow/agents
263
- projection) — the panel renders ONLY what the evidence shows.
310
+ read / settle / catalog-join listeners), `gates/catalog.ts` (agent-flow line
311
+ + `source` view) and `client/panel/graph/project-graph.ts` (the ZoneView
312
+ flow/agents projection) — the panel renders ONLY what the evidence shows.
264
313
 
265
314
  ## PM dispatch
266
315
 
@@ -299,15 +348,36 @@ the "queued messages" dock instead of reaching the parent (observed on dsh).
299
348
  The closing message is the guaranteed delivery channel; reserve `report` for
300
349
  MID-turn findings that change what the parent should do next.
301
350
 
351
+ ### Progress discipline — native workflow, never `/goal`
352
+
353
+ dsh progress is driven by the **native workflow**: the workflow snapshot phases
354
+ + the dispatch gates + **subagent settle notifications**. mstar **stops arming**
355
+ a goal on dsh — the surviving bridge is advisory-only (no `create` / `edit` /
356
+ `complete` / `pause` / `resume`, no goal read) — so no goal round loop drives
357
+ mstar work here. Never drive a dsh session with a `/goal` objective or a goal
358
+ round loop: `goal-round-driver` opens a round whenever the goal is active +
359
+ armed and the agent is idle, and it knows nothing about running subagents, so
360
+ an operator who arms `/goal` manually can still get rounds firing while a
361
+ dispatched child owns the critical path.
362
+
363
+ **Phase 2 continuous execution is a PM-local loop**: dispatch → **wait for the
364
+ child's settle notification** → next dispatch. When a dispatched child owns the
365
+ critical path, the correct action is to **wait** — not to open another unit of
366
+ work against the same worktree.
367
+
302
368
  ### QC default
303
369
 
304
- - **`Execution mode: sdd`**: **N=3** `subagent` dispatches — one per QC seat
305
- (`qc-specialist`, `qc-specialist-2`, `qc-specialist-3`), each body **Act as**
306
- the respective QC role + QC skill load. **MUST dispatch all three with
307
- `run_in_background: true` in one message** → the seats run CONCURRENTLY
308
- (background children; wall ≈ single seat); foreground (no
309
- `run_in_background`) runs serially (wall ≈ 3× single seat) and does NOT
310
- count as parallel tri. Cannot emit required **N** → **`Blocked`**.
370
+ - **`Execution mode: sdd`**: **N=3** seats — one per QC seat (`qc-specialist`,
371
+ `qc-specialist-2`, `qc-specialist-3`), each body **Act as** the respective QC
372
+ role + QC skill load. Read-only fan-out of N≥3 on dsh uses the native
373
+ **`workflow`** tool (the `mstar-qc-tri` script — § Read-only fan-out via the
374
+ `workflow` tool): one run, three concurrent children, one conversation
375
+ `workflow-run` node. When the tool is not mounted (the `ptc` preset hides it),
376
+ fall back to the `subagent` path below. **The `subagent` path MUST dispatch all
377
+ three with `run_in_background: true` in one message** → the seats run
378
+ CONCURRENTLY (background children; wall ≈ single seat); foreground (no
379
+ `run_in_background`) runs serially (wall ≈ 3× single seat) and does NOT count
380
+ as parallel tri. Cannot emit required **N** → **`Blocked`**.
311
381
  - **`inline`**: **N=1**.
312
382
 
313
383
  ### SDD implement (serial)
@@ -316,6 +386,63 @@ MID-turn findings that change what the parent should do next.
316
386
  task reviewer = a separate dispatch (SDD review role) — no sticky resume
317
387
  unless the host's continuable-subagent id is available and recorded.
318
388
 
389
+ ## Read-only fan-out via the `workflow` tool
390
+
391
+ dsh also exposes the upstream **`workflow`** tool
392
+ (`@deepseek-ai/dsh-tool-workflow`, mounted by the shipped agent presets; the
393
+ `ptc` preset disables it in favour of its own orchestration surface). It runs a
394
+ model-written plain-JavaScript script that fans children out inside ONE run; the
395
+ run is recorded as durable `tool-workflow/*` session events and the stock dsh UI
396
+ (`dsh-client-ui-workflow-run`) folds them into one conversation **`workflow-run`**
397
+ node the operator expands by phase and member. Use it for **read-only fan-out of
398
+ N ≥ 3 seats** — plan QC tri, large-repo audit categories, `/amazing-pr-review
399
+ deep` seats — and copy the `script` + `meta` + `args` from this skill →
400
+ `references/dsh-workflow-scripts.md`. For **1–2** delegations keep **`subagent`**
401
+ (the tool's own guidance): the two-seat default tier of `/amazing-pr-review`
402
+ shows two subagent cards and no `workflow-run` node, and that is expected.
403
+
404
+ **Read-only only.** A workflow child is a delegated child (the shipped `spawn`
405
+ provider pins `approval: never` for the whole delegation), and the run has **no
406
+ per-child pre-start veto seam** — so a script is never the channel for writable
407
+ work; writable fan-out stays on `subagent` behind the dispatch and lease gates.
408
+ Seats return findings in their result payload and must never depend on writing
409
+ files — the caller persists the seat reports.
410
+
411
+ **Every `agent()` prompt starts with the Assignment header** — `## Assignment`
412
+ plus `Execute as` / `Delegation` / `Task category` as the first lines:
413
+
414
+ ```markdown
415
+ ## Assignment
416
+
417
+ Execute as: qc-specialist
418
+ Delegation: forbidden
419
+ Task category: audit
420
+ ```
421
+
422
+ Role binding on dsh is prompt-only (there is no `agent` field), and the same
423
+ engine grammar is what the role-persona channel parses
424
+ (`packages/dsh/src/gates/role-persona.ts` reads only the header region) — so
425
+ `Execute as: qc-specialist` resolves the QC role persona for that child. Keep
426
+ body-quoted field examples out of the header region, and never pass the deferred
427
+ `agentType` option: the engine rejects it loudly.
428
+
429
+ | Operator types | N | Tool | `meta.name` | Operator sees |
430
+ |---|---|---|---|---|
431
+ | `/codebase-audit` (large repo) | ≥3 | native `workflow` | `mstar-audit-fanout` | conversation `workflow-run` node |
432
+ | `/amazing-pr-review deep` | ≥3 | native `workflow` | `mstar-pr-seats` | same |
433
+ | `/amazing-pr-review` default tier | 2 | `subagent` | — | two subagent cards, no node (expected) |
434
+ | Plan QC tri (PM already in session, no extra slash) | 3 | native `workflow` | `mstar-qc-tri` | conversation `workflow-run` node |
435
+ | Any 1–2 read-only delegation | 1–2 | `subagent` | — | expected |
436
+
437
+ `meta.name` is the gate identity — keep it kebab-case and on the recommended
438
+ list. With the default Config (`workflowNames` unset) every name is *unknown*,
439
+ which under the default `workflowGate: warn` is one `workflow.name.unknown`
440
+ **advisory that the run survives** — acceptable on a first run, not a failure. A
441
+ production overlay may set `workflowNames: ['mstar-qc-tri', 'mstar-audit-fanout',
442
+ 'mstar-pr-seats']` (and, separately, `workflowGate: hard`); both are operator
443
+ choices, never mstar defaults. The same run also reaches the panel's 事件记录 tab
444
+ through the agent-flow ledger (§ Agent-flow ledger).
445
+
319
446
  ## Commands and skills paths
320
447
 
321
448
  | Surface | Path / invocation |
@@ -104,6 +104,8 @@ In invoke-based hosts (OpenCode / Cursor Task / Codex with callable multi-agent
104
104
 
105
105
  Host invoke/dispatch details: `mstar-host` → active host reference and `references/parallel-dispatch.md`.
106
106
 
107
+ **dsh:** mstar **stops arming** a goal — dsh progress is the native workflow (workflow snapshot phases + dispatch gates + **subagent settle notifications**), never a `/goal` objective or goal round loop. Phase 2 is a PM-local loop (dispatch → wait for the child's settle notification → next dispatch); a dispatched child owning the critical path means **wait**, not a duplicate work unit. Rule → `mstar-host` → `references/dsh.md`.
108
+
107
109
  Dispatch mechanics and templates:
108
110
  `references/project-manager/dispatch-and-assignment.md`.
109
111
 
@@ -94,6 +94,8 @@ Host mapping → **`mstar-host`** references (`model` / Task field).
94
94
  - **Honest non-convergence**: open findings at wave close → list them in detail and state the disposition — re-feed to the next fix round **or** transfer to residual tracking — never silently close.
95
95
  4. QA gate → **`mstar-harness-core`** Done rules; PM **`mstar-roles/references/project-manager/qa-trigger-matrix.md`**
96
96
 
97
+ > **On dsh:** the plan QC tri MAY run through the native **`workflow`** tool instead of three `subagent` dispatches — take the `script` + `meta` (`meta.name: mstar-qc-tri`) from skill **`mstar-host`** → `references/dsh-workflow-scripts.md` (§ `mstar-qc-tri`); the three seats stay read-only and PM persists `{SDD_DIR}/review/qc1.md`…`qc3.md` from their returned envelopes. Per-task implementers stay **serial `subagent`** — the `workflow` channel is read-only fan-out only; when the tool is unmounted (`ptc` preset) dispatch the three seats as background `subagent` calls (skill **`mstar-host`** → `references/dsh.md`).
98
+
97
99
  ## Progress ledger(Evidence)
98
100
 
99
101
  At start: `cat {SDD_DIR}/progress.md`. Tasks marked complete are DONE — do not re-dispatch after compaction.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/dsh",
3
- "version": "3.8.1",
3
+ "version": "3.8.2",
4
4
  "description": "Morning Star harness dsh (DeepSeek Harness) cordis function plugin — in-process engine gates (status/dispatch/lease) with hard refusal channels.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -145,7 +145,7 @@
145
145
  "anser": "^2.3.5",
146
146
  "bun-types": "^1.2.17",
147
147
  "clsx": "^2.0.0",
148
- "dsh-llm-fallbacks": "0.4.1",
148
+ "dsh-llm-fallbacks": "0.5.2",
149
149
  "immer": "^10.1.1",
150
150
  "js-yaml": "^4.1.0",
151
151
  "katex": "^0.16.47",