@mstar-harness/dsh 2.1.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.
Files changed (146) hide show
  1. package/README.i18n.yaml +7 -0
  2. package/README.md +448 -0
  3. package/README.zh.md +221 -0
  4. package/bundle/README.md +312 -0
  5. package/bundle/cordis.patch.yml +17 -0
  6. package/dist/client/index.d.ts +14 -0
  7. package/dist/client/panel/PanelView.d.ts +67 -0
  8. package/dist/client/panel/TabNav.d.ts +28 -0
  9. package/dist/client/panel/graph/event-log.d.ts +76 -0
  10. package/dist/client/panel/graph/project-graph.d.ts +499 -0
  11. package/dist/client/panel/graph/schema.d.ts +224 -0
  12. package/dist/client/panel/guards.d.ts +12 -0
  13. package/dist/client/panel/locale.d.ts +134 -0
  14. package/dist/client/panel/pages/AgentCanvasPage.d.ts +363 -0
  15. package/dist/client/panel/pages/EventLogPage.d.ts +48 -0
  16. package/dist/client/panel/pages/IterationInfoSection.d.ts +80 -0
  17. package/dist/client/panel/pages/IterationTaskPage.d.ts +37 -0
  18. package/dist/client/panel/panel-meta.d.ts +18 -0
  19. package/dist/client/panel/plan-sort.d.ts +54 -0
  20. package/dist/client/panel/sidebar.d.ts +17 -0
  21. package/dist/client/panel/state-section.d.ts +23 -0
  22. package/dist/client/panel/use-mstar-engine-status.d.ts +42 -0
  23. package/dist/client/panel/zones/Legend.d.ts +18 -0
  24. package/dist/client/panel/zones/TaskBoard.d.ts +40 -0
  25. package/dist/client.d.ts +1 -0
  26. package/dist/client.js +4486 -0
  27. package/dist/gates/_shared.d.ts +198 -0
  28. package/dist/gates/adapter.d.ts +131 -0
  29. package/dist/gates/agent-flow.d.ts +320 -0
  30. package/dist/gates/catalog.d.ts +118 -0
  31. package/dist/gates/dispatch.d.ts +152 -0
  32. package/dist/gates/seams.d.ts +152 -0
  33. package/dist/gates/skill-lint.d.ts +87 -0
  34. package/dist/gates/status.d.ts +81 -0
  35. package/dist/gates/tools.d.ts +37 -0
  36. package/dist/index.d.ts +107 -0
  37. package/dist/index.js +5748 -0
  38. package/dist/invariant.d.ts +15 -0
  39. package/dist/invariant.js +29 -0
  40. package/dist/service.d.ts +96 -0
  41. package/dist/types.d.ts +241 -0
  42. package/harness-commands/codebase-audit.md +40 -0
  43. package/harness-commands/iteration-drive.md +129 -0
  44. package/harness-commands/iteration-loop.md +139 -0
  45. package/harness-commands/iteration-start.md +179 -0
  46. package/harness-skills/grill-me/SKILL.md +10 -0
  47. package/harness-skills/mstar-audit/SKILL.md +183 -0
  48. package/harness-skills/mstar-audit/references/audit-playbook.md +130 -0
  49. package/harness-skills/mstar-audit/references/finding-format.md +65 -0
  50. package/harness-skills/mstar-branch-worktree/SKILL.md +219 -0
  51. package/harness-skills/mstar-branch-worktree/references/parallel-writable-pre-dispatch.md +68 -0
  52. package/harness-skills/mstar-coding-behavior/SKILL.md +147 -0
  53. package/harness-skills/mstar-compound/SKILL.md +105 -0
  54. package/harness-skills/mstar-compound/assets/resolution-template.md +94 -0
  55. package/harness-skills/mstar-compound/references/category-mapping.md +37 -0
  56. package/harness-skills/mstar-compound/references/compound-workflow.md +155 -0
  57. package/harness-skills/mstar-compound/references/concepts-vocabulary.md +44 -0
  58. package/harness-skills/mstar-compound/references/schema.yaml +122 -0
  59. package/harness-skills/mstar-compound-refresh/SKILL.md +140 -0
  60. package/harness-skills/mstar-compound-refresh/references/project-knowledge-bootstrap.md +164 -0
  61. package/harness-skills/mstar-design-md/SKILL.md +142 -0
  62. package/harness-skills/mstar-design-md/references/completeness-checklist.md +181 -0
  63. package/harness-skills/mstar-design-md/references/design-md-spec.md +508 -0
  64. package/harness-skills/mstar-design-md/references/vercel-example.md +200 -0
  65. package/harness-skills/mstar-design-md/templates/DESIGN.dark.md.template +354 -0
  66. package/harness-skills/mstar-design-md/templates/DESIGN.md.template +474 -0
  67. package/harness-skills/mstar-dispatch-gates/SKILL.md +128 -0
  68. package/harness-skills/mstar-dispatch-gates/references/leaf-executor-checklist.md +23 -0
  69. package/harness-skills/mstar-harness-core/SKILL.md +180 -0
  70. package/harness-skills/mstar-host/SKILL.md +78 -0
  71. package/harness-skills/mstar-host/references/_shared/host-role-binding-core.md +51 -0
  72. package/harness-skills/mstar-host/references/_shared/plan-mode-bridge-core.md +91 -0
  73. package/harness-skills/mstar-host/references/codex.md +61 -0
  74. package/harness-skills/mstar-host/references/cursor-plan-mode-bridge.md +159 -0
  75. package/harness-skills/mstar-host/references/cursor.md +183 -0
  76. package/harness-skills/mstar-host/references/dsh.md +502 -0
  77. package/harness-skills/mstar-host/references/kimi-plan-mode-bridge.md +36 -0
  78. package/harness-skills/mstar-host/references/kimi.md +136 -0
  79. package/harness-skills/mstar-host/references/omp-plan-mode-bridge.md +32 -0
  80. package/harness-skills/mstar-host/references/omp.md +244 -0
  81. package/harness-skills/mstar-host/references/opencode.md +76 -0
  82. package/harness-skills/mstar-host/references/parallel-dispatch.md +68 -0
  83. package/harness-skills/mstar-host/references/zcode-plan-mode-bridge.md +36 -0
  84. package/harness-skills/mstar-host/references/zcode.md +129 -0
  85. package/harness-skills/mstar-iteration/SKILL.md +393 -0
  86. package/harness-skills/mstar-iteration/references/autonomous-direction-lock.md +90 -0
  87. package/harness-skills/mstar-iteration/references/iteration-artifact-boundaries.md +103 -0
  88. package/harness-skills/mstar-iteration/references/iteration-compass-template.md +142 -0
  89. package/harness-skills/mstar-iteration/references/iteration-corpus-hygiene.md +45 -0
  90. package/harness-skills/mstar-iteration/references/iteration-workspace-readme-template.md +27 -0
  91. package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +193 -0
  92. package/harness-skills/mstar-iteration/references/phase-3-iteration-close.md +95 -0
  93. package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +84 -0
  94. package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +24 -0
  95. package/harness-skills/mstar-phase-gates/SKILL.md +112 -0
  96. package/harness-skills/mstar-plan-artifacts/SKILL.md +46 -0
  97. package/harness-skills/mstar-plan-artifacts/references/done-compaction.md +88 -0
  98. package/harness-skills/mstar-plan-artifacts/references/knowledge-and-designs.md +100 -0
  99. package/harness-skills/mstar-plan-artifacts/references/plan-files-and-reports.md +99 -0
  100. package/harness-skills/mstar-plan-artifacts/references/plan-quality-bar.md +99 -0
  101. package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +570 -0
  102. package/harness-skills/mstar-plan-artifacts/templates/README.md +9 -0
  103. package/harness-skills/mstar-plan-artifacts/templates/notes.empty.json +5 -0
  104. package/harness-skills/mstar-plan-artifacts/templates/plan.main.md +54 -0
  105. package/harness-skills/mstar-plan-artifacts/templates/plans-done.empty.json +3 -0
  106. package/harness-skills/mstar-plan-artifacts/templates/status.empty.json +7 -0
  107. package/harness-skills/mstar-plan-conventions/SKILL.md +165 -0
  108. package/harness-skills/mstar-plan-conventions/references/artifact-storage-paths.md +50 -0
  109. package/harness-skills/mstar-plan-conventions/references/effort-estimation.md +38 -0
  110. package/harness-skills/mstar-plan-conventions/references/harness-bootstrap-and-agents-layering.md +93 -0
  111. package/harness-skills/mstar-review-qc/SKILL.md +60 -0
  112. package/harness-skills/mstar-review-qc/references/review-responsibility-boundaries.md +54 -0
  113. package/harness-skills/mstar-roles/SKILL.md +86 -0
  114. package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +46 -0
  115. package/harness-skills/mstar-roles/references/architect.md +114 -0
  116. package/harness-skills/mstar-roles/references/code-reviewer.md +109 -0
  117. package/harness-skills/mstar-roles/references/frontend-dev.md +70 -0
  118. package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +89 -0
  119. package/harness-skills/mstar-roles/references/ops-engineer.md +78 -0
  120. package/harness-skills/mstar-roles/references/product-manager.md +107 -0
  121. package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +198 -0
  122. package/harness-skills/mstar-roles/references/project-manager/plan-management.md +61 -0
  123. package/harness-skills/mstar-roles/references/project-manager/qa-trigger-matrix.md +56 -0
  124. package/harness-skills/mstar-roles/references/project-manager/qc-and-residuals.md +98 -0
  125. package/harness-skills/mstar-roles/references/project-manager/routing-and-dev-allocation.md +99 -0
  126. package/harness-skills/mstar-roles/references/project-manager.md +310 -0
  127. package/harness-skills/mstar-roles/references/prompt-engineer.md +71 -0
  128. package/harness-skills/mstar-roles/references/qa-engineer/acceptance-gate.md +62 -0
  129. package/harness-skills/mstar-roles/references/qa-engineer.md +79 -0
  130. package/harness-skills/mstar-roles/references/qc-specialist/deep-review-lenses.md +95 -0
  131. package/harness-skills/mstar-roles/references/qc-specialist/report-template.md +72 -0
  132. package/harness-skills/mstar-roles/references/qc-specialist/reviewer-checklist.md +44 -0
  133. package/harness-skills/mstar-roles/references/qc-specialist/reviewer-workflow.md +57 -0
  134. package/harness-skills/mstar-roles/references/qc-specialist-shared.md +128 -0
  135. package/harness-skills/mstar-roles/references/writing-specialist.md +59 -0
  136. package/harness-skills/mstar-sdd/SKILL.md +133 -0
  137. package/harness-skills/mstar-sdd/references/file-handoffs.md +83 -0
  138. package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +44 -0
  139. package/harness-skills/mstar-sdd/references/implementer-prompt.md +56 -0
  140. package/harness-skills/mstar-sdd/references/sticky-implementer-session.md +103 -0
  141. package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +53 -0
  142. package/harness-skills/mstar-skill-authoring/SKILL.md +162 -0
  143. package/harness-skills/mstar-skill-authoring/references/skillsbench-authoring.md +117 -0
  144. package/harness-skills/mstar-strategy/SKILL.md +130 -0
  145. package/harness-skills/pm/SKILL.md +40 -0
  146. package/package.json +92 -0
