@mokuyoaxis/dsh-iris 0.1.3 → 0.2.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 (91) hide show
  1. package/.dsh/skills/iris-compose-media/SKILL.md +23 -49
  2. package/.dsh/skills/iris-compose-media/references/task-v2-recovery.md +30 -0
  3. package/.dsh/skills/iris-compose-media/references/workflows.md +38 -0
  4. package/.dsh/skills/iris-verify-ui/SKILL.md +3 -25
  5. package/.dsh/skills/iris-verify-ui/agents/openai.yaml +4 -0
  6. package/.dsh/skills/iris-verify-ui/references/verdict-and-degradation.md +31 -0
  7. package/CHANGELOG.md +77 -2
  8. package/README.en.md +98 -19
  9. package/README.md +98 -19
  10. package/bin/dsh-iris.js +392 -13
  11. package/docs/AGENT_QUICKSTART.md +35 -0
  12. package/docs/ARCHITECTURE.md +82 -52
  13. package/docs/ARTIFACT_LIBRARY.md +24 -0
  14. package/docs/ARTIFACT_MANIFEST.md +60 -0
  15. package/docs/CORE_RUNTIME_CONTRACT.md +83 -0
  16. package/docs/DSH_CORE_MIGRATION.md +106 -0
  17. package/docs/DSH_RC2_ADAPTATION.md +36 -0
  18. package/docs/HEADLESS_CLI.md +217 -0
  19. package/docs/HOST_ADAPTER_CONTRACT.md +105 -0
  20. package/docs/HOST_DOCTOR.md +49 -0
  21. package/docs/MODEL_PORT_CONTRACT.md +300 -0
  22. package/docs/PROVIDER_ADAPTER_CONTRACT.md +138 -0
  23. package/docs/PROVIDER_HEALTH.md +39 -0
  24. package/docs/PROVIDER_RUNTIME_HARNESS.md +33 -0
  25. package/docs/PROVIDER_SUBMISSION_CONTRACT.md +2 -2
  26. package/docs/ROADMAP.md +42 -76
  27. package/docs/SECURITY.md +10 -5
  28. package/docs/TASK_SEMANTICS.md +3 -2
  29. package/docs/assets/diagrams/iris-architecture.png +0 -0
  30. package/docs/assets/diagrams/iris-architecture.svg +5 -5
  31. package/docs/assets/logo/README.md +55 -0
  32. package/docs/assets/logo/iris-bubble-concept.svg +67 -0
  33. package/docs/assets/logo/iris-bubble.svg +14 -0
  34. package/docs/assets/logo/iris-interim-flower.png +0 -0
  35. package/docs/assets/logo/iris-logo-mono-inverse.svg +78 -0
  36. package/docs/assets/logo/iris-logo-mono.svg +78 -0
  37. package/docs/assets/logo/iris-logo.svg +78 -0
  38. package/docs/assets/logo/iris-mark-mono-inverse.svg +42 -0
  39. package/docs/assets/logo/iris-mark-mono.svg +42 -0
  40. package/docs/assets/logo/iris-mark.svg +42 -0
  41. package/docs/releases/0.1.4.md +59 -0
  42. package/docs/releases/0.2.0.md +48 -0
  43. package/lib/actions.js +673 -525
  44. package/lib/adapters.js +58 -21
  45. package/lib/api.js +182 -16
  46. package/lib/artifacts.js +239 -0
  47. package/lib/bundled-skills.js +5 -5
  48. package/lib/client.js +1116 -86
  49. package/lib/command-service.js +420 -0
  50. package/lib/config.js +245 -49
  51. package/lib/core-artifact-store.js +598 -0
  52. package/lib/core-artifacts.js +4 -0
  53. package/lib/core-attention.js +103 -0
  54. package/lib/core-contract.js +105 -0
  55. package/lib/core-doctor.js +41 -0
  56. package/lib/core-lease-recovery.js +170 -0
  57. package/lib/core-runtime.js +232 -0
  58. package/lib/core-tasks.js +560 -0
  59. package/lib/core-user-projection.js +192 -0
  60. package/lib/doctor.js +260 -30
  61. package/lib/dsh-core-adapter.js +599 -0
  62. package/lib/dsh-host-adapter.js +240 -0
  63. package/lib/generation-input.js +95 -0
  64. package/lib/guard.js +3 -3
  65. package/lib/host-contract.js +131 -0
  66. package/lib/host-runtime.js +156 -0
  67. package/lib/index.js +255 -166
  68. package/lib/locate.js +1 -1
  69. package/lib/media.js +16 -6
  70. package/lib/model-invoker.js +218 -0
  71. package/lib/model-port-contract.js +333 -0
  72. package/lib/models.js +97 -11
  73. package/lib/prompt-optimizer.js +10 -20
  74. package/lib/provider-adapter.js +397 -0
  75. package/lib/provider-adapters.js +342 -0
  76. package/lib/provider-catalog.js +171 -0
  77. package/lib/provider-contract.js +72 -3
  78. package/lib/provider-health.js +59 -0
  79. package/lib/provider-protocol.js +51 -2
  80. package/lib/provider-task-runner.js +328 -0
  81. package/lib/render.js +43 -12
  82. package/lib/tasks.js +45 -9
  83. package/lib/vision.js +51 -56
  84. package/package.json +20 -14
  85. package/user_guide.md +67 -12
  86. package/docs/assets/diagrams/iris-architecture.drawio +0 -1
  87. package/docs/assets/diagrams/iris-task-lifecycle.drawio +0 -1
  88. package/docs/assets/diagrams/iris-workflow-compose.drawio +0 -1
  89. package/docs/releases/0.1.1.md +0 -51
  90. package/docs/releases/0.1.2.md +0 -26
  91. package/docs/releases/0.1.3.md +0 -30
