dsh-task-dispatch-table 0.0.0 → 0.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 (48) hide show
  1. package/README.md +101 -31
  2. package/README.zh.md +119 -0
  3. package/assets/icon-scheduler.svg +1 -0
  4. package/cordis.patch.yml +9 -0
  5. package/dist/attachment-allowlist.d.ts +24 -0
  6. package/dist/attachment-allowlist.js +41 -0
  7. package/dist/calendar-plan.d.ts +55 -0
  8. package/dist/calendar-plan.js +104 -0
  9. package/dist/client.js +72655 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/config.d.ts +79 -0
  12. package/dist/config.js +80 -0
  13. package/dist/deps.d.ts +25 -0
  14. package/dist/deps.js +54 -0
  15. package/dist/dispatch.d.ts +133 -0
  16. package/dist/dispatch.js +509 -0
  17. package/dist/event-bus.d.ts +16 -0
  18. package/dist/event-bus.js +67 -0
  19. package/dist/event-catalog.d.ts +42 -0
  20. package/dist/event-catalog.js +60 -0
  21. package/dist/host.d.ts +299 -0
  22. package/dist/host.js +1 -0
  23. package/dist/index.d.ts +25 -0
  24. package/dist/index.js +0 -0
  25. package/dist/receipt.d.ts +38 -0
  26. package/dist/receipt.js +236 -0
  27. package/dist/reconcile.d.ts +105 -0
  28. package/dist/reconcile.js +641 -0
  29. package/dist/runtime-index.d.ts +102 -0
  30. package/dist/runtime-index.js +340 -0
  31. package/dist/schedule-next.d.ts +44 -0
  32. package/dist/schedule-next.js +216 -0
  33. package/dist/scheduler.d.ts +82 -0
  34. package/dist/scheduler.js +639 -0
  35. package/dist/store.d.ts +461 -0
  36. package/dist/store.js +845 -0
  37. package/dist/submit.d.ts +1 -0
  38. package/dist/submit.js +60 -0
  39. package/dist/task-assets.d.ts +124 -0
  40. package/dist/task-assets.js +380 -0
  41. package/dist/task-sort.d.ts +27 -0
  42. package/dist/task-sort.js +59 -0
  43. package/dist/tasks.d.ts +191 -0
  44. package/dist/tasks.js +527 -0
  45. package/locale/en.json +6 -0
  46. package/locale/zh.json +6 -0
  47. package/package.json +67 -6
  48. package/index.js +0 -7