@@ -0,0 +1,198 @@
1
+ import z from 'schemastery';
2
+ import type { GateResult, ValidationResult } from '@mstar-harness/engine';
3
+ import type { Config as SkillLocalConfig } from '@deepseek-ai/dsh-skill-filesystem';
4
+ import type { IterationGateListView, IterationGateViolationView } from '../types.ts';
5
+ /** Canonical harness status file name (mstar-plan-artifacts status.json). */
6
+ export declare const STATUS_FILE = "status.json";
7
+ /** Plugin configuration. */
8
+ export interface Config {
9
+ /**
10
+ * Explicit harness root. When set, wins over engine probing (plan-conventions
11
+ * `{HARNESS_DIR}` resolution order); when absent the plugin probes from
12
+ * the SESSION workspace root (`agent.session.header.cwd`) — never the
13
+ * process cwd — walking `.mstar/` → `.agents/` → `.plans/`/`plans/`.
14
+ * Required for repos whose harness root is not a probed name (e.g. a
15
+ * `.harness/` maintenance root).
16
+ */
17
+ harnessDir?: string;
18
+ /**
19
+ * Per-deployment enforcement override. `hard` forces
20
+ * hard gates, `soft` forces warn-only even when an active iteration compass
21
+ * declares `enforcement: hard` (local rollback); absent → the compass
22
+ * frontmatter decides, warn-only when no compass hardens (never a global default).
23
+ */
24
+ enforcement?: 'hard' | 'soft';
25
+ /**
26
+ * Model-facing delegation tool name(s) the dispatch gate matches. The dsh
27
+ * subagent tool registers as `subagent` by default, but its `toolName`
28
+ * config may rename instances (tool-subagent README: each instance needs a
29
+ * distinct name), so the match list is deployment-settable. Defaults to
30
+ * `['subagent']`.
31
+ */
32
+ dispatchTools?: string[];
33
+ /**
34
+ * The dispatching agent's own harness role/type (e.g. `fullstack-dev`), used
35
+ * as the anti-recursion binding: an Assignment whose `Execute as` equals this
36
+ * role is a self-dispatch (critical violation — leaf executors must not
37
+ * re-invoke their own role). dsh exposes no agent role on the tool-execution
38
+ * context, so the deployment declares it. Absent → the anti-recursion
39
+ * precheck is skipped (an empty binding is not self-recursion).
40
+ */
41
+ dispatchBinding?: string;
42
+ /**
43
+ * Additional skill roots registered with the dsh skill-filesystem provider
44
+ * (skill-filesystem `Config.customSkillDirs` semantics — scanned after project
45
+ * roots and before user roots — single canonical mount).
46
+ * Dev-time: the mirror `<repo-root>/skills` absolute path. Each root's
47
+ * children are skill dirs (`<name>/SKILL.md`) or flat skill files
48
+ * (`<name>.md`). Absent → no custom-root registration.
49
+ */
50
+ skillRoots?: string[];
51
+ /**
52
+ * Bundled skill root registered with the dsh skill-filesystem provider
53
+ * (skill-filesystem `Config.bundledSkillDir` semantics — scanned last, trusted).
54
+ * Production: a `skills/` dir shipped inside the plugin package (the
55
+ * canonical published form — dsh defaults `$DSH_BUNDLED_SKILL_DIR` when
56
+ * default roots are included; this plugin mounts an isolated provider, so
57
+ * the bundled root is registered explicitly). Absent → no bundled-root
58
+ * registration.
59
+ */
60
+ bundledSkillDir?: string;
61
+ /**
62
+ * Catalog refresh interval in milliseconds — how often the per-workspace
63
+ * pre-step catalog cache (engine-status watermark, iteration-gate row,
64
+ * harness-state row) re-reads status.json / the compass / the knowledge
65
+ * index. Default 60000: a mid-session plan/compass/residual change lands
66
+ * within one TTL (the hot path stays a timestamp compare + cache hit
67
+ * between refreshes; a bounded sync re-read per workspace at most once
68
+ * per interval). Absent → 60000.
69
+ */
70
+ catalogTtlMs?: number;
71
+ }
72
+ /** 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), so both dispatch keys preserve omission via `.default(undefined)`. */
73
+ export declare const Config: z<Config>;
74
+ /** One violation line for logs and the typed veto message. */
75
+ export declare function formatViolation(violation: ValidationResult): string;
76
+ /** Narrow an unknown value to a record. */
77
+ export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
78
+ /**
79
+ * Resolve the hard-enforcement flag for the artifact gates: explicit
80
+ * Config override wins, else the iteration compass frontmatter (when a
81
+ * harness dir resolves), else warn-only. {@link resolveHard} parity with a
82
+ * null-tolerant harness dir — the skill roots and the artifact
83
+ * seams (design-md / audit / compound / roles) do not require
84
+ * `{HARNESS_DIR}` (compound scoping is the only seam that does, and only
85
+ * for its knowledge-path matcher).
86
+ */
87
+ export declare function resolveSeamHard(harnessDir: string | null, config: Config): boolean;
88
+ /**
89
+ * Resolve the plugin package's own `harness-skills/` mirror (synced from the
90
+ * repo root by `bundle-assets` at build/postinstall; gitignored), anchored at
91
+ * the file URL of one module in the package. Pure — the caller passes its own
92
+ * module URL string, so the dual-depth resolution is directly unit-testable
93
+ * at either layout depth without touching `import.meta`. Resolved
94
+ * package-relative — NOT cwd-anchored — so the shipped bundled mount works
95
+ * from any launch cwd (this resolves the cwd-anchoring limitation for the
96
+ * default; an explicit `bundledSkillDir` still wins). Returns undefined when
97
+ * the mirror is absent (e.g. a checkout where `bundle-assets` has not run —
98
+ * the default mount is then inert).
99
+ *
100
+ * Dual-depth probe semantics: the module moved from `src/index.ts` (one level
101
+ * below the package root) into `src/gates/_shared.ts` (two levels below in
102
+ * the source layout, but still inlined one level below in the bundled
103
+ * `dist/index.js`). Probe both depths — same dual-depth pattern as
104
+ * `pluginVersion()` — so the mirror resolves identically from source and from
105
+ * the bundle (behavior-preserving move; the dist path is the original one):
106
+ * - `'../harness-skills'` — dist 布局候选(`dist/index.js` 深度):shipped
107
+ * form(`package.json` `main: ./dist/index.js`),第一候选直接命中;
108
+ * - `'../../harness-skills'` — 源码布局候选(`src/gates/` 深度):dev-time
109
+ * form;该深度下第一候选解析到 `src/harness-skills`——非规范路径——落空后
110
+ * 命中本候选(规范 `packages/dsh/harness-skills`)。
111
+ * `src/harness-skills` 非规范(镜像仅由 `bundle-assets` 生成到规范位置);
112
+ * 若同名目录意外出现(陈旧镜像),shallow-first 既定——dist 布局命中优先于
113
+ * 源码布局,与 `pluginVersion()` 探测顺序一致(源/dist 不分叉)。
114
+ *
115
+ * @param fileUrl - the module's `import.meta.url` string (or any file URL at
116
+ * the depth whose layout should be probed).
117
+ */
118
+ export declare function resolvePackagedSkillsDir(fileUrl: string): string | undefined;
119
+ export declare function packagedSkillsDir(): string | undefined;
120
+ /**
121
+ * Per-workspace `{HARNESS_DIR}` resolution for the plugin.
122
+ *
123
+ * The probe NEVER starts from the process cwd — it starts from the WORKSPACE
124
+ * root of the session whose agent drives the event (the session cwd,
125
+ * `agent.session.header.cwd` — the dsh workspace the user opened) AND stops
126
+ * there: `workspaceRoot = 探测起点` (roadmap §7c), so the walk-up never
127
+ * leaves the session workspace (the `~/.mstar` global-collision defect is
128
+ * the special case) and the dsh boundary deliberately diverges from the
129
+ * CLI's git-top-level boundary. An
130
+ * explicit `harnessDir` config still wins outright (resolved once at boot;
131
+ * a relative value is launch-cwd anchored — config path anchoring, not
132
+ * probing — matching the `bundledSkillDir` precedent and the engine's
133
+ * `resolve(startDir, explicit)` semantics). Probing results are memoized
134
+ * per workspace root, so the agent-loop hot path does one Map lookup after
135
+ * the first event of each workspace.
136
+ *
137
+ * An event without a session workspace (no agent / no header cwd) resolves
138
+ * to the explicit config or `null` — never a process-cwd probe: without a
139
+ * workspace there is nothing to probe FROM.
140
+ */
141
+ export declare class HarnessResolver {
142
+ private readonly explicit;
143
+ private readonly cache;
144
+ constructor(explicit: string | undefined);
145
+ /**
146
+ * Resolve for one workspace root (the session cwd).
147
+ * @param cwd - the workspace root; `undefined` when the event carries no session.
148
+ * @returns the resolved `{HARNESS_DIR}` (explicit override, else the probe
149
+ * from the workspace root), or `null` when none resolves.
150
+ *
151
+ * Boundary (roadmap §7c): the probe stops AT the workspace root —
152
+ * `workspaceRoot = 探测起点` (the session cwd itself), so it never walks up
153
+ * beyond the session workspace (the `~/.mstar` global-collision special
154
+ * case), and it does NOT inherit the engine's default git-top-level
155
+ * boundary (the CLI surface). An empty/missing `cwd` keeps the current
156
+ * contract: `null`, never a process-cwd probe.
157
+ */
158
+ forWorkspace(cwd: string | undefined): string | null;
159
+ /**
160
+ * Resolve for one agent: the workspace root is the agent's session cwd.
161
+ * @param agent - the agent handle an event carries (structural read).
162
+ */
163
+ forAgent(agent: unknown): string | null;
164
+ }
165
+ /** The workspace root of one agent — the session cwd (structural read; never trusts the runtime shape). */
166
+ export declare function sessionCwdOf(agent: unknown): string | undefined;
167
+ /** The tool-execution actor of one fs-intent event, when it carries an agent. */
168
+ export declare function actorAgentOf(actor: object | undefined): unknown;
169
+ /**
170
+ * Map one engine `ValidationResult` to its lossless JSON view (`fix` omitted
171
+ * when absent so `additionalProperties: false` never sees an undefined key).
172
+ * The view interfaces live in `types.ts` (shared with the pre-step
173
+ * iteration-gate catalog row).
174
+ */
175
+ export declare function iterationViolationView(v: ValidationResult): IterationGateViolationView;
176
+ /** Map one engine gate (`GateResult`) to its JSON view. */
177
+ export declare function iterationGateView(gate: GateResult): IterationGateListView;
178
+ /**
179
+ * Build the dsh skill-filesystem registration payload from the plugin Config
180
+ * (single canonical mount). Semantics mirror the skill-filesystem
181
+ * `Config` contract: `skillRoots` → `customSkillDirs` (custom roots),
182
+ * `bundledSkillDir` → `bundledSkillDir` (bundled root). The provider is
183
+ * named `mstar` and default roots are excluded (`includeDefaultRoots: false`
184
+ * — the repository-plugin convention: an isolated provider must see only its
185
+ * explicit roots, so the mstar mount never claims the host app's own skills;
186
+ * without this the app's user/project skills would be re-discovered under
187
+ * the mstar provider). Returns `undefined` when nothing is configured — no
188
+ * registration happens.
189
+ *
190
+ * The bundled default is the package's OWN `harness-skills/` mirror (synced
191
+ * from the repo root by `bundle-assets` at build/postinstall; gitignored),
192
+ * resolved package-relative — NOT cwd-anchored — so a deployment launching
193
+ * from any cwd gets the bundled mount (this resolves the
194
+ * cwd-anchoring limitation for the shipped default; an explicit
195
+ * `bundledSkillDir` still wins).
196
+ * @param config - validated plugin configuration.
197
+ */
198
+ export declare function skillLocalConfig(config: Config): SkillLocalConfig | undefined;
@@ -0,0 +1,131 @@
1
+ import { Service, type Context } from '@deepseek-ai/cordis';
2
+ import type { AssignmentFields, GateResult, HostAdapter, IntegrationMergeLease, ValidationResult } from '@mstar-harness/engine';
3
+ import type { ToolExecution } from '@deepseek-ai/dsh-tools';
4
+ import type { HarnessResolver, Config } from './_shared.ts';
5
+ import type { AgentFlowPairing } from './agent-flow.ts';
6
+ /** Options for {@link DshHostAdapter}. */
7
+ export interface DshHostAdapterOptions {
8
+ /**
9
+ * The per-workspace `{HARNESS_DIR}` resolver (explicit config wins; the
10
+ * probe never starts from the process cwd). The exec-bound gate paths
11
+ * resolve per the calling session's workspace.
12
+ */
13
+ readonly resolver: HarnessResolver;
14
+ /** The plugin Config the gates resolve enforcement + anti-recursion binding from. */
15
+ readonly config: Config;
16
+ /**
17
+ * The apply-scoped agent-flow pairing store (plan
18
+ * `20260811-panel-f4-timeliness` Task 1 — created by the entry `apply`,
19
+ * shared with the settle listener): passed to `recordDispatch` so an
20
+ * exec-bound dispatch registers `callId → dispatchRef` for the later
21
+ * post-execute settle pairing. Absent (host-adapter tests / direct
22
+ * construction) → no pairing registration (record-only).
23
+ */
24
+ readonly pairing?: AgentFlowPairing;
25
+ /**
26
+ * Log sink for `HostAdapter.log`. Defaults to the dsh ctx logger scoped
27
+ * `mstar/host-adapter` (dsh logger naming: `<scope>/<subject>`).
28
+ */
29
+ readonly log?: (level: 'info' | 'warn' | 'error', msg: string) => void;
30
+ }
31
+ /**
32
+ * The plugin's `HostAdapter` implementation (engine `host.ts` type-only
33
+ * contract) — the HOST-FACING facade over the gate
34
+ * internals: `host: 'dsh'`, `log` → dsh ctx logger, and the optional hooks
35
+ * wired to the SAME code paths the in-plugin gates use, so host hooks and
36
+ * gates share ONE validation path:
37
+ *
38
+ * - `beforeStatusWrite(path, doc)` — validates the incoming document when
39
+ * the host provides it (the write's content — the opencode consumer
40
+ * convention for this engine hook), else the current on-disk document at
41
+ * `path` via the gate's single-read `validateStatusDoc` semantics (missing
42
+ * file = first create = pass). Both inputs flow through
43
+ * `validateStatusValue` — the same pipeline the fs-intent gate runs, so
44
+ * codes match by construction. Returns the FIRST violation: the engine
45
+ * hook shape is one `ValidationResult`; the gate's full violation list
46
+ * stays available on the fs-intent slot.
47
+ * - `beforeDispatch(assignment)` — the dispatch gate validation path
48
+ * (engine `composeDispatchGate` — fields + branch gate + anti-recursion —
49
+ * plus worktree L1/L2 checks; read-only roles skip the branch gate). The lease gate
50
+ * stays listener-side: it binds the ToolExecution context (session id)
51
+ * this hook's contract does not carry. The parsed `AssignmentFields` form
52
+ * is normalized to the engine's own header grammar (lossless — the
53
+ * parsers read exactly these labels) and gated through the same text path.
54
+ * Enforcement is applied like the listener (opencode parity): the
55
+ * returned GateResult carries `hardBlocked` so a refusal-capable host can
56
+ * refuse the dispatch.
57
+ * - `beforeMerge(lease)` — thin wrapper over the engine
58
+ * `validateIntegrationMergeLease` (reserve/validate the integration merge
59
+ * lease; the reservation WRITE into status.json is a P3 seam).
60
+ */
61
+ export declare class DshHostAdapter extends Service implements HostAdapter {
62
+ /** Engine host identity (`HostId` union). */
63
+ readonly host: "dsh";
64
+ private readonly resolver;
65
+ private readonly config;
66
+ private readonly pairing;
67
+ private readonly logSink;
68
+ constructor(ctx: Context, options: DshHostAdapterOptions);
69
+ /**
70
+ * `HostAdapter.log` — the adapter's own reporting channel (the gates keep
71
+ * their scoped loggers; this is the host-facing sink).
72
+ * @param level - log level.
73
+ * @param msg - message.
74
+ */
75
+ log(level: 'info' | 'warn' | 'error', msg: string): void;
76
+ /**
77
+ * Shared status-gate core (plugin-internal): the fs-intent listeners and
78
+ * the `beforeStatusWrite` on-disk fallback route through this method —
79
+ * ONE validation code path. Missing file = first create = pass (the
80
+ * intent waterfall carries no incoming content, so the vetoable signal is
81
+ * the pre-write on-disk state).
82
+ * @param statusPath - the canonical `{HARNESS_DIR}/status.json` path.
83
+ */
84
+ statusGate(statusPath: string): GateResult;
85
+ /**
86
+ * Shared dispatch-gate core (plugin-internal): the `tools/pre-execute`
87
+ * listener and `beforeDispatch` route through this method — ONE
88
+ * validation code path (field gate + anti-recursion + branch gate +
89
+ * worktree L1/L2 checks; read-only roles skip the branch gate). The
90
+ * listener passes `exec` so the lease gate (ToolExecution-bound: session
91
+ * id, in-flight call) joins the same verdict; the host hook has no exec
92
+ * context and covers the field/branch/anti-recursion/worktree path.
93
+ * @param prompt - the Assignment text (engine header grammar).
94
+ * @param exec - the in-flight delegation tool call (listener path only).
95
+ * @param hard - the caller's ONE `resolveDispatchHard` resolution (qc1
96
+ * F-002 / qc2 F-3 / qc3 F-002 fix-wave): passed in so the record block and
97
+ * the caller's enforcement decision share a single compass resolution;
98
+ * when omitted (external callers) the adapter resolves it itself.
99
+ */
100
+ dispatchGate(prompt: string, exec?: ToolExecution, hard?: boolean): GateResult;
101
+ /**
102
+ * `HostAdapter.beforeStatusWrite` — see the class doc for the doc-first /
103
+ * on-disk-fallback semantics. Never throws; a failing gate maps to its
104
+ * FIRST violation (severity/code/message/fix/aliases preserved — failing
105
+ * gates always carry ≥1 violation), a passing gate to
106
+ * `host.beforeStatusWrite.ok` (the engine test convention for this hook).
107
+ * @param path - the status.json target path.
108
+ * @param doc - the document about to be written (undefined → validate the
109
+ * on-disk document at `path`).
110
+ */
111
+ beforeStatusWrite(path: string, doc: unknown): Promise<ValidationResult>;
112
+ /**
113
+ * `HostAdapter.beforeDispatch` — the dispatch gate validation path (see
114
+ * the class doc). Accepts the raw Assignment text (full fidelity: the
115
+ * `Enforcement` header flag participates in enforcement resolution) or the
116
+ * parsed `AssignmentFields` (engine-typed hook input; normalized to the
117
+ * engine's header grammar before gating). Returns the enforced GateResult
118
+ * — `hardBlocked` mirrors the `tools/pre-execute` deny decision under the
119
+ * same enforcement resolution.
120
+ * @param assignment - raw Assignment text or parsed header fields.
121
+ */
122
+ beforeDispatch(assignment: AssignmentFields | string): Promise<GateResult>;
123
+ /**
124
+ * `HostAdapter.beforeMerge` — reserve/validate the integration merge
125
+ * lease. Thin wrapper over the engine `validateIntegrationMergeLease`
126
+ * (the engine owns the lease shape; the reservation write into
127
+ * `{HARNESS_DIR}/status.json` is a P3 seam).
128
+ * @param lease - the `metadata.integration_merge_lease` object.
129
+ */
130
+ beforeMerge(lease: IntegrationMergeLease): Promise<GateResult>;
131
+ }
@@ -0,0 +1,320 @@
1
+ import { type Context } from '@deepseek-ai/cordis';
2
+ import type { AgentFlowView } from '../types.ts';
3
+ import type { Config } from './_shared.ts';
4
+ /** The agent-flow ledger file name under `{HARNESS_DIR}`. */
5
+ export declare const AGENT_FLOW_FILE = "agent-flow.jsonl";
6
+ /** Truncation bound: the ledger keeps only the most recent events. */
7
+ export declare const AGENT_FLOW_MAX_EVENTS = 500;
8
+ /** Default read limit (the catalog passes 50 per spec §2.2). */
9
+ export declare const AGENT_FLOW_DEFAULT_LIMIT = 50;
10
+ /**
11
+ * The append size gate (qc2 F-1 / qc3 F-001/003 — fix-wave): the truncation
12
+ * read-modify-write runs only when the file exceeds ~500 lines' typical
13
+ * size (conservative ≈ 500 × 128 B average line); smaller files stay
14
+ * append-only. The bound is therefore approximate ("~500 events") — a file
15
+ * of unusually tiny events can grow past 500 lines under the gate until its
16
+ * BYTES cross the threshold (documented tradeoff; the gate keeps the common
17
+ * small-file append path free of a full read per dispatch).
18
+ */
19
+ export declare const AGENT_FLOW_SIZE_GATE_BYTES: number;
20
+ /** Logger label for the agent-flow ledger (dsh logger naming: `<scope>/<subject>`). */
21
+ export declare const AGENT_FLOW_LOGGER = "mstar/agent-flow";
22
+ /**
23
+ * The settle seam name — the dsh-tools registry's `tools/post-execute`
24
+ * waterfall. VERIFIED to be dispatched by the real registry for every tool
25
+ * call (`runPostExecute` → `postExecute`, upstream source; pinned by the
26
+ * real-call probe in `tests/agent-flow.spec.ts`), so settles are no longer
27
+ * host-emission-dependent (plan `20260811-panel-f4-timeliness` Task 1 — the
28
+ * old "not part of the verified surface" assumption is obsolete).
29
+ */
30
+ export declare const SETTLE_SEAM = "tools/post-execute";
31
+ /**
32
+ * The once-per-apply settle-pairing trace (plan `20260811-panel-f4-timeliness`
33
+ * Task 1). Historical name `SETTLE_SEAM_UNAVAILABLE_NOTE` (qc1 F-105 / qc2
34
+ * N-002 fix-wave): the old name claimed the seam was UNAVAILABLE, which the
35
+ * message itself refutes — the seam IS a verified part of the registry
36
+ * surface, so the constant was renamed to the accurate `PAIRING` name. The
37
+ * message states the VERIFIED pairing facts: the seam is emitted by the
38
+ * registry; foreground dispatch calls settle via it, background subagents
39
+ * settle via `ctx.jobs.onJobDone` pairing; only unpaired payloads stay
40
+ * dispatch-only (never fabricated settlement). Logged ONCE per logger binding
41
+ * (≈ once per apply — the same module-level flag, qc1 F-006) when the pairing
42
+ * listener is registered.
43
+ */
44
+ export declare const SETTLE_SEAM_PAIRING_NOTE = "settle seam \"tools/post-execute\" IS part of the verified dsh-tools registry surface (runPostExecute dispatches it for every tool call) \u2014 foreground dispatch calls settle here, background subagents settle via ctx.jobs.onJobDone pairing; only UNPAIRED payloads (non-dispatch tools, calls outside the apply-scoped pairing window) stay dispatch-only \u2014 never a fabricated settle";
45
+ /** Dispatch verdict vocabulary (spec §2.1.3). */
46
+ export type DispatchVerdict = 'ok' | 'advisory' | 'denied';
47
+ /** Settle outcome vocabulary (spec §2.1.3). */
48
+ export type SettleOutcome = 'ok' | 'error' | 'denied';
49
+ /**
50
+ * One v1 ledger event (spec §2.1.3 schema — the JSONL line). Optional fields
51
+ * are OMITTED from the serialized line when absent (Session.append's lossless
52
+ * JSON discipline starts at the record boundary).
53
+ */
54
+ export type AgentFlowEvent = {
55
+ v: 1;
56
+ ts: number;
57
+ kind: 'dispatch';
58
+ /** The dispatching session's stable id (exec.agent.id; host-hook path has no exec → absent). */
59
+ agent?: string;
60
+ /** Assignment `Execute as` ('' when missing). */
61
+ role: string;
62
+ /** planIdOf(header): `Plan Path` / `SDD dir` / `plan_id` basename. */
63
+ planId?: string;
64
+ /** Body `Task N` best-effort extraction (taskIdOf). */
65
+ taskId?: string;
66
+ /** Assignment `Task category`. */
67
+ taskCategory?: string;
68
+ /** Gate verdict derivation: no violations → ok; hard + violations → denied; else advisory. */
69
+ verdict: DispatchVerdict;
70
+ /** resolveDispatchHard result (recorded unconditionally, incl. hard denies). */
71
+ hard: boolean;
72
+ } | {
73
+ v: 1;
74
+ ts: number;
75
+ kind: 'settle';
76
+ /** The settled session's stable id (the paired dispatch's agent). */
77
+ agent?: string;
78
+ outcome: SettleOutcome;
79
+ durationMs?: number;
80
+ /**
81
+ * The PAIRED dispatch's identity (plan `20260811-panel-f4-timeliness`
82
+ * Task 1) — same field names + semantics as the dispatch event:
83
+ * `role` is the Assignment `Execute as` ('' when missing), `planId` /
84
+ * `taskId` the plan + `Task N` tags. Written for every paired settle;
85
+ * ABSENT on unpaired (legacy) settles — the client pairs on identity
86
+ * presence. The registry background-task id is deliberately NOT
87
+ * written here (`taskRef` is reserved as the distinct field name if a
88
+ * future audit needs it — it never collides with `taskId`).
89
+ */
90
+ role?: string;
91
+ planId?: string;
92
+ taskId?: string;
93
+ };
94
+ /**
95
+ * The identity of one recorded dispatch, carried by the pairing store so a
96
+ * later completion (post-execute settle / onJobDone terminal) can record a
97
+ * settle carrying the SAME identity fields as its dispatch event.
98
+ */
99
+ export interface AgentFlowDispatchRef {
100
+ /** The resolved `{HARNESS_DIR}` the dispatch recorded into (settles record into the same ledger). */
101
+ harnessDir: string;
102
+ /** The dispatching session's stable id ('' when the exec carried none). */
103
+ agent?: string;
104
+ /** Assignment `Execute as` ('' when missing — the dispatch event's grammar). */
105
+ role: string;
106
+ /** `planIdOf(header)` — the dispatch event's grammar. */
107
+ planId?: string;
108
+ /** `taskIdOf(prompt)` — the Assignment `Task N` tag, NOT a registry task id. */
109
+ taskId?: string;
110
+ }
111
+ /**
112
+ * The apply-scoped pairing store (plan `20260811-panel-f4-timeliness` Task 1,
113
+ * decision D1 — created in the entry `apply`, same lifetime as the catalog
114
+ * cache; an HMR restart resets it, and completions outside the window stay
115
+ * unpaired → no settle, the documented honest degrade). Maps are keyed by
116
+ * the TWO verified pairing keys: the tool-call `callId` (pre → post-execute)
117
+ * and the registry background-task id (post-execute background shape →
118
+ * `onJobDone` terminal).
119
+ */
120
+ export interface AgentFlowPairing {
121
+ /**
122
+ * The agent-namespaced call key → the dispatch it recorded (populated by
123
+ * `recordDispatch` when an exec is present). Key = `${sessionId}\u0000${callId}`
124
+ * (qc1 F-101 fix-wave): a raw `ToolExecution.callId` is NOT globally unique
125
+ * in one process — dsh runs many sessions concurrently and upstream mints
126
+ * per-message ids (`call-${index}`), so the dispatching session id must
127
+ * namespace the key or session B's same-id call could overwrite session A's
128
+ * pairing and mis-pair A's settle into B's dispatchRef. Consumed (deleted)
129
+ * by the post-execute branch — the map holds only in-flight calls.
130
+ */
131
+ dispatchByCallId: Map<string, AgentFlowDispatchRef>;
132
+ /** Registry background-job id (`JobSnapshot.id`) → the dispatch that started it (populated by the post-execute background branch; consumed by `recordTaskSettle`). */
133
+ dispatchByTaskId: Map<string, AgentFlowDispatchRef>;
134
+ }
135
+ /** Module-scoped log sink (bound to `mstar/agent-flow` by the entry at apply). */
136
+ type AgentFlowLogSink = (level: 'info' | 'warn' | 'error', message: string) => void;
137
+ /**
138
+ * Module-scoped catalog-invalidation hook (plan `20260811-panel-f4-timeliness`
139
+ * Task 1 — the `invalidateCatalog` 挂钩 that Task 2 consumes): called with
140
+ * the affected `{HARNESS_DIR}` after every SUCCESSFUL ledger record
141
+ * (`recordDispatch` / `recordSettle`). The entry binds the real invalidation
142
+ * closure at apply (Task 2 shipped the apply-scoped harnessDir → cache-key
143
+ * reverse-map closure in `index.ts` — see `createCatalogInvalidation`);
144
+ * unbound → no-op. Never throws into the record path.
145
+ */
146
+ type AgentFlowInvalidator = (harnessDir: string) => void;
147
+ /**
148
+ * Bind the module's catalog-invalidation hook (plan
149
+ * `20260811-panel-f4-timeliness` Task 1 — same pattern as
150
+ * {@link setAgentFlowLogger}; the entry binds at apply; Task 2 shipped the
151
+ * real binding — the apply-scoped harnessDir → cache-key reverse-map
152
+ * closure in `index.ts`).
153
+ * @param invalidate - the hook (`undefined` clears the binding).
154
+ * @returns the PREVIOUS hook (tests restore it in a `finally`).
155
+ */
156
+ export declare function setAgentFlowInvalidator(invalidate: AgentFlowInvalidator | undefined): AgentFlowInvalidator | undefined;
157
+ /**
158
+ * Bind the module's log sink (called once at apply; tests may rebind to
159
+ * capture ledger logs). Rebinding RESETS the once-per-apply settle trace
160
+ * flag — each binding is a fresh "apply" (production binds once; tests bind
161
+ * per case for deterministic capture).
162
+ * @param sink - the sink (entry binds `ctx.logger('mstar/agent-flow')`);
163
+ * `undefined` clears the binding (restores the pre-bind no-op state).
164
+ * @returns the PREVIOUS sink (tests restore it in a `finally`).
165
+ */
166
+ export declare function setAgentFlowLogger(sink: AgentFlowLogSink | undefined): AgentFlowLogSink | undefined;
167
+ /**
168
+ * Best-effort extraction of the targeted `Task N` from the Assignment BODY
169
+ * (spec §2.1.1 — `taskIdOf`). The engine `assignmentHeaderRegion` boundary is
170
+ * reused: only text AFTER the header region is scanned, so a `## Task N`
171
+ * example quoted in the header never resolves a task id. Only a LEVEL-2
172
+ * heading (`^## Task N`) matches (qc2 F-8: an example or sub-heading at
173
+ * another depth before the real task must not resolve — lower false-hit
174
+ * surface); normalized to `T<n>` (matches the panel render `planId#taskId`,
175
+ * e.g. `20260810-x#T2`).
176
+ * @param prompt - the full Assignment text.
177
+ */
178
+ export declare function taskIdOf(prompt: string): string | undefined;
179
+ /**
180
+ * Record one dispatch event (spec §2.1.3). Fully try/catch-contained — NEVER
181
+ * throws into the gate; a failing record logs only (`mstar/agent-flow`).
182
+ * Verdict derivation (ok/advisory/denied, incl. hard denies) and the header
183
+ * identity derivation (role / planId / taskId / taskCategory) reuse the gate's
184
+ * own parsers — one grammar.
185
+ *
186
+ * Pairing (plan `20260811-panel-f4-timeliness` Task 1): when the input
187
+ * carries an `exec` AND the apply-scoped `pairing` store, the successful
188
+ * record registers the agent-namespaced key `${sessionId}\u0000${callId}` →
189
+ * dispatchRef (the full dispatch identity), so a later
190
+ * `tools/post-execute` for the same call can settle with the SAME identity
191
+ * (qc1 F-101 fix-wave: the session id namespaces the key — a raw callId is
192
+ * not globally unique across sessions in one process). The pairing registers
193
+ * only after the ledger append SUCCEEDED — a failed record never pairs to a
194
+ * phantom dispatch. An exec-less record (host-hook path) has no callId → no
195
+ * pairing. The pairing sub-path has its OWN catch scope (qc1 F-106 / qc2
196
+ * N-001 / qc3 F-006 fix-wave): a `Map.set` throw must not log "record
197
+ * failed" after the dispatch was already appended.
198
+ * @param input - harness dir + exec (agent id) + Assignment text + the gate's
199
+ * violations + the hard-enforcement resolution + the apply-scoped pairing
200
+ * store (the adapter passes its own; direct callers may omit it).
201
+ */
202
+ export declare function recordDispatch(input: {
203
+ harnessDir: string;
204
+ exec?: unknown;
205
+ prompt: string;
206
+ violations: readonly unknown[];
207
+ hard: boolean;
208
+ pairing?: AgentFlowPairing;
209
+ }): void;
210
+ /**
211
+ * Record one settle event (spec §2.1.3). Fully try/catch-contained; a failing
212
+ * record logs only. Callers resolve the harness dir from the PAIRED dispatch
213
+ * (the pairing store's dispatchRef — never a payload probe).
214
+ * @param input - harness dir + agent id + outcome + optional duration + the
215
+ * PAIRED dispatch's identity (`role`/`planId`/`taskId` — same field names +
216
+ * semantics as the dispatch event; written for every paired settle, so the
217
+ * client can exactly pair the settle back to its dispatch).
218
+ */
219
+ export declare function recordSettle(input: {
220
+ harnessDir: string;
221
+ agent?: string;
222
+ outcome: SettleOutcome;
223
+ durationMs?: number;
224
+ role?: string;
225
+ planId?: string;
226
+ taskId?: string;
227
+ }): void;
228
+ /**
229
+ * Read the agent-flow ledger as the catalog view (spec §2.1.3 — fix-wave
230
+ * qc1 F-001 / qc2 F-6): the latest events first (bounded by `limit`) plus
231
+ * the role × outcome summary over the SAME window (so `by role` counts sum
232
+ * to the event count). A MISSING ledger file returns the EMPTY view
233
+ * `{ events: [], summary: [] }` — recording hasn't started (it begins at
234
+ * plan merge), and the panel renders its "no actual dispatches yet" empty
235
+ * state instead of an evidence-missing degrade; only an UNREADABLE file
236
+ * returns null (advisory degrade — the catalog renders no agent-flow line).
237
+ * Malformed lines are skipped, never fatal.
238
+ * @param harnessDir - the resolved `{HARNESS_DIR}`.
239
+ * @param limit - explicit window bound: `undefined` → `AGENT_FLOW_DEFAULT_LIMIT`;
240
+ * otherwise `Math.max(0, Math.floor(limit))` — `0` requests the EMPTY window.
241
+ */
242
+ export declare function readAgentFlow(harnessDir: string, limit?: number): AgentFlowView | null;
243
+ /**
244
+ * The `tools/post-execute` settle pairing (plan `20260811-panel-f4-timeliness`
245
+ * Task 1 — replaces the old defensive payload probing): the VERIFIED
246
+ * dsh-tools registry dispatches this seam for every tool call
247
+ * (`runPostExecute` → `postExecute`, upstream source), so the listener only
248
+ * decides whether a completion signal exists for the PAIRED dispatch:
249
+ *
250
+ * - non-dispatch tool (`exec.name` ∉ Config `dispatchTools`) → nothing;
251
+ * - dispatch tool whose agent-namespaced call key
252
+ * (`${sessionId}\u0000${callId}`, qc1 F-101 fix-wave) is not in the pairing
253
+ * store (HMR reset, host-hook dispatch, non-gate path) → nothing (warned
254
+ * once per registration — honest degrade, never fabricated settlement);
255
+ * - `result.isError === true` OR an `error` payload present → settle `error`
256
+ * immediately (fabrication guard, qc2 F-001 / qc3 F-003a — the dispatch
257
+ * call failed; a result carrying `error` without `isError` never settles ok);
258
+ * - successful `result.value` shape `{ kind: 'background', taskId }` with a
259
+ * valid taskId → store `taskId → dispatchRef` (the real settle arrives via
260
+ * `ctx.jobs.onJobDone`); `{ kind: 'background' }` WITHOUT a valid taskId
261
+ * → nothing mappable (no settle, qc3 F-003b);
262
+ * - `{ kind: 'continuable', subagentId }` → no terminal signal this round →
263
+ * no settle (documented limit — the child owns its turns);
264
+ * - any other successful value (foreground `{ kind: 'foreground', … }`
265
+ * included) → settle `ok` (the call completed synchronously).
266
+ * The consumed `dispatchByCallId` entry is DELETED after the branch resolves
267
+ * the call (map pruning, qc1 F-102 / qc2 F-002 / qc3 F-002 — each callId
268
+ * pairs exactly once; the map holds only in-flight calls).
269
+ *
270
+ * The waterfall MUST be delegated via `next()` on every path — returning
271
+ * without calling `next` bails the chain and breaks every tool call. A
272
+ * throwing record never propagates.
273
+ *
274
+ * Cordis typing note: `ctx.on` only accepts declared event keys and
275
+ * `tools/post-execute` is undeclared — the registration casts through the
276
+ * runtime-accepted event-name string (the event bus dispatches any name).
277
+ * @param ctx - registrant context (fiber disposal unwinds the listener).
278
+ * @param config - the plugin Config (dispatch-tool matching).
279
+ * @param pairing - the apply-scoped pairing store (dispatchByCallId read,
280
+ * dispatchByTaskId written by the background branch).
281
+ */
282
+ export declare function registerSettleListener(ctx: Context, config: Config, pairing: AgentFlowPairing): void;
283
+ /**
284
+ * The structural read of the dsh-jobs terminal snapshot the pairing consumes
285
+ * (plan `20260811-panel-f4-timeliness` Task 1). The `ctx.jobs.onJobDone`
286
+ * contract was verified against the upstream `@deepseek-ai/dsh-jobs`
287
+ * `types.ts`: `JobDoneListener = (snapshot, owner) => …`, terminal
288
+ * `snapshot.status` ∈ `completed | killed | failed`, `startedAt`/`finishedAt`
289
+ * are epoch ms (`finishedAt` absent while running). Structural (no runtime or
290
+ * type import of the optional dsh-jobs seam — the plugin treats it as an
291
+ * optional service, wired via `ctx.inject(['jobs'])`).
292
+ */
293
+ export interface TaskDoneSnapshot {
294
+ /** The registry-issued task id (`<kind>-N`, e.g. `subagent-1`). */
295
+ id: string;
296
+ /** Terminal lifecycle status: `completed | killed | failed`. */
297
+ status: string;
298
+ /** Epoch ms when the task was registered. */
299
+ startedAt?: number;
300
+ /** Epoch ms when the task settled. */
301
+ finishedAt?: number;
302
+ }
303
+ /**
304
+ * Record the settle for one background-task terminal (plan
305
+ * `20260811-panel-f4-timeliness` Task 1 — the `ctx.jobs.onJobDone` path):
306
+ * the snapshot's task id must hit the pairing store's `dispatchByTaskId`
307
+ * (populated by the post-execute background branch) — a miss records NOTHING
308
+ * (honest degrade, never fabricated). Outcome mapping: `completed → ok` /
309
+ * `killed → denied` / `failed → error`; `durationMs = finishedAt − startedAt`
310
+ * when both are present. After a SUCCESSFUL settle the consumed
311
+ * `dispatchByTaskId` entry is deleted (map pruning, qc1 F-102 / qc2 F-002 /
312
+ * qc3 F-002 — the map holds only in-flight tasks; a contract-violating
313
+ * non-terminal snapshot records nothing and KEEPS the entry so a later real
314
+ * terminal can still settle). Fully contained — never throws into the task
315
+ * registry's listener notification.
316
+ * @param snapshot - the terminal task snapshot (structural read).
317
+ * @param pairing - the apply-scoped pairing store.
318
+ */
319
+ export declare function recordTaskSettle(snapshot: TaskDoneSnapshot, pairing: AgentFlowPairing): void;
320
+ export {};