@mstar-harness/dsh 3.7.0 → 3.7.1
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 +2 -2
- package/README.md +4 -2
- package/README.zh.md +4 -2
- package/dist/gates/_shared.d.ts +18 -7
- package/dist/gates/fallbacks-advisory.d.ts +53 -15
- package/dist/gates/role-persona.d.ts +121 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +268 -161
- package/harness-skills/mstar-harness-core/SKILL.md +8 -1
- package/harness-skills/mstar-host/references/zcode.md +7 -1
- package/package.json +1 -1
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:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 189bec515fe5fce73de5afad7e2d1678e0f55ea5
|
|
6
|
+
README.zh.md: 05affb493e99da9b45d0b8dd2743ccedaecc0b11
|
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ The shipped headless template auto-initializes on first use (`@deepseek-ai/dsh-b
|
|
|
69
69
|
| `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). |
|
|
70
70
|
| `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. |
|
|
71
71
|
| `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). |
|
|
72
|
-
| `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)
|
|
72
|
+
| `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). Merge order: the request's own `persona` wins AS-IS (a caller-set persona is never overridden — no role merge); otherwise a non-empty entry beats the bundled `harness-agents/` mirror default, an **empty-string** entry is treated as unset and falls through to the mirror default, and an absent entry uses the mirror default (see LLM fallbacks integration). |
|
|
73
73
|
| `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. |
|
|
74
74
|
| `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. |
|
|
75
75
|
| `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. |
|
|
@@ -169,9 +169,11 @@ Persona delivery rides dsh's NATIVE `SubagentStartRequest.persona` slot (`@deeps
|
|
|
169
169
|
|
|
170
170
|
**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.
|
|
171
171
|
|
|
172
|
+
**Seam probe (fail-loud)**: the channel probes the cordis `internal/get` seam once per apply (temporary canary listener + one controlled proxied `ctx.subagents` read — never `ctx.get`); a missing or unrecognized seam logs ONE warn — `role persona channel not installed — cordis 'internal/get' seam missing or unrecognized (rolePersonas will not be merged into subagent starts)` + ` (reason: seam-absent | wrap-skipped)` — instead of failing silently. A healthy boot produces NO warn (the locked outcome table): on today's composition the apply ctx does not resolve `subagents`, so each apply emits one no-warn `service-absent` debug — cordis resolves the service in dispatch scopes, where reads are intercepted per read; probe-internal errors degrade fail-open (one debug). `wrap-skipped` is pinned but not reachable from the shipped apply wiring — it fires where `subagents` is resolvable at apply, a path covered by the harness pins. The seam name is pinned by the dedicated probe family `tests/persona-seam-probe.spec.ts` (via the exported `PERSONA_SEAM_EVENT` constant); the installed-artifact assertion arms once the release carrying the probe publishes (surface-vintage guard in `tests/install-e2e.spec.ts`).
|
|
173
|
+
|
|
172
174
|
### Role seeds + adoption advisory
|
|
173
175
|
|
|
174
|
-
When the optional `dsh-llm-fallbacks` capability is **mounted** (the second install command — see Install paths), the mstar plugin **zero-config declares the 13 `mode: subagent` mstar role seeds** into the fallbacks seed registry: persona = the `harness-agents/` mirror `description` (verbatim) + one mandatory-load guide line (`Load mstar-roles (references/<role-id>.md) first — identity comes before skills; load topic skills only when the Assignment activates them via its Skill presets field.`); a persona carrying the `{{...}}` interpolation hazard is skipped + warned, never declared. The declaration **merge-preserves the currently-seeded non-mstar ids** from the readback — e.g. the 7 omp-style preset roles the upstream package self-declares at its own apply: upstream `declare` REPLACES the whole registry, so without preservation a mstar-only batch would strip preset ids of their seeded annotations (rows remain, unseeded). The declaration re-fires idempotently on every fallbacks (re-)apply (HMR/fiber swap) — never from a one-shot latch — so either boot order (presets first or mstar first) converges to the same 20-id fully-seeded registry.
|
|
176
|
+
When the optional `dsh-llm-fallbacks` capability is **mounted** (the second install command — see Install paths), the mstar plugin **zero-config declares the 13 `mode: subagent` mstar role seeds** into the fallbacks seed registry: persona = the `harness-agents/` mirror `description` (verbatim) + one mandatory-load guide line (`Load mstar-roles (references/<role-id>.md) first — identity comes before skills; load topic skills only when the Assignment activates them via its Skill presets field.`); a persona carrying the `{{...}}` interpolation hazard is skipped + warned, never declared. The declaration **merge-preserves the currently-seeded non-mstar ids** from the readback — e.g. the 7 omp-style preset roles the upstream package self-declares at its own apply: upstream `declare` REPLACES the whole registry, so without preservation a mstar-only batch would strip preset ids of their seeded annotations (rows remain, unseeded). The declaration re-fires idempotently on every fallbacks (re-)apply (HMR/fiber swap) — never from a one-shot latch — so either boot order (presets first or mstar first) converges to the same 20-id fully-seeded registry. Boot-time convergence is a bounded retry: the provider's seed write channel binds one macrotask after its apply, so a first-attempt reject with `seeds: settings service is unavailable` inside that apply window is retried (3 attempts across the provider's apply window) and a transient reject converges on its own; only if every attempt ultimately fails does the declaration log exactly one terminal error, while the advisory's decision-point re-declare stays available as the retry path. **No manual `roles.list` edit is required.**
|
|
175
177
|
|
|
176
178
|
A warn-only advisory pass (logger `mstar/fallbacks-advisory`) runs **once per apply** — attempted at apply and, when the fallbacks row mounts after `dsh` (the loader mounts entries concurrently), once at the first `subagent/start` decision point. With the service present, the pass FIRST awaits the idempotent re-declare (closing the boot race) then reads the EFFECTIVE state (`getEffectiveRoles`) and reports, bounded to **at most one warn per category**:
|
|
177
179
|
|
package/README.zh.md
CHANGED
|
@@ -68,7 +68,7 @@ dsh plugin --profile headless add @mstar-harness/dsh
|
|
|
68
68
|
| `dispatchTools` | `string[]` | `['subagent', 'subagent_fork']` | 派发闸门匹配的委派工具名——dsh preset 的**两个**委派工具:`subagent` 及其 fork 兄弟 `subagent_fork`(两者都携带 Assignment 形态的 `{ description, prompt }` 参数;`toolName` 配置可重命名实例)。 |
|
|
69
69
|
| `dispatchBinding` | `string` | 未设置 → hard 下 fail-closed `empty-binding` | 派发方 agent 自身的 harness 角色(反递归 caller);Assignment 的 `Execute as` 等于它即自我递归。 |
|
|
70
70
|
| `roleMap` | `Record<string, string>` | 未设置 | mstar 角色 id(`Execute as`)→ dsh-llm-fallbacks 角色 id。**仅**作日志与未来规则驱动互操作的分类桥——persona 通道从不读取它(见 LLM fallbacks integration)。 |
|
|
71
|
-
| `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id(`Execute as`)→ persona 文本;原生 subagent persona 通道的**覆盖**来源——角色匹配的 start(一次性 `start` 或可选的 continuable `startContinuable`)会把 persona 合入原生请求的 `persona` 槽(子会话体现角色 persona 而**非**部署 persona;持久化并在 resume
|
|
71
|
+
| `rolePersonas` | `Record<string, string>` | 未设置(打包镜像默认) | mstar 角色 id(`Execute as`)→ persona 文本;原生 subagent persona 通道的**覆盖**来源——角色匹配的 start(一次性 `start` 或可选的 continuable `startContinuable`)会把 persona 合入原生请求的 `persona` 槽(子会话体现角色 persona 而**非**部署 persona;持久化并在 resume 时重放)。合并次序:请求自身已携带 `persona` 时**原样生效**(调用方意图绝不被覆盖——不做角色合并);否则非空条目优先于打包的 `harness-agents/` 镜像默认值,**空字符串**条目视为未设置并回落到镜像默认值,无条目时使用镜像默认值(见 LLM fallbacks integration)。 |
|
|
72
72
|
| `skillRoots` | `string[]` | 未设置(不注册自定义根) | 向 dsh skill-filesystem 提供者注册的额外技能根(`customSkillDirs` 语义——先于用户根扫描)。开发期:镜像 `<repo-root>/skills` 的绝对路径。 |
|
|
73
73
|
| `bundledSkillDir` | `string` | 打包的 `harness-skills/` 镜像(包相对路径) | 向 dsh skill-filesystem 提供者注册的打包技能根(`bundledSkillDir` 语义——最后扫描、受信任)。默认取包内自带的 `harness-skills/` 镜像(`bundle-assets` 同步;gitignore)——包相对路径,**非** cwd 锚定。显式值优先。 |
|
|
74
74
|
| `catalogTtlMs` | `number` | `60000` | pre-step catalog 缓存刷新间隔(毫秒):按工作区缓存的统一 `mstar-engine-status` 行(水印 + 迭代闸门 + 工作区摘要)多久重读一次 `status.json` / compass / 知识索引。刷新间隔之间热路径只是时间戳比较 + Map 命中;会话中 plan/compass/residual 的变化会在一个间隔内落地。 |
|
|
@@ -168,9 +168,11 @@ persona 交付走 dsh 原生的 `SubagentStartRequest.persona` 槽(`@deepseek-
|
|
|
168
168
|
|
|
169
169
|
**零配置默认值**:当 `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。
|
|
170
170
|
|
|
171
|
+
**Seam 探针(fail-loud)**:通道每次 apply 对 cordis `internal/get` seam 探测一次(临时 canary 监听器 + 一次受控代理式 `ctx.subagents` 读取——绝不 `ctx.get`);seam 缺失或未被识别时记录恰一条 warn——`role persona channel not installed — cordis 'internal/get' seam missing or unrecognized (rolePersonas will not be merged into subagent starts)` + ` (reason: seam-absent | wrap-skipped)`——而非静默失败。健康 boot 不产生任何 warn(锁定的判定表):在今天的组合形态下 apply ctx 不解析 `subagents`,因此每次 apply 发出一条无 warn 的 `service-absent` debug——cordis 在 dispatch 作用域解析该服务,读取在那时逐次被拦截;探针内部错误按 fail-open 降级(一条 debug)。`wrap-skipped` 已被钉死但无法从当前发布的 apply 布线触达——它只在 apply 时即可解析 `subagents` 的场景触发,该路径由 harness pins 覆盖。seam 名由专用探针家族 `tests/persona-seam-probe.spec.ts` 钉死(经导出的 `PERSONA_SEAM_EVENT` 常量);安装产物断言在携带探针的版本发布后自动启用(`tests/install-e2e.spec.ts` 的 surface-vintage guard)。
|
|
172
|
+
|
|
171
173
|
### 角色 seeds 与采纳建议(Adoption advisory)
|
|
172
174
|
|
|
173
|
-
当可选的 `dsh-llm-fallbacks` 能力**已挂载**(第二条安装命令——见 Install paths)时,mstar 插件会向 fallbacks seed registry **零配置声明 13 个 `mode: subagent` mstar 角色 seed**:persona = `harness-agents/` 镜像 `description`(原样)+ 一行强制加载引导(`Load mstar-roles (references/<role-id>.md) first — identity comes before skills; load topic skills only when the Assignment activates them via its Skill presets field.`);含 `{{...}}` 插值风险的 persona 跳过并告警,绝不声明。声明会**合并保留 readback 中当前已 seeded 的非 mstar id**——例如上游包在其自身 apply 时自声明的 7 个 omp 风格 preset 角色:上游 `declare` **全量替换** registry,若不保留,mstar-only 批会摘掉 preset id 的 seeded 注记(行仍在,仅失去 seeded)。声明在每次 fallbacks(重新)apply(HMR/纤程切换)时幂等重放——绝不用一次性 latch——因此两种 boot 顺序(presets 先或 mstar 先)都收敛到同一 20-id 全 seeded registry。
|
|
175
|
+
当可选的 `dsh-llm-fallbacks` 能力**已挂载**(第二条安装命令——见 Install paths)时,mstar 插件会向 fallbacks seed registry **零配置声明 13 个 `mode: subagent` mstar 角色 seed**:persona = `harness-agents/` 镜像 `description`(原样)+ 一行强制加载引导(`Load mstar-roles (references/<role-id>.md) first — identity comes before skills; load topic skills only when the Assignment activates them via its Skill presets field.`);含 `{{...}}` 插值风险的 persona 跳过并告警,绝不声明。声明会**合并保留 readback 中当前已 seeded 的非 mstar id**——例如上游包在其自身 apply 时自声明的 7 个 omp 风格 preset 角色:上游 `declare` **全量替换** registry,若不保留,mstar-only 批会摘掉 preset id 的 seeded 注记(行仍在,仅失去 seeded)。声明在每次 fallbacks(重新)apply(HMR/纤程切换)时幂等重放——绝不用一次性 latch——因此两种 boot 顺序(presets 先或 mstar 先)都收敛到同一 20-id 全 seeded registry。boot 时收敛经 bounded retry(有界重试):上游的 seed 写通道在其 apply 之后一个 macrotask 才绑定,因此 apply 窗口内首次尝试被 `seeds: settings service is unavailable` 拒绝时会重试(跨上游 apply 窗口的 3 次尝试),暂时性拒绝自行收敛;仅当所有尝试最终失败时,声明才记录恰好一条终态错误,同时 advisory 的决策点 re-declare 仍可用作 retry 路径。**无需手动编辑 `roles.list`。**
|
|
174
176
|
|
|
175
177
|
一条只告警的采纳建议通道(日志器 `mstar/fallbacks-advisory`)**每次 apply 只跑一遍**——apply 时先尝试一次;当 fallbacks 行在 `dsh` 之后挂载(loader 并发挂载条目)时,改在首个 `subagent/start` 决策点只跑一遍。服务存在时,通道**先 await 幂等 re-declare**(闭合 boot 竞争窗口)再读取**有效状态**(`getEffectiveRoles`),并按**每类至多一条告警**有界报告:
|
|
176
178
|
|
package/dist/gates/_shared.d.ts
CHANGED
|
@@ -79,13 +79,24 @@ export interface Config {
|
|
|
79
79
|
roleMap?: Record<string, string>;
|
|
80
80
|
/**
|
|
81
81
|
* mstar role id → persona text — the native persona channel's only
|
|
82
|
-
* payload source
|
|
83
|
-
*
|
|
84
|
-
* slot — dsh composes it as the scoped shadowing
|
|
85
|
-
* section on the child, persists it in the child
|
|
86
|
-
* it on resume. Lookup is DIRECT — never gated
|
|
87
|
-
* fallbacks mounted state (persona delivery is
|
|
88
|
-
*
|
|
82
|
+
* payload source. A role-matched start (one-shot `start` or the opt-in
|
|
83
|
+
* continuable `startContinuable`) merges the persona into the request's
|
|
84
|
+
* native `persona` slot — dsh composes it as the scoped shadowing
|
|
85
|
+
* `deployment:persona` section on the child, persists it in the child
|
|
86
|
+
* descriptor, and reapplies it on resume. Lookup is DIRECT — never gated
|
|
87
|
+
* on `roleMap` or on the fallbacks mounted state (persona delivery is
|
|
88
|
+
* fallbacks-independent).
|
|
89
|
+
*
|
|
90
|
+
* MERGE ORDER (doc-only statement of the decision chain in
|
|
91
|
+
* `role-persona.ts` / `agent-personas.ts` — no behavior change): the
|
|
92
|
+
* request's own `persona` wins AS-IS — a start that already carries one
|
|
93
|
+
* is returned untouched, with no role merge at all (caller intent is
|
|
94
|
+
* never overridden). Otherwise the per-role lookup is config over mirror:
|
|
95
|
+
* a non-empty `rolePersonas[roleId]` beats the bundled `harness-agents/`
|
|
96
|
+
* mirror default; an EMPTY-STRING value is treated as unset and falls
|
|
97
|
+
* through to the mirror default (parity with the pre-channel decoration's
|
|
98
|
+
* config check); an absent entry uses the mirror default; a lookup miss
|
|
99
|
+
* (no config value and no mirror default) → no merge.
|
|
89
100
|
*
|
|
90
101
|
* INTERPOLATION CONSTRAINT: dsh renders persona text with STRICT
|
|
91
102
|
* `{{variable}}` interpolation (the native persona has the same template
|
|
@@ -27,12 +27,18 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Unreadable row config (absent field / non-object, or an unreadable
|
|
29
29
|
* `roles.list`) → skip + one debug log. Unmounted → the pass is not invoked
|
|
30
|
-
* (
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
30
|
+
* (`{ ran: false, converged: false }`, no logs). An aborted pass (any caught
|
|
31
|
+
* error, including a rejected re-declare) reports `{ ran: true, converged:
|
|
32
|
+
* false }` — the honest latch: the caller arms its one-shot latch only on
|
|
33
|
+
* `ran && converged`, so a failed pass never suppresses the decision-point
|
|
34
|
+
* retry. The degraded-abort warn is deduplicated to at most ONE per apply
|
|
35
|
+
* (module flag; the entry resets it via {@link resetAdvisoryAbortWarn}).
|
|
36
|
+
* The advisory NEVER writes the fallbacks config — the read is read-only
|
|
37
|
+
* over the deployment's config layer (never the fallbacks plugin's module
|
|
38
|
+
* internals); the only write path is the idempotent seeds re-declare
|
|
39
|
+
* through the released seeds surface (no-delta → no settings write
|
|
40
|
+
* upstream). The advisory never throws (the caller's dispatch/apply flow is
|
|
41
|
+
* never affected).
|
|
36
42
|
*
|
|
37
43
|
* Module boundary: no barrel — the entry imports this module by explicit
|
|
38
44
|
* relative path (the role-persona module pattern).
|
|
@@ -59,18 +65,50 @@ export declare function setAdvisoryLogger(sink: AdvisoryLogSink): AdvisoryLogSin
|
|
|
59
65
|
*/
|
|
60
66
|
export declare const ADVISORY_ID_LIST_CAP = 20;
|
|
61
67
|
/**
|
|
62
|
-
* One advisory pass
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
+
* One advisory pass outcome (the honest-latch contract):
|
|
69
|
+
* - `ran` — the pass executed (the capability is mounted); `false` means the
|
|
70
|
+
* pass was not invoked (unmounted). Carries the one-pass-per-apply
|
|
71
|
+
* bookkeeping.
|
|
72
|
+
* - `converged` — the pass reached its converged end. Per return path:
|
|
73
|
+
* unmounted → `false`; aborted pass (any caught error, including a
|
|
74
|
+
* rejected re-declare) → `false`; a no-re-declare path (loader-fallback
|
|
75
|
+
* structural read, unreadable config, or a service-present pass that
|
|
76
|
+
* never reaches the re-declare) → `true`; service-present path → reflects
|
|
77
|
+
* the re-declare resolving.
|
|
78
|
+
*
|
|
79
|
+
* The caller (entry `apply`) arms its one-shot latch only on
|
|
80
|
+
* `ran && converged` — a rejected re-declare must never suppress the
|
|
81
|
+
* `subagent/start` decision-point retry.
|
|
82
|
+
*/
|
|
83
|
+
export interface AdvisoryPassReport {
|
|
84
|
+
ran: boolean;
|
|
85
|
+
converged: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Reset the degraded-abort warn dedup flag (one warn per apply budget).
|
|
89
|
+
* Called by the entry at `apply` (next to the advisory sink binding) and in
|
|
90
|
+
* the `llm-fallbacks` inject child's teardown (a fiber swap re-opens the
|
|
91
|
+
* budget for the re-applied fiber). Exported for the suite's dedup case.
|
|
92
|
+
*/
|
|
93
|
+
export declare function resetAdvisoryAbortWarn(): void;
|
|
94
|
+
/**
|
|
95
|
+
* One advisory pass: unmounted → not invoked (`{ ran: false, converged:
|
|
96
|
+
* false }`, no logs); mounted → report the taxonomy adoption state (bounded:
|
|
97
|
+
* ≤1 warn per category). With the service present the pass is ASYNC: it
|
|
98
|
+
* awaits the idempotent re-declare before the effective-state readback
|
|
99
|
+
* (report determinism — the boot dual-inject-child race window is closed).
|
|
100
|
+
* Never throws — every failure mode degrades to skip + one debug/warn, and
|
|
101
|
+
* an aborted pass reports `converged: false` (the honest latch). Never
|
|
102
|
+
* writes the fallbacks config.
|
|
68
103
|
*
|
|
69
104
|
* @param ctx - the plugin's registrant context (the app composition root).
|
|
70
105
|
* @param agentsDir - the `harness-agents/` mirror root the mstar role-id set
|
|
71
106
|
* is derived from; absent → the taxonomy checks are skipped (one debug
|
|
72
107
|
* log; the legacy-keys check is mirror-independent and still runs).
|
|
73
|
-
* @returns
|
|
74
|
-
*
|
|
108
|
+
* @returns the {@link AdvisoryPassReport} — `ran` marks a mounted pass (the
|
|
109
|
+
* one-pass-per-apply bookkeeping), `converged` marks a pass that reached
|
|
110
|
+
* its converged end; the caller (entry `apply`) arms the one-shot latch
|
|
111
|
+
* only on `ran && converged`, so an aborted pass (e.g. a rejected
|
|
112
|
+
* re-declare) never suppresses the decision-point retry.
|
|
75
113
|
*/
|
|
76
|
-
export declare function runFallbacksAdvisory(ctx: Context, agentsDir: string | undefined): Promise<
|
|
114
|
+
export declare function runFallbacksAdvisory(ctx: Context, agentsDir: string | undefined): Promise<AdvisoryPassReport>;
|
|
@@ -43,7 +43,13 @@
|
|
|
43
43
|
* `roleMap` is a taxonomy bridge for logging + future rule-driven interop
|
|
44
44
|
* only. The mirror root is bound at apply (`setRolePersonaAgentsDir` ←
|
|
45
45
|
* `packagedAgentsDir()`), package-relative so the shipped bundle works from
|
|
46
|
-
* any launch cwd.
|
|
46
|
+
* any launch cwd. Lifetime: the root is a module-level binding with ONE
|
|
47
|
+
* writer — the per-apply `setRolePersonaAgentsDir` call — and it is read
|
|
48
|
+
* per start, so every start observes an apply-constant value; re-calling
|
|
49
|
+
* the setter (an HMR re-apply) IS the re-bind, and that re-bind is the
|
|
50
|
+
* intended reset (it also re-arms the mirror-absent latch below). The
|
|
51
|
+
* per-apply payload `Config.rolePersonas` is the contrast: closed over per
|
|
52
|
+
* apply in `registerRolePersonaChannel`.
|
|
47
53
|
*
|
|
48
54
|
* Capability gates (native fail-loud contracts, per surface): one-shot
|
|
49
55
|
* `SubagentRuntime.start` REJECTS a request carrying `persona` for a
|
|
@@ -68,6 +74,22 @@
|
|
|
68
74
|
* per apply (S-002 latch); a throwing merge aborts the merge only — the
|
|
69
75
|
* ORIGINAL request reaches the service and the start is never affected.
|
|
70
76
|
*
|
|
77
|
+
* Seam probe (apply-time, observation only): a future cordis rename/removal
|
|
78
|
+
* of `internal/get` would stop the listener from ever firing — persona
|
|
79
|
+
* delivery would silently degrade to the raw service with no runtime
|
|
80
|
+
* signal. {@link probeRolePersonaSeam} runs ONCE per apply right after
|
|
81
|
+
* {@link registerRolePersonaChannel}: a temporary canary listener + ONE
|
|
82
|
+
* controlled proxied read (`ctx.subagents` — NEVER `ctx.get`, whose accessor
|
|
83
|
+
* bypasses the waterfall and would false-warn every healthy boot) assert
|
|
84
|
+
* that the seam dispatched AND the returned value carries the wrapper brand.
|
|
85
|
+
* A broken seam warns ONCE per apply (fail-loud); an unresolved service is
|
|
86
|
+
* `service-absent` (`ok: true` + one debug — the apply ctx does not resolve
|
|
87
|
+
* `subagents`; cordis resolves the service in dispatch scopes, where reads
|
|
88
|
+
* are intercepted per read); any probe-internal error fails
|
|
89
|
+
* OPEN (`ok` + one debug) — the probe never throws and never blocks a
|
|
90
|
+
* dispatch. The decision core is the pure {@link evaluateSeamProbe}, so the
|
|
91
|
+
* whole outcome table is unit-pinnable without cordis internals.
|
|
92
|
+
*
|
|
71
93
|
* Persona text is rendered by dsh system-prompt's STRICT `{{...}}`
|
|
72
94
|
* interpolation (the native persona has the same template semantics as the
|
|
73
95
|
* deployment persona), so persona values MUST NOT contain `{{` paired with
|
|
@@ -77,7 +99,12 @@
|
|
|
77
99
|
* boot throw).
|
|
78
100
|
*
|
|
79
101
|
* Module boundary: no barrel — the entry imports this module by explicit
|
|
80
|
-
* relative path and re-exports the public names verbatim
|
|
102
|
+
* relative path and re-exports the public names verbatim, EXCEPT the four
|
|
103
|
+
* probe exports (`PERSONA_SEAM_EVENT`, `ROLE_PERSONA_WRAPPER_BRAND`,
|
|
104
|
+
* `evaluateSeamProbe`, `probeRolePersonaSeam`), which are deliberately NOT
|
|
105
|
+
* re-exported from the entry: the frozen entry surface keeps the probe
|
|
106
|
+
* observable only through this module (tests import it directly; the
|
|
107
|
+
* shipped bundle exports no probe symbol). No dsh-subagent
|
|
81
108
|
* dependency: the runtime surface is consumed structurally (same pattern as
|
|
82
109
|
* the probe's `LoaderEntryView` and T2's `fallbacks-structural.ts`).
|
|
83
110
|
*/
|
|
@@ -85,6 +112,23 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
85
112
|
import type { Config } from './_shared.ts';
|
|
86
113
|
/** Logger label for the role-persona channel (dsh logger naming: `<scope>/<subject>`). */
|
|
87
114
|
export declare const ROLE_PERSONA_LOGGER = "mstar/role-persona";
|
|
115
|
+
/**
|
|
116
|
+
* The interception seam: the cordis service-read waterfall event the channel
|
|
117
|
+
* listener registers on. The registration and the apply-time seam probe both
|
|
118
|
+
* reference THIS constant — a future cordis rename of `internal/get` becomes
|
|
119
|
+
* a one-line, probe-family-caught edit here instead of a silent delivery
|
|
120
|
+
* stop (the probe family pins the literal; see `probeRolePersonaSeam`).
|
|
121
|
+
*/
|
|
122
|
+
export declare const PERSONA_SEAM_EVENT = "internal/get";
|
|
123
|
+
/**
|
|
124
|
+
* Wrapper brand — the non-enumerable symbol own property every persona
|
|
125
|
+
* wrapper carries (`wrapSubagentsService` stamps it at creation). The apply-
|
|
126
|
+
* time seam probe reads it to assert the wrapper was actually installed on
|
|
127
|
+
* the controlled read. Non-enumerable + symbol keeps the wrapper's
|
|
128
|
+
* key/spread/JSON surface identical to the wrapped service's (behavior-
|
|
129
|
+
* neutral by construction).
|
|
130
|
+
*/
|
|
131
|
+
export declare const ROLE_PERSONA_WRAPPER_BRAND: symbol;
|
|
88
132
|
/** One consumed prompt content block (`@deepseek-ai/dsh-llm` `ContentBlock` text members). */
|
|
89
133
|
interface PromptBlockView {
|
|
90
134
|
readonly type: string;
|
|
@@ -166,8 +210,14 @@ export type RolePersonaLogSink = (level: RolePersonaLogLevel, message: string) =
|
|
|
166
210
|
*/
|
|
167
211
|
export declare function setRolePersonaLogger(sink: RolePersonaLogSink): RolePersonaLogSink;
|
|
168
212
|
/**
|
|
169
|
-
* Bind the persona-defaults mirror root
|
|
170
|
-
*
|
|
213
|
+
* Bind the persona-defaults mirror root — the module sink's only writer,
|
|
214
|
+
* invoked once per apply from the entry with `packagedAgentsDir()`, so an
|
|
215
|
+
* HMR re-apply re-binds the root instead of inheriting the previous
|
|
216
|
+
* apply's binding. That re-bind is the intended reset: beyond swapping the
|
|
217
|
+
* root it re-arms the S-002 mirror-absent latch (`mirrorAbsentDebugged`),
|
|
218
|
+
* keeping the "no mirror" debug at most once per apply, and the returned
|
|
219
|
+
* PRIOR binding lets a caller restore the previous root (test pattern:
|
|
220
|
+
* {@link setRolePersonaLogger}).
|
|
171
221
|
* @param dir - the mirror root, or `undefined` to disable mirror defaults.
|
|
172
222
|
*/
|
|
173
223
|
export declare function setRolePersonaAgentsDir(dir: string | undefined): string | undefined;
|
|
@@ -187,4 +237,71 @@ export declare function setRolePersonaAgentsDir(dir: string | undefined): string
|
|
|
187
237
|
* only payload source; `roleMap` is never consulted for the merge).
|
|
188
238
|
*/
|
|
189
239
|
export declare function registerRolePersonaChannel(ctx: Context, config: Config): void;
|
|
240
|
+
/** Outcome of one apply-time seam probe ({@link probeRolePersonaSeam}). */
|
|
241
|
+
export interface PersonaSeamProbeResult {
|
|
242
|
+
/** `true` = the channel is healthy OR the probe failed open (never block apply). */
|
|
243
|
+
ok: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Why the probe classified the channel the way it did. `ok: false` ALWAYS
|
|
246
|
+
* carries a reason; `service-absent` may appear with `ok: true` (the
|
|
247
|
+
* sanctioned no-warn unresolved-service classification).
|
|
248
|
+
*/
|
|
249
|
+
reason?: 'seam-absent' | 'wrap-skipped' | 'service-absent';
|
|
250
|
+
}
|
|
251
|
+
/** One probe observation — the inputs of the pure decision core. */
|
|
252
|
+
export interface SeamProbeInputs {
|
|
253
|
+
/** Whether the temporary canary listener fired during the controlled read. */
|
|
254
|
+
dispatched: boolean;
|
|
255
|
+
/** The value the controlled read threw (`undefined` = the read resolved). */
|
|
256
|
+
readError: unknown;
|
|
257
|
+
/** The controlled read's resolved value (`undefined` when the read threw). */
|
|
258
|
+
value: unknown;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Pure decision core of the seam probe — the ENTIRE outcome table, unit-
|
|
262
|
+
* pinnable without cordis internals:
|
|
263
|
+
*
|
|
264
|
+
* - canary silent → `{ ok: false, reason: 'seam-absent' }` — cordis no
|
|
265
|
+
* longer dispatches the seam; our listener can never run. Dominates the
|
|
266
|
+
* other inputs (a silent canary means the delivery channel is gone).
|
|
267
|
+
* - canary fired + read threw → `{ ok: true, reason: 'service-absent' }` —
|
|
268
|
+
* the seam works but the reading ctx does not resolve `subagents` (on the
|
|
269
|
+
* real composition the apply ctx is inject-guarded; cordis resolves the
|
|
270
|
+
* service in dispatch scopes, where reads are intercepted per read). Never
|
|
271
|
+
* a warn.
|
|
272
|
+
* - canary fired + branded value → `{ ok: true }` — healthy.
|
|
273
|
+
* - canary fired + any other resolved value (unbranded object, primitive,
|
|
274
|
+
* undefined) → `{ ok: false, reason: 'wrap-skipped' }` — the listener ran
|
|
275
|
+
* but the shape was unrecognized (the `wrapSubagentsService` pass-through).
|
|
276
|
+
*/
|
|
277
|
+
export declare function evaluateSeamProbe({ dispatched, readError, value }: SeamProbeInputs): PersonaSeamProbeResult;
|
|
278
|
+
/**
|
|
279
|
+
* Apply-time seam probe — runs EXACTLY ONCE per apply, immediately after
|
|
280
|
+
* {@link registerRolePersonaChannel} (entry wiring), and classifies the
|
|
281
|
+
* channel's install state per {@link evaluateSeamProbe} (observation only —
|
|
282
|
+
* it never changes delivery semantics):
|
|
283
|
+
*
|
|
284
|
+
* 1. register a TEMPORARY {@link PERSONA_SEAM_EVENT} canary listener
|
|
285
|
+
* (`(ctx, name, error, next) => { dispatched = true; return next() }`),
|
|
286
|
+
* keeping the disposer `ctx.on` returns;
|
|
287
|
+
* 2. perform ONE controlled proxied read `ctx.subagents` inside try/catch —
|
|
288
|
+
* the exact read path the per-call `ctx.subagents.start(...)` dispatch
|
|
289
|
+
* takes. NEVER `ctx.get('subagents')`: the accessor reads the service
|
|
290
|
+
* store directly and bypasses the waterfall, which would false-warn
|
|
291
|
+
* `seam-absent` on every healthy boot;
|
|
292
|
+
* 3. dispose the canary SYNCHRONOUSLY (`finally` — also on the throwing
|
|
293
|
+
* read path);
|
|
294
|
+
* 4. classify via {@link evaluateSeamProbe} and log: `ok === false` → ONE
|
|
295
|
+
* warn ({@link SEAM_WARN} + reason); `service-absent` → one debug; a
|
|
296
|
+
* healthy probe stays silent.
|
|
297
|
+
*
|
|
298
|
+
* Contained failure: the body is fully try/catch-wrapped — any probe-
|
|
299
|
+
* internal error (e.g. a rejected listener registration) fails OPEN with
|
|
300
|
+
* `{ ok: true }` plus ONE debug naming the error. Never throws out of
|
|
301
|
+
* `apply`; never affects a subagent start.
|
|
302
|
+
*
|
|
303
|
+
* @param ctx - the plugin's registrant context (a runtime-bearing context —
|
|
304
|
+
* proxied property reads on it dispatch the seam waterfall).
|
|
305
|
+
*/
|
|
306
|
+
export declare function probeRolePersonaSeam(ctx: Context): PersonaSeamProbeResult;
|
|
190
307
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type { DispatchGateAdvisory } from './gates/dispatch.ts';
|
|
|
29
29
|
export { ROLE_PERSONA_LOGGER, registerRolePersonaChannel, setRolePersonaAgentsDir, setRolePersonaLogger, } from './gates/role-persona.ts';
|
|
30
30
|
export type { RolePersonaLogLevel, RolePersonaLogSink, SubagentStartRequestView, SubagentsServiceView } from './gates/role-persona.ts';
|
|
31
31
|
export { ADVISORY_LOGGER, runFallbacksAdvisory, setAdvisoryLogger } from './gates/fallbacks-advisory.ts';
|
|
32
|
-
export type { AdvisoryLogLevel, AdvisoryLogSink } from './gates/fallbacks-advisory.ts';
|
|
32
|
+
export type { AdvisoryLogLevel, AdvisoryLogSink, AdvisoryPassReport } from './gates/fallbacks-advisory.ts';
|
|
33
33
|
export { DshHostAdapter } from './gates/adapter.ts';
|
|
34
34
|
export type { DshHostAdapterOptions } from './gates/adapter.ts';
|
|
35
35
|
/** Cordis function-plugin name registered by the Loader. */
|