dsh-task-dispatch-table 0.0.0 → 0.1.0

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 +95 -31
  2. package/README.zh.md +113 -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,79 @@
1
+ import z from '@deepseek-ai/schemastery';
2
+ export interface PluginConfig {
3
+ /** SQLite 状态库绝对路径;空串 = 宿主数据根 storages/dsh-task-dispatch-table/state.db(决策 14)。 */
4
+ statePath: string;
5
+ /** tick 周期(毫秒)。 */
6
+ tickMs: number;
7
+ /** dispatched 等待 session/created 的宽限期(毫秒)(state-machine §4)。 */
8
+ dispatchGraceMs: number;
9
+ /** running 租约时长(毫秒)(state-machine §4,默认 30min)。 */
10
+ leaseMs: number;
11
+ /** unknown 只观察不动作的宽限期(毫秒)(state-machine §4,默认 5min)。 */
12
+ unknownGraceMs: number;
13
+ /** 任务定义目录(*.json)。相对路径相对宿主进程 cwd 解析。 */
14
+ tasksDir: string;
15
+ /** 内嵌任务表 JSON 数组(临时 UI,决策 16 v1 补充):非空时优先于 tasksDir。 */
16
+ tasksInline: string;
17
+ /** 调试快照 JSON(临时调试通道,决策 16 例外):宿主写入、配置页只读展示,非用户设置。 */
18
+ debugSnapshot: string;
19
+ /** 插件级默认 provider(决策 22 漏斗第②层):与 defaultModel 成对;留空则漏到宿主默认。 */
20
+ defaultProvider: string;
21
+ /** 插件级默认 model(决策 22 漏斗第②层):与 defaultProvider 成对;留空则漏到宿主默认。 */
22
+ defaultModel: string;
23
+ /** task_log 保留期(天):到期行由 tick 内 purgeLog 清除(决策 32)。 */
24
+ logRetentionDays: number;
25
+ /**
26
+ * ⚠️ **执行记录(task_instances + task_events)永久保留,没有保留期字段**——
27
+ * 历史是用来查的、不该被清(用户 2026-10-08 拍板,原 `historyRetentionDays` 与 `purgeHistory` 一并删除)。
28
+ */
29
+ /** 上传临时区保留期(天):到期文件由 tick 内清道夫删除(默认 7)。 */
30
+ attachmentTmpRetentionDays: number;
31
+ }
32
+ /**
33
+ * **系统默认值**(全量,含字符串路径类)—— `Config` schema 与设置页「用户没设时显示什么」的唯一真源。
34
+ *
35
+ * 2026-10-08:此前只有 `ConfigDefaults`(7 个计时/保留期字段),字符串字段的默认值只写在 schema 里
36
+ * (`statePath:''` / `tasksDir:'tasks'` / 两个默认模型 `''`)⇒ 设置页要显示「系统默认值」时拿不到,
37
+ * 只能在前端另抄一份(必然分叉)。故合并成一份全量对象,schema 的 `.default()` 全部引用它。
38
+ */
39
+ export declare const CONFIG_DEFAULTS: PluginConfig;
40
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
41
+ statePath: z<string, string, "defined">;
42
+ tickMs: z<number, number, "defined">;
43
+ dispatchGraceMs: z<number, number, "defined">;
44
+ leaseMs: z<number, number, "defined">;
45
+ unknownGraceMs: z<number, number, "defined">;
46
+ tasksDir: z<string, string, "defined">;
47
+ tasksInline: z<string, string, "defined">;
48
+ debugSnapshot: z<string, string, "defined">;
49
+ defaultProvider: z<string, string, "defined">;
50
+ defaultModel: z<string, string, "defined">;
51
+ logRetentionDays: z<number, number, "defined">;
52
+ attachmentTmpRetentionDays: z<number, number, "defined">;
53
+ }>>, Schemastery.ObjectT<NoInfer<{
54
+ statePath: z<string, string, "defined">;
55
+ tickMs: z<number, number, "defined">;
56
+ dispatchGraceMs: z<number, number, "defined">;
57
+ leaseMs: z<number, number, "defined">;
58
+ unknownGraceMs: z<number, number, "defined">;
59
+ tasksDir: z<string, string, "defined">;
60
+ tasksInline: z<string, string, "defined">;
61
+ debugSnapshot: z<string, string, "defined">;
62
+ defaultProvider: z<string, string, "defined">;
63
+ defaultModel: z<string, string, "defined">;
64
+ logRetentionDays: z<number, number, "defined">;
65
+ attachmentTmpRetentionDays: z<number, number, "defined">;
66
+ }>>, "plain">;
67
+ /**
68
+ * rc.1 volatile 字段的解析结果是**带 get() 的引用**(非纯值);读取时解包(与参考插件
69
+ * dsh-task-board 的 readConfigField 同款)。非 volatile 字段原样返回;undefined/null 回落 fallback。
70
+ * @param field - 配置字段(可能是 Volatile 引用或纯值)。
71
+ * @param fallback - 字段缺失时的回落值。
72
+ */
73
+ export declare function readConfigField<T>(field: unknown, fallback: T): T;
74
+ /**
75
+ * 状态库路径(决策 14):配置覆盖 > 宿主数据根 storages/dsh-task-dispatch-table/state.db。
76
+ * 宿主数据根解析复刻 packages/util/home-paths/src/index.ts:87-100:配置路径 > $DSH_HOME > ~/.dsh。
77
+ * 放 config.ts 而非 index.ts:scheduler/submit 也要用(避免 index 循环导入)。
78
+ */
79
+ export declare function resolveStatePath(statePath: string): string;
package/dist/config.js ADDED
@@ -0,0 +1,80 @@
1
+ // 插件配置:schemastery z schema 一份两用——patch Config 导出 + ctx.settings 命名空间。
2
+ // ⚠️ 升到 @deepseek-ai/schemastery ^3.18.4:rc.1 设置系统(SettingsForms)要求运行时可写字段
3
+ // 标 .volatile()(3.18.2 无此方法);该版本与 dsh 0.1.7-rc.1 线一致(参考插件即依赖 ^3.18.4)。
4
+ import { homedir } from 'node:os';
5
+ import { join, resolve } from 'node:path';
6
+ import z from '@deepseek-ai/schemastery';
7
+ /**
8
+ * **系统默认值**(全量,含字符串路径类)—— `Config` schema 与设置页「用户没设时显示什么」的唯一真源。
9
+ *
10
+ * 2026-10-08:此前只有 `ConfigDefaults`(7 个计时/保留期字段),字符串字段的默认值只写在 schema 里
11
+ * (`statePath:''` / `tasksDir:'tasks'` / 两个默认模型 `''`)⇒ 设置页要显示「系统默认值」时拿不到,
12
+ * 只能在前端另抄一份(必然分叉)。故合并成一份全量对象,schema 的 `.default()` 全部引用它。
13
+ */
14
+ export const CONFIG_DEFAULTS = {
15
+ statePath: '',
16
+ tasksDir: 'tasks',
17
+ tasksInline: '',
18
+ debugSnapshot: '',
19
+ defaultProvider: '',
20
+ defaultModel: '',
21
+ tickMs: 60_000,
22
+ dispatchGraceMs: 60_000,
23
+ leaseMs: 30 * 60_000,
24
+ unknownGraceMs: 5 * 60_000,
25
+ logRetentionDays: 30,
26
+ attachmentTmpRetentionDays: 7,
27
+ };
28
+ // ⚠️ rc.1(0.1.7-rc.1)约束:宿主插件配置字段**不能标 .volatile()**。
29
+ // 实测根因(set717/lib/index.js:417 + types/index.js:368-380):configForms 的读写都要求字段
30
+ // volatile,且 describe() 只投影 volatileForm(schema)(即只有 volatile 字段才暴露给客户端);
31
+ // 但宿主 Loader 会把 volatile 字段的默认按 `{}` 提交进 profile,重装后 z.number()/z.string()
32
+ // 校验失败 → entry 不激活(日志 `$.tickMs expected number but got [object Object]`)。
33
+ // 故宿主插件配置一律为静态字段;运行时数据(快照 / 任务表回写)改走宿主服务
34
+ // `ctx.set('taskDispatchTable', ...)`,客户端经 `ctx.get('remote').taskDispatchTable` 取
35
+ // (参考插件即靠 `ctx.get('remote')` 调宿主服务,不走 configForms)。
36
+ export const Config = z.object({
37
+ statePath: z.string().default(CONFIG_DEFAULTS.statePath),
38
+ tickMs: z.number().default(CONFIG_DEFAULTS.tickMs),
39
+ dispatchGraceMs: z.number().default(CONFIG_DEFAULTS.dispatchGraceMs),
40
+ leaseMs: z.number().default(CONFIG_DEFAULTS.leaseMs),
41
+ unknownGraceMs: z.number().default(CONFIG_DEFAULTS.unknownGraceMs),
42
+ tasksDir: z.string().default(CONFIG_DEFAULTS.tasksDir),
43
+ tasksInline: z.string().role('textarea').default(CONFIG_DEFAULTS.tasksInline),
44
+ // 调试快照:运行时数据,不进 Config;宿主经 taskDispatchTable.getSnapshot() 暴露给客户端。
45
+ debugSnapshot: z.string().default(CONFIG_DEFAULTS.debugSnapshot),
46
+ // 决策 22 漏斗第②层:留空 = 未配,派发时漏到下一层。解析结果只用于本次派发,不回写本字段。
47
+ defaultProvider: z.string().default(CONFIG_DEFAULTS.defaultProvider),
48
+ defaultModel: z.string().default(CONFIG_DEFAULTS.defaultModel),
49
+ logRetentionDays: z.number().min(1).default(CONFIG_DEFAULTS.logRetentionDays),
50
+ attachmentTmpRetentionDays: z.number().min(1).default(CONFIG_DEFAULTS.attachmentTmpRetentionDays),
51
+ });
52
+ /**
53
+ * rc.1 volatile 字段的解析结果是**带 get() 的引用**(非纯值);读取时解包(与参考插件
54
+ * dsh-task-board 的 readConfigField 同款)。非 volatile 字段原样返回;undefined/null 回落 fallback。
55
+ * @param field - 配置字段(可能是 Volatile 引用或纯值)。
56
+ * @param fallback - 字段缺失时的回落值。
57
+ */
58
+ export function readConfigField(field, fallback) {
59
+ if (field === undefined || field === null)
60
+ return fallback;
61
+ if (typeof field === 'object' && typeof field.get === 'function') {
62
+ return field.get();
63
+ }
64
+ return field;
65
+ }
66
+ /**
67
+ * 状态库路径(决策 14):配置覆盖 > 宿主数据根 storages/dsh-task-dispatch-table/state.db。
68
+ * 宿主数据根解析复刻 packages/util/home-paths/src/index.ts:87-100:配置路径 > $DSH_HOME > ~/.dsh。
69
+ * 放 config.ts 而非 index.ts:scheduler/submit 也要用(避免 index 循环导入)。
70
+ */
71
+ export function resolveStatePath(statePath) {
72
+ if (statePath.trim().length > 0)
73
+ return resolve(statePath);
74
+ const raw = process.env['DSH_HOME'];
75
+ const selected = raw !== undefined && raw.trim().length > 0 ? raw : join(homedir(), '.dsh');
76
+ const home = selected === '~' || selected.startsWith('~/')
77
+ ? join(homedir(), selected.slice(selected.length === 1 ? 1 : 2))
78
+ : selected;
79
+ return join(resolve(home), 'storages', 'dsh-task-dispatch-table', 'state.db');
80
+ }
package/dist/deps.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /** 一条已解析的上游依赖:Loop A 判定通过时固化,Loop B 只读不重判。 */
2
+ export interface ResolvedDependency {
3
+ /** 上游任务 id(depends_on.task 原值)。 */
4
+ task: string;
5
+ semantics: 'same_period' | 'latest_success';
6
+ /** 判定通过那一刻命中的上游实例 id。 */
7
+ instanceId: string;
8
+ /** 上游实例的计划时刻(ISO)。 */
9
+ scheduledAt: string;
10
+ /** 上游实例的会话 id(无则 null)。 */
11
+ sessionId: string | null;
12
+ /** 上游实例快照的工作区 path(产出相对路径的绝对化基准);上游旧行无快照为 null。 */
13
+ workspacePath: string | null;
14
+ /** 上游回执声明并校验过的产出(相对上游工作区;未声明为空数组)。目录以尾斜杠结尾。 */
15
+ outputs: string[];
16
+ }
17
+ /** 解析 resolvedDeps:字段缺失(旧行)⇒ undefined;任一条形状不对 ⇒ 整组丢弃(不让坏数据进 UI)。 */
18
+ export declare function parseResolvedDeps(raw: unknown): ResolvedDependency[] | undefined;
19
+ /**
20
+ * 实例快照 JSON → 已解析的上游依赖清单(**客户端便捷入口**)。
21
+ * 与服务端 `parseInstanceSnapshot` 同一套校验,但**不强求整份快照合法**——
22
+ * 客户端只想看「接收了什么」,快照里别的字段缺了不该让这一块消失。
23
+ * 空 / 坏 JSON / 旧行(无 resolvedDeps)⇒ `[]`(调用方按「无上游」渲染,不显示该区)。
24
+ */
25
+ export declare function resolvedDepsOf(raw: string | null): ResolvedDependency[];
package/dist/deps.js ADDED
@@ -0,0 +1,54 @@
1
+ // 依赖快照(决策 43)的中立模块:**零运行时依赖**(不碰 node:* / sqlite),
2
+ // 服务端(store.ts / scheduler.ts)与客户端(会话弹窗「接收」区)共用同一份解析逻辑
3
+ // ——同一机制只解释一次,不允许两处各写一份形状校验。
4
+ //
5
+ // 语义:Loop A 判定通过的**那一刻**把命中的上游实例(id + 产出)冻结进执行记录快照,
6
+ // Loop B(发动 / 重试 / 追问 / 回执裁决)只读,不复判 ⇒ 下游拿到的永远是判定依据那一份。
7
+ /** 解析 resolvedDeps:字段缺失(旧行)⇒ undefined;任一条形状不对 ⇒ 整组丢弃(不让坏数据进 UI)。 */
8
+ export function parseResolvedDeps(raw) {
9
+ if (raw === undefined)
10
+ return undefined;
11
+ if (!Array.isArray(raw))
12
+ return undefined;
13
+ const out = [];
14
+ for (const item of raw) {
15
+ if (typeof item !== 'object' || item === null)
16
+ return undefined;
17
+ const d = item;
18
+ if (typeof d.task !== 'string' || typeof d.instanceId !== 'string' || typeof d.scheduledAt !== 'string'
19
+ || (d.semantics !== 'same_period' && d.semantics !== 'latest_success')
20
+ || (d.sessionId !== null && typeof d.sessionId !== 'string')
21
+ || (d.workspacePath !== null && typeof d.workspacePath !== 'string')
22
+ || !Array.isArray(d.outputs))
23
+ return undefined;
24
+ out.push({
25
+ task: d.task,
26
+ semantics: d.semantics,
27
+ instanceId: d.instanceId,
28
+ scheduledAt: d.scheduledAt,
29
+ sessionId: d.sessionId ?? null,
30
+ workspacePath: d.workspacePath ?? null,
31
+ outputs: d.outputs.filter((x) => typeof x === 'string'),
32
+ });
33
+ }
34
+ return out;
35
+ }
36
+ /**
37
+ * 实例快照 JSON → 已解析的上游依赖清单(**客户端便捷入口**)。
38
+ * 与服务端 `parseInstanceSnapshot` 同一套校验,但**不强求整份快照合法**——
39
+ * 客户端只想看「接收了什么」,快照里别的字段缺了不该让这一块消失。
40
+ * 空 / 坏 JSON / 旧行(无 resolvedDeps)⇒ `[]`(调用方按「无上游」渲染,不显示该区)。
41
+ */
42
+ export function resolvedDepsOf(raw) {
43
+ if (raw === null || raw === '')
44
+ return [];
45
+ try {
46
+ const value = JSON.parse(raw);
47
+ if (typeof value !== 'object' || value === null)
48
+ return [];
49
+ return parseResolvedDeps(value.resolvedDeps) ?? [];
50
+ }
51
+ catch {
52
+ return [];
53
+ }
54
+ }
@@ -0,0 +1,133 @@
1
+ import type { HostContext, HostLogger, HostWorkspace, UserFileContent, UserMessage } from './host.js';
2
+ import type { PluginConfig } from './config.js';
3
+ import type { InstanceSnapshot, TaskStore } from './store.js';
4
+ /**
5
+ * 派发前置条件失败(决策 22 / 决策 23):scheduler 按具体 reason 收敛实例,而非笼统 dispatch-error。
6
+ * reason 取值:no-model-route / agent-create-failed / receipt-tool-unavailable / workspace-attach-failed。
7
+ */
8
+ export declare class DispatchPreconditionError extends Error {
9
+ readonly reason: string;
10
+ constructor(reason: string, message: string);
11
+ }
12
+ /**
13
+ * 工作区名 → 工作区实体(决策 22:target.workspace 语义是**工作区**,不是工作目录;
14
+ * 目录由实体 path 派生)。registry 无按 name 查询 API,遍历 list() 比对:
15
+ * title 精确匹配优先,id 兜底。匹配不到即抛错 ⇒ 任务判失败,绝不落到「未分组」或随便找个目录跑。
16
+ * (Loop A 落库前的前置检查用;Loop B 发动走 resolveWorkspaceByPath——快照里存的是 path。)
17
+ */
18
+ export declare function resolveWorkspace(ctx: HostContext, name: string): HostWorkspace;
19
+ /**
20
+ * 工作区 path → 工作区实体(决策 41:Loop B 发动只读快照的 workspacePath)。
21
+ * 快照里的 path 是落库时从实体原样取的,精确比对即可;找不到 = 工作区被删/重建,
22
+ * 行保留走重试判定(失败原因落事件)。
23
+ */
24
+ export declare function resolveWorkspaceByPath(ctx: HostContext, path: string): HostWorkspace;
25
+ /** 命中漏斗的层级(写进 dispatch 事件,便于排查本次用了哪一层)。 */
26
+ export type ModelSource = 'task' | 'plugin-config' | 'host-default' | 'llm-first';
27
+ export interface ModelResolution {
28
+ provider: string;
29
+ model: string;
30
+ source: ModelSource;
31
+ }
32
+ /**
33
+ * 模型解析漏斗(决策 22,决策 41 修订第①层来源):逐层下漏,四层全空返回 undefined
34
+ * (调用方判失败,走重试判定、行保留)。
35
+ *
36
+ * ① 派发快照的 provider/model 提示(= 落库时的任务 target,决策 41:Loop B 不读任务表)
37
+ * ② 插件配置 defaultProvider/defaultModel
38
+ * ③ 宿主默认 ctx.get('agentDefaultModel').currentSelection()(= 用户配的 / 上次用的模型)
39
+ * ④ llm 首个可用:listProviders() 首个能列出模型的 provider + 其首个模型
40
+ *
41
+ * ⚠️ 只在落库 / 发动时现算,**绝不回写**任务定义或配置:用户日后换模型要能自动跟上,
42
+ * 在配置期固化等于自己废掉兜底。
43
+ */
44
+ export declare function resolveModelRoute(ctx: HostContext, logger: HostLogger, providerHint: string, modelHint: string, config: PluginConfig, hintLabel?: string): Promise<ModelResolution | undefined>;
45
+ /**
46
+ * 插件→会话的用户消息(决策 19:追问层用,form=notice 走系统通知样式)。
47
+ * source.kind 用**生产者自有 kind**(0.1.7 v4 格式要求,`kind: 'plugin'` 已废弃被拒)。
48
+ */
49
+ export declare function userNotice(text: string, summary: string, files?: readonly UserFileContent[]): UserMessage;
50
+ /**
51
+ * 派发消息拼装(决策 12 模板 + 决策 24 回执工具 + 决策 41 快照化 + 决策 43 依赖冻结段 +
52
+ * 决策 49 团队段 + **随附文件段(决策 54)** + **执行时间段(U4,2026-10-05)**):短指令 prompt +
53
+ * 手册路径 + 执行时间(原定 / 实际派发,给了 times 才注入)+ 上游依赖段 + **随附文件段** +
54
+ * 团队执行段(仅 agentTeam 且宿主具备时)+ 回执调用说明。
55
+ * prompt / manual / validStatuses / resolvedDeps / attachments 全部来自派发快照,与任务设置无关。
56
+ *
57
+ * 随附文件**两手都给**(2026-10-03 拍板):
58
+ * ① **文本路径**——把**绝对路径**逐条写清(「从哪一层开始」就是它),并显式声明「允许读取」,否则
59
+ * 会与下面的权限指令(「仅工作区」)打架——upload 型附件落在**任务目录**(工作区之外),
60
+ * 不开口子模型就等于看不见;
61
+ * ② **官方 file 内容块**——把文件注册进宿主附件库(`ctx.attachments`),模型侧由宿主换成一句
62
+ * 「只读副本路径」(`projectFilesToText`),**不额外吃 token**;人的那一面则由官方渲染成
63
+ * **附件卡**(图标 + 文件名 + 大小,可点开),且 fork 续聊带得走、当时那一份内容被钉住。
64
+ */
65
+ export declare function buildMessage(snapshot: InstanceSnapshot, workspacePath: string, logicalDate: string, teamMode?: boolean, attachments?: readonly DispatchAttachment[], fileBlocks?: readonly UserFileContent[],
66
+ /** 执行时间两条(用户 2026-10-05 拍板,U4 收口):不给 ⇒ 不注入该段(旧调用 / 冒烟旧行为不变)。 */
67
+ times?: {
68
+ scheduledAt: string;
69
+ dispatchedAt: string;
70
+ }): UserMessage;
71
+ /**
72
+ * 派发消息里的随附文件条目(2026-09-30):ref 已在 Loop B 解析成**绝对路径**。
73
+ * `path === null` = 来源工作区解析不出 ⇒ 如实标注「工作区相对路径」,**绝不猜**。
74
+ */
75
+ export interface DispatchAttachment {
76
+ name: string;
77
+ kind: 'link' | 'upload';
78
+ /** link 型的工作区相对路径原文(基准未知时如实展示)。 */
79
+ ref: string;
80
+ path: string | null;
81
+ }
82
+ /**
83
+ * 随附文件 → 官方 `file` 内容块(2026-10-03 拍板「附加文件走 A」)。
84
+ *
85
+ * 逐个把文件字节交给宿主附件服务 `ctx.attachments.saveFile`(内容寻址、不可变、
86
+ * **永不自动删除**),拿回持久引用后拼成 file 块随派发消息发出 ⇒ 官方界面渲染成
87
+ * **附件卡**(图标 + 文件名 + 大小,可点开)、fork 续聊带得走、当时那份内容被钉住。
88
+ *
89
+ * **降级不阻塞**:宿主没挂 `dsh-attachment-local`、文件不在盘上、是目录、超过上限、
90
+ * 或 saveFile 抛错 ⇒ 该附件**只留文本路径**(2026-10-03 前的行为),派发照常。
91
+ *
92
+ * ⚠️ 目录**不能**作为附件:官方附件 = 一段字节,`FileAttachmentRef` 里没有路径
93
+ * (`dsh-attachment` `lib/types/types.d.ts:34-41`)。
94
+ */
95
+ export declare function attachmentFileBlocks(ctx: HostContext, attachments: readonly DispatchAttachment[], logger: HostLogger, instanceId: string): Promise<UserFileContent[]>;
96
+ export interface DispatchInput {
97
+ ctx: HostContext;
98
+ /** tee logger(显式传参——ctx 不可包装,见 host.ts HostLogger 注释)。 */
99
+ logger: HostLogger;
100
+ store: TaskStore;
101
+ /** 已落库实例:UUID 主键,状态应为 dispatched(决策 41:Loop B 发动)。 */
102
+ instanceId: string;
103
+ logicalDate: string;
104
+ scheduledAt: string;
105
+ /** 派发快照(决策 41):prompt / manual / workspacePath / 模型提示 / validStatuses 全在其中。 */
106
+ snapshot: InstanceSnapshot;
107
+ /** 已按快照 path 解析的工作区实体(决策 22):cwd 由它的 path 派生,会话建成后 attach 归组。 */
108
+ workspace: HostWorkspace;
109
+ /**
110
+ * 随附文件(2026-09-30):ref 已由 Loop B 解析成**绝对路径**,随派发消息注入。
111
+ * (2026-10-03 起两手都给:文本路径 + 官方 file 内容块,见 {@link attachmentFileBlocks}。)
112
+ */
113
+ attachments: readonly DispatchAttachment[];
114
+ /** 插件配置(决策 22 漏斗第②层取 defaultProvider/defaultModel,发动时现算)。 */
115
+ config: PluginConfig;
116
+ }
117
+ /** agent handle:ctx.agents.create 的返回(追问时用于再推一轮对话)。 */
118
+ export type AgentHandle = Awaited<ReturnType<HostContext['agents']['create']>>;
119
+ /**
120
+ * 发动一个已落库实例(决策 41:Loop B 发动;决策 22 顺序 + 决策 23 preset 组装):
121
+ * 解析模型漏斗(第①层取快照提示)→ **解析部署默认 preset** → 落 session_id → agents.create
122
+ * (自建会话并 announce session/created,对账收到时实例必已带 session_id;preset 在 create 的
123
+ * setup 里 mount,工具/prompt sections/skill 由此挂上)→ **工作区 attachSession 归组**
124
+ * → 落 dispatch 事件(含本次实测 route、命中层级与 preset)→ send。
125
+ * 会话改名在 reconciler.onCreated 做——此处拿不到 Session 对象(handle 只有 agent)。
126
+ * @returns sessionId 与 agent handle——handle 供对账层超时追问(决策 19 第二层)。
127
+ * @throws DispatchPreconditionError 模型解析不出、会话建不起来(含 preset 挂载失败)、
128
+ * 或会话建好后无法归组工作区——调用方(Loop B)按重试判定收敛、**行保留**。
129
+ */
130
+ export declare function dispatchTask(input: DispatchInput): Promise<{
131
+ sessionId: string;
132
+ handle: AgentHandle;
133
+ }>;