@@ -0,0 +1,24 @@
1
+ # Iris 作品库 v0
2
+
3
+ 状态:v0.1.4 候选实现。
4
+
5
+ 作品库解决“清除任务历史后仍能看到本地作品”的问题。任务记录描述执行过程;作品记录只负责本地媒体的发现、展示和访问。两者生命周期彼此独立。
6
+
7
+ ## 用户语义
8
+
9
+ - 新生成并成功落盘的图片、视频和音频会自动进入作品库。
10
+ - 首次升级到带作品库的版本时,Iris 会扫描现有 `outputs/` 并建立最小索引。
11
+ - “清空已完成”或“清理 7 天前”只删除终态任务记录,作品仍可从工作台和泡泡打开。
12
+ - “找回本地作品”会重新扫描 `outputs/`,补录受支持的普通媒体文件,并移除文件已经不存在的失效索引。
13
+ - 删除单件作品或清空作品库会删除实际媒体文件,需要独立确认;相关任务历史保留,但其中的旧媒体链接将无法再打开。
14
+ - “删除孤儿产物”不会删除已经纳入作品库的文件。
15
+
16
+ ## 数据与隐私
17
+
18
+ 最小索引保存在 `$DSH_HOME/iris/v1/artifacts.json`,POSIX 文件权限为 `0600`。每条记录只包含随机作品 ID、文件 basename、媒体类型、大小、时间和随机访问令牌,不保存 Prompt、Provider、Model、API Key、任务关系或宿主绝对路径。
19
+
20
+ 作品链接继续复用 `/iris/media`,使用 128-bit 随机能力令牌并只从索引解析文件。错误 ID、令牌、文件名或路径穿越输入统一返回 404。作品库不是备份:删除作品文件、删除整个 Iris 数据目录或存储损坏仍可能造成数据丢失,重要作品应另行备份。
21
+
22
+ ## 与未来 Artifact Manifest 的边界
23
+
24
+ v0 不是完整 Artifact Manifest:没有内容哈希、去重、旁车数据、来源/派生关系、引用图或跨宿主导出契约。完整 Manifest 完成崩溃一致性和安全评审后,再承载收藏、标签、搜索、筛选和批量导出等能力。
@@ -0,0 +1,60 @@
1
+ # Artifact Manifest v0
2
+
3
+ Artifact Manifest v0 是 Iris 0.2.0 使用的内部格式,尚未作为公开 package API 冻结。它不替换 0.1.4 的 `outputs/` 与 `artifacts.json`;后续 Host 迁移只能显式、逐件复制旧作品,失败时保留原文件。
4
+
5
+ ## 存储与提交顺序
6
+
7
+ ```text
8
+ artifact-store/v0/
9
+ ├── objects/<artifact-id>.<ext>
10
+ ├── manifests/<artifact-id>.json
11
+ ├── records/<artifact-id>.json
12
+ └── index.json
13
+ ```
14
+
15
+ 写入顺序固定为 `object → manifest → record → index`:
16
+
17
+ - object 是受控媒体内容;
18
+ - manifest 保存 SHA-256、媒体类型、大小、中性元数据和关系边;
19
+ - record 是最小提交标记。只有 record、manifest 与 object 一致的 Artifact 才属于已提交事实;
20
+ - index 只是分页查询缓存。它可以损坏或丢失,不影响按稳定 ID 检查已提交 Artifact。
21
+
22
+ Index 更新失败不会撤销已经提交的 Artifact,避免调用方因本地缓存错误重新生成或重复付费。显式 `artifact rebuild` 会从提交记录和旁车 Manifest 重建 Index。
23
+
24
+ ## 内容完整性
25
+
26
+ Manifest 使用小写十六进制 SHA-256,并同时记录字节数。`inspect`、`export`、`list` 和重建都会核验对象;即使文件大小不变,内容被替换也返回 `IRIS_ARTIFACT_DIGEST_MISMATCH`。
27
+
28
+ 哈希通过固定大小分块读取,不把完整视频再次载入内存。Manifest、错误和 CLI 结果不保存输入路径、旧作品文件名、DSH URL 或供应商下载 URL。
29
+
30
+ ## 关系边
31
+
32
+ 关系方向固定为“当前 Artifact 指向既有 Artifact”。v0 支持:
33
+
34
+ - `derived-from`
35
+ - `preview-of`
36
+ - `frame-of`
37
+ - `transcript-of`
38
+ - `audio-for`
39
+
40
+ 创建时目标必须已经存在且通过完整性检查,重复边会被拒绝。目标后续丢失时,来源 Artifact 仍保持可用;重建报告 `danglingRelations`,不会级联删除或猜测修复关系。
41
+
42
+ ## 重建与孤儿
43
+
44
+ `rebuildCoreArtifactIndex()` 属于 writer 的显式 `recover` 操作,reader 不会偷偷修复:
45
+
46
+ - 早期 Core v0 单文件记录:计算真实哈希,生成 Manifest,并将 record 升级为提交标记;
47
+ - object + manifest、缺 record:验证后补写提交标记;
48
+ - 只有命名和媒体扩展合法的 object:计算哈希,以 `kind=recovered`、`metadata.recovered=true` 补全;
49
+ - manifest 缺 object、哈希不匹配、结构损坏或未知文件:不进入 Index、不自动删除,只计入 `invalid` 或 `unresolved`。
50
+
51
+ 原子写入过程中遗留的临时文件也属于 unresolved 现场。自动清理和数据删除需要单独的用户授权,不属于 rebuild。
52
+
53
+ `adoptCoreArtifactFile()` 用于后续渐进接回 0.1.4 作品:来源必须是明确的普通文件,Core 复制内容并计算哈希,既不移动来源,也不在 Manifest 中保存来源路径。批量扫描和旧 ID 映射留给 DSH 消费迁移阶段。
54
+
55
+ ## 当前限制
56
+
57
+ - Manifest 和 record 格式仍是内部候选,版本发布前可能调整;
58
+ - 当前没有删除、去重、垃圾回收或关系编辑 API;
59
+ - 进程崩溃窗口已通过 fixture 验证;突然断电后的持久性仍取决于宿主文件系统,v0 不宣称跨文件系统事务或 `fsync` 级保证;
60
+ - Android 共享存储、网络文件系统和原生 Windows 的恢复行为仍需各自的真实验证。
@@ -0,0 +1,83 @@
1
+ # Core Runtime v0 候选契约
2
+
3
+ 本文定义 0.2.0 的 Core Runtime 内部接口。内部接口在后续版本仍可能调整,npm 包不把它作为公开 API 导出;现有 `config.js`、`tasks.js` 和 `artifacts.js` 也尚未迁移。
4
+
5
+ ## 目标与范围
6
+
7
+ Core Runtime 由调用方显式创建、启动和释放。数据根、操作权限、取消和清理都属于实例;存储缓存与观察器接入后也必须遵守同一归属。Core 不推断 DSH profile,不读取 `ctx`,不启动浏览器或监听端口,也不在启动、Doctor 或能力枚举时触发供应商请求。
8
+
9
+ 0.2.0 包含 Runtime、Task/Attempt、Artifact Manifest、本地与媒体 Command,以及 DSH 对已迁移媒体任务的同源消费。s2v、视觉理解等未迁移能力仍走 legacy Host;完整迁移与公开 Core API 冻结留待后续版本。
10
+
11
+ ## 数据根和进程归属
12
+
13
+ - `dataRoot` 必须由 DSH Host Adapter、CLI 或测试宿主选择后,以绝对路径显式传给 Core。Core 不读取 `DSH_HOME`、`HOME` 或当前工作目录来猜测位置。
14
+ - 每个数据根只允许一个写者。写者必须在读取、初始化、规范化配置、接回旧作品、重建索引或启动任务观察器之前取得数据根租约,并持有到实例完成释放。
15
+ - 其他进程可以用 `reader` 打开同一数据根,但只能执行无副作用的检查。DSH 正在使用该数据根时,CLI 写操作返回 `IRIS_CORE_DATA_ROOT_BUSY`;用户可以停止现有写者,或显式选择另一数据根。
16
+ - 只读不是隐式写入:不得创建缺失文件、修改权限、隔离损坏文件、修复/迁移记录、接回 `outputs/`、更新健康时间或启动任务观察器。
17
+ - 写者冲突必须 fail-fast,普通 Runtime **不得自动夺取**租约。0.2.0 提供独立的 `runtime recover` 显式流程:先由只读 Doctor 报告 owner,再要求用户回显陈旧 PID,并在接管时复核证据、写私有审计;活跃、未知或损坏状态拒绝。PID 不存在本身仍不是跨主机安全证明。
18
+ - 路径别名必须在取得租约前解析为同一物理数据根。不能只依赖字符串规范化或原子 `rename`:后者可以防止半写文件,不能阻止两个带缓存的进程互相覆盖。
19
+
20
+ 初版租约优先使用 Node 标准库和本地文件系统能力,不新增生产依赖。Android 共享存储、网络文件系统和异常退出后的恢复只有拿到真实证据后才声明支持;实现不得假设 systemd 或常驻 daemon 存在。
21
+
22
+ ## 访问模式和操作分类
23
+
24
+ | 模式 | `inspect` | `execute` | `recover` |
25
+ |---|---:|---:|---:|
26
+ | `reader` | 允许 | 拒绝 | 拒绝 |
27
+ | `writer` | 允许 | 允许 | 允许 |
28
+
29
+ `inspect` 只读取已有事实并返回中性的可序列化结果。`execute` 包含本地动作、远端提交和任何持久化变化。`recover` 包含显式迁移、索引重建、损坏隔离和租约恢复;它不是普通读取的自动副作用。
30
+
31
+ 上表是 Core 操作的权限分类。CLI 的 `runtime recover` 是租约外的独立、需人工确认的接管入口;它不能先取得被陈旧 owner 占用的普通 writer 租约,也不能由 reader 或 Doctor 隐式触发。
32
+
33
+ 启动、释放、Doctor、Provider 列表与 capability 列表本身不触发供应商请求、不产生费用,也不偷偷恢复远端任务。真实验证和生成必须由用户显式执行,并继续遵守现有受理、重试、取消和预算规则。
34
+
35
+ ## 生命周期
36
+
37
+ ```text
38
+ created --start--> started --dispose--> disposing --finish-dispose--> disposed
39
+ \----------------dispose---------->/
40
+ ```
41
+
42
+ - 实例只能启动一次;已经释放的实例不能重启。
43
+ - `dispose` 可以重复调用,并返回同一个释放过程。
44
+ - 释放顺序固定为:停止接收新 Command;传播取消信号;等待或保守挂起在途操作;停止任务观察器和 Host 注册;刷写已承诺记录;最后释放数据根租约。
45
+ - 如果仍可能存在写入,或最终刷写失败,不能提前释放租约来伪造“已安全退出”。远端是否取消仍以供应商证据为准,本地释放不得猜测。
46
+ - Host 生命周期只能拥有它创建的 Core 实例和注册资源;不得让模块级缓存、timer 或 listener 泄漏到下一次插件重载。
47
+
48
+ ## 错误与结果边界
49
+
50
+ 候选稳定错误码:
51
+
52
+ - `IRIS_CORE_OPTIONS_INVALID`:选项或显式数据根无效;
53
+ - `IRIS_CORE_STATE_INVALID`:生命周期顺序无效;
54
+ - `IRIS_CORE_OPERATION_INVALID`:未知操作类型;
55
+ - `IRIS_CORE_READ_ONLY`:只读实例收到写操作;
56
+ - `IRIS_CORE_DATA_ROOT_BUSY`:该数据根已有写者;
57
+ - `IRIS_CORE_DATA_ROOT_NOT_FOUND`:reader 指定的数据根不存在,且不会自动创建;
58
+ - `IRIS_CORE_DATA_ROOT_UNAVAILABLE`:无法安全创建、访问或检查数据根;
59
+ - `IRIS_CORE_LEASE_INVALID`:租约证据异常或无法安全释放,保留现场等待显式处理;
60
+ - `IRIS_CORE_LEASE_NOT_FOUND`:显式恢复时没有租约;
61
+ - `IRIS_CORE_LEASE_CONFIRMATION_MISMATCH`:用户回显的 PID 与租约 owner 不一致;
62
+ - `IRIS_CORE_LEASE_OWNER_ALIVE` / `IRIS_CORE_LEASE_OWNER_UNVERIFIED`:owner 仍活跃或无法证明已退出;
63
+ - `IRIS_CORE_LEASE_RECOVERY_FAILED`:恢复或审计未安全完成,现场已保留。
64
+
65
+ 错误、Doctor 证据和 Command 输出不得包含 API Key、授权头、私有签名 URL 或不必要的本机绝对路径。Core 的 Artifact 结果使用稳定 ID 和中性元数据;HTTP/media URL、DSH attachment 与会话展示均由 Host Adapter 投影。
66
+
67
+ ## 当前接口与后续范围
68
+
69
+ 当前候选实现包括:
70
+
71
+ - `normalizeCoreOptions()`:规范化显式数据根和 reader/writer 模式;
72
+ - `createCoreRuntime()`:管理写者租约、状态、`AbortSignal`、在途操作和 cleanup;
73
+ - `createCommandService()`:提供 `crop`、只读 `task.list/task.inspect`、显式单步 `task.observe`/`task.reobserve`(同一份实现,`reobserve` 是人工触发观察的对外命令名)、人工重新交付 `task.redeliver`(只开放 outcome=succeeded / deliveryState=failed,一次带 redelivery 标志的 re-poll + 下载,绝不 submit、绝不重新生成)、人工取消 `task.cancel`(只开放已受理未终态任务,只有 Provider 明确确认才写 canceled,不支持/无法确认保持真实状态)、人工重试为新任务 `task.retry`(只开放终态未成功交付任务;必须显式 confirm_billing 确认重复计费;新 Task 记录单向 retriedFrom 关系,候选链按宿主实况重新解析;Core 不持久化 Prompt,prompt 必须由调用方重新提供),以及 Artifact inspect/list/export/rebuild;Task reader 返回既有安全事实,不读取 Provider 配置,也不创建、修复或迁移记录;`observe/reobserve/redeliver/cancel` 只接受宿主注入的 Adapter resolver,`retry` 只接受宿主注入的候选链 resolver,Core 不读取配置路径;Task capability 现已覆盖 image、video、tts 与 transcribe——交付按 `provider-task-runner.js` 的 DELIVERY_PROFILES 冻结(video:`video/mp4` + `generated-video`;tts:`audio/mpeg`/`audio/wav` + `generated-audio`,同步 completed 同次调用内交付;transcribe:`text/plain` + `transcript`,正文物化为 UTF-8 Artifact),不共用不准确的图片交付语义;
74
+ - Artifact Manifest v0:保存受控对象、SHA-256、关系边和可重建 Index,可跨 CLI 进程检查、导出和显式重建;Doctor 只报告孤立/未解析条目,不自动删除或修复。
75
+
76
+ [Headless CLI](HEADLESS_CLI.md) 记录了当前开发接口,包括只读配置查询、Core Doctor 与陈旧租约显式恢复。FakeProvider 与各媒体 Profile 的离线生命周期测试已经存在;真实 Provider、Android 目视、跨平台 CI 和发布门禁仍须分别举证。未迁移能力保持 legacy 路径,不冒充 Core 事实。
77
+
78
+ ## 非目标
79
+
80
+ - 当前接口尚未作为 package export 或第三方 SDK 发布。0.2.0 的 F 阶段已正式决定:**不新增 `./core` 公开 export**——Root 插件与 `bin/dsh-iris` CLI 承载全部对外能力,内部模块(core-runtime、core-tasks、command-service、provider-task-runner、core-artifact*、core-user-projection)保持私有,可在 minor 版本间调整;冻结为公开 export 的决策顺延到 M2(0.3.0)的 Recipe/Serve 边界定稿后再审。届时一旦公开即写兼容策略与 semver 边界;
81
+ - 不提供 standalone 服务、账号、多租户或额外监听端口;
82
+ - 不包含新 Provider、收藏、标签、搜索或 Flow/Recipe;
83
+ - 不把 0.1.4 的模块级存储包装成实例存储,也不允许 CLI 与 DSH 无租约并发写同一数据根。
@@ -0,0 +1,106 @@
1
+ # DSH → Core 渐进迁移
2
+
3
+ 本文描述 Iris 0.2.0 的实现与迁移边界。迁移逐条切换消费者,不原地改写 0.1.4 数据;未迁移能力继续使用原有实现。
4
+
5
+ ## 已切换的执行链:本地媒体处理与新生成任务
6
+
7
+ - `iris_crop` 和工作台 crop 共用 Command Service 与 Artifact Manifest。attachment 输入先成为 `host-input` Artifact,裁剪结果用 `derived-from` 保存关系;工具名、参数和附件输出不变。
8
+ - 新图片任务的同步、异步与混合候选均使用同一 Core Task/Attempt/Artifact。每个候选先落盘 Attempt,只有明确 `not_accepted` 才允许切换;收到远端 ID 或受理未知后停止候选提交。
9
+ - 新 Attempt 可选记录七个单调 `stageTimestamps` 边界,区分排队、提交、远端执行、下载和本地 Artifact 处理;旧记录缺失该字段仍合法,未发生的阶段不补写。
10
+ - Provider 只收到原始模型 ID;Core 保存 `providerId::modelId` 和非敏感端点 binding,不保存 Prompt、凭据、下载 URL 或 DSH 会话。
11
+ - DSH 边界选择 `$DSH_HOME/iris/v1/core-v0`,与旧 `tasks.json`、`artifacts.json`、`outputs/` 隔离。旧任务仍由旧观察器读取和接管;新图片不双写旧存储。
12
+
13
+ `iris_draw_image` 等待同一 Core Task,ready 后通过命名 Attachment Port 返回图片。等待超时只返回稳定 Task ID,后台观察继续;停止工具等待不等于远端取消。宿主投影失败不会撤销 Core 中已经成功交付的产物。
14
+
15
+ ## 异步观察与重启接管
16
+
17
+ Core runner 不拥有 timer,单次 observe 最多执行一次 poll,绝不 resubmit。DSH Host 在此之上提供有界调度:
18
+
19
+ - 每次观察重新读取 Task,并按原 Provider、模型和 binding 恢复 Adapter;端点/协议漂移、停用、缺凭据或模型不可用时不发送请求。API Key 可以轮换。
20
+ - 每次 submit/observe 使用独立、短生命周期 writer Runtime;同进程操作排队,跨进程 writer 冲突仍 fail-fast。等待下次节拍不占用 writer 租约。
21
+ - 强杀残留租约先由 `doctor --data-root ... --json` 只读确认;仅 owner PID 为 `missing`、用户确认无跨主机写者并用 `--confirm-stale-pid` 回显该 PID 时,`dsh-iris runtime recover` 才接管、写私有审计并释放。活跃/未知/损坏证据全部拒绝,DSH 不自动恢复。
22
+ - 默认间隔 2.5 秒,本轮最多观察 20 分钟;连续 5 次观察错误停止自动等待,保留远端受理与未知事实,不伪造远端失败。
23
+ - 启动扫描全部 Task 页,保守恢复 submitting、active、取消响应和交付中断窗口;仅接管仍有远端受理证据、且在自动窗口内的图片。旧无 binding Task 不猜测恢复配置。
24
+ - timer 使用 unref,随插件 Fiber 清理;在途观察收到取消信号,旧回调不能清掉同一 Task 的新观察器。停止本地观察不宣称已取消远端任务。
25
+
26
+ Headless CLI 使用同一控制面,但不自动循环:`task observe` 每次显式调用只 poll 一次,Provider 配置路径由 CLI 边界提供。
27
+
28
+ DSH 工作台现也开放同一份显式单步观察(D1 reobserve):`POST /iris/api/core/task/:id/reobserve` 经 Command Service 命令 `task.reobserve`(与 `task.observe` 同实现),adapter/binding 恢复与 Host 观察节拍共用同一 resolver。用户任务区的 Core 投影行在服务端的行 DTO 标记 `observable`(已受理、有远端 ID、结果未定论、非终态)时显示「重新观察」按钮,点击后单次调用、禁用期间防重复,完成后复用刷新节拍重拉快照;高级诊断卡对符合同一受理事实门的任务提供同一动作。每次调用至多一次 poll,绝不 submit;终态、未受理、无远端 ID 或 binding 漂移的任务在网络与写入前被拒绝并返回稳定错误码。
29
+
30
+ 人工控制面第二项 redeliver(D2)也已开放:`POST /iris/api/core/task/:id/redeliver` 与 CLI `task redeliver` 经 Command Service 命令 `task.redeliver`,只对 outcome=succeeded / deliveryState=failed 的 Task 开放——一次带 redelivery 标志的 re-poll 拿远端产物清单 → 下载 → 新 Artifact,绝不 submit、绝不重新生成、不新建 Attempt。行 DTO 在五类状态中的 `delivery_failed` 上标记 `redeliverable`,工作台相应投影行与高级诊断卡显示「重新取回作品」;成功即 ready 且门反转(再次调用被拒),下载失败回落 failed 可再次显式执行。
31
+
32
+ 人工控制面第三项 cancel(D3)同样开放:`POST /iris/api/core/task/:id/cancel` 与 CLI `task cancel` 经 Command Service 命令 `task.cancel`,只对已受理、有远端 ID、未终态且未请求过取消的 Task 开放。结果只有三种,且**绝不伪造已取消**:① 供应商明确确认 → outcome=canceled、cancelState=remote_confirmed;② 供应商不支持远端取消(当前 DashScope 与 OpenAI Images 媒体协议均不提供经过验证的取消实现)→ 取消未发生,回落到可继续观察的真实状态(outcome 不变);③ 超时或网络失败 → cancelState=unknown、保持非终态,可显式 reobserve 收敛。竞态下远端先沉淀的成功事实不得被取消覆盖;已请求过取消但未确认的任务拒绝再次取消。工作台按钮「取消任务」需要二次确认,五类用户状态保持不变,三种结果态在高级诊断的「取消状态」字段如实区分(已确认 / 已请求未确认 / 无请求)。
33
+
34
+ 人工控制面最后一项 retry as new task(D4)也已开放,控制面四个动作全部收口:`POST /iris/api/core/task/:id/retry` 与 CLI `task retry` 经 Command Service 命令 `task.retry`。这是唯一产生新的真实计费的动作,三层都强制显式确认——CLI `--confirm-billing`、API 请求体 `confirmBilling:true`、UI 含重复计费警示的确认弹窗,缺一不进且在网络与创建之前拒绝。只对终态且未成功交付的 Task 开放(succeeded+ready 拒绝)。新 Task 有全新 id/attempts/binding,候选链按当前 assignments/池实况重新解析(旧 binding 可能正是失败原因),`model_ref`/`modelRef` 可显式指定;记录单向 `retriedFrom` 关系指向旧 Task,旧 Task 事实零变化,高级诊断以「重试来源」展示该关系。**Core 记录不持久化 Prompt**,生成指令必须由调用方重新提供(CLI `--input` / API `prompt` / 工作台弹窗重新输入),绝不从旧任务"恢复"——这是隐私设计,不是缺陷。同一请求网络重放的幂等键未实现:每次显式确认即一个新任务,属预期语义。
35
+
36
+ ## 作品与只读诊断
37
+
38
+ 工作台只有一个作品库:Core 图片与旧 outputs 作品一起显示,原始输入 Artifact 不进入作品视图。Core 媒体路由 `/iris/api/core/artifact/<artifact_id>/media` 没有独立 token:它按随机 96-bit Artifact ID 读取,每次验证 SHA-256,并由默认回环/显式 trusted Host 与浏览器 `Origin`/`Sec-Fetch-Site` 守卫拒绝明确跨站请求。Artifact ID 持有者在可达受信 Host 时即可读取;Host allowlist 不等于身份认证。Host URL 不写回 Core。
39
+
40
+ 默认收起的“高级诊断 → Core 任务事实”展示同一批作品背后的 Task/Attempt,可展开、复制 ID 和打开图片,不是第二个作品库。`iris_task_status` 可查询同一 Core ID;CLI 指定同一 profile 数据根时可以 inspect/export,反向也成立。重复读取和附件投影不触发生成或修改 Core 事实。
41
+
42
+ 工作台与泡泡的普通任务区现已消费同一快照的 `userTasks` 安全投影:Core 任务与旧版任务合并进同一个运行中/需要处理/历史分区,对外只呈现五类用户状态——`running`、`observation_paused`、`attention`、`delivery_failed`、`succeeded`。观察暂停的文案明确说明远端可能仍在运行,与“已明确失败”严格区分。卡片显示稳定 Task ID、模型、更新时间和关联作品链接;供应商身份、binding、错误原文与路径不进入普通任务区。投影是纯只读:刷新、展开、关闭与历史清理不会 poll、submit、删除或修复 Core 事实;完成提示在会话内只出现一次,刷新页面后从事实快照重新计算,不持久化提醒偏好。单条任务记录损坏或媒体文件丢失只触发局部降级(跳过该条、作品卡片显示占位),快照与其余条目照常可用。Core 的人工恢复四个动作 reobserve/redeliver/cancel/retry 已全部开放(见上节,CLI/API/UI 同一 Command Service);需要处理条目在投影行或高级诊断中有对应动作入口,旧任务继续由 legacy 记录处理。
43
+
44
+ ## 注意力处置(0.2.x 补丁)
45
+
46
+ Core 任务的提醒处置属于 **Host 偏好**(计划铁律:提醒已读/处置不修改远端事实字段)。偏好存 `$DSH_HOME/iris/v1/core-attention.json`(0600、tmp+rename 原子写、损坏降级为无偏好、只存 Task ID 与时间戳),**绝不写入 Core 数据根**;「移除」也只是本机隐藏,任务与产物记录完整保留,高级诊断标注"已隐藏"并可「恢复显示」,CLI 与 reader 照常可查。
47
+
48
+ 工作台 attention 行(失败/取回失败/受理未知)提供「不再提醒」(受理后移出需要处理,历史区仍可见并可「恢复提醒」)与「移除」(本机隐藏,任务区/泡泡全部过滤)。泡泡计数与列表跟随过滤;泡泡亮度仍只由 Provider 健康决定。高级诊断(tasks.recent 全量记录)不受偏好影响,并新增「处置状态」展示 acknowledged/hidden/suppressed 三种口径。
49
+
50
+ 已确认取消的任务仍保留 Core 事实投影 `outcome=canceled → userState=attention` 与原语义校验,但 DSH 安全投影额外标记 `historical:true`:工作台与泡泡将其放入历史,不计「需要处理」或角标,不显示注意力处置按钮。失败、受理未知、结果未知和交付失败仍照常进入 attention。
51
+
52
+ 此外由事实派生的**自动静默**:若任务 X 处于 attention 且存在 `retriedFrom = X` 的后继任务已成功交付,X 自动静默(客户端连同手动处置一起过滤);后继后续失败则静默撤销。该派生每次快照重算,不缓存、不落偏好——这正是 D 阶段 D4 关系字段的用户侧收益,也是计划 §4.D.5(提醒已读/处置属于 Host 偏好,不修改远端事实字段)的落地。
53
+
54
+ ## 视频迁移(E 阶段第一项)
55
+
56
+ t2v/i2v 视频已迁到 Core,与图片共用 Task/Attempt 事实轴但**不共用图片状态机**:交付走冻结的视频 Profile(`lib/provider-task-runner.js` 的 `DELIVERY_PROFILES.video`:媒体白名单 `video/mp4`、Artifact kind `generated-video`、metadata 带 `capability`),观察用视频长轮询档(默认 6s/拍),受理、取消(当前真实协议不支持远端取消,not_supported 如实回落)、redeliver/retry 与 CLI/API/UI 控制面全部对视频生效。Agent 工具与工作台视频动作经 `submitCoreVideo` 落到 Core,**零 legacy 双写**(不再写 `tasks.json`/`outputs/`;旧视频任务继续 legacy 只读兼容)。同源媒体路由按 ID 播放 mp4;视频作品在任务区行内给出链接,不进入图片画廊网格。s2v 数字人(受理边界前需上传首帧与音频到临时存储)暂留 legacy 链路,后续单独迁移。真实 Provider 视频 canary 待验收。
57
+
58
+ ## 语音合成迁移(E 阶段第二项)
59
+
60
+ TTS 是同步完成型,与视频的长轮询不同:一次 submit 内 completed,同一次调用直接交付为 Core Artifact(`DELIVERY_PROFILES.tts`:媒体白名单 `audio/mpeg`/`audio/wav`、kind `generated-audio`;remote-url 走下载,inline base64 直接物化)。Agent 工具 `iris_speak_text`、工作台语音动作与 CLI `run tts` 全部落到 Core,**零 legacy 双写**;同步完成即终态,observe/redeliver/cancel 对终态语音任务全部稳定拒绝,终态失败可用 retry 显式重试为新任务(输入为 `{text, voice?}`,候选链按实况解析)。语义差如实记录:legacy 是"单 Task 多 Attempt、每次尝试独立交付到 outputs/",Core 是"单 Task 多 Attempt、一次 Artifact 交付";候选链共用一个 voice(Core providerInput 静态)。同源媒体路由按 ID 播放音频。真实 Provider 语音 canary 待验收。
61
+
62
+ ## 转写迁移(E 阶段第三项)
63
+
64
+ 转写是上传型异步,Profile 独立:音频在 Host/CLI 边界上传到首选候选 Provider 的临时存储(`oss://` 签名地址只进 providerInput,**绝不落 Core 记录**),经受理边界提交后走 Core 长轮询(默认 2.5s/拍),远端成功后正文物化为 `text/plain` 的 `transcript` Artifact(adapter 在 poll 成功时把正文转为 inline-base64,不依赖签名 URL 生命周期)。CLI `run transcribe` 支持 `audio_url`(公网/oss:// 直达)或 `audio_path`(本地文件经同一上传通道);Agent 工具与工作台转写动作切 Core,完成时结果直接附转写正文。**零 legacy 双写**,旧转写任务继续 legacy 只读兼容。取消沿用 not_supported 如实语义;retry 输入为 `audio_url`(Core 不持久化音频地址,必须由调用方重新提供)。已知边界:临时音频 URL 属于首选候选的账号,failover 到不同账号时该候选会如实失败。真实 Provider 转写 canary 待验收。
65
+
66
+ ## 本地媒体原语
67
+
68
+ Core Command Service 已纳入两项确定性、零 Provider 的本地能力:`media.diff` 用 Sharp 生成指标与 `pixel-diff` 热力图 Artifact;`media.frames` 用本机 ffmpeg/ffprobe 返回视频元数据并生成 `video-frame` Artifact。两者均可读取宿主绝对路径;读取既有 Core Artifact 时分别写入 `derived-from` 或 `frame-of` 关系,Manifest 不保存宿主或临时路径。Headless CLI 的 `media diff` / `media frames` 直接消费同一 Command Service,不读取 Provider 配置、不发起网络请求。
69
+
70
+ DSH 的 `iris_pixel_diff`、`iris_video_frames` 与工作台对应动作也消费上述 Command:Host 只解析图片附件/本地来源,并将已落盘的 Artifact 字节投影为附件或首帧预览。diff 的附件输入先形成 `host-input` Artifact,热力图保存 `derived-from` 关系;本地视频路径不伪造来源关系。结果提供 `artifactIds`,CLI 可从同一 Core 根检查和导出相同字节,DSH 不再为这两项另写 legacy Task 或 `outputs/`。
71
+
72
+ 图片、t2v/i2v 视频、TTS 与转写的正常提交和知情重试共用 `generation-input.js`:统一文本修剪、数量/时长/长度校验,并把 `img_data_url`、`audio_url` 转为 Adapter 的 `imgDataUrl`、`audioUrl`。非法输入在 Provider 提交和新 Task 创建前拒绝;CLI 仍返回 usage 退出码,Command 仍返回 `IRIS_COMMAND_INPUT_INVALID`。工作台清空可选文本框仍由 Host 解释为使用默认值。音频路径与签名地址不落 Core,上传和附件解析仍属于入口;S2V 的 legacy 参数链保持原边界。
73
+
74
+ 依赖视觉模型或 Host Browser 的 `locate`、长图 OCR、媒体摘要和 HTML 渲染不进入这条本地命令链;它们留到中立 Text/Vision Port 冻结后再迁移,避免把网络模型或浏览器对象塞进 Core。
75
+
76
+ ## Text/Vision 下一步(M1 完成,消费者未迁移)
77
+
78
+ [Text/Vision Model Port v0](MODEL_PORT_CONTRACT.md) 固定目标请求、完整结果、错误、取消/预算与 DSH 图片桥接边界。后续顺序为纯契约/Fake Port → 提示词优化 → look/relook → 定位/OCR/拼图摘要,逐个消费者举证。取消后 fallback、缺终态的部分文字成功、OCR 吞取消继续分块均列为待修行为,现有测试通过不能算作新契约已通过。
79
+
80
+ 纯契约、调用控制与 Fake Port 已完成 M1,共用有限调用预算、严格结果验证与取消语义;真实 HTTP/DSH 适配器尚未接入。提示词优化继续讨论主动提示词组装与不可信输入隔离,本轮不迁移该消费者。M1 不增加 Task/Artifact 写入,不修改 v1 配置或公开 export。HTML/Browser、S2V 与自持文本能力目录独立处理;媒体摘要复用 Core 抽帧也需后续单独接线。
81
+
82
+ ## 尚未迁移或开放
83
+
84
+ - s2v 数字人视频的 Core Command/Task 消费;
85
+ - 依赖 Text/Vision Model Port 或 Host Browser 的 locate、长图 OCR、媒体摘要与 HTML 渲染;
86
+ - 旧任务、旧作品 ID 与 Core ID 的显式映射;
87
+ - Core Task/Artifact 删除、清理、孤儿 purge 与完整作品分页(提醒处置和人工控制面 reobserve/redeliver/cancel/retry 已开放);
88
+ - 真实 DSH 对话 attachment、浏览器进度/作品区和异步重启 canary。
89
+
90
+ 旧作品重新索引、删除、清空和孤儿清理仍只操作 legacy `outputs/`;Core Task/Artifact 在 DSH 工作台和 Headless CLI 中都保持只读。Doctor 会报告 Core 孤立对象、未提交 Manifest 与未解析条目,但不会删除或修复它们。Core 删除与清理能力计划在 0.2.x 开放;不要手动移动或删除 `core-v0` 中的 object、Manifest、record 或租约文件。
91
+
92
+ ## 验证证据与限制
93
+
94
+ - 2026-09-30 当前开发工作树已完成仓库外真实 tarball 安装验收:空项目安装当前包和 Sharp,不含 DSH/Cordis,也不复用仓库依赖。安装后的 CLI 实际完成 crop/diff/抽帧和四类 Provider fixture 生成,13 份 Artifact 的导出字节及 SHA-256 一致;跨进程 reader/导出零 Core 写入、零额外 Provider 请求。可在源码仓库执行 `node scripts/verify-headless-package.mjs` 复现,缓存完整时支持 `--offline`。本机为 Linux ARM64/PRoot、Node 22;这项证据不替代真实 Provider、DSH 异步重启或其他平台验收。
95
+ - 完整离线回归为 96 个测试文件,lint 覆盖 151 个 JS/MJS 文件。同步、多产物、混合 failover、受理未知、交付失败、跨进程观察、零 legacy 双写、用户侧只读投影(五类真值表、零写入、局部降级、窄屏断言)与 D1 reobserve、D2 redeliver、D3 cancel、D4 retry(Command 门真值表零网络零写入、幂等矩阵、redelivery 标志、取消三分支如实语义与竞态防护、计费确认三层门、retriedFrom 关系与 prompt 零持久化、失败回落显式收敛、API 状态码/脱敏、CLI↔API 同一 Task 事实连续性、客户端投影门)均有 fixture;E 阶段视频、语音、转写迁移各有独立 conformance(视频长轮询多拍/mp4 Profile、语音同步双产物形态/音频 Profile、转写上传通道/文本物化 Profile)与 CLI/DSH 端到端 fixture。
96
+ - 2026-09-19 最新完整门禁为 113 个测试文件、lint 173 个 JS/MJS 文件;新增证据包括 T-09 七阶段时间戳与旧记录兼容,以及 T-12 本地 diff/抽帧 CLI、Artifact 关系和路径脱敏。上一条 96/151 为早期迁移阶段的历史计数。
97
+ - DSH 异步工具 fixture 实际执行注册后的工具,贯通 submit → poll → download → Core Artifact → attachment;另验证 active 崩溃接管、唯一 Attempt、端点漂移零 poll/零 Task 写入。
98
+ - Headless CLI 与真实 DSH action 已用百炼同步模型完成图片生成,Manifest、同源媒体和 CLI 导出 hash 一致。这些证据不包含真实异步 Provider 或会话附件。
99
+ - 最近一次真实对话验收在进入 Iris 前被 DSH 主模型的 429 限流阻断,未新增 Core Task/Artifact,也未调用媒体 Provider。未改动用户全局模型设置。
100
+ - 早期候选 tarball 已在仓库外、无 DSH 包的临时项目安装并完成 crop/inspect;后续新增代码仍需最终候选重新打包审计。Windows CI 和安卓浏览器目视未以离线测试替代。
101
+
102
+ ## 后续验收
103
+
104
+ Core 任务到工作台进度/提醒的只读安全投影已完成(五类状态、合并任务区、会话内一次性完成提示、损坏/缺媒体局部降级),人工控制面四个动作已全部开放(reobserve/redeliver/cancel/retry,CLI/API/UI 同一 Command Service,retry 三层强制计费确认)。图片、t2v/i2v、TTS、转写以及本地 crop/diff/抽帧已有 Core 执行链;接下来补恢复后真实会话附件、浏览器与异步重启证据,验证停止 DSH 后 CLI 仍可 inspect/observe/export。旧 ID 映射和尚未迁移能力按后续计划单独处理。
105
+
106
+ 发行验证覆盖最终 tarball、无 DSH 安装闭包、Linux/Windows CI 和真实安装的 rc.2 服务隔离检查;这些检查不替代付费 Provider、个人 profile 的停机接管/回退与逐项浏览器验收。上述剩余范围继续跟踪;未验证的宿主版本与 Provider 路径不作为支持声明。
@@ -0,0 +1,36 @@
1
+ # DSH 0.2.0-rc.2 适配
2
+
3
+ 本适配随 Iris `0.2.0` 发布;npm 0.1.4 包不包含这些后续修正。Iris 0.2.0 要求 Node.js `>=22.0.0`,DSH engines、五项客户端 peers 与 Host Doctor 仅放行准确版本 `0.2.0-rc.2`,不再沿用旧版支持窗口,也不推定其他 0.2 预览版或正式版兼容。
4
+
5
+ 旧 DSH `>=0.1.2-rc.1 <0.1.3-0` 或 `0.1.5-rc.1` 按历史验证范围使用稳定包 `@mokuyoaxis/dsh-iris@0.1.4`。安装与 npm tarball 下载方式见 [README](../README.md#最快开始)。保留的旧桥接与 fixture 测试不构成 Iris 0.2.0 的旧宿主支持承诺。
6
+
7
+ ## 宿主边界的修正
8
+
9
+ | 边界 | 问题与修正 |
10
+ |---|---|
11
+ | 加载器与诊断 | rc.2 加载器检查 `peerDependencies`,原旧版客户端范围会被拒绝。当前客户端 peers、DSH engines、锁文件和 Host Doctor 均收敛到准确 rc.2,无需版本豁免。 |
12
+ | 会话附件 | 扫描引用时曾丢弃 `bytes/width/height`,真实 `readImage()` 因完整性不匹配拒绝读取。适配器保留这些已知事实及 `originalDimensions` 的独立副本,不猜测缺失值,不复制额外 Host 字段。 |
13
+ | 宿主视觉 | rc.2 的 `llm.stream()` 需要明确 Provider/模型路由。默认选择仅在精确模型元数据确认接受 `image` 时成为视觉候选;文本模型、未知能力和身份漂移在生成前拒绝,错误事件以及 `finish.reason.kind` 的 `error/aborted` 不再被当作空回答或部分成功。 |
14
+ | 客户端会话 | rc.2 列表没有旧 `current` 字段。适配器使用唯一的 `retainedBy.mainView` 持有者,通知时回读 `getSnapshot()`,卸载时释放订阅;保留旧接口,有歧义或无选择时不取任意列表项。 |
15
+
16
+ 修改位于 DSH Host Adapter、客户端边界、Host Doctor 与兼容元数据。Core Runtime、Command、Provider、Task/Artifact 存储和 CLI 实现不因该宿主升级修改;不迁移用户配置或已有数据。
17
+
18
+ ## 验证方式与证据范围
19
+
20
+ 常规 `npm test` 包含 rc.2 附件/视觉边界、客户端真实附件请求和 Doctor 的准确版本判定;Doctor 对旧 DSH 返回不在当前支持范围,并提示固定 Iris 0.1.4。旧接口 fixture 回归保留,但不作为旧宿主实际验收。
21
+
22
+ 若本机已安装 DSH rc.2,可在仓库运行以下手动验收,无需为 Iris 添加 DSH/React 生产依赖:
23
+
24
+ ```bash
25
+ node scripts/verify-dsh-host.mjs --dsh-root /absolute/path/to/@deepseek-ai/dsh
26
+ ```
27
+
28
+ 脚本在仓库外创建新临时数据根,载入实际安装的 Cordis、加载器兼容检查、附件、工具、Skill、LLM、默认模型、WebServer 与客户端 SlotRegistry。模型使用本地 Fake Adapter,正常流遵循安装包的 `index` 和对象终态格式,并验证真实 Runtime 将异常转换为失败终态;禁止外部请求。会话日志和列表是显式 fixture,宿主进程入口是已核实 DSH bin 的模拟。实际 WebServer 只绑定临时 loopback 端口,退出时卸载所有 Fiber。临时目录与 `report.json` 保留供复核。
29
+
30
+ 它检查 14 个工具、2 项 Skill、Doctor 路由、DSH → Core diff → DSH 附件,以及四个客户端座位的注册和卸载。SlotRegistry 使用安装包中的真实代码,React/DOM 为 stub,因此不证明完整 Web profile 装载、实际组件渲染、点击和草稿写回。另用 `scripts/verify-headless-package.mjs --offline` 验证当前 tarball 在无 DSH/Cordis 安装树中执行 CLI 和 Artifact 导出。
31
+
32
+ ## 当前限制
33
+
34
+ 真实用户 profile 若禁用 Iris,路由不存在属于预期状态,不据此判定适配失败。启用后仍需实机验证工作台、会话附件选择、提示词预览/写回和媒体展示。验证脚本不自动启用、安装、重载或重启用户插件,也不运行付费探针。
35
+
36
+ 这次修正保留现有 `textModel.stream()` / `visionModel.analyze()` 消费链;没有将真实适配器或业务接入 [Model Port M1](MODEL_PORT_CONTRACT.md)。视觉完整终态、统一输出预算、候选控制和 OCR 取消的进一步收口仍按该契约的后续阶段验收,不能把 rc.2 桥接测试当作迁移完成证据。
@@ -0,0 +1,217 @@
1
+ # Headless CLI(0.2.0)
2
+
3
+ Iris 0.2.0 提供无 DSH 的本地裁剪、图片 diff、视频抽帧,以及 Provider 媒体任务闭环。结果保存为 Core Artifact,并可在后续进程中检查或导出。Core 内部接口与 Artifact v0 尚未冻结为跨版本公共 SDK。
4
+
5
+ 需要 Node.js ≥ 22.0.0。在自己的项目安装 `npm install @mokuyoaxis/dsh-iris@0.2.0` 后,通过 `npx dsh-iris ...` 使用命令;也可临时运行 `npx --package @mokuyoaxis/dsh-iris@0.2.0 dsh-iris --help`。下文的 `dsh-iris` 指该版本提供的可执行入口,不需要安装 DSH。
6
+
7
+ ## 配置查询与离线诊断
8
+
9
+ ```bash
10
+ dsh-iris providers list --provider-config /absolute/path/to/providers.json
11
+ dsh-iris capabilities list --provider-config /absolute/path/to/providers.json
12
+ dsh-iris doctor --data-root /absolute/path/to/iris-data --json
13
+ ```
14
+
15
+ 前两项只读取显式提供的私有配置文件,不创建 Core Runtime 或数据根,也不请求 Provider。`providers list` 输出供应商身份、启用/配置状态、认证方式、媒体协议及其推断标记、配置能力与模型数;不输出 API Key 或端点。`capabilities list` 按五种配置能力列出 `providerId::modelId` 候选链,沿用 DSH 的“手工分配优先、模型池顺序补齐”规则;空链标为 `gap: no_configured_model`。这些只是配置事实,不证明远端模型或协议可调用。
16
+
17
+ 显式 `doctor --data-root` 是只读 Core 盘点:检查 Task/Artifact 结构、Index 一致性、孤立/未解析条目和写者租约;不创建缺失的根、不执行写入探针、不重建索引,也不释放租约。活跃写者可能使盘点在读取期间变化。省略 `--data-root` 时仍检查 DSH profile,保留原有写入探针,并纳入该 profile 的 `core-v0`。两种模式都返回 legacy/Core 计数对照,显式模式只统计指定根同层的 legacy 文件。退出码为 `0` 正常、`1` 警告、`2` 硬错误;诊断不会调用 Provider。
18
+
19
+ ## 异常退出后的写者租约
20
+
21
+ SIGINT/SIGTERM 可被 CLI 捕获并释放运行中的租约;SIGKILL、OOM 或断电可能留下租约。后续写操作返回 `IRIS_CORE_DATA_ROOT_BUSY` 时,先用 `doctor --data-root <absolute-path> --json` 只读查看 `core-writer-lease`。仅当报告中的 owner PID 为 `missing`,并且你已确认没有跨主机或其他仍在写入的进程,才可显式回显该 PID:
22
+
23
+ ```bash
24
+ dsh-iris runtime recover --data-root /absolute/path/to/iris-data --confirm-stale-pid 12345
25
+ ```
26
+
27
+ 此命令会再次核对租约证据和 PID,写入私有恢复审计记录后释放陈旧租约;活跃、无法确认、损坏或 PID 不匹配时拒绝。它不是 Doctor 的自动副作用,也不会修复 Task/Artifact。不要手动删除 `.iris-runtime-writer-v0` 或把“PID 不存在”单独当作安全证明。
28
+
29
+ ## 裁剪并保存 Artifact
30
+
31
+ ```bash
32
+ dsh-iris run crop \
33
+ --data-root /absolute/path/to/iris-data \
34
+ --input '{"image_path":"/absolute/path/input.png","left":10,"top":20,"width":640,"height":480}'
35
+ ```
36
+
37
+ 输出为 JSON,其中包含 `artifact.id`、媒体类型、字节数、创建时间与裁剪尺寸。结果不会返回输入文件或数据根的绝对路径。
38
+
39
+ ## 本地图片差异与视频抽帧
40
+
41
+ 两项命令只使用本机文件、Core Artifact、Sharp 与可选系统 ffmpeg;不读取 Provider 配置,不发起网络请求:
42
+
43
+ ```bash
44
+ dsh-iris media diff \
45
+ --data-root /absolute/path/to/iris-data \
46
+ --input '{"image_a_path":"/absolute/path/a.png","image_b_path":"/absolute/path/b.png","grid":8,"top_regions":3}'
47
+
48
+ dsh-iris media frames \
49
+ --data-root /absolute/path/to/iris-data \
50
+ --input '{"video_path":"/absolute/path/clip.mp4","max_frames":8,"target_width":640,"format":"jpeg","quality":85}'
51
+ ```
52
+
53
+ `media.diff` 返回差异比例、像素计数、最差区域和 `pixel-diff` 热力图 Artifact。A/B 两侧也可分别用 `image_a_artifact_id` / `image_b_artifact_id` 读取已有图片 Artifact;此时热力图写入 `derived-from` 关系。
54
+
55
+ `media.frames` 返回视频元数据和一组 `video-frame` Artifact;输入也可用 `artifact_id` 指向已有视频 Artifact,此时每帧写入 `frame-of` 关系。帧数最多 20,格式仅支持 `jpeg` 或 `png`;系统没有 ffmpeg/ffprobe 或视频无效时命令稳定失败,不影响其他 CLI 能力。Manifest 和命令结果都不保存宿主输入路径。
56
+
57
+ ## Provider 图片生成
58
+
59
+ CLI 必须同时收到显式 Core 数据根和私有供应商配置文件,不推断 DSH、HOME 或 cwd:
60
+
61
+ ```bash
62
+ dsh-iris run image \
63
+ --data-root /absolute/path/to/iris-core-data \
64
+ --provider-config /absolute/path/to/providers.json \
65
+ --input '{"prompt":"一朵雨后的鸢尾花","model_ref":"provider-id::model-id","size":"1024*1024","n":1}'
66
+ ```
67
+
68
+ `model_ref` 可省略;省略时采用“手工 assignment 顺序优先、模型池顺序补齐”的安全 failover。每个请求从首项开始,只有明确 `not_accepted` 才进入下一项。配置文件须为普通文件,POSIX 权限不得开放给 group/other;API Key、端点、Prompt 和下载 URL都不会写入 Task 输出。
69
+
70
+ 模型必须存在于配置的 `models` 或旧模型字段中,且具备所请求的能力;缺失时返回配置错误,不注入厂商默认模型。显式 `models:[]` 表示没有可用模型。`model_ref` 也接受裸模型名,同名跨供应商时按配置中的供应商顺序取首项;需要精确绑定账号时使用 `providerId::modelId`。显式指定只选择该模型,不扩展 failover 候选。
71
+
72
+ 旧裸 DashScope 账号的已知目录仅在 DSH 配置加载或保存时一次性写入 `models`,随后可见、可编辑;CLI 只读配置,不执行该迁移。独立 CLI 配置须自行声明模型。
73
+
74
+ 同步图片会在一次命令内完成 Task → Attempt → Provider Adapter → download → Artifact。异步图片模型先持久化受理事实与远端 Task ID;之后由用户显式执行单步观察,不建立后台 timer。
75
+
76
+ 视频(t2v/i2v)同样走 Core:
77
+
78
+ ```bash
79
+ dsh-iris run video \
80
+ --data-root /absolute/path/to/iris-data \
81
+ --provider-config /absolute/path/to/providers.json \
82
+ --input '{"prompt":"海浪拍岸","size":"1280*720","duration":5}'
83
+ ```
84
+
85
+ 输入冻结为 `{prompt, size?, duration?, img_data_url?, model_ref?}`:`img_data_url` 是首帧的 `data:image/` data URL(i2v);s2v 数字人上传流程不在 headless 面开放。视频交付走独立 Profile:远端成功后下载为 `video/mp4`,Artifact kind 为 `generated-video`。受理后由显式 `task observe` 逐拍推进(DashScope 视频通常需要数拍)。
86
+
87
+ 语音合成是同步完成型,一次命令内完成 Task → Attempt → 交付:
88
+
89
+ ```bash
90
+ dsh-iris run tts \
91
+ --data-root /absolute/path/to/iris-data \
92
+ --provider-config /absolute/path/to/providers.json \
93
+ --input '{"text":"要合成的文本","voice":"Cherry"}'
94
+ ```
95
+
96
+ 输入冻结为 `{text, voice?, model_ref?}`;产物走语音 Profile:`audio/mpeg`/`audio/wav` 白名单,Artifact kind 为 `generated-audio`(远端 URL 下载物化,inline base64 直接落盘)。同步完成即终态,`task observe/redeliver/cancel` 对终态语音任务一律拒绝,终态失败可用 `task retry` 显式重试为新任务。
97
+
98
+ 转写是上传型异步:
99
+
100
+ ```bash
101
+ dsh-iris run transcribe \
102
+ --data-root /absolute/path/to/iris-data \
103
+ --provider-config /absolute/path/to/providers.json \
104
+ --input '{"audio_url":"https://example.com/public.wav"}'
105
+ # 或本地文件(经首选候选 Provider 的临时存储上传):
106
+ dsh-iris run transcribe \
107
+ --data-root /absolute/path/to/iris-data \
108
+ --provider-config /absolute/path/to/providers.json \
109
+ --input '{"audio_path":"/absolute/path/to/voice.wav"}'
110
+ ```
111
+
112
+ 输入冻结为 `{audio_url | audio_path, model_ref?}`(二选一):`audio_url` 必须是 `https://` 或 `oss://`;`audio_path` 在命令内先上传为临时 `oss://` 地址再提交——**签名/临时 URL 绝不写入 Core 记录**。受理后由显式 `task observe` 逐拍推进;远端成功后正文物化为 `text/plain` 的 `transcript` Artifact(`artifact inspect/export` 可直接读取/导出文本)。终态失败可用 `task retry --input '{"audio_url":"..."}' --confirm-billing` 显式重试为新任务。
113
+
114
+ ## 检查 Task 与 Artifact
115
+
116
+ Task 查询是纯 reader,不需要 Provider 配置,也不会触发 submit、poll、恢复或下载:
117
+
118
+ ```bash
119
+ dsh-iris task list --data-root /absolute/path/to/iris-data
120
+
121
+ dsh-iris task inspect task_0123456789abcdef01234567 \
122
+ --data-root /absolute/path/to/iris-data
123
+ ```
124
+
125
+ 输出只包含已经持久化的安全 Task/Attempt 事实;不返回 Prompt、API Key、下载 URL 或数据根路径。
126
+
127
+ 新建 Attempt 可选保存 `stageTimestamps`:排队、开始提交、提交响应、远端终态、开始下载、下载校验完成和本地 Artifact 处理完成七个边界。字段按发生顺序单调不减;旧记录缺失该字段仍可读取。重新交付会从新的下载开始边界重新计时,不伪造尚未跨过的阶段。
128
+
129
+ 新建 Attempt 还可选保存 `selectionReason`:`explicit` 表示调用方显式提供 `model_ref`,`assignment` 表示候选来自提交当时的能力分配,`pool` 表示由配置模型池按顺序补齐。它与 Attempt 一起在 Provider submit 前落盘;`task inspect` 只展示持久事实,不会用当前可能已变化的 assignment 事后猜测。旧记录没有该字段时保持缺失,不伪造默认值;第几次 failover 仍看 `ordinal`。
130
+
131
+ 已受理的异步图片 Task 可以显式推进一次:
132
+
133
+ ```bash
134
+ dsh-iris task observe task_0123456789abcdef01234567 \
135
+ --data-root /absolute/path/to/iris-data \
136
+ --provider-config /absolute/path/to/providers.json
137
+ ```
138
+
139
+ 每次命令最多执行一次 Provider `poll`;若远端已成功,则在同一次命令中下载并写入 Core Artifact。它不会调用 `submit`、不会采用当前 assignment/failover,也不会自动循环。CLI 只按 Task 中保存的 `providerId::modelId` 恢复原 Adapter:API Key 可以轮换;Provider 被停用、模型被移除或失去图片能力时会在网络请求前失败。
140
+
141
+ 新 Task 还保存提交协议与实际媒体端点的 SHA-256 binding,不保存端点本身。端点或协议改变时,`observe` 会拒绝把旧远端 Task ID 发送给新端点。此前没有 binding 的异步 Task 保持可读,但不会被猜测性恢复;可继续使用创建它的旧入口处理。
142
+
143
+ 同一份"显式单步观察、绝不重新提交"也已在 DSH 侧开放:工作台 API 提供 `POST /iris/api/core/task/:id/reobserve`,用户任务区的 Core 投影行和高级诊断卡提供「重新观察」按钮。三者经同一个 Command Service 命令(对外命令名 `task.reobserve`,实现与 `task.observe` 相同),共用原 Provider/binding 校验;每次调用至多一次 poll,对终态、未受理、无远端 ID 或 binding 漂移的任务在网络前拒绝。
144
+
145
+ 已成功但本地产物取回失败(deliveryState=failed)的 Task 可以显式重新取回,绝不重新生成:
146
+
147
+ ```bash
148
+ dsh-iris task redeliver task_0123456789abcdef01234567 \
149
+ --data-root /absolute/path/to/iris-data \
150
+ --provider-config /absolute/path/to/providers.json
151
+ ```
152
+
153
+ 每次命令至多一次带 redelivery 语义标志的 `poll`(拿远端产物清单)接一轮下载,写入新的 Core Artifact;不调用 `submit`、不新建 Attempt、不产生第二次生成费用。非 failed、无远端 ID 或 binding 漂移时在调用前拒绝;成功后再次调用被同样拒绝,失败回落 failed 后可再次显式执行。DSH 侧同构开放:`POST /iris/api/core/task/:id/redeliver` 与工作台「重新取回作品」按钮(delivery_failed 投影行的唯一动作)。
154
+
155
+ 已受理且尚未终态的 Task 可以显式请求远端取消:
156
+
157
+ ```bash
158
+ dsh-iris task cancel task_0123456789abcdef01234567 \
159
+ --data-root /absolute/path/to/iris-data \
160
+ --provider-config /absolute/path/to/providers.json
161
+ ```
162
+
163
+ **只有供应商明确确认才把 outcome 写成 `canceled`**;供应商不支持远端取消(当前 DashScope 与 OpenAI Images 媒体协议均不提供经过验证的取消实现)时,取消未发生,任务保持真实状态并可继续显式观察;超时或网络失败记 `cancelState=unknown` 且保持非终态,可用 `task observe` 显式收敛。任何分支都绝不伪造"已取消"。已请求过取消但远端未确认的任务拒绝再次取消;竞态下远端先沉淀的成功事实不得被取消覆盖。DSH 侧同构开放:`POST /iris/api/core/task/:id/cancel` 与工作台需二次确认的「取消任务」按钮。
164
+
165
+ 终态且未成功交付的 Task 可以重试为**新任务**。这是控制面唯一产生新的真实计费的动作,必须显式确认:
166
+
167
+ ```bash
168
+ dsh-iris task retry task_0123456789abcdef01234567 \
169
+ --data-root /absolute/path/to/iris-data \
170
+ --provider-config /absolute/path/to/providers.json \
171
+ --input '{"prompt":"重新输入的生成指令"}' \
172
+ --confirm-billing \
173
+ [--model-ref providerId::modelId]
174
+ ```
175
+
176
+ 缺 `--confirm-billing` 时在网络与创建之前拒绝。候选链按当前 assignments/池实况重新解析(不绑定旧 Provider/binding——旧配置可能正是失败原因),`--model-ref` 可显式指定。新 Task 有全新 id、attempts 与提交时实况 binding,并记录单向 `retriedFrom` 指向旧 Task;旧 Task 零变化。**Core 记录不持久化 Prompt**,所以生成指令必须由 `--input` 重新提供,绝不从旧任务恢复。DSH 侧同构开放:`POST /iris/api/core/task/:id/retry`(请求体必须 `confirmBilling:true`)与工作台「重试为新任务」按钮(重新输入指令 + 重复计费确认弹窗)。
177
+
178
+ 重试输入按旧 Task 的能力校验:图片为 `{prompt, size?, n?}`,视频为 `{prompt, size?, duration?, img_data_url?}`,TTS 为 `{text, voice?}`,转写为 `{audio_url}`。视频首帧和转写地址会转换为 Provider 所需字段;原任务中的媒体输入不会自动恢复。转写 retry 要求重新提供 HTTPS/OSS 地址,本地 `audio_path` 上传仍通过正常提交入口处理;模型覆盖使用外层 `--model-ref`,不放在 retry 的 `--input` 中。
179
+
180
+ CLI、DSH 正常生成与 retry 共用输入规范:Prompt/文本修剪后为 1–20000 字符,图片 `n` 为 1–4 的整数(缺省 1),视频时长为 1–60 的数字,规范化后的显式 size/voice 为 1–64 字符。转写地址修剪后最多 20000 字符。数字字符串会转为数字;非法生成参数在提交前拒绝,不创建新的计费 Task。CLI 和 retry 还会拒绝未知输入字段;DSH 保留自己的宿主参数,由入口提取生成参数,工作台清空可选文本框仍使用默认值。
181
+
182
+ ```bash
183
+ dsh-iris artifact inspect artifact_0123456789abcdef01234567 \
184
+ --data-root /absolute/path/to/iris-data
185
+
186
+ dsh-iris artifact list --data-root /absolute/path/to/iris-data
187
+
188
+ dsh-iris artifact export artifact_0123456789abcdef01234567 \
189
+ --data-root /absolute/path/to/iris-data \
190
+ --output /absolute/path/cropped.png
191
+
192
+ dsh-iris artifact rebuild --data-root /absolute/path/to/iris-data
193
+ ```
194
+
195
+ `task` 与 `artifact` 的 `inspect/list` 以 reader 打开数据根,不创建或修复文件。`run`、`export` 使用 writer;`rebuild` 是显式 recover 操作。同一数据根已有写者时返回 `IRIS_CORE_DATA_ROOT_BUSY`。导出默认不覆盖已有文件。
196
+
197
+ ## 当前边界
198
+
199
+ - Core 的 `run`、`media`、`task`、`artifact` 和 `runtime recover` 操作必须显式提供绝对 `--data-root`,避免误写日常 profile;配置查询只要求 `--provider-config`,Doctor 省略数据根时按上述默认范围检查。
200
+ - 该路径只使用 Node.js、`sharp` 和 Iris Core,不加载 DSH/Cordis,也不启动服务;只有显式 `run image`、`run video`、`run tts`、`run transcribe`、`task observe`、`task redeliver`、`task cancel` 和 `task retry` 会访问供应商。
201
+ - Artifact Manifest v0 已包含 SHA-256、关系边、可重建 Index 和进程崩溃窗口恢复;格式与限制见 [Artifact Manifest v0](ARTIFACT_MANIFEST.md)。
202
+ - 当前开放 `crop`、同步/异步图片提交、视频 t2v/i2v 提交、语音同步合成(`run tts`)、音频转写(`run transcribe`)、图片/视频/转写单步观察(CLI `task observe` 与工作台「重新观察」共用)、失败产物重新取回(CLI `task redeliver` 与工作台「重新取回作品」共用)、人工取消(CLI `task cancel` 与工作台「取消任务」共用,只有供应商明确确认才记为已取消)、重试为新任务(CLI `task retry` 与工作台「重试为新任务」共用,必须显式确认计费且重新提供 prompt/文本/音频地址)、Task 只读查询与 Artifact 管理;自动观察、其他媒体能力和其余 Command 会按相同事实语义逐项迁入。
203
+ - CLI 暂不提供 Core Task/Artifact 删除能力(`task`/`artifact` 的 `inspect/list` 均为纯 reader);DSH 工作台的删除、清空与孤儿清理也只处理 legacy `outputs/`,Core 作品同样只读。不要手动删除 `core-v0` 中的记录、Manifest 或对象;Core 删除与清理能力计划在 0.2.x 开放。
204
+
205
+ ## 源码仓库的包外验收
206
+
207
+ 在源码仓库运行以下开发验收命令,需要 Node/npm 与本机 ffmpeg/ffprobe:
208
+
209
+ ```bash
210
+ node scripts/verify-headless-package.mjs
211
+ # npm 缓存完整时也可让依赖安装离线执行:
212
+ node scripts/verify-headless-package.mjs --offline
213
+ ```
214
+
215
+ 脚本在仓库外的独立临时目录打包、安装 tarball,通过 npm 安装的 `dsh-iris` 入口验证 help、crop、diff、抽帧以及图片、视频、TTS、转写的 Task/Artifact 闭环。安装树不含 DSH/Cordis,不链接仓库依赖;Provider 请求全部由复制到包外的 fixture 接管,本地 Sharp/ffmpeg 则实际处理媒体。报告检查每次 observe 只有一次 poll、无重提,Artifact 导出字节与 Manifest SHA-256 一致,reader 和导出保持 Core 零写入且不请求 Provider。
216
+
217
+ 每次运行保留独立目录内的 tarball、安装日志、fixture 数据、导出产物和 `report.json`,终端输出验收目录和报告位置。该脚本属于源码开发工具,不随 npm 包发布;没有真实 Provider、DSH 重启或其他平台的验收结果时,不据此声明那些路径已通过。