@mstar-harness/dsh 3.5.1 → 3.6.0-alpha.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.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # Blob hashes (git hash-object) of each side as of the last confirmation that
3
3
  # both languages say the same thing (dsh i18n contract: a pair is three
4
4
  # sibling files; editing either side obligates re-confirming and re-recording).
5
- README.md: eff5613d26d4ca7cae84f6970cae737603ccf73e
6
- README.zh.md: 908af5a5e893f39b8479928adeca722b07d49f0e
5
+ README.md: 0ac2dde792b70de22ca30d83141dd3144a975c72
6
+ README.zh.md: 29ec00188f7e58176dadb85d3688a4f7551dad74
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [中文](README.zh.md)
4
4
 
5
- ![dsh](https://img.shields.io/badge/dsh-0.1.1--rc.2-4B32C3.svg)
5
+ ![dsh](https://img.shields.io/badge/dsh-0.1.2--alpha.2-4B32C3.svg)
6
6
 
7
7
  [Morning Star](https://github.com/btspoony/mstar-harness) as a first-class dsh (DeepSeek Harness) host — a cordis function plugin that mounts the mstar engine in-process, implements the engine `HostAdapter` (`host: 'dsh'`), guards `{HARNESS_DIR}/status.json` writes (validate + advisory; repair-escape under hard), blocks disallowed subagent dispatches when `Enforcement: hard` is on, lints `SKILL.md` writes under the mounted skill roots, mounts the mstar `skills/` mirror through the dsh skill-filesystem provider (single canonical mount), and appends a durable `mstar-engine-status` catalog row to every composed agent step. Boot with a dsh Loader app; everything acts through the seam's refusal/advisory channels, never by patching the tools.
8
8
 
@@ -51,8 +51,8 @@ The **two-command install is the contract** — folding a `dsh-llm-fallbacks` ro
51
51
  | `enforcement` | `'hard' \| 'soft'` | compass, else warn-only | Per-deployment override. Precedence: Config wins; else the Assignment's own `**Enforcement**: hard` header flag (dispatch gate only); else the repo `.mstarc` `[config] enforcement`; else the iteration compass frontmatter; else warn-only. Config / `.mstarc` `soft` are the ONLY local rollbacks — an Assignment-level `soft` does NOT override a hard compass. |
52
52
  | `dispatchTools` | `string[]` | `['subagent', 'subagent_fork']` | Delegation tool names the dispatch gate matches — the dsh preset's TWO delegation tools, `subagent` and its fork sibling `subagent_fork` (both carry Assignment-shaped `{ description, prompt }` args; a `toolName` config may rename instances). |
53
53
  | `dispatchBinding` | `string` | unset → fail-closed `empty-binding` under hard | The dispatching agent's own harness role (the anti-recursion CALLER); an Assignment whose `Execute as` equals it is self-recursion. |
54
- | `roleMap` | `Record<string, string>` | unset | mstar role id (`Execute as`) → dsh-llm-fallbacks role id. A taxonomy bridge for logging + future rule-driven interop ONLY — never consulted by the decoration (see LLM fallbacks integration). |
55
- | `rolePersonas` | `Record<string, string>` | unset (bundled mirror default) | mstar role id (`Execute as`) → persona text; the role-based subagent decoration's **override** source — a role-matched `subagent/start` registers the persona as the child's `mstar:role-persona` system-prompt section; when unset for a role, the bundled `harness-agents/` mirror default is used (see LLM fallbacks integration). |
54
+ | `roleMap` | `Record<string, string>` | unset | mstar role id (`Execute as`) → dsh-llm-fallbacks role id. A taxonomy bridge for logging + future rule-driven interop ONLY — never consulted by the persona channel (see LLM fallbacks integration). |
55
+ | `rolePersonas` | `Record<string, string>` | unset (bundled mirror default) | mstar role id (`Execute as`) → persona text; the native subagent persona channel's **override** source — a role-matched start (one-shot `start` or the opt-in continuable `startContinuable`) merges the persona into the native request `persona` slot (the child embodies the role persona INSTEAD OF the deployment persona; persisted + reapplied on resume); when unset for a role, the bundled `harness-agents/` mirror default is used (see LLM fallbacks integration). |
56
56
  | `skillRoots` | `string[]` | unset (no custom-root registration) | Additional skill roots registered with the dsh skill-filesystem provider (`customSkillDirs` semantics — scanned before user roots). Dev-time: the mirror `<repo-root>/skills` absolute path. |
57
57
  | `bundledSkillDir` | `string` | packaged `harness-skills/` mirror (package-relative) | Bundled skill root registered with the dsh skill-filesystem provider (`bundledSkillDir` semantics — scanned last, trusted). Defaults to the package's OWN `harness-skills/` mirror (synced by `bundle-assets`; gitignored) — package-relative, NOT cwd-anchored. An explicit value wins. |
58
58
  | `catalogTtlMs` | `number` | `60000` | Pre-step catalog cache refresh interval (ms): how often the per-workspace unified `mstar-engine-status` catalog row (watermark + iteration gate + workspace-state digest) re-reads `status.json` / the compass / the knowledge index. The hot path is a timestamp compare + cache hit between refreshes; a mid-session plan/compass/residual change lands within one interval. |
@@ -133,7 +133,7 @@ A `tools/pre-execute` branch (BEFORE the subagent prompt branch) gates the **`wo
133
133
 
134
134
  ## LLM fallbacks integration
135
135
 
136
- The optional `dsh-llm-fallbacks` plugin (installed with the second command — see Install paths) powers **role-based subagent configuration**: a role-matched subagent dispatch injects the configured persona into the child session's system prompt. The mstar plugin declares it as a registry `dependencies` entry and imports it **type-only** — `dist/` carries **no bundled runtime import** of the package (only three string literals naming it the probe's loader-entry match and the two decoration log lines never an import; `--external dsh-llm-fallbacks` in the build stays as the guard for any future library-form import); the interop is a decision-point **capability probe**, never a module-internals read.
136
+ The optional `dsh-llm-fallbacks` plugin (installed with the second command — see Install paths) powers **role-based subagent configuration** the role seeds and the adoption advisory; role persona delivery itself rides dsh's NATIVE subagent persona channel (independent of fallbacks, see below). The mstar plugin carries **zero runtime AND zero type references** to the package — `src/` has no import of it (runtime or type); the consumed service surface is mirrored by the local structural types in `src/gates/fallbacks-structural.ts`, and the package itself is a **dev-time-only dependency** of the mstar plugin (type mirroring + the real-package test harness). `dist/` names the package only in ONE string literal the probe's loader-entry match — never an import or a type reference; the interop is a decision-point **capability probe**, never a module-internals read.
137
137
 
138
138
  ### Capability probe
139
139
 
@@ -144,15 +144,13 @@ Two views over the mounted state (point-in-time reads at decision points, no cac
144
144
 
145
145
  Distinct states: **mounted** (service applied — full capability), **unmounted** (no entry: the fallbacks plugin was not installed — the mstar capability degrades, never breaks), **disabled** (entry present but disabled/grouped — capability off), and the HMR window (entry lives, service absent — the loader fallback covers it).
146
146
 
147
- ### Role-based decoration
147
+ ### Role persona delivery (native subagent persona channel)
148
148
 
149
- Decoration rides the `subagent/start` EMIT not `tools/pre-execute` (tool args are deep-frozen snapshots; persona/`agentOptions` come from tool-subagent's own Config, never call args). The synchronous listener resolves the published child via `ctx.get('agents')?.get(info.id)` and, when the child's seeded task prompt is Assignment-shaped, registers the persona as the child's **agent-scoped `mstar:role-persona` system-prompt section** (order 1 right after the deployment persona slot; unwinds on child disposal). Role identity uses the SAME engine Assignment header grammar as the dispatch gate. Persona lookup is the single `personaFor` chain — `rolePersonas[executeAs]` → bundled mirror default → skip — **never gated on `roleMap` or on the fallbacks mounted state**.
149
+ Persona delivery rides dsh's NATIVE `SubagentStartRequest.persona` slot (`@deepseek-ai/dsh-subagent`): the plugin intercepts the `ctx.subagents` service READ through the cordis `internal/get` waterfall the framework's documented service-read interception hook and wraps the runtime value so a role-matched start merges the persona into the request BEFORE the child is composed — on BOTH start surfaces: the one-shot `start` AND the opt-in continuable `startContinuable` (tool-subagent `backgroundMode: 'continuable'`; its `ContinuableStartSpec.request` carries the same `persona` slot). The underlying `SubagentRuntime` object is never mutated (no monkey-patching), and the wrapping listener is fiber-scoped (an HMR re-apply unwinds and restores it, re-binding the fresh Config). Native semantics (dsh `0.1.2-alpha.2`): the request persona registers the scoped `deployment:persona` section (order 0) on the child, SHADOWING the deployment persona for that child alone — the child EMBODIES the role persona instead of coexisting with it — is persisted in the child descriptor, and is reapplied on resume. Role identity uses the SAME engine Assignment header grammar as the dispatch gate. Persona lookup is the single `personaFor` chain — `rolePersonas[executeAs]` → bundled mirror default → skip — **never gated on `roleMap` or on the fallbacks mounted state** (persona delivery is fallbacks-independent). An explicit request persona (tool-subagent's own `Config.persona`) wins over the role persona — caller intent is never overridden.
150
150
 
151
- **Zero-config defaults**: when `rolePersonas` has no entry for a role, the persona comes from the bundled `harness-agents/` mirror the repo-root `agents/` shells synced by `bundle-assets` at build (shipped in the published tarball; package-relative resolution, so the bundle works from any launch cwd). The shell file stem is the role id; the default is its frontmatter `description` block scalar. A shell is eligible when its frontmatter `mode` is absent or `subagent` the `primary` shell (`project-manager`) is never offered as a subagent persona default. A default whose description carries the interpolation hazard (`{{` paired with a later `}}`) is warned + skipped at extraction (never a boot throw); a shell edit (mtime change) re-extracts on the next decision-point read. With the mirror absent (`bundle-assets` not run) lookups are config-only, and a config miss logs one debug per apply.
152
-
153
- **Unmounted degradation is same-channel + one debug log**: no fallbacks entry → the persona is still injected through the identical decoration channel (from the mstar Config or the harness-agents mirror default), with exactly one source-aware debug log; mounted → one info-level interop log carrying the service version. The listener never throws — `agents` service absent, child unresolvable, non-Assignment or role-unmatched prompts are skip/no-op (the dispatch itself is never affected).
151
+ **Capability gate (per surface)**: one-shot `SubagentRuntime.start` REJECTS a persona request for a provider without the native `persona` capability (fail loud, no silent degradation out-of-process providers ship without it), so the channel checks `getProvider(name).capabilities.persona` FIRST on that surface. The continuable surface is gated by the NATIVE continuable contract instead `SubagentCapabilities` is documented as ONE-SHOT-scoped and continuable children are composed by the continuation manager itself, gated by `provider.prepareContinuable`; the channel checks that, skipping the merge for providers without continuable support (the native start fails loud on its own the persona is never logged as delivered for a start that would reject). Either way the merge is skipped with one contained debug log and the start proceeds unchanged never a failed dispatch.
154
152
 
155
- **Persona text constraints**: dsh system-prompt renders persona text with STRICT `{{variable}}` interpolation, so persona values MUST NOT contain `{{` paired with a later `}}` (the renderer throws on unknown/malformed references at child prompt assembly breaking every role-matched dispatch). The Config schema rejects such `rolePersonas` values at plugin mount with a clear error. A lone `{{` with no later `}}` renders as literal prose; the escape rule is single braces or rewording. Keep persona text concise (a few sentences); bound its length at deployment.
153
+ **Zero-config defaults**: when `rolePersonas` has no entry for a role, the persona comes from the bundled `harness-agents/` mirror the repo-root `agents/` shells synced by `bundle-assets` at build (shipped in the published tarball; package-relative resolution, so the bundle works from any launch cwd). The shell file stem is the role id; the default is its frontmatter `description` block scalar. A shell is eligible when its frontmatter `mode` is absent or `subagent` — the `primary` shell (`project-manager`) is never offered as a subagent persona default. A default whose description carries the interpolation hazard (`{{` paired with a later `}}`) is warned + skipped at extraction (never a boot throw); a shell edit (mtime change) re-extracts on the next decision-point read. With the mirror absent (`bundle-assets` not run) lookups are config-only, and a config miss logs one debug per apply.
156
154
 
157
155
  ### Role seeds + adoption advisory
158
156
 
@@ -172,8 +170,8 @@ On the loader-fallback path (no service) the structural `roles.list` read is pre
172
170
 
173
171
  | Key | Type | Default | Meaning |
174
172
  | --- | --- | --- | --- |
175
- | `roleMap` | `Record<string, string>` | unset | mstar role id → fallbacks role id. **Taxonomy bridge** for logging + future rule-driven interop only — unused in decoration by design (persona injection is `rolePersonas`/mirror-sourced). |
176
- | `rolePersonas` | `Record<string, string>` | unset (bundled mirror default) | mstar role id → persona text; the decoration's **override** source — a mirror default is used when a role has no entry. |
173
+ | `roleMap` | `Record<string, string>` | unset | mstar role id → fallbacks role id. **Taxonomy bridge** for logging + future rule-driven interop only — unused by the persona channel by design (persona delivery is `rolePersonas`/mirror-sourced). |
174
+ | `rolePersonas` | `Record<string, string>` | unset (bundled mirror default) | mstar role id → persona text; the persona channel's **override** source — a mirror default is used when a role has no entry. |
177
175
 
178
176
  ## Service
179
177
 
@@ -504,7 +502,7 @@ closed and archived 2026-08-10.
504
502
 
505
503
  ## Development
506
504
 
507
- Commands (from `packages/dsh`): the coverage gate is per-file 100% on `src/` (dsh testing policy); the build bun-bundles the src entries into `dist/` (engine + schemastery inlined; `@deepseek-ai/cordis` and the runtime seam imports — `@deepseek-ai/dsh-skill-filesystem`, `@deepseek-ai/dsh-tools` (`defineTool`), `@deepseek-ai/dsh-llm` — external, plus the type-only `dsh-llm-fallbacks`), runs `build-client` (`scripts/build-client-bundle.ts` — the closure-factory CJS browser bundle per spec §6.2, `dist/client.js`) and emits tsc declarations.
505
+ Commands (from `packages/dsh`): the coverage gate is per-file 100% on `src/` (dsh testing policy); the build bun-bundles the src entries into `dist/` (engine + schemastery inlined; `@deepseek-ai/cordis` and the runtime seam imports — `@deepseek-ai/dsh-skill-filesystem`, `@deepseek-ai/dsh-tools` (`defineTool`), `@deepseek-ai/dsh-llm` — external), runs `build-client` (`scripts/build-client-bundle.ts` — the closure-factory CJS browser bundle per spec §6.2, `dist/client.js`) and emits tsc declarations.
508
506
 
509
507
  ```sh
510
508
  bun test --coverage
@@ -558,13 +556,13 @@ The catalog row is appended at the END of the composed step messages, after dele
558
556
  - **Profile-bundle install into the `web` profile: registry and local checkout** — `dsh plugin --profile web add @mstar-harness/dsh` (registry) and `add <local checkout>` are the supported paths; both run through the same pnpm + reconcile mechanism (the reconcile step joins `@mstar-harness/dsh` to `dsh.profile.bundles`). A local checkout needs a prior `bun run build` — the package has no `prepare` script (the monorepo builds packages explicitly), so an unbuilt checkout installs an empty `dist/`.
559
557
  - **`lintSkillWrite` typed veto not production-wired** — the incoming-document hard veto (`SkillLintVetoError`, code `skill-lint.veto`) is exported and test-covered, but has no production caller yet: the engine `HostAdapter` has no content-carrying skill-write hook (only `beforeStatusWrite`/`beforeDispatch`/`beforeMerge`), and the fs intent slot is content-blind. Wiring lands with a future content-carrying hook; until then the listener path enforces only via the repair-escape advisory (never a veto).
560
558
  - **CLI `HOST_SIGNALS` lacks the `subagent` token** — the engine `ToolSignal` union includes it and `detectHost` handles it, but `packages/cli` `HOST_SIGNALS` is not updated yet, so `mstar host detect --signals subagent` would reject until the CLI list is updated on upstreaming.
561
- - **Entry is a module index over `src/gates/*`** — the split shipped: `src/index.ts` (371 lines) re-exports the frozen 47-name export surface (28 value + 19 type-only names; `Config` counts once) from the gate modules (`_shared` / `status` / `skill-lint` / `seams` / `dispatch` / `catalog` / `tools` / `adapter`) and keeps the plugin manifest, the single cordis augmentation point, the command registration, and the `apply()` startup wiring. The surface is frozen by `tests/export-surface.spec.ts` — the runtime value-export set plus, under `typecheck:tests` (`bunx tsc --noEmit -p tests/tsconfig.json`), the value-namespace identity and the per-name type-only probes.
559
+ - **Entry is a module index over `src/gates/*`** — the split shipped: `src/index.ts` re-exports the frozen 56-name export surface (31 value + 25 type-only names; `Config` counts once) from the gate modules (`_shared` / `status` / `skill-lint` / `seams` / `dispatch` / `catalog` / `tools` / `adapter`) and keeps the plugin manifest, the single cordis augmentation point, the command registration, and the `apply()` startup wiring. The surface is frozen by `tests/export-surface.spec.ts` — the runtime value-export set plus, under `typecheck:tests` (`bunx tsc --noEmit -p tests/tsconfig.json`), the value-namespace identity and the per-name type-only probes.
562
560
  - **Engine dsh rows are upstreaming-destined** — the dsh changes to engine `host.ts` (`DetectResult`, `ToolSignal`, `resolveSkillRoot`) live in the mstar-workflow engine mirror and are intended for a user-authorized upstream PR into mstar-harness; the `mstar-host` skill mirror (§ Detect / § Resolve loaded skill root / `references/dsh.md`) updates with it.
563
561
  - **Iteration stepper: Step 1 is compass-driven, Step 5 is schema-driven** — the zone dashboard's Step 1 (iteration-start) is the current step while the steering compass is `status: active` (Phase 1 in flight — no gate verdict, so no PASS/FAIL badge); Step 5 (merge-ready) is a schema constant the engine gate never lights as current (transition covers Phase 2→3→4 only), so it always renders idle — recorded in the iteration guide, not a defect. The full panel-limitation list lives in the Web client plugin section.
564
- - **`dsh-llm-fallbacks` is a registry `dependencies` entry with type-only imports**caret range lives in `package.json` (the probe shape-assertion test is the executable drift gate) and `--external` in the build, so `dist/` carries no bundled runtime import (only three string literals naming the package — the probe's loader-entry match and the two decoration log lines; the advisory logs say `fallbacks`); activation is a SEPARATE explicit install (two-command contract), never transitive. The library-form dependency exists so future value imports resolve without a manifest change; `--external` remains the guard.
562
+ - **`dsh-llm-fallbacks` is an optional dev-time-only dependency** — dsh `0.1.2-alpha.2` natively covers subagent customization, so fallbacks is strictly optional: `src/` carries zero imports of it (runtime and type the consumed surface is the local structural mirror `fallbacks-structural.ts`, kept in sync by the probe's exact-keys drift gate plus the `typecheck:tests` real → view assignability check), `package.json` carries it only under `devDependencies` (type mirroring + the real-package test harness), and `dist/` carries no import and no type reference (only ONE string literal naming the package — the probe's loader-entry match; the advisory logs say `fallbacks`). Activation is a SEPARATE explicit install (two-command contract), never transitive; there is no `--external` guard anymore — a future value import must re-add a runtime dependency by design.
565
563
  - **Role→model override NOT delivered this batch** — routing a role to a fallbacks `model` (or persona via fallbacks rules) would require rewriting the child's `agentOptions` on the start request, but start-request options are caller-controlled (tool-subagent's own Config; call args are `description`/`prompt`/`run_in_background` only, deep-frozen). Awaits upstream `fallbacks-explicit-role-tool` or the N-B1 systemPrompt adoption (roadmap §10.4).
566
- - **Decoration is a minimal per-child section, not the N-B1 systemPrompt adoption** `mstar:role-persona` is one agent-scoped section on the child's context; no harness-rules sections, no PromptContext, no variables. N-B1 (roadmap §10.4) may absorb or replace this channel later without changing the observable (AC-3).
567
- - **Persona injection is fallbacks-independent** — `dsh-llm-fallbacks` only routes LLM failures; it is never required for decoration. Unmounted → the same persona lands from the mstar Config through the same channel with one debug log (AC-4). If `ctx.get('agents')` is absent in a composition (no dsh-agent), decoration is skipped with one debug log.
564
+ - **Persona delivery is dsh-native no additive section** the role persona merges into `SubagentStartRequest.persona` (one-shot `start` AND the opt-in continuable `startContinuable`) and SHADOWS the deployment persona for role-matched children (child embodies the role; persisted + reapplied on resume). There is NO `mstar:role-persona` system-prompt section anymore (plan 20260831-dsh-alpha2-optional-fallbacks).
565
+ - **Persona injection is fallbacks-independent** — `dsh-llm-fallbacks` only routes LLM failures; it is never required for persona delivery. Unmounted → the same persona lands via the native channel with the single delivery debug log (AC-4). One-shot starts for providers without the native `persona` capability (out-of-process) skip the persona with one contained debug log; continuable starts for providers without `prepareContinuable` skip it the same way (the native start fails loud on its own) the start is never failed by the channel for either.
568
566
  - **Fork gating is default-only; explicit `dispatchTools` can omit `subagent_fork`** — a custom `dispatchTools` list overrides the default wholesale (pre-existing rename pattern), so a deployment that declares its own list must include `subagent_fork` to keep fork dispatches gated.
569
567
  - **Persona values must not contain `{{...}}`** — dsh system-prompt renders persona text with strict `{{variable}}` interpolation and throws on a `{{` paired with a later `}}` (unknown/malformed/undefined reference), which would break child prompt assembly for every role-matched dispatch. The Config schema rejects such `rolePersonas` values at plugin mount with a clear error; the escape rule is single braces or rewording (a lone `{{` with no later `}}` renders as literal prose).
570
568
  - **Seed re-convergence after a fallbacks HMR re-mount is bounded by the seeded-only preservation design** — the seed registry is per-apply in-memory state, so a fiber swap (HMR / settings edit) drops it and both declarers re-declare from scratch. The mstar re-declare merge-preserves ONLY ids that are already seeded (seeded-only by design), so in the preset-last commit ordering the preset rows' seeded annotations are not restored by the re-declare — they recover at the NEXT fallbacks apply (the upstream preset self-declare re-seeds them). The advisory one-shot latch re-arms when the `llm-fallbacks` service disappears (an inject teardown), so the next decision point re-converges the mstar side; the preset side is a documented transient of the seeded-only preservation design.
package/README.zh.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | 中文
4
4
 
5
- ![dsh](https://img.shields.io/badge/dsh-0.1.1--rc.2-4B32C3.svg)
5
+ ![dsh](https://img.shields.io/badge/dsh-0.1.2--alpha.2-4B32C3.svg)
6
6
 
7
7
  让 [Morning Star](https://github.com/btspoony/mstar-harness) 成为一等公民的 dsh(DeepSeek Harness)宿主——一个 cordis 函数插件,将 mstar engine 进程内挂载,实现 engine `HostAdapter`(`host: 'dsh'`),守护 `{HARNESS_DIR}/status.json` 写入(校验 + 咨询;hard 下按修复逃生放行),在 `Enforcement: hard` 开启时阻止被禁止的 subagent 派发,对挂载技能根下的 `SKILL.md` 写入执行技能撰写 lint,通过 dsh skill-filesystem 提供者挂载 mstar `skills/` 镜像(单一规范挂载),并向每个组合后的 agent 步骤追加一条持久化的 `mstar-engine-status` catalog 行。随 dsh Loader 应用启动;一切均通过 seam 的拒绝/咨询通道行使职责,从不改动工具本身。
8
8
 
@@ -51,8 +51,8 @@ dsh plugin --profile web add dsh-llm-fallbacks
51
51
  | `enforcement` | `'hard' \| 'soft'` | compass,否则仅告警 | 按部署覆盖。优先级:Config 优先;否则取 Assignment 自身的 `**Enforcement**: hard` 头字段(仅派发闸门);否则取仓库 `.mstarc` `[config] enforcement`;否则取迭代 compass frontmatter;否则仅告警。Config / `.mstarc` `soft` 是仅有的本地回滚——Assignment 级 `soft` 不能覆盖 hard compass。 |
52
52
  | `dispatchTools` | `string[]` | `['subagent', 'subagent_fork']` | 派发闸门匹配的委派工具名——dsh preset 的**两个**委派工具:`subagent` 及其 fork 兄弟 `subagent_fork`(两者都携带 Assignment 形态的 `{ description, prompt }` 参数;`toolName` 配置可重命名实例)。 |
53
53
  | `dispatchBinding` | `string` | 未设置 → hard 下 fail-closed `empty-binding` | 派发方 agent 自身的 harness 角色(反递归 caller);Assignment 的 `Execute as` 等于它即自我递归。 |
54
- | `roleMap` | `Record<string, string>` | 未设置 | mstar 角色 id(`Execute as`)→ dsh-llm-fallbacks 角色 id。**仅**作日志与未来规则驱动互操作的分类桥——装饰从不读取它(见 LLM fallbacks integration)。 |
55
- | `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id(`Execute as`)→ persona 文本;基于角色的 subagent 装饰的**覆盖**来源——角色匹配的 `subagent/start` 会把 persona 注册为子会话的 `mstar:role-persona` system-prompt 段;某角色未设置时使用打包的 `harness-agents/` 镜像默认值(见 LLM fallbacks integration)。 |
54
+ | `roleMap` | `Record<string, string>` | 未设置 | mstar 角色 id(`Execute as`)→ dsh-llm-fallbacks 角色 id。**仅**作日志与未来规则驱动互操作的分类桥——persona 通道从不读取它(见 LLM fallbacks integration)。 |
55
+ | `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id(`Execute as`)→ persona 文本;原生 subagent persona 通道的**覆盖**来源——角色匹配的 start(一次性 `start` 或可选的 continuable `startContinuable`)会把 persona 合入原生请求的 `persona` 槽(子会话体现角色 persona 而**非**部署 persona;持久化并在 resume 时重放);某角色未设置时使用打包的 `harness-agents/` 镜像默认值(见 LLM fallbacks integration)。 |
56
56
  | `skillRoots` | `string[]` | 未设置(不注册自定义根) | 向 dsh skill-filesystem 提供者注册的额外技能根(`customSkillDirs` 语义——先于用户根扫描)。开发期:镜像 `<repo-root>/skills` 的绝对路径。 |
57
57
  | `bundledSkillDir` | `string` | 打包的 `harness-skills/` 镜像(包相对路径) | 向 dsh skill-filesystem 提供者注册的打包技能根(`bundledSkillDir` 语义——最后扫描、受信任)。默认取包内自带的 `harness-skills/` 镜像(`bundle-assets` 同步;gitignore)——包相对路径,**非** cwd 锚定。显式值优先。 |
58
58
  | `catalogTtlMs` | `number` | `60000` | pre-step catalog 缓存刷新间隔(毫秒):按工作区缓存的统一 `mstar-engine-status` 行(水印 + 迭代闸门 + 工作区摘要)多久重读一次 `status.json` / compass / 知识索引。刷新间隔之间热路径只是时间戳比较 + Map 命中;会话中 plan/compass/residual 的变化会在一个间隔内落地。 |
@@ -133,7 +133,7 @@ profile bundle 组合出以下行——注册表行来自 `@deepseek-ai/dsh-base
133
133
 
134
134
  ## LLM fallbacks integration
135
135
 
136
- 可选的 `dsh-llm-fallbacks` 插件(以第二条命令安装——见 Install paths)驱动**基于角色的 subagent 配置**:角色匹配的 subagent 派发会把配置的 persona 注入子会话的 system prompt。mstar 插件将其声明为 registry `dependencies` 条目并**仅作类型导入**——`dist/` 对该包**无打包运行时导入**(仅 3 处命名该包的字符串字面量——探测的 loader 条目匹配与两条装饰日志——绝非导入;构建中的 `--external dsh-llm-fallbacks` 仍是对未来库形态导入的护栏);互操作是决策点**能力探测**,绝不读取其他插件的模块内部。
136
+ 可选的 `dsh-llm-fallbacks` 插件(以第二条命令安装——见 Install paths)驱动**基于角色的 subagent 配置**——角色种子与采纳建议;角色 persona 交付本身走 dsh 原生 subagent persona 通道(与 fallbacks 无关,见下文)。mstar 插件对该包携带**零运行时与零类型引用**——`src/` 无任何导入(运行时或类型);被消费的服务面由 `src/gates/fallbacks-structural.ts` 的本地结构类型镜像,该包仅是 mstar 插件的**开发期依赖**(类型镜像 + 真实包测试 harness)。`dist/` 仅在 1 处字符串字面量中命名该包——探测的 loader 条目匹配——绝非导入或类型引用;互操作是决策点**能力探测**,绝不读取其他插件的模块内部。
137
137
 
138
138
  ### 能力探测
139
139
 
@@ -144,15 +144,13 @@ profile bundle 组合出以下行——注册表行来自 `@deepseek-ai/dsh-base
144
144
 
145
145
  状态区分:**mounted**(服务已 apply——完整能力)、**unmounted**(无条目:未安装 fallbacks 插件——mstar 能力降级,绝不中断)、**disabled**(条目存在但禁用/分组——能力关闭),以及 HMR 窗口(条目在、服务缺——loader 回退覆盖)。
146
146
 
147
- ### 基于角色的装饰
147
+ ### 角色 persona 交付(原生 subagent persona 通道)
148
148
 
149
- 装饰挂在 `subagent/start` EMIT 上——而非 `tools/pre-execute`(工具参数是深度冻结快照;persona/`agentOptions` 来自 tool-subagent 自己的 Config,绝不来自调用参数)。同步监听器经 `ctx.get('agents')?.get(info.id)` 解析已发布的子会话,当子会话的种子任务提示为 Assignment 形态时,把 persona 注册为子会话的 **agent 作用域 `mstar:role-persona` system-prompt 段**(order 1——紧随部署 persona 槽之后;子会话销毁时自动卸载)。角色身份使用与派发闸门**相同**的 engine Assignment 头语法。persona 查找是单一 `personaFor` 链——`rolePersonas[executeAs]` → 打包镜像默认值跳过——**绝不**以 `roleMap` 或 fallbacks 挂载状态为前提。
149
+ persona 交付走 dsh 原生的 `SubagentStartRequest.persona` 槽(`@deepseek-ai/dsh-subagent`):插件经 cordis `internal/get` waterfall——框架文档化的服务读取拦截钩子——拦截 `ctx.subagents` 的服务读取并包装运行时值,使角色匹配的 start 在子会话组装之前把 persona 合入请求——**同时覆盖两个启动面**:一次性 `start` 与可选的 continuable `startContinuable`(tool-subagent `backgroundMode: 'continuable'`;其 `ContinuableStartSpec.request` 携带同一个 `persona` 槽)。底层 `SubagentRuntime` 对象绝不被改动(无 monkey-patching),包装监听器归 apply fiber 所有(HMR 重挂载会先卸载再恢复,并重新绑定新 Config)。原生语义(dsh `0.1.2-alpha.2`):请求 persona 会以作用域化的 `deployment:persona` 段(order 0)注册到子会话上,对该子会话**遮蔽**部署 persona——子会话**体现**角色 persona 而非与其共存——并持久化进子会话描述符、在 resume 时重放。角色身份使用与派发闸门相同的 engine Assignment 头语法。persona 查找是单一 `personaFor` 链——`rolePersonas[executeAs]` → 打包镜像默认跳过——**从不以 `roleMap` 或 fallbacks 挂载状态为前提**(persona 交付与 fallbacks 无关)。显式的请求 persona(tool-subagent 自身的 `Config.persona`)优先于角色 persona——绝不覆盖调用方意图。
150
150
 
151
- **零配置默认值**:当 `rolePersonas` 未为某角色配置条目时,persona 取自打包的 `harness-agents/` 镜像——构建时由 `bundle-assets` 从仓库根 `agents/` 同步(随发布 tarball 携带;包相对路径解析,任意启动 cwd 均可用)。镜像文件名主干即角色 id;默认值为其 frontmatter `description` 块标量。镜像 shell 在 frontmatter `mode` 缺失或为 `subagent` 时才有资格——`primary` shell(`project-manager`)绝不作为 subagent persona 默认值。默认值 description 若含插值风险(配对的 `{{`/`}}`)则在提取时告警并跳过(绝非启动抛错);shell 改动(mtime 变化)会在下一次决策点读取时重新提取。镜像缺失(未运行 `bundle-assets`)时查找仅走配置,配置也未命中时每次 apply 记一条 debug。
152
-
153
- **未挂载的降级为同通道 + 一条 debug 日志**:无 fallbacks 条目 → persona 仍经完全相同的装饰通道注入(来自 mstar Config 或 harness-agents 镜像默认值),仅多一条来源可辨的 debug 日志;已挂载 → 一条携带服务版本的 info 级互操作日志。监听器绝不抛出——`agents` 服务缺失、子会话无法解析、非 Assignment 或角色未匹配的提示均跳过/无操作(派发本身永不受影响)。
151
+ **能力闸门(按启动面)**:一次性 `SubagentRuntime.start` 会对不具备原生 `persona` 能力的提供者直接拒绝 persona 请求(fail loud、绝不静默降级——进程外提供者即无此能力),因此该启动面通道先检查 `getProvider(name).capabilities.persona`。continuable 启动面改按**原生 continuable 契约**闸门——`SubagentCapabilities` 文档仅限一次性路径,continuable 子会话由延续管理器自行组装、以 `provider.prepareContinuable` 为闸门;通道检查该字段,对不支持 continuable 的提供者跳过合并(原生 start 会自行 fail loud——绝不会在会被拒绝的 start 上把 persona 记为已交付)。两种情况都以一条受控 debug 日志跳过合并、启动原样继续——通道绝不因此使派发失败。
154
152
 
155
- **persona 文本约束**:dsh system-prompt 以**严格 `{{variable}}` 插值**渲染 persona 文本,因此 persona 值**绝不能**包含与后文 `}}` 配对的 `{{`(渲染器在子会话提示组装时对未知/畸形引用直接抛错——会破坏每一次角色匹配的派发)。Config schema 会在插件挂载时以清晰报错拒绝此类 `rolePersonas` 值。不带后续 `}}` 的孤立 `{{` 按字面散文渲染(安全);转义规则是改用单花括号或改写措辞。persona 文本保持简短(几句话);长度在部署侧设限。
153
+ **零配置默认值**:当 `rolePersonas` 未为某角色配置条目时,persona 取自打包的 `harness-agents/` 镜像——构建时由 `bundle-assets` 从仓库根 `agents/` 同步(随发布 tarball 携带;包相对路径解析,任意启动 cwd 均可用)。镜像文件名主干即角色 id;默认值为其 frontmatter `description` 块标量。镜像 shell frontmatter `mode` 缺失或为 `subagent` 时才有资格——`primary` shell(`project-manager`)绝不作为 subagent persona 默认值。默认值 description 若含插值风险(配对的 `{{`/`}}`)则在提取时告警并跳过(绝非启动抛错);shell 改动(mtime 变化)会在下一次决策点读取时重新提取。镜像缺失(未运行 `bundle-assets`)时查找仅走配置,配置也未命中时每次 apply 记一条 debug。
156
154
 
157
155
  ### 角色 seeds 与采纳建议(Adoption advisory)
158
156
 
@@ -172,8 +170,8 @@ loader 回退路径(无服务)保留结构化 `roles.list` 读取(缺失 i
172
170
 
173
171
  | Key | Type | Default | Meaning |
174
172
  | --- | --- | --- | --- |
175
- | `roleMap` | `Record<string, string>` | 未设置 | mstar 角色 id → fallbacks 角色 id。**仅**作日志与未来规则驱动互操作的分类桥——装饰按设计不使用(persona 注入以 `rolePersonas`/镜像为源)。 |
176
- | `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id → persona 文本;装饰的**覆盖**来源——某角色无条目时使用镜像默认值。 |
173
+ | `roleMap` | `Record<string, string>` | 未设置 | mstar 角色 id → fallbacks 角色 id。**仅**作日志与未来规则驱动互操作的分类桥——persona 通道按设计不使用(persona 交付以 `rolePersonas`/镜像为源)。 |
174
+ | `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id → persona 文本;persona 通道的**覆盖**来源——某角色无条目时使用镜像默认值。 |
177
175
 
178
176
  ## Service
179
177
 
@@ -280,7 +278,7 @@ dsh web # 启动 → 服务 /plugins/@mstar-harness/dsh/clie
280
278
 
281
279
  ## Development
282
280
 
283
- 命令(在 `packages/dsh` 下执行):覆盖率门禁为 `src/` 逐文件 100%(dsh 测试策略);构建命令把 src 条目 bun 打包进 `dist/`(内联 engine 与 schemastery;`@deepseek-ai/cordis` 与运行时 seam 导入——`@deepseek-ai/dsh-skill-filesystem`、`@deepseek-ai/dsh-tools`(`defineTool`)、`@deepseek-ai/dsh-llm`——保持外部,外加仅类型导入的 `dsh-llm-fallbacks`),运行 `build-client`(`scripts/build-client-bundle.ts`——按 spec §6.2 产出的 closure-factory CJS 浏览器 bundle `dist/client.js`)并输出 tsc 声明。
281
+ 命令(在 `packages/dsh` 下执行):覆盖率门禁为 `src/` 逐文件 100%(dsh 测试策略);构建命令把 src 条目 bun 打包进 `dist/`(内联 engine 与 schemastery;`@deepseek-ai/cordis` 与运行时 seam 导入——`@deepseek-ai/dsh-skill-filesystem`、`@deepseek-ai/dsh-tools`(`defineTool`)、`@deepseek-ai/dsh-llm`——保持外部),运行 `build-client`(`scripts/build-client-bundle.ts`——按 spec §6.2 产出的 closure-factory CJS 浏览器 bundle `dist/client.js`)并输出 tsc 声明。
284
282
 
285
283
  ```sh
286
284
  bun test --coverage
@@ -331,13 +329,13 @@ catalog 行在委托之后追加到组合步骤消息的**末尾**——请求
331
329
  - **profile-bundle 安装到 `web` profile:registry 与 local checkout**——`dsh plugin --profile web add @mstar-harness/dsh`(registry)与 `add <本地检出>` 为受支持途径,均走同一 pnpm + reconcile 机制(reconcile 步骤把 `@mstar-harness/dsh` 并入 `dsh.profile.bundles`)。local checkout 需要先执行 `bun run build`——本包没有 `prepare` 脚本(monorepo 显式构建各包),未构建的检出会装入空的 `dist/`。
332
330
  - **`lintSkillWrite` 类型化否决尚未接入生产**——传入文档分支的 hard 否决(`SkillLintVetoError`,码 `skill-lint.veto`)已导出并测试覆盖,但尚无生产调用方:engine `HostAdapter` 没有携带内容的技能写入钩子(只有 `beforeStatusWrite`/`beforeDispatch`/`beforeMerge`),且 fs intent 槽位内容盲。接线随未来携带内容的钩子落地;在此之前监听器路径只通过修复逃生咨询执行(从不否决)。
333
331
  - **CLI `HOST_SIGNALS` 缺少 `subagent` token**——engine `ToolSignal` 联合已包含它且 `detectHost` 能处理,但 `packages/cli` 的 `HOST_SIGNALS` 尚未更新,`mstar host detect --signals subagent` 会拒绝,直到上游化时更新 CLI 列表。
334
- - **入口是 `src/gates/*` 之上的模块索引**——拆分已交付:`src/index.ts`(371 行)从各 gate 模块(`_shared` / `status` / `skill-lint` / `seams` / `dispatch` / `catalog` / `tools` / `adapter`)原样 re-export 冻结的 47 名导出面(28 值导出 + 19 type-only 名;`Config` 计一次),并保留插件 manifest、单一 cordis augmentation 点、命令注册与 `apply()` 启动接线。导出面由 `tests/export-surface.spec.ts` 冻结——运行时值导出集 + `typecheck:tests`(`bunx tsc --noEmit -p tests/tsconfig.json`)下的值命名空间恒等与逐名类型探测。
332
+ - **入口是 `src/gates/*` 之上的模块索引**——拆分已交付:`src/index.ts` 从各 gate 模块(`_shared` / `status` / `skill-lint` / `seams` / `dispatch` / `catalog` / `tools` / `adapter`)原样 re-export 冻结的 56 名导出面(31 值导出 + 25 type-only 名;`Config` 计一次),并保留插件 manifest、单一 cordis augmentation 点、命令注册与 `apply()` 启动接线。导出面由 `tests/export-surface.spec.ts` 冻结——运行时值导出集 + `typecheck:tests`(`bunx tsc --noEmit -p tests/tsconfig.json`)下的值命名空间恒等与逐名类型探测。
335
333
  - **engine dsh 行待上游化**——engine `host.ts` 的 dsh 改动(`DetectResult`、`ToolSignal`、`resolveSkillRoot`)位于 mstar-workflow engine 镜像,计划经用户授权的上游 PR 合入 mstar-harness;`mstar-host` 技能镜像(§ Detect / § Resolve loaded skill root / `references/dsh.md`)随之一并更新。
336
334
  - **迭代 stepper:Step 1 为 compass 驱动,Step 5 为 schema 驱动**——zone dashboard 的 Step 1(iteration-start)在 steering compass `status: active`(Phase 1 进行中)时为当前步(无 gate 判定 → 无 PASS/FAIL 徽标);Step 5(merge-ready)是 engine 闸门永不点亮为当前的 schema 常量(transition 只覆盖 Phase 2→3→4,merge-ready 从不是 gate transition);仅当 Step 4 为当前步时作为 `next` 渲染,其余为 idle——已记录于迭代 guide,非缺陷。完整面板限制清单见 Web 客户端插件一节。
337
- - **`dsh-llm-fallbacks` registry `dependencies` 条目且仅类型导入**——caret 范围写在 `package.json`(探测形状断言测试是可执行的漂移闸门)并在构建中 `--external`,因此 `dist/` 无打包运行时导入(仅 3 处命名该包的字符串字面量——探测的 loader 条目匹配与两条装饰日志;建议日志写作 `fallbacks`);激活是**单独显式安装**(双命令契约),绝不传递。库形态依赖存在是为未来值导入无需改 manifest 即可解析;`--external` 仍是护栏。
335
+ - **`dsh-llm-fallbacks` 为可选的开发期依赖**——dsh `0.1.2-alpha.2` 原生覆盖 subagent 定制,fallbacks 因此严格可选:`src/` 对其零导入(运行时与类型——被消费面是本地结构镜像 `fallbacks-structural.ts`,由探测的 exact-keys 漂移闸门 + `typecheck:tests` real → view 可赋值检查保持同步),`package.json` 仅在 `devDependencies` 携带它(类型镜像 + 真实包测试 harness),`dist/` 无导入也无类型引用(仅 1 处命名该包的字符串字面量——探测的 loader 条目匹配;建议日志写作 `fallbacks`)。激活是**单独显式安装**(双命令契约),绝不传递;不再有 `--external` 护栏——未来的值导入必须按设计重新加入运行时依赖。
338
336
  - **本批次未交付角色→模型覆盖**——把角色路由到 fallbacks `model`(或经 fallbacks 规则路由 persona)需要改写启动请求上的子会话 `agentOptions`,但启动请求选项由调用方控制(tool-subagent 自己的 Config;调用参数仅为 `description`/`prompt`/`run_in_background`,且深度冻结)。等待上游 `fallbacks-explicit-role-tool` 或 N-B1 systemPrompt 采纳(roadmap §10.4)。
339
- - **装饰是最小化的每子会话段,而非 N-B1 systemPrompt 采纳**——`mstar:role-persona` 是子上下文上的一个 agent 作用域段;无 harness 规则段、无 PromptContext、无变量。N-B1(roadmap §10.4)日后可吸收或替换该通道而不改变可观察行为(AC-3)。
340
- - **persona 注入与 fallbacks 无关**——`dsh-llm-fallbacks` 只路由 LLM 失败;装饰从不依赖它。未挂载 → 同一 persona 经同一通道来自 mstar Config,仅多一条 debug 日志(AC-4)。若组合中缺 `ctx.get('agents')`(无 dsh-agent),装饰以一条 debug 日志跳过。
337
+ - **persona 交付为 dsh 原生——不再有附加段**——角色 persona 合入 `SubagentStartRequest.persona`(一次性 `start` 与可选的 continuable `startContinuable` 两个启动面),对角色匹配的子会话**遮蔽**部署 persona(子会话体现角色;持久化并在 resume 时重放)。`mstar:role-persona` system-prompt 段已不复存在(plan 20260831-dsh-alpha2-optional-fallbacks)。
338
+ - **persona 注入与 fallbacks 无关**——`dsh-llm-fallbacks` 只路由 LLM 失败;persona 交付从不依赖它。未挂载 → 同一 persona 经原生通道交付,仅一条交付 debug 日志(AC-4)。一次性 start 中不具备原生 `persona` 能力的提供者(进程外)以一条受控 debug 日志跳过 persona;continuable start 中不具备 `prepareContinuable` 的提供者同样跳过(原生 start 会自行 fail loud)——通道绝不因两者使 start 失败。
341
339
  - **fork 门禁仅默认开启;显式 `dispatchTools` 可省略 `subagent_fork`**——自定义 `dispatchTools` 列表整体覆盖默认(既有重命名模式),因此自行声明列表的部署须包含 `subagent_fork` 才能继续门禁 fork 派发。
342
340
  - **persona 值绝不能包含 `{{...}}`**——dsh system-prompt 以严格 `{{variable}}` 插值渲染 persona 文本,对与后文 `}}` 配对的 `{{`(未知/畸形/未定义引用)直接抛错,会破坏每一次角色匹配派发的子会话提示组装。Config schema 在插件挂载时以清晰报错拒绝此类 `rolePersonas` 值;转义规则是改用单花括号或改写措辞(不带后续 `}}` 的孤立 `{{` 按字面散文渲染)。
343
341
  - **fallbacks HMR 重挂后的 seeds 再收敛受 seeded-only preservation 设计边界限制**——seed registry 是每次 apply 的内存态,纤程切换(HMR / 设置编辑)会丢弃它并让双方 declarer 从头重放。mstar re-declare 只合并保留**已 seeded** 的 id(seeded-only,设计使然),因此在 preset-last 提交顺序下,preset 行的 seeded 注记不会被 re-declare 恢复——它们在下一次 fallbacks apply 时恢复(上游 preset 自声明重新播种)。`llm-fallbacks` 服务消失时 advisory 一次性 latch 会重新武装(inject teardown),因此下一个决策点会重新收敛 mstar 侧;preset 侧是 seeded-only preservation 设计的有文档说明的暂时现象。
@@ -8,7 +8,7 @@
8
8
  * thunk — the trajectory precedent shape). The tab label re-reads through
9
9
  * `ctx.locale.bind(NS)` so a locale switch flips it without re-registering.
10
10
  */
11
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
11
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
12
12
  /** Cordis service faces the plugin waits for (spec §4.4: slots + sessions + locale). */
13
13
  export declare const inject: string[];
14
14
  export declare function apply(ctx: ClientContext): void;
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Inputs: the session standard kit (`ConvViewProps`) and the typed `t` seat
6
6
  * (`locale: 'mstar-panel'`). The catalog row + message time come from the
7
- * `useMstarEngineStatus()` hook riding the kit's `useSession` selector (spec
7
+ * `useMstarEngineStatus()` hook riding the kit's `useChat` selector (spec
8
8
  * §5) — the render body is a pure function of (source, lastUpdated, t).
9
9
  *
10
10
  * Layout (spec panel-tabs §2, plan 20260811-panel-tabs-shell): root grid
@@ -64,4 +64,4 @@ export interface PanelContentProps {
64
64
  * AgentEventDock — 无双份日志, the dock is removed with this plan).
65
65
  */
66
66
  export declare function PanelContent({ tab, source, t }: PanelContentProps): React.JSX.Element;
67
- export declare function PanelView({ t, useSession }: MstarPanelViewProps): React.JSX.Element;
67
+ export declare function PanelView({ t, useChat }: MstarPanelViewProps): React.JSX.Element;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Data hook for the workflow panel (spec §5): subscribes to the active
3
- * session's conversation snapshot through the session standard kit
4
- * (`useSession`, a uSES selector hook) and scans the log for the latest
5
- * `mstar-engine-status` catalog row.
3
+ * session's conversation log through the session standard kit's chat target
4
+ * (`useChat`, a uSES selector hook over the `chat` conversation view target)
5
+ * and scans the log for the latest `mstar-engine-status` catalog row.
6
6
  *
7
7
  * Node discriminator (spec §2.4): `kind === 'context'` + `form === 'catalog'`
8
8
  * + `source.kind === 'mstar-engine-status'`; the LATEST row wins (snapshot
@@ -18,7 +18,7 @@
18
18
  * instead of bubbling a crash (spec §5 degradation path; the strict-session
19
19
  * slot normally guarantees a session — the guard is belt-and-suspenders).
20
20
  */
21
- import type { ConversationSnapshot } from '@deepseek-ai/dsh-client-runtime/client';
21
+ import type { ChatSnapshot } from '@deepseek-ai/dsh-client-ui-chat/client';
22
22
  import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
23
23
  import type { MstarEngineStatusSource } from '../../types.ts';
24
24
  /** The hook result: the latest catalog row plus its message time (spec §5). */
@@ -28,10 +28,10 @@ export interface MstarEngineStatusView {
28
28
  lastUpdated: number | null;
29
29
  }
30
30
  /**
31
- * `useMstarEngineStatus(useSession): MstarEngineStatusView` — the panel's data
32
- * hook (spec §5). The session standard kit's `useSession` is passed in (the
31
+ * `useMstarEngineStatus(useChat): MstarEngineStatusView` — the panel's data
32
+ * hook (spec §5). The session standard kit's `useChat` is passed in (the
33
33
  * view ring hands it to every `conversation.view` entry); the hook rides it as
34
- * a selector over the conversation snapshot, so a snapshot bump (new catalog
34
+ * a selector over the chat target snapshot, so a snapshot bump (new catalog
35
35
  * row) re-runs the selection and refreshes the panel.
36
36
  *
37
37
  * The hook never throws (spec §5 degradation path; Task 3 contract): a
@@ -39,4 +39,4 @@ export interface MstarEngineStatusView {
39
39
  * signal instead of bubbling a crash — the strict-session slot normally
40
40
  * guarantees a session, the guard is belt-and-suspenders.
41
41
  */
42
- export declare function useMstarEngineStatus(useSession: SnapshotSelectorHook<ConversationSnapshot>): MstarEngineStatusView;
42
+ export declare function useMstarEngineStatus(useChat: SnapshotSelectorHook<ChatSnapshot>): MstarEngineStatusView;
package/dist/client.js CHANGED
@@ -4662,7 +4662,7 @@ function sameView(a, b) {
4662
4662
  }
4663
4663
  function selectEngineStatus(snapshot) {
4664
4664
  try {
4665
- const row = latestEngineStatusRow(snapshot.nodes);
4665
+ const row = latestEngineStatusRow(snapshot.legacy.nodes);
4666
4666
  if (row === null)
4667
4667
  return EMPTY;
4668
4668
  return { source: row.source, lastUpdated: row.time };
@@ -4670,9 +4670,9 @@ function selectEngineStatus(snapshot) {
4670
4670
  return EMPTY;
4671
4671
  }
4672
4672
  }
4673
- function useMstarEngineStatus(useSession) {
4673
+ function useMstarEngineStatus(useChat) {
4674
4674
  try {
4675
- const view = useSession(selectEngineStatus, sameView);
4675
+ const view = useChat(selectEngineStatus, sameView);
4676
4676
  return view ?? EMPTY;
4677
4677
  } catch {
4678
4678
  return EMPTY;
@@ -4703,8 +4703,8 @@ function PanelContent({ tab, source, t }) {
4703
4703
  t
4704
4704
  });
4705
4705
  }
4706
- function PanelView({ t, useSession }) {
4707
- const { source, lastUpdated } = useMstarEngineStatus(useSession);
4706
+ function PanelView({ t, useChat }) {
4707
+ const { source, lastUpdated } = useMstarEngineStatus(useChat);
4708
4708
  const [tab, setTab] = import_react3.useState("tasks");
4709
4709
  if (source === null || source === undefined) {
4710
4710
  return /* @__PURE__ */ jsx_runtime12.jsx("div", {
@@ -73,22 +73,26 @@ export interface Config {
73
73
  /**
74
74
  * Taxonomy bridge: mstar role id → fallbacks role id (the
75
75
  * `dsh-llm-fallbacks` role taxonomy). Logging + future rule-driven
76
- * interop only — NOT required for persona injection (`rolePersonas` is
77
- * the decoration's only payload source). Absent → no bridge mapping.
76
+ * interop only — NOT required for persona delivery (`rolePersonas` is
77
+ * the channel's only payload source). Absent → no bridge mapping.
78
78
  */
79
79
  roleMap?: Record<string, string>;
80
80
  /**
81
- * mstar role id → persona text — the subagent decoration's only payload
82
- * source (plan `20260814-dsh-fallbacks-integration` Task 2). A
83
- * role-matched `subagent/start` registers the persona as the child's
84
- * `mstar:role-persona` system-prompt section (agent-scoped on
85
- * `Agent.ctx`, unwinds on disposal). Lookup is DIRECT never gated on
86
- * `roleMap` or on the fallbacks mounted state (unmounted same
87
- * injection from Config + one debug log). Absent no decoration.
81
+ * mstar role id → persona text — the native persona channel's only
82
+ * payload source (plan `20260814-dsh-fallbacks-integration` Task 2;
83
+ * channel reworked onto the native `SubagentStartRequest.persona` slot by
84
+ * plan `20260831-dsh-alpha2-optional-fallbacks` Task 3). A role-matched
85
+ * one-shot start merges the persona into the request's native `persona`
86
+ * slot dsh composes it as the scoped shadowing `deployment:persona`
87
+ * section on the child, persists it in the child descriptor, and reapplies
88
+ * it on resume. Lookup is DIRECT — never gated on `roleMap` or on the
89
+ * fallbacks mounted state (persona delivery is fallbacks-independent).
90
+ * Absent → no merge.
88
91
  *
89
- * INTERPOLATION CONSTRAINT: dsh system-prompt renders section text with
90
- * STRICT `{{variable}}` interpolation and throws on any `{{` paired with a
91
- * later `}}` (unknown/malformed/undefined reference), so persona values
92
+ * INTERPOLATION CONSTRAINT: dsh renders persona text with STRICT
93
+ * `{{variable}}` interpolation (the native persona has the same template
94
+ * semantics as the deployment persona) and throws on any `{{` paired with
95
+ * a later `}}` (unknown/malformed/undefined reference), so persona values
92
96
  * MUST NOT contain that pattern — a violating persona would break child
93
97
  * prompt assembly at the child's first render, for EVERY role-matched
94
98
  * dispatch. The Config schema rejects such values at plugin mount with a
@@ -130,7 +134,8 @@ export interface Config {
130
134
  * (`renderPrompt` → `interpolate` in `@deepseek-ai/dsh-system-prompt`) scans
131
135
  * section text for `{{` and THROWS on any `{{` paired with a later `}}` in
132
136
  * the same text (unknown variable, malformed group, or undefined value).
133
- * Persona text lands in the `mstar:role-persona` section verbatim, so a
137
+ * Persona text lands in the native request `persona` slot verbatim (the
138
+ * same STRICT `{{...}}` template semantics as the deployment persona), so a
134
139
  * persona containing this pattern breaks child prompt assembly at the
135
140
  * child's first render — every role-matched dispatch. The Config schema
136
141
  * rejects such values at validation (plugin mount) with a clear error. The
@@ -156,12 +161,39 @@ export declare const PERSONA_INTERPOLATION_HAZARD: RegExp;
156
161
  * can never break prompt assembly.
157
162
  */
158
163
  export declare function stripInterpolationHazard(text: string): string;
159
- /** Schemastery configuration schema for the plugin consumer. Object keys are optional by default (`.optional()` is a vendored-fork addition not present in npm schemastery); omitted ARRAY keys would materialize as `[]` (schemastery empty-value default — the tool-subagent `toolFilter` pitfall) and omitted DICT keys would materialize as `{}`, so the dispatch keys and the decoration keys all preserve omission via `.default(undefined)`. */
164
+ /** Schemastery configuration schema for the plugin consumer. Object keys are optional by default (`.optional()` is a vendored-fork addition not present in npm schemastery); omitted ARRAY keys would materialize as `[]` (schemastery empty-value default — the tool-subagent `toolFilter` pitfall) and omitted DICT keys would materialize as `{}`, so the dispatch keys and the persona keys all preserve omission via `.default(undefined)`. */
160
165
  export declare const Config: z<Config>;
161
166
  /** One violation line for logs and the typed veto message. */
162
167
  export declare function formatViolation(violation: ValidationResult): string;
163
168
  /** Narrow an unknown value to a record. */
164
169
  export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
170
+ /**
171
+ * Cap on the plan / lease rows joined into the `<mstar_engine_status>`
172
+ * catalog state lines (plan `20260830-dsh-catalog-cap` D1): ONE catalog-owned
173
+ * constant shared by the `plans:` and `leases:` joins so an oversized
174
+ * workflow snapshot cannot balloon the single-line catalog state section.
175
+ * Numeric precedent: `DIGEST_PLAN_CAP` in `system-prompt.ts` (digest-side,
176
+ * non-Done-only — intentionally NOT reused here; the catalog renders the
177
+ * full, unfiltered snapshot rows).
178
+ */
179
+ export declare const CATALOG_STATE_JOIN_LIMIT = 8;
180
+ /**
181
+ * Join the screened projection of `items` in catalog-array order, capped at
182
+ * `cap`: when `items.length > cap` the FIRST `cap` items render followed by
183
+ * a final `+N more` overflow marker (`N = items.length - cap`) as the last
184
+ * join element; at or under the cap the full join renders with no marker.
185
+ * The `render` callback owns any per-item `stripInterpolationHazard`
186
+ * screening (before the join, same as the uncapped code); the marker is an
187
+ * engine-derived literal and stays unscreened. Callers guard the empty case
188
+ * (`length === 0` → `none` / `none registered` / `none active`) — this
189
+ * helper is never reached for empty arrays.
190
+ *
191
+ * Hoisted from `system-prompt.ts` (plan `20260830-dsh-catalog-cap` D3) so
192
+ * the GLOBAL digest and the catalog state lines share ONE join-capping
193
+ * implementation; `_shared.ts` imports no gates-local module, so no import
194
+ * cycle is introduced.
195
+ */
196
+ export declare function joinCapped<T>(items: readonly T[], cap: number, separator: string, render: (item: T) => string): string;
165
197
  /**
166
198
  * Resolve the hard-enforcement flag for the artifact gates: explicit
167
199
  * Config override wins, else the repo `.mstarc` `[config] enforcement`,
@@ -19,12 +19,12 @@ export interface PersonaLookup {
19
19
  /** The mirror root (`harness-agents/`); absent → mirror defaults are skipped. */
20
20
  agentsDir?: string;
21
21
  }
22
- /** Warn sink for extraction-time hazards (bound by the decoration to its warn channel). */
22
+ /** Warn sink for extraction-time hazards (bound by the persona channel to its warn sink). */
23
23
  export type PersonaWarnSink = (message: string) => void;
24
24
  /**
25
- * The decoration's single persona lookup: `rolePersonas[roleId]` → mirror
25
+ * The persona channel's single lookup: `rolePersonas[roleId]` → mirror
26
26
  * default → undefined. Pure — the mirror root is passed explicitly (the
27
- * decoration supplies the apply-bound packaged root; tests supply fixtures).
27
+ * channel supplies the apply-bound packaged root; tests supply fixtures).
28
28
  *
29
29
  * @param roleId - the mstar role id (Assignment `Execute as`).
30
30
  * @param lookup - the config override map and the mirror root.
@@ -36,14 +36,14 @@
36
36
  * dispatch/apply flow is never affected).
37
37
  *
38
38
  * Module boundary: no barrel — the entry imports this module by explicit
39
- * relative path (the decoration-module pattern).
39
+ * relative path (the role-persona module pattern).
40
40
  */
41
41
  import type { Context } from '@deepseek-ai/cordis';
42
42
  /** Logger label for the adoption advisory (dsh logger naming: `<scope>/<subject>`). */
43
43
  export declare const ADVISORY_LOGGER = "mstar/fallbacks-advisory";
44
44
  /** Advisory log levels the module sink understands. */
45
45
  export type AdvisoryLogLevel = 'debug' | 'warn';
46
- /** Module-level advisory log sink — bound by `apply` to `ctx.logger(ADVISORY_LOGGER)` (decoration-module pattern). */
46
+ /** Module-level advisory log sink — bound by `apply` to `ctx.logger(ADVISORY_LOGGER)` (role-persona module pattern). */
47
47
  export type AdvisoryLogSink = (level: AdvisoryLogLevel, message: string) => void;
48
48
  /**
49
49
  * Bind the advisory log sink (the entry `apply` binds it to
@@ -2,11 +2,17 @@
2
2
  * Capability probes for the OPTIONAL `dsh-llm-fallbacks` plugin (plan
3
3
  * `20260814-dsh-fallbacks-integration` Task 1 — probe foundation).
4
4
  *
5
- * The fallbacks plugin is registry-declared (`dependencies`) and external in
6
- * the build, and every import here is TYPE-ONLY: `dist/index.js` must carry
7
- * ZERO runtime references to `dsh-llm-fallbacks`. The package's
5
+ * The fallbacks plugin is an optional SEPARATE install (two-command
6
+ * contract) and a dev-time-only dependency of this package: src carries
7
+ * ZERO imports of it (runtime and type) the consumed service surface is
8
+ * the local structural mirror in `fallbacks-structural.ts`, so `dist/`
9
+ * carries zero runtime AND zero type references to `dsh-llm-fallbacks`.
10
+ * When the dev dependency is installed, the package's
8
11
  * `declare module '@deepseek-ai/cordis'` augmentation types
9
- * `ctx.get('llm-fallbacks')` for importers.
12
+ * `ctx.get('llm-fallbacks')` for importers — under `typecheck:tests` the
13
+ * uncast return in {@link fallbacksService} is the compile-time real →
14
+ * view assignability gate (the published build never loads the
15
+ * augmentation; the untyped string overload applies there).
10
16
  *
11
17
  * Two views:
12
18
  * - {@link fallbacksService} — the named cordis service while the plugin is
@@ -19,7 +25,7 @@
19
25
  * concurrently (plugin-inventory philosophy).
20
26
  */
21
27
  import type { Context } from '@deepseek-ai/cordis';
22
- import type { FallbacksService } from 'dsh-llm-fallbacks';
28
+ import type { FallbacksServiceView } from './fallbacks-structural.ts';
23
29
  /** Loader entry name of the `dsh-llm-fallbacks` plugin row. */
24
30
  export declare const FALLBACKS_ENTRY_NAME = "dsh-llm-fallbacks";
25
31
  /**
@@ -44,7 +50,7 @@ export interface LoaderEntryView {
44
50
  fiber: unknown;
45
51
  }
46
52
  /** Service view: the named `llm-fallbacks` cordis service while applied. */
47
- export declare function fallbacksService(ctx: Context): FallbacksService | undefined;
53
+ export declare function fallbacksService(ctx: Context): FallbacksServiceView | undefined;
48
54
  /**
49
55
  * The fallbacks loader row when present and enabled (group rows skipped).
50
56
  * Unlike {@link fallbacksMounted}, NO live-fiber requirement: the entry is