@@ -0,0 +1,60 @@
1
+ // event-catalog.ts — 事件推送的**事件目录**(前后端共用)。
2
+ //
3
+ // 事件模型:`{ type: 固定常量, payload?: 任意业务对象 }`。
4
+ // · `type` 只来自本文件(谁都不许随手造新码);
5
+ // · `payload` 由各业务自定义、**可为空**(如 FORCE_REFRESH);
6
+ // · 事件是「**失效信号**」——**不承载数据、不写库**,订阅方收到后自行重读真源(任务表 / 实例表)。
7
+ //
8
+ // ⚠️ 本文件必须**纯常量、无 Node 依赖**:它会被 tsdown 内联进单文件客户端产物 `dist/client.js`
9
+ // (见 design/event-push.md 与 docs/design/external/host-webserver-streaming.md)。
10
+ /** 事件类型目录(前后端唯一真源;新增类型只在这里加)。 */
11
+ export const EventType = {
12
+ /** 任务定义增删改(含开关 / 整批替换 / 版本删除 / 附件文件变更;这些写路径都汇聚到 onDefinitionsChanged)。 */
13
+ TASKS_CHANGED: 'tasks.changed',
14
+ /** 实例进入 dispatched / running(自动调度或「立即执行」)。 */
15
+ TASK_RUN_STARTED: 'task.run.started',
16
+ /** 实例成功终态。 */
17
+ TASK_RUN_SUCCEEDED: 'task.run.succeeded',
18
+ /** 实例失败终态(含判死 / 租约回收 / 回执缺失收敛)。 */
19
+ TASK_RUN_FAILED: 'task.run.failed',
20
+ /** 跳过 / 错过刻度 / 过期(「未执行」的原因类)。 */
21
+ TASK_RUN_SKIPPED: 'task.run.skipped',
22
+ /** 其余实例行变化(重试退回 / unknown 复活 / 转 running / redispatch / 删行 / 阻塞原因变化)。 */
23
+ TASK_RUN_CHANGED: 'task.run.changed',
24
+ /** 插件配置变更。 */
25
+ CONFIG_CHANGED: 'config.changed',
26
+ /** 无参:强制前端重读一次当前值(后端升级 / 索引重建等)。 */
27
+ FORCE_REFRESH: 'force.refresh',
28
+ };
29
+ /** 「实例运行态」这一族事件(订阅方通常一并关心)。 */
30
+ export const RUN_EVENT_TYPES = [
31
+ EventType.TASK_RUN_STARTED,
32
+ EventType.TASK_RUN_SUCCEEDED,
33
+ EventType.TASK_RUN_FAILED,
34
+ EventType.TASK_RUN_SKIPPED,
35
+ EventType.TASK_RUN_CHANGED,
36
+ ];
37
+ /**
38
+ * 连接心跳的事件类型(**不属于业务事件目录**,故意不在 `EventType` 里):
39
+ * 服务端每 `SSE_HEARTBEAT_MS` 发一条,客户端只用它判断「这条连接还是活的」——这是「`readyState` 是
40
+ * OPEN 但已经半死」唯一可观测的判据(反向代理静默丢流 / 无 FIN 的黑洞)。
41
+ * ⚠️ 必须是**真实 data 帧**:SSE 注释帧(`: ping`)浏览器直接吞掉,前端 `onmessage` 根本看不到。
42
+ * 前端 `byType` 里没有它的订阅者 ⇒ 收到后直接丢弃,不会当成业务事件(2026-10-06 审计)。
43
+ */
44
+ export const HEARTBEAT_TYPE = 'sys.ping';
45
+ /** 与心跳相关的**非**业务类型集合(订阅方一律忽略;留一处便于将来扩充)。 */
46
+ export const NON_BUSINESS_TYPES = [HEARTBEAT_TYPE];
47
+ /**
48
+ * 实例状态 → 事件类型(`RuntimeIndex.markTerminal` / `markDispatched` 的映射)。
49
+ * 只按「类型」订阅的前端拿它区分成功 / 失败 / 跳过 / 其它;状态细节交给重读。
50
+ */
51
+ export function runEventTypeOf(status) {
52
+ switch (status) {
53
+ case 'succeeded': return EventType.TASK_RUN_SUCCEEDED;
54
+ case 'failed': return EventType.TASK_RUN_FAILED;
55
+ case 'skipped': return EventType.TASK_RUN_SKIPPED;
56
+ case 'dispatched':
57
+ case 'running': return EventType.TASK_RUN_STARTED;
58
+ default: return EventType.TASK_RUN_CHANGED;
59
+ }
60
+ }
package/dist/host.d.ts ADDED
@@ -0,0 +1,299 @@
1
+ import type z from '@deepseek-ai/schemastery';
2
+ export type z_any<T> = z<T>;
3
+ /** 会话 id:宿主侧为 brand string(core/session/src/types.ts),本插件按字符串处理。 */
4
+ export type SessionId = string;
5
+ /**
6
+ * 会话最小面。形状依据 core/session/src/index.ts:442-510(Session 存储会话,
7
+ * header 含 id/createdAt/cwd)。
8
+ */
9
+ export interface HostSession {
10
+ readonly id: SessionId;
11
+ }
12
+ /**
13
+ * 消息面。形状依据 0.1.7 v4 会话格式(session-format-v3-to-v4/src/message-sources.ts):
14
+ * source.kind 必须是**生产者自有 kind**(`kind: 'plugin'` 是 v3 retired 语法,v4 校验直接
15
+ * 抛 "format v4 message requires a producer-owned source kind")。notice 形状参照宿主自带
16
+ * schedule 插件(runtime.ts:119-121 `{ kind: 'schedule' }`)与 subagent 结算通知
17
+ * (continuation-messages.ts:30-38 `{ kind, form: 'notice', summary }`)。
18
+ */
19
+ /** 文本块(`dsh-llm@0.2.0-rc.2` ContentBlockMap 的 `text`)。 */
20
+ export interface UserTextContent {
21
+ readonly type: 'text';
22
+ readonly text: string;
23
+ }
24
+ /**
25
+ * 官方附件引用(`dsh-attachment@0.2.0-rc.2` `lib/types/types.d.ts:34-41`)。
26
+ * ⚠️ **没有路径**:`attachmentId` 是内容寻址摘要(`never a filesystem path`),
27
+ * ⇒ 附件 = **字节副本**,不是链接;目录无法作为附件。
28
+ */
29
+ export interface FileAttachmentRef {
30
+ readonly attachmentId: string;
31
+ readonly name: string;
32
+ readonly bytes: number;
33
+ }
34
+ /** 文件块(`ContentBlockMap` 的 `file`):附件由宿主附件服务持有,会话里只记引用。 */
35
+ export interface UserFileContent {
36
+ readonly type: 'file';
37
+ readonly attachment: FileAttachmentRef;
38
+ }
39
+ export interface UserMessage {
40
+ readonly id: string;
41
+ readonly role: 'user';
42
+ readonly content: readonly (UserTextContent | UserFileContent)[];
43
+ readonly source: {
44
+ kind: 'task-dispatch-table';
45
+ form: 'notice';
46
+ summary: string;
47
+ };
48
+ }
49
+ /**
50
+ * 附件服务最小面(`ctx.attachments`,`dsh-attachment@0.2.0-rc.2` `lib/types/index.d.ts`):
51
+ * `saveFile` 把文件**按字节原样**提交进宿主附件库(harness home,内容寻址、不可变、
52
+ * **永不自动删除**),返回持久引用。可选面 —— 宿主未挂载 `dsh-attachment-local` 时缺失,
53
+ * 派发降级为「只给路径」。
54
+ */
55
+ export interface HostAttachments {
56
+ saveFile(input: {
57
+ data: Uint8Array;
58
+ name?: string;
59
+ }): Promise<FileAttachmentRef>;
60
+ }
61
+ /**
62
+ * Agent 最小面。形状依据 core/agent/src/runtime-types.ts:163-242:
63
+ * send(message, target: 'next-turn' | 'next-step', wakeup)、whenIdle()。
64
+ */
65
+ export interface HostAgent {
66
+ readonly id: SessionId;
67
+ send(message: UserMessage, target: 'next-turn' | 'next-step', wakeup: boolean): void;
68
+ whenIdle(): Promise<void>;
69
+ }
70
+ /** AgentHandle:core/agent/src/index.ts:160-163。 */
71
+ export interface AgentHandle {
72
+ readonly agent: HostAgent;
73
+ dispose(): Promise<void>;
74
+ }
75
+ /**
76
+ * 模型 route:provider 与 model 成对(决策 22)。宿主 agent-loop 的 prepareRequest
77
+ * 对二者一并校验:`if (!proposedConfig.provider || !proposedConfig.model) throw`——
78
+ * 只给一个等于没给,故本插件一律成对传递。
79
+ */
80
+ export interface ModelRoute {
81
+ provider: string;
82
+ model: string;
83
+ }
84
+ /** AgentOptions:core/agent/src/runtime-types.ts:26-35。⚠️ 缺省并非「走宿主默认路由」——必须显式给(决策 22)。 */
85
+ export interface AgentOptions {
86
+ provider?: string;
87
+ model?: string;
88
+ }
89
+ /**
90
+ * CreateAgentOptions:core/agent/src/index.ts:62-119。sessionId 必填(调用者供给,
91
+ * 与 session 日志共享同一身份);meta.cwd 必须绝对路径(session header 校验,
92
+ * core/session/src/index.ts:111-115)。
93
+ */
94
+ export interface CreateAgentOptions {
95
+ readonly sessionId: SessionId;
96
+ /**
97
+ * 会话创建元数据。agentPreset 是**持久化**的会话身份(决策 23):写入后该会话即绑定此
98
+ * preset,后续 adopt/resume 会做一致性校验(不匹配抛 preset conflict)。
99
+ */
100
+ readonly meta?: {
101
+ readonly cwd?: string;
102
+ readonly agentPreset?: string;
103
+ };
104
+ readonly agentOptions?: AgentOptions;
105
+ /**
106
+ * 发布前的 agent 作用域组装(决策 23)。工厂在 mint agentCtx 之后、announce
107
+ * `session/created`/`agent/created` 之前 await 本回调;**工具、prompt sections、skill
108
+ * 目录只在这里挂得上**(presets.mount),晚于发布就没有模型可见的层了。
109
+ * 抛错 ⇒ 整个作用域回滚、会话与 agent 都不发布。
110
+ */
111
+ readonly setup?: AgentSetup;
112
+ }
113
+ /**
114
+ * 组装回调(CreateAgentOptions.setup / ResumeAgentOptions.setup 共用)。
115
+ * agentCtx 是 agent 的**作用域 ctx**,正是 agentPresets.mount 需要的参数。
116
+ */
117
+ export type AgentSetup = (agentCtx: unknown, agent: HostAgent) => void | Promise<void>;
118
+ /** AgentRegistry.create:core/agent/src/index.ts:388-398。 */
119
+ export interface HostAgents {
120
+ create(options: CreateAgentOptions): Promise<AgentHandle>;
121
+ }
122
+ /**
123
+ * agent preset 服务(@deepseek-ai/dsh-agent-presets 0.1.6-alpha.2,服务名 `agentPresets`):
124
+ * preset 决定一个 agent 的**工具、prompt sections、skill 目录**(决策 23)。
125
+ * ⚠️ 未加入 preset 的 agent 落到「空的全局层」——实测只剩根作用域注册的东西
126
+ * (MCP 工具在、fs/bash 全无),宿主自己的会话都经 setup 里 mount 加入。
127
+ */
128
+ export interface HostAgentPresets {
129
+ /** 解析 preset id;省略/undefined = 部署默认(settings 的 selectionPolicy().defaultId,热读)。 */
130
+ resolve(id?: string): Promise<{
131
+ readonly id: string;
132
+ }>;
133
+ /** 把 agent 作用域绑定到该 preset 的 standing composition。agentCtx 必须是作用域 ctx。 */
134
+ mount(agentCtx: unknown, id?: string): Promise<unknown>;
135
+ }
136
+ /** GoalRegistry.create(@deepseek-ai/dsh-goal 0.2.0-rc.2 lib/types/index.d.ts:83):给 agent 挂持久目标;
137
+ * goal 续跑轮(goal continuation round)由宿主自动接管,直到 agent 标记 complete(GoalPhase)。 */
138
+ export interface HostGoals {
139
+ create(agent: unknown, request: {
140
+ objective: string;
141
+ maxGoalRounds?: number;
142
+ }): Promise<unknown>;
143
+ }
144
+ /** TeamService 探测面(@deepseek-ai/dsh-experimental-agent-team 0.2.0-rc.2 lib/types/index.d.ts:18):
145
+ * 实验性 Agent Teams 服务,experimental profile 启用后才存在(cordis.patch.yml 插 agent-team)。
146
+ * profile 一并启用 tool-agent-team ⇒ 每个根会话 agent 自动成为 Team Lead 并装上
147
+ * spawn_teammate / send_message / list_agents / wait_agent / interrupt_agent / team_task_* 模型工具。
148
+ * 插件只做存在性探测(决策 49:缺 = 降级单轮),不直接驱动 roster。 */
149
+ export interface HostAgentTeams {
150
+ tryMembership(agent: unknown): unknown;
151
+ }
152
+ /** SessionStore.create(id?):core/session/src/index.ts:969,id 可由调用者供给。 */
153
+ export interface HostSessions {
154
+ create(id?: SessionId): HostSession;
155
+ }
156
+ /**
157
+ * Workspace 实体最小面(@deepseek-ai/dsh-workspace 0.1.6-alpha.2 entity):
158
+ * id / path(fs.realpath 归一的绝对路径)/ title,外加归组用的 attachSession。
159
+ */
160
+ export interface HostWorkspace {
161
+ readonly id: string;
162
+ readonly path: string;
163
+ readonly title: string;
164
+ /**
165
+ * 本工作区名下的会话 id(0.2.0-rc.1 `entity.sessionIds` getter,源码已核实;含归档会话的槽位,
166
+ * 追加序)。旧版本实体可能没有 ⇒ optional、取值方判空。用于「选择工作区文件」的浏览锚点:
167
+ * workspaceFiles.list 以 sessionId 解析工作区根,必须有属于该工作区的会话才能列其文件。
168
+ */
169
+ readonly sessionIds?: readonly string[];
170
+ /**
171
+ * 会话归组的唯一途径(决策 22):把 sessionId 登记进本工作区记录的 sessionIds。
172
+ * 前置校验 = 读会话 header 的 cwd → realpath 归一 → 必须 === 本工作区 path,
173
+ * 否则抛错(所以 meta.cwd 必须直接用本实体的 path,不可自行拼写)。
174
+ * ⚠️ 只设 meta.cwd **不会**自动归组;必须显式调用本方法。
175
+ */
176
+ attachSession(sessionId: SessionId): Promise<void>;
177
+ }
178
+ /**
179
+ * WorkspaceRegistry(@deepseek-ai/dsh-workspace 0.1.6-alpha.2):无按 name 查询 API,
180
+ * 只有 get(id)/list()/resolveByPath()/create();按 name 匹配须遍历 list() 比对 title。
181
+ * archiveSession(id):程序化归档,只追加 registry 级 archivedSessionIds(不动工作区槽位)。
182
+ */
183
+ export interface HostWorkspaceRegistry {
184
+ list(): readonly HostWorkspace[];
185
+ get(id: string): HostWorkspace | undefined;
186
+ archiveSession(id: SessionId): Promise<void>;
187
+ /**
188
+ * 反归档(恢复显示):`api/workspace-controller/src/commands.ts:171` 有 `unarchiveSession`
189
+ * (host `workspaceRegistry.unarchiveSession` + remote 双通道),官方「已归档会话」设置页
190
+ * 就靠它恢复(dsh-capabilities 决策 29 修正)。
191
+ * 可选:宿主版本缺该面时,临时反归档查看通路不可用(对应路由返回 501)。
192
+ */
193
+ unarchiveSession?(id: SessionId): Promise<void>;
194
+ }
195
+ /** 已注册 provider 的展示元数据(@deepseek-ai/dsh-llm types:LlmProviderInfo)。 */
196
+ export interface HostLlmProviderInfo {
197
+ /** provider 路由键,即 AgentOptions.provider 的取值。 */
198
+ readonly id: string;
199
+ readonly name: string;
200
+ }
201
+ /** 适配器发现的模型条目(@deepseek-ai/dsh-llm types:LlmModelInfo;目录为 advisory)。 */
202
+ export interface HostLlmModelInfo {
203
+ readonly provider: string;
204
+ /** 模型 id,即 AgentOptions.model 的取值。 */
205
+ readonly id: string;
206
+ readonly name: string;
207
+ }
208
+ /**
209
+ * llm 服务最小面(@deepseek-ai/dsh-llm 0.1.6-alpha.2):决策 22 漏斗第④层与
210
+ * 「只给 model 反查 provider」用。两个查询均为只读;模型目录是 advisory——
211
+ * 未列出不等于不可用(故反查失败时继续下漏而非直接判失败)。
212
+ */
213
+ export interface HostLlm {
214
+ /** 已注册 provider,按注册序(同步)。 */
215
+ listProviders(): readonly HostLlmProviderInfo[];
216
+ /** 某 provider 可发现的模型,按适配器偏好序(异步)。 */
217
+ listModels(provider: string): Promise<readonly HostLlmModelInfo[]>;
218
+ }
219
+ /**
220
+ * 宿主默认模型服务(@deepseek-ai/dsh-agent-default-model 0.1.6-alpha.2,服务名 agentDefaultModel):
221
+ * 部署在 composition 里配 provider+model(二者 required),用户在 settings 命名空间
222
+ * `agent-default-model` 的改动 live 生效;UI 换模型会 saveSelection 写回。
223
+ * ⇒ currentSelection() 即「用户配的 / 最后一次用的」模型,是决策 22 漏斗第③层。
224
+ */
225
+ export interface HostAgentDefaultModel {
226
+ currentSelection(): ModelRoute;
227
+ }
228
+ /** SettingsScope:packages/settings/settings/src/index.ts:115-141(update 见 :133,owner scope 专用)。 */
229
+ export interface SettingsScope<T> {
230
+ get(): T;
231
+ /** 运行期合并写入用户层并提交(:456 owner scope 暴露;read-only provider 抛错,:636)。 */
232
+ update(patch: Partial<T>): Promise<void>;
233
+ watch(callback: (next: T, prev: T) => void | Promise<void>): () => void;
234
+ }
235
+ /** SettingsProvider.register:packages/settings/settings/src/index.ts:419-459,schema 为 schemastery z。 */
236
+ export interface HostSettings {
237
+ register<T>(ns: string, schema: z_any<T>, options?: {
238
+ base?: Partial<T>;
239
+ }): SettingsScope<T>;
240
+ }
241
+ /** SessionTitleService.rename:packages/session/session-title/src/index.ts:395-401,参数是 Session 对象。 */
242
+ export interface HostSessionTitle {
243
+ rename(session: HostSession, title: string): unknown;
244
+ }
245
+ /** 会话事件最小面:本插件只消费 event.type('turn/end' 等,core/session/src/known-event-types.ts)。 */
246
+ export interface HostSessionEvent {
247
+ readonly type: string;
248
+ }
249
+ /** cordis ctx 最小面(本插件用到的成员)。 */
250
+ export interface HostContext {
251
+ logger: {
252
+ info(message: string): void;
253
+ warn(message: string): void;
254
+ error(message: string): void;
255
+ };
256
+ /** 官方定时器:vendor/timer/src/index.ts:47-62,ctx.interval(fn, ms) 返回 dispose,卸载自动清理。 */
257
+ interval(callback: () => void, delay: number): () => void;
258
+ /** cordis 事件监听;会话三事件见 core/session/src/index.ts:50-72。'dispose' 为 cordis 内置事件。 */
259
+ on(event: 'session/created', listener: (session: HostSession) => void): () => void;
260
+ on(event: 'session/event', listener: (session: HostSession, event: HostSessionEvent) => void): () => void;
261
+ on(event: 'session/disposed', listener: (session: HostSession) => void): () => void;
262
+ on(event: 'dispose', listener: () => void): () => void;
263
+ agents: HostAgents;
264
+ sessions: HostSessions;
265
+ /** 可选:宿主 0.2.0-rc.2 起 ctx.goals(Goal service,backed by session log);旧版本无此 face ⇒ 派发侧降级单轮。 */
266
+ goals?: HostGoals;
267
+ /** 可选:实验性 Agent Teams 服务(决策 49);experimental profile 未启用 ⇒ undefined ⇒ 降级单 Agent。 */
268
+ agentTeams?: HostAgentTeams;
269
+ /**
270
+ * 可选:宿主附件服务 `ctx.attachments`(0.2.0-rc.2,需 `dsh-attachment-local` 已挂载)。
271
+ * 见 {@link HostAttachments}:用于把随附文件以**官方 file 内容块**发进会话
272
+ * ⇒ 官方界面渲染成附件卡、fork 续聊也带得走,且当时那一份内容被钉住。
273
+ * 缺失 ⇒ 降级为「只在消息文本里给绝对路径」(2026-10-03 前的行为)。
274
+ */
275
+ attachments?: HostAttachments;
276
+ workspaceRegistry: HostWorkspaceRegistry;
277
+ settings: HostSettings;
278
+ sessionTitle: HostSessionTitle;
279
+ /**
280
+ * cordis 可选服务探测(决策 22 漏斗 / 决策 23 preset 挂载用)。**一律不写进 inject**:
281
+ * 声明组合满足不了的依赖会让 entry 一直 pending、卡死整个 dsh 启动(决策 17 真机教训)。
282
+ * 未挂载时返回 undefined。
283
+ */
284
+ get(name: 'llm'): HostLlm | undefined;
285
+ get(name: 'agentDefaultModel'): HostAgentDefaultModel | undefined;
286
+ get(name: 'agentPresets'): HostAgentPresets | undefined;
287
+ get(name: string): unknown;
288
+ /**
289
+ * cordis 服务订阅(dsh-context installSettings 同款):依赖就绪后才执行回调,惰性服务可守卫。
290
+ * 用于 settings——其 register 面可能延迟挂上或干脆缺失,顶层 inject 写法会卡死/崩。
291
+ */
292
+ inject(deps: readonly string[], callback: (ctx: HostContext) => void): unknown;
293
+ }
294
+ /**
295
+ * 宿主 logger 最小面。⚠️ ctx 本体不可包装(cordis ctx 是 Proxy:set trap 拒绝赋值
296
+ * vendor/cordis/src/reflect.ts:172-196;on/interval 等 mixin 方法不在自有属性上,
297
+ * 展开拷贝拿不到 :221)——需要替换 logger 的模块一律经显式参数接收本类型。
298
+ */
299
+ export type HostLogger = HostContext['logger'];
package/dist/host.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { HostContext } from './host.js';
2
+ import { Config, resolveStatePath } from './config.js';
3
+ import type { PluginConfig } from './config.js';
4
+ export declare const name = "dsh-task-dispatch-table";
5
+ /** 宿主服务依赖:以源码实际服务名为准(决策 15 / PROGRESS「已核实的 DSH 能力」)。
6
+ * ⚠️ settings 不在此列:settings 服务以「带 register 面」或「惰性形态」两种组合入场,
7
+ * 缺失 register 时硬性依赖会令 entry 卡死/崩;改由 apply 内 ctx.inject(['settings'], ...)
8
+ * 订阅并在 register 就绪才激活(参照 dsh-context installSettings,决策 17 真机教训)。 */
9
+ export declare const inject: readonly ["timer", "agents", "sessions", "workspaceRegistry", "sessionTitle", "sessionProjections"];
10
+ export { Config, resolveStatePath };
11
+ export type { PluginConfig };
12
+ /**
13
+ * 设置页 GET/POST 的统一响应体:**当前生效值** + **系统默认值**(都只投影可编辑白名单)。
14
+ *
15
+ * - `config` = 生效值(用户层已合并;用户没设的字段就是系统默认值 ⇒ 前端直接显示即可)。
16
+ * - `defaults` = `CONFIG_DEFAULTS` 的白名单子集。⚠️ **必须投影**:`CONFIG_DEFAULTS` 还含
17
+ * `tasksInline`(整份任务表 JSON)与 `debugSnapshot`(宿主调试数据),不能整份吐给浏览器。
18
+ */
19
+ export declare function configView(config: PluginConfig): {
20
+ config: Record<string, string | number>;
21
+ defaults: Record<string, string | number>;
22
+ };
23
+ /** 附件约束(白名单/上限/扩展名解析)与浏览器端预检**共用同一份**,防两处漂移。 */
24
+ export { ATTACHMENT_MAX_BYTES, ALLOWED_ATTACHMENT_EXT, extOf } from './attachment-allowlist.js';
25
+ export declare function apply(ctx: HostContext, config: unknown): void;
package/dist/index.js ADDED
Binary file
@@ -0,0 +1,38 @@
1
+ import type { HostLogger } from './host.js';
2
+ import type { TaskStore } from './store.js';
3
+ /**
4
+ * 工具名 = **包名去掉 `dsh-` 前缀 + `_receipt`** ⇒ `task_dispatch_table_receipt`。
5
+ *
6
+ * 为什么带命名空间而不是短名:宿主对重名的处理是「**同层抛错 / 跨层 scoped 遮蔽 global**」
7
+ * (`@deepseek-ai/dsh-tools`:`NamedEntries` 冲突直接 throw;类注释 `Scoped registrations
8
+ * shadow globals`)——两种都不希望发生。带插件名前缀把撞名概率压到可忽略,也让模型一眼看出归属。
9
+ * 宿主对工具名没有格式/长度校验,所以这纯粹是防撞考虑。
10
+ */
11
+ export declare const RECEIPT_TOOL_NAME = "task_dispatch_table_receipt";
12
+ export interface ReceiptToolDeps {
13
+ store: TaskStore;
14
+ /** 会话显示名(决策 42 快照 title):只用于工具描述文案,模型不可据此伪造身份。 */
15
+ taskName: string;
16
+ /** 闭包注入的实例身份(UUID 主键),模型不可见。 */
17
+ instanceId: string;
18
+ /** 闭包注入的本次派发会话,模型不可见 ⇒ 回执不可冒充。 */
19
+ sessionId: string;
20
+ /** 回执 status 合法值(决策 41:来自派发快照,不读活任务表)。 */
21
+ validStatuses: readonly string[];
22
+ logger: HostLogger;
23
+ /** 闭包注入的 turnBoundary 投影读取面:取 `deliverables/presented` 事件所需的 turn。 */
24
+ sessionProjections?: unknown;
25
+ }
26
+ /**
27
+ * 把回执工具注册进该 agent 的作用域(**只在 setup 里调**——发布前生效,见文件头)。
28
+ * @returns true = 已注册;false = 宿主 agent 作用域未暴露 tools 服务(跳过并告警:
29
+ * 该会话没有回执通道,对账会按「缺回执」收敛,reason 会指向这里)。
30
+ */
31
+ export declare function registerReceiptTool(agentCtx: unknown, deps: ReceiptToolDeps): boolean;
32
+ /**
33
+ * 回执调用说明(派发消息与追问消息共用)。写给模型看:**传什么、失败怎么办、什么时候必须停**。
34
+ *
35
+ * ⚠️ 刻意不提供任何替代通道(不跑命令、不写库、不碰沙箱)——真机上 agent 曾自行 `chmod`、
36
+ * 拷库、改用 sqlite3/node 绕道,全是无效动作(沙箱层面就不可能成功),白烧 token。
37
+ */
38
+ export declare function receiptInstruction(validStatuses: readonly string[]): string;