@iqiyi-intl-nadoupro/nadoupro-cli 1.0.0-test.2

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 (62) hide show
  1. package/README.md +25 -0
  2. package/package.json +42 -0
  3. package/scripts/bootstrap.js +393 -0
  4. package/scripts/install.js +99 -0
  5. package/scripts/run.js +65 -0
  6. package/scripts/skill-sync.js +18 -0
  7. package/skills/nadou/SKILL.md +68 -0
  8. package/skills/nadou/commands/audio.md +125 -0
  9. package/skills/nadou/commands/auth.md +91 -0
  10. package/skills/nadou/commands/canvas-attachment.md +71 -0
  11. package/skills/nadou/commands/canvas-edge.md +65 -0
  12. package/skills/nadou/commands/canvas-graph.md +191 -0
  13. package/skills/nadou/commands/canvas-management.md +77 -0
  14. package/skills/nadou/commands/canvas-media.md +377 -0
  15. package/skills/nadou/commands/canvas-node.md +228 -0
  16. package/skills/nadou/commands/canvas.md +123 -0
  17. package/skills/nadou/commands/evidence.md +30 -0
  18. package/skills/nadou/commands/image-tools.md +88 -0
  19. package/skills/nadou/commands/image.md +273 -0
  20. package/skills/nadou/commands/material.md +59 -0
  21. package/skills/nadou/commands/media.md +156 -0
  22. package/skills/nadou/commands/model.md +103 -0
  23. package/skills/nadou/commands/points.md +43 -0
  24. package/skills/nadou/commands/schedule.md +112 -0
  25. package/skills/nadou/commands/space.md +253 -0
  26. package/skills/nadou/commands/system.md +50 -0
  27. package/skills/nadou/commands/task-request.md +188 -0
  28. package/skills/nadou/commands/task.md +229 -0
  29. package/skills/nadou/commands/text.md +81 -0
  30. package/skills/nadou/commands/video-advanced.md +96 -0
  31. package/skills/nadou/commands/video.md +247 -0
  32. package/skills/nadou/guides/artifact-presentation.md +146 -0
  33. package/skills/nadou/guides/canvas-dependency-graph.md +101 -0
  34. package/skills/nadou/guides/canvas-first-complex-workflow.md +83 -0
  35. package/skills/nadou/guides/execution-interaction.md +54 -0
  36. package/skills/nadou/guides/failure-cost-presentation.md +42 -0
  37. package/skills/nadou/guides/intent-templates.md +53 -0
  38. package/skills/nadou/guides/model-rules.md +7 -0
  39. package/skills/nadou/guides/utf8-input-safety.md +13 -0
  40. package/skills/nadou/node-types/audio.md +66 -0
  41. package/skills/nadou/node-types/clip.md +43 -0
  42. package/skills/nadou/node-types/director3d.md +41 -0
  43. package/skills/nadou/node-types/group.md +59 -0
  44. package/skills/nadou/node-types/image.md +137 -0
  45. package/skills/nadou/node-types/index.md +77 -0
  46. package/skills/nadou/node-types/json-contract.md +275 -0
  47. package/skills/nadou/node-types/model3d.md +35 -0
  48. package/skills/nadou/node-types/storyboard.md +43 -0
  49. package/skills/nadou/node-types/text.md +93 -0
  50. package/skills/nadou/node-types/video.md +119 -0
  51. package/skills/nadou/policies/core-safety.md +35 -0
  52. package/skills/nadou/policies/cost-and-write.md +37 -0
  53. package/skills/nadou/policies/result-and-recovery.md +41 -0
  54. package/skills/nadou/recipes/atomic-image.md +77 -0
  55. package/skills/nadou/recipes/canvas-image.md +92 -0
  56. package/skills/nadou/recipes/one-click-film.md +234 -0
  57. package/skills/nadou/recipes/quality-review.md +95 -0
  58. package/skills/nadou/recipes/typical-flows-host-adaptation.md +113 -0
  59. package/skills/nadou/workflows/atomic.md +61 -0
  60. package/skills/nadou/workflows/canvas.md +59 -0
  61. package/skills/nadou/workflows/local.md +41 -0
  62. package/skills/nadou/workflows/task-recovery.md +45 -0
@@ -0,0 +1,77 @@
1
+ # 画布管理与实时读取
2
+
3
+ 使用 `canvas list/create/rename/move/delete/restore` 管理自由画布;使用 `canvas get` 读取当前画布 Graph。
4
+ 用户侧统一称“画布 ID”,协议字段仍可为 `workflowId`。
5
+
6
+ ```sh
7
+ nadou canvas get --canvas-id <canvas-id> --profile <profile> --json
8
+ nadou canvas get --canvas-id <canvas-id> --raw --profile <profile> --json
9
+ nadou canvas get --canvas-id <canvas-id> --node-id <node-id> --profile <profile> --json
10
+ nadou canvas rename --canvas-id <canvas-id> <name> --profile <profile> --json
11
+ ```
12
+
13
+ `canvas get` 只读取当前画布 Graph;草稿投影不是该命令的数据源:
14
+
15
+ | 模式 | 用法 | 输出 |
16
+ | --- | --- | --- |
17
+ | 默认 / `--summary` | `canvas get --canvas-id <id>` | 紧凑结构摘要,不含节点业务数据 |
18
+ | `--raw` | `canvas get --raw --canvas-id <id>` | 完整实时节点/连线投影 |
19
+ | `--node-id` | `canvas get --node-id <id> ...` | 焦点节点及其直接上下游邻接;`focus_nodes` 含完整业务数据 |
20
+
21
+ CLI 不保存当前画布。Agent 在当前会话中保留用户明确给出的画布 ID,
22
+ 每次单画布命令都重复传入 `--canvas-id`。普通发现、对账和恢复都使用 `canvas get`。
23
+
24
+ 若创建响应包含 `canvasEntryUrl`,CLI 原样输出该入口地址;字段缺失时只报告“服务端未提供入口”,
25
+ 不按域名、路径前缀和画布 ID 自行拼接链接。
26
+
27
+ 创建、改名、移动、删除和恢复都是远端写操作,只发送一次;结果不确定时先回读。永久删除必须由用户确认,非交互模式同时传 `--permanent --yes`。通用创建不复制 Graph、任务、作业或素材。
28
+
29
+ ## 创建目标与归属验证
30
+
31
+ 创建画布前先解析目标空间与目录,不能依赖服务端在缺少 `groupId/directoryId` 时默认落入个人空间:
32
+
33
+ - 直接执行 `canvas create <name>` 时,CLI 在本次请求中读取权威当前空间及其唯一根目录,并把两者显式放入创建请求;它不会执行 `space use`。
34
+ - 只给 `--group-id` 时,CLI 从该空间的权威目录列表解析唯一根目录。
35
+ - 同时给 `--group-id` 和 `--directory-id` 时,CLI 验证目录确实属于该空间;只给目录 ID、空间或目录不存在、根目录不唯一时,在创建写入前失败。
36
+ - Agent 面对“个人空间”“团队空间”或名称可能重复的自然语言目标时,必须先列出候选并让用户选择;不得用省略目标表达个人空间,也不得按名称猜 ID。
37
+
38
+ 创建已知成功后,CLI 会按返回的画布 ID 回读真实归属。机器结果分别给出 `planned_target`、
39
+ `actual_target` 和 `target_verification`;只有 `target_verification=MATCHED` 才表示画布已位于计划位置。
40
+ `CANVAS_TARGET_MISMATCH` 表示画布已创建但位置错位,`CANVAS_TARGET_UNVERIFIED` 表示画布已创建但本轮无法确认归属。
41
+ 这两种状态都保留画布 ID 和只读恢复建议,不得自动移动、删除或重新创建。
42
+
43
+ ## 生命周期对账
44
+
45
+ 写入前先明确目标画布 ID、期望名称和位置;名称相同不等于同一画布。同一登录身份下的个人/团队空间、目录、
46
+ 目标画布或永久删除范围有歧义时必须先询问,不发送写请求。
47
+
48
+ 每次创建、重命名、移动、删除或恢复都只发送一次,并保留请求 ID 和响应中的画布 ID。
49
+ 成功或结果不确定后,使用对应的只读命令核对实际状态:
50
+
51
+ | 写操作 | 写后只读核对 |
52
+ | --- | --- |
53
+ | 创建 | 命令已用返回的画布 ID 回读归属;错位或未验证时按错误中的 workflow ID 再做只读详情对账。没有返回 ID 时可用 `canvas list --query <name>` 查找候选,但不能仅凭同名认定成功 |
54
+ | 重命名 | `canvas get <canvas-id>`,核对名称 |
55
+ | 移动 | `canvas get <canvas-id>` 或在明确目录范围内重新列表,核对目录 |
56
+ | 删除 | `canvas list --deleted --query <name>`,核对同一画布 ID |
57
+ | 恢复 | `canvas get <canvas-id>`,并确认它不再出现在已删除列表 |
58
+
59
+ 断网、超时或 `REQUEST_OUTCOME_UNKNOWN` 时不得自动重放。先按上表读取实际状态;仍无法
60
+ 确认时,报告原操作、目标画布 ID、请求 ID 和当前观察结果,等待调用方决定。永久删除
61
+ 尤其不得以“没看到成功响应”为由再次提交。
62
+
63
+ ## 使用已有空间文件夹
64
+
65
+ 产品所称“项目”如指个人或团队空间中的文件夹,应直接使用目录 ID,不需要工作台项目接口。先通过
66
+ `space directory list --group-id <group-id>` 或 `space directory contents` 取得用户明确选择的既有目录。
67
+
68
+ 个人和团队目录都可在创建时直接作为画布落点;`--group-id` 是该已选文件夹所属空间的 ID,而不是
69
+ “仅团队”字段:
70
+
71
+ ```sh
72
+ nadou canvas create "短片创作" \
73
+ --group-id <selected-folder-group-id> --directory-id <selected-folder-id> \
74
+ --profile <profile> --json
75
+ ```
76
+
77
+ 文件夹 ID 但缺少所属空间 ID 时,先停止并从已选目录的发现结果取得两者;不得以当前空间或文件夹名称猜测。`canvas move` 仅用于用户明确要求改变已有画布的位置。创建和移动都是独立写操作,结果未知时先读取或列出目录对账,不能自动重试或重复创建。CLI 当前不提供新建目录命令。
@@ -0,0 +1,377 @@
1
+ # 画布剪辑与成片导出
2
+
3
+ 本页用于用户明确要求“在画布中剪辑、按时间轴合成、导出成片”时。CLI 接收 Web 剪辑器协议的完整
4
+ Timeline JSON,复用既有 Canvas Graph 与通用任务能力;它不实现可视化时间轴编辑器,也不把本地
5
+ `nadou media` 的拼接结果解释为画布回填。若输入 Timeline 已有素材但所有轨道的 `segments` 都为空,
6
+ CLI 会按 `materials.videos` 的明确数组顺序和素材时长补一条主视频轨道;这只是补全显式输入,不会根据
7
+ Graph 位置、节点名称或连线来猜测顺序。
8
+
9
+ ## Agent 决策门(先判断输入,再选命令)
10
+
11
+ 看到 `{openId, assets}`、素材候选或空白剪辑节点时,**不要手写或直接 `web-write` 一个通用
12
+ `{canvas, materials, tracks}` JSON**。网页剪辑台存档需要完整工程根字段
13
+ `schemaVersion`、非空 `id`、根级 `durationUs` 以及素材池和轨道;通用 Timeline 即使能通过离线
14
+ `validate`,也可能被页面当成空工程,导致时间轴不显示。
15
+
16
+ - 真实画布首次打开或需要安全补全:优先执行 `timeline initialize`。它会先读;明确缺失、显式
17
+ `--repair-empty` 的全空存档,或与本次工程语义一致的 `bare-timeline` 才会写回 Web 信封并回读。
18
+ - 需要先审查生成结果:先执行 `timeline init --input-file ... --output-file timeline.json`,再对生成文件执行
19
+ `timeline validate`,最后才执行 `timeline web-write` → `timeline web-read`。
20
+ - 已有页面确认过的完整工程 JSON 才能直接 `web-write`;缺少上述根字段时 CLI 会在本地返回
21
+ `INVALID_ARGUMENT`、`request_sent=false`,并提示回到 `timeline init`/`timeline initialize`,不会触发远端写入。
22
+
23
+ ## 先判定持久化模式
24
+
25
+ 网页剪辑台展示和 CLI/后端成片导出有不同的底层持久化职责;调用方不手工混选,组合式
26
+ `backend-submit` 是唯一由代码安全衔接两者的入口:
27
+
28
+ | 用户目标 | 必须使用 | 回读方式 |
29
+ | --- | --- | --- |
30
+ | 让画布网页剪辑节点显示素材、主轨和 Timeline | `timeline web-write` / `timeline web-read` | 固定 `node-data`;用 `read_node_data?type=CLIP` 回读 `response.data.data`,Graph 只做写前节点/锁预检 |
31
+ | CLI/后端导出链路的 Timeline 证据 | `timeline export-write` / `timeline export-read` | 固定 `clip-sidecar`;`backend-submit` 提交前由代码确保网页 `node-data` 是可读取的 Web 信封 |
32
+
33
+ 隐藏的通用 `timeline write/read` 不可执行,会在本地直接返回 `INVALID_ARGUMENT`,不发送写请求,也不允许人工选择持久化模式。
34
+ 不要在同一条流程里手工混选持久化模式,也不要把一个命令的成功当成另一条路径已经写入。
35
+ `timeline initialize` 和 `timeline web-write` 面向网页剪辑节点,固定使用 `node-data`;组合式
36
+ `export backend-submit` 会在发出 `clip/export` 前由应用层写入并确认网页 `node-data`,Agent 无需补发 `web-write`。
37
+
38
+ `backend-submit` 的自动同步条件是严格的:旁路 Timeline 先通过主轨和语义回读门禁;网页 `node-data` 明确缺失、可读但全轨为空,或是与本次导出一致的裸 Timeline 时,先调用 `write_node_data` 并确认回读形态为 `web-editor-envelope`。已有匹配 Web 信封不重复写,非空但不一致、读取异常或回读仍为 `bare-timeline` 都会在发送 `clip/export` 前失败关闭。`clip/export` 返回明确成功或失败后,CLI 立即读取同一行;若后端已把它覆盖为匹配的裸 Timeline,再执行一次 Web 信封恢复并回读,不等待渲染完成。POST 收据的 `workflowId`、`clipNodeId`、`task.idempotencyKey` 必须匹配原请求,并只用 `task.submitState` 判定提交状态;状态查询则校验 `workflowId`、`task.idempotencyKey` 并只用 `task.status`。`PROCESSING/RECONCILING`(通常是同 key 的并发重放,即使 `replayed` 缺失也失败关闭)会有限轮询原 key 的只读收据;终态后才恢复,身份错配、状态缺失或超时都按结果未知返回且不做竞态写;同 key 不同请求体的幂等冲突也不做后置写。成功结果返回 `web_editor_sync_action=restored_after_export`;已完成幂等重放未发生覆盖时返回 `preserved_after_export`。其他确定性失败仍保留原导出错误,并附带 `restored_after_export_error` 或恢复失败状态。
39
+
40
+ 组合命令本身也有独立的提交前预览:先用同样的 Timeline、画布、clip 节点和幂等键执行
41
+ `canvas media export backend-submit --dry-run --json`。该命令只做本地解析,返回
42
+ `request_sent=false`、Timeline digest/摘要、预期 Graph 变更和 `cost_confirmation`;不会创建服务对象、写 Graph 或提交任务。
43
+ 当前后端没有该组合请求的已批准 CLI 估价接口,因此预览中的 `estimated_points` 为 `null`、
44
+ `status=unavailable`,不得按 0 积分或已确认解释。正式执行必须在审阅后显式使用 `--yes`,
45
+ 或在交互提示中确认;`--no-interactive` 未带 `--yes` 会在本地以
46
+ `CONFIRMATION_REQUIRED` 停止,`request_sent=false`。提交结果未知时仍只用原幂等键查询
47
+ `backend-status`,不能因为预览或确认失败而换键重提。
48
+
49
+ 导出结果未知时绝不执行后置写入,先用原 `Idempotency-Key` 查询 `backend-status`。导出已受理但 Web 信封恢复失败属于部分成功:保留原 key、request/output/mutation receipt,禁止自动创建新导出;对账后显式执行同一 Timeline 的 `timeline web-write`。
50
+
51
+ 后端部署了组合式导出契约时,优先使用对应的 `timeline export-write/export-read` 与
52
+ `canvas media export backend-submit/backend-status`:后端负责渲染任务以及导出结果节点/边,CLI 发送完整
53
+ Timeline 与目标 `clip` 节点,并以同一 `Idempotency-Key` 对账;源素材到 `clip` 的依赖边仍由 Agent 按依赖图显式核对或创建。
54
+ 若当前环境没有该契约或没有可用 `clip` 节点,才报告能力阻塞;遇到 `NOT_FOUND`、`PROCESSING` 或
55
+ `B00001/INVALID_ARGUMENT` 时先只查询原键,不切换其他接口或自动重复提交。若后端已经明确给出
56
+ 可修复的入参契约错误,修正请求后由用户显式换用新键再提交。
57
+ 即使分步导出链路随后能够成功,也只能作为用户另行明确选择的独立验收,不能作为本次
58
+ `backend-submit` 的回退,也不能把两条链路的任务、节点或回填状态合并成一个成功事实。
59
+
60
+ ## 原子流程
61
+
62
+ 组合式后端导出链路使用以下流程,不要与分步 `prepare`/`submit`/`observe` 链路混用:
63
+
64
+ ```text
65
+ canvas media timeline validate
66
+ -> canvas media timeline web-write -> canvas media timeline web-read
67
+ (网页剪辑台路径,固定 node-data)
68
+ 或 canvas media timeline export-write -> canvas media timeline export-read
69
+ (CLI/后端导出证据,固定 clip-sidecar)
70
+ -> canvas media export backend-submit
71
+ (先确保网页主轴可见,再提交导出;明确受理后立即恢复可能被覆盖的 Web 信封)
72
+ -> canvas media export backend-status
73
+ ```
74
+
75
+ ### 剪辑台打开参数与 CLIP 存档是两套契约
76
+
77
+ 前端提供的 `openClipEditor`/`init` 参数和 CLIP 存档写入不能混用:
78
+
79
+ - **打开剪辑台**只接收最小素材候选对象,例如
80
+ `{openId, workflowId?, assets, arrangeAssetsOnMainTrack?}`。它用于让页面初始化素材池和主轨编排,
81
+ 不是 `write_node_data` 的请求体;前端直连该初始化契约时,`assets` 应为非空数组,需要宿主自动编排时显式传
82
+ `arrangeAssetsOnMainTrack: true`。不要把完整 Timeline 或 `timeline` 字段塞进这个初始化对象。
83
+ - **保存 CLIP 存档**必须另走 `timeline web-write`/`timeline initialize`。完整工程 JSON 必须经过两层字符串包装,
84
+ 等价于:
85
+
86
+ ```js
87
+ const inner = JSON.stringify({ timeline: JSON.stringify(project) });
88
+ writeNodeData({ workflowId, nodeId: openId, type: "CLIP" }, { data: inner });
89
+ ```
90
+
91
+ 不要直接发送 `project`,也不要把它改成只有一层 `{data: project}`。写入成功后仍以
92
+ `read_node_data?type=CLIP` 回读的 `response.data.data` 为准。
93
+ - `timeline web-write` 的输入必须是上述完整网页工程存档;不能把 `timeline validate` 能接受的通用
94
+ Timeline 当成网页工程。最小输入只能交给 `timeline init`/`timeline initialize` 转换。
95
+ - CLI 的 `timeline init/initialize` 是本地规范化和安全存档初始化入口,不调用前端 `openClipEditor`。
96
+ 在 CLI 语义中,`ready` 视频默认进入主轨;`arrangeAssetsOnMainTrack: true` 只额外把 `ready` 图片编排到主轨,
97
+ 默认仍保留图片 `sticker` 轨的兼容行为。CLI 为离线表示显式空剪辑而接受 `assets: []`,但该输入不能直接转发给前端
98
+ `openClipEditor` 初始化请求。
99
+
100
+ ### 从剪辑台最小输入初始化 Timeline
101
+
102
+ 前端提供的 `{openId, assets}` 是“打开剪辑台时的素材候选”输入,不是可直接提交的完整 Timeline。CLI 在离线规范化时也接受同一结构,
103
+ 并支持可选的 `"arrangeAssetsOnMainTrack"`;省略或传 `false` 时,CLI 保持兼容行为:`ready` 视频进入主轨,`ready` 图片进入 `sticker` 轨;显式传 `true` 时,`ready` 图片也按素材顺序进入主视频轨。
104
+ 音频和文本仍只进入素材池。`assets: []` 可表示显式的新空剪辑,CLI 会保留它但标记为不可导出;`assets` 缺失或为 `null` 仍会在本地拒绝。CLI 提供两个层次:
105
+
106
+ ```sh
107
+ # 只做本地转换,不登录、不写画布;输出可审查的完整 Timeline
108
+ nadou canvas media timeline init \
109
+ --input-file clip-editor-input.json \
110
+ --output-file timeline.json --json
111
+
112
+ # 面向真实剪辑节点的安全初始化:先读;只修复缺失、显式空存档或语义匹配的裸 Timeline
113
+ nadou canvas media timeline initialize \
114
+ --canvas-id <canvas-id> \
115
+ --input-file clip-editor-input.json --json
116
+
117
+ # 已确认页面主轴为空时,显式修复该空存档;非空存档仍不会覆盖
118
+ nadou canvas media timeline initialize \
119
+ --canvas-id <canvas-id> \
120
+ --input-file clip-editor-input.json --repair-empty --json
121
+ ```
122
+
123
+ `initialize` 使用输入中的 `openId` 作为目标 `clip` 节点 ID,并固定走已批准的 Web `node-data` 读写契约;它不是强制覆盖命令:
124
+
125
+ - 第一次读取到已有 Web 信封 Timeline 时返回 `action=preserved`,不会按照本次 `assets` 重排;若读取到与本次生成结果语义一致的裸 Timeline,则写回 Web 信封并返回 `action=restored_bare`。非空不一致的裸 Timeline 不覆盖。
126
+ - 只有读取明确返回 `TIMELINE_MISSING`、显式 `--repair-empty` 且存档全轨为空,或读取到与本次工程语义一致的 `bare-timeline` 时才发送修复写;写入前通过完整实时 `graph/query` 做目标节点/锁预检,并把 Timeline 素材唯一映射到入边源节点 ID;写入后通过已批准的 `read_node_data?type=CLIP` 回读并校验 Web 信封。
127
+ - 节点不存在、被锁定、读取失败、数据格式异常或回读不一致都会停止,不把异常当成“空存档”。
128
+ - `ready` 视频按 `assets` 顺序连续生成主视频轨;输入显式传 `arrangeAssetsOnMainTrack: true` 时,`ready` 图片也按同一顺序进入主视频轨,省略或传 `false` 时生成 `sticker` 轨片段。图片使用前端剪辑台约定的默认 4 秒显示时长;`running`/`missing`、音频和文本只进入素材池,不生成片段。就绪音频只要求 `url` 和 `durationUs`,不要求宽高。
129
+ - 最小输入无法表达图片的精确显示时长或位置,因此图片的 4 秒只是可审查的默认值;需要精确编排时,使用前端确认过的完整 Timeline JSON,其中包含明确的微秒时长和轨道位置。
130
+ - `--repair-empty` 只在明确确认页面已有可读 Timeline、但所有轨道都没有片段时启用;生成结果有可渲染片段才会单次写入并回读。已有非空 Timeline、格式异常、读取失败或节点锁定时仍停止,不覆盖。
131
+ - `assets[].materialId` 被视为页面已约定的素材身份;如果它只是业务资产 ID 而不是实时 Graph 中的源素材节点 ID,必须先做唯一映射,不能直接写入后再用 URL 补救。
132
+
133
+ `init` 输出 `valid_for_export=false` 只表示当前输入没有可渲染主视频片段,并不表示素材池写入失败;这种结果可以用于页面初始化,但必须先补齐主轴并完成 `timeline web-read` 或 `timeline export-read` 对账后才能导出。`init --output-file` 不覆盖已有本地文件。
134
+
135
+ ### 主轨持久化门禁
136
+
137
+ `timeline validate` 是离线校验;即使输出 `auto_main_track=true`,也只表示 CLI 在内存中把素材补成了主轨,不能证明画布剪辑台已经保存了主轨。
138
+ 长视频、多片段合成和“放入剪辑台”场景必须把同一份规范 Timeline 写入目标 `clip`,随后读取回同一节点。只有回读内容与校验后的
139
+ Timeline 语义一致,并且存在一个包含 `segments` 的主视频轨道,才能执行任一导出提交。
140
+
141
+ `backend-submit` 在真正创建渲染任务前确保网页 `node-data` 已按双层 Web 信封保存同一份可见主轨:缺失、全空或匹配的裸 Timeline 会先写入并回读;匹配的 Web 信封直接保留。非空不一致、回读缺失、无主轨、主轨为空、格式无效或回读形态错误时,命令返回 `TIMELINE_NOT_PERSISTED`,不会创建导出任务。
142
+
143
+ 当前 `clip/export` 会在最终响应前把同一 CLIP 行覆盖成网页不能解析的裸 Timeline,所以请求返回明确成功或失败后 CLI 都会核对并按需恢复 Web 信封;这是提交后的即时对账,不等待成片生成。`export submit` 只按显式 `--persistence` 校验所选存储;若需要“导出并保证网页主轴可见”,统一使用组合式 `backend-submit`。因此“素材池有素材、主轴为空”既会在导出前修复,也不会在确定性响应后被误报为成功。
144
+
145
+ ### Web 剪辑台节点数据模式
146
+
147
+ 为避免把“CLI 可导出”误认为“网页剪辑台主轴可见”,网页场景只能使用下面两个意图明确的命令;命令内部固定使用
148
+ `node-data`,不暴露 `--persistence` 选择项:
149
+
150
+ ```sh
151
+ nadou canvas media timeline web-write \
152
+ --canvas-id <canvas-id> --node-id <clip-node-id> \
153
+ --timeline-file timeline.json \
154
+ --profile <profile> --json
155
+
156
+ nadou canvas media timeline web-read \
157
+ --canvas-id <canvas-id> --node-id <clip-node-id> \
158
+ --profile <profile> --json
159
+ ```
160
+
161
+ 该模式对应页面的 `POST /apis/nadouai/canvas/workflow/write_node_data`,查询参数固定带
162
+ `workflowId`、`nodeId`、`type=CLIP`,请求体是两层序列化:
163
+ `{"data":"{\"timeline\":\"<完整 Timeline JSON>\"}"}`。HTTP 2xx 且 `code=A00000` 即表示写请求成功,
164
+ 即使响应 `data:null` 也不视为失败。CLI 写入一次后用已批准的
165
+ `GET /apis/nadouai/canvas/workflow/read_node_data?type=CLIP` 回读,解析 `response.data.data` 得到完整
166
+ Timeline;内层顶层字段是 `canvas`、`tracks`、`materials`,不要继续查找或强制包裹 `timeline` 字段。
167
+ 写入前的完整 `graph/query` 同时用于目标节点/锁预检和素材身份归一化:`materials.*[].meta.materialId` 若是后端数值
168
+ `assetId`,必须根据入边源节点的 ID、资产标识或可信 URL 唯一转换为源节点 ID;找不到或有歧义时在发写请求前失败。
169
+ `graph/query` 不用于验证 `node.data.timeline`;回读不到或不一致时失败关闭。
170
+ Agent 不能把 `web-read` 退出成功本身当作“网页主轴可见”:必须同时核对
171
+ `persistence_shape=web-editor-envelope`,并确认 Timeline 的主视频轨含有非空 `segments`;`bare-timeline`
172
+ 只用于诊断或导出覆盖对账。
173
+ 写入未知时不自动重试,必须先对账。隐藏的 `timeline write/read` 即使带上 `--persistence` 也只会返回不可用提示,不会触网。
174
+ `web-write` 在构造服务和发出 `write_node_data` 之前还会检查完整网页工程根字段;失败时给出
175
+ `timeline init`/`timeline initialize` 的回退指引,并保证 `request_sent=false`。
176
+
177
+ ### CLI/后端导出数据模式
178
+
179
+ CLI/后端导出使用另一组固定命令,内部固定 `clip-sidecar`:
180
+
181
+ ```sh
182
+ nadou canvas media timeline export-write \
183
+ --canvas-id <canvas-id> --node-id <clip-node-id> \
184
+ --timeline-file timeline.json \
185
+ --profile <profile> --json
186
+
187
+ nadou canvas media timeline export-read \
188
+ --canvas-id <canvas-id> --node-id <clip-node-id> \
189
+ --profile <profile> --json
190
+ ```
191
+
192
+ `export-write/export-read` 仍是 CLI/后端的旁路证据,只有同一路径回读一致才进入
193
+ `backend-submit`;进入后网页主轨由代码在导出前写入,并在导出明确受理后保持为 Web 信封。不要用 `export-write` 单独冒充网页主轨写入,也不要为了触发自动同步而手工覆盖已有非空 `node-data`。
194
+
195
+ 分步 `prepare -> submit -> observe` 仅适用于 CLI 自己创建的标准 `editSourceNodeId`/
196
+ `imageNodeOrigin` 输出节点;`backend-submit` 创建的回执型输出节点应使用
197
+ `backend-status` 对账原幂等键的提交收据,再通过兼容后端回执的任务/callback 观察流程等待渲染;提交收据
198
+ `SUCCEEDED` 不等于成片已经完成。
199
+
200
+ 分步链路的完整流程如下:
201
+
202
+ ```text
203
+ canvas media timeline validate
204
+ -> canvas media timeline export-write
205
+ -> canvas media timeline export-read
206
+ -> canvas media export prepare
207
+ -> canvas media export submit --dry-run
208
+ -> canvas media export submit
209
+ -> canvas media export observe
210
+ ```
211
+
212
+ 每条写命令最多一次写请求:`prepare` 只写一次 Graph,输出视频节点使用带 `avoidCollision=true` 的
213
+ `RIGHT_OF_NODE` 布局,`submit` 只提交一次任务。任一写结果未知时
214
+ 立即停止后续写入,保留画布 ID、来源/输出节点 ID、Timeline 摘要、变更/请求/任务 ID,
215
+ 先用只读画布和任务命令对账;不得自动重试、自动删除占位节点或重新提交合成。
216
+
217
+ ## 1. 离线校验 Timeline
218
+
219
+ 在任何 Timeline 写入前,先完成 [画布依赖图](../guides/canvas-dependency-graph.md) 的输入边核对:读取实时 Graph,
220
+ 将 `materials` 唯一映射到源节点,补齐并回读所有缺失的 `源节点 -> clip` 边。边缺失、候选不唯一或结果未知时,停在写入前,
221
+ 不要先写 Timeline 再补边。
222
+
223
+ ```sh
224
+ nadou canvas media timeline validate \
225
+ --timeline-file timeline.json --json
226
+ ```
227
+
228
+ 也可用 `--stdin`,但二者必须恰好选择一个。最大输入 8 MiB。此命令完全离线,不登录、不读取画布、
229
+ 不提交任务。成功结果的摘要绑定后续准备和提交;`materials`、`tracks`、扩展轨道及未来字段按
230
+ Web Timeline 传输 JSON 保留,不能替换成 CLI 简化 Timeline 合同。
231
+
232
+ 当 CLI 补全了空主轨时,校验结果会带 `auto_main_track=true`,后续对应的 `timeline web-write`/`export-write`、分步导出和
233
+ `backend-submit` 使用同一份补全后的 Timeline;`backend-submit` 会在导出前把它保存为网页可读信封,并在导出请求明确受理后恢复后端可能造成的裸 Timeline 覆盖。
234
+ 素材必须有 `durationUs`(微秒)或 `duration`/
235
+ `durationMs`(毫秒);已有任意片段、素材顺序不明确或时长缺失时不自动改写,直接按原 Timeline 校验并报错。
236
+
237
+ `targetTimerange` 与 `sourceTimerange` 的 `start`/`duration` 是渲染时间单位(微秒)。如果同一时间范围
238
+ 同时提供 `startUs`/`durationUs`,两组值必须表达同一个渲染时间;单位不一致时 CLI 会在离线阶段拒绝。
239
+ `canvas.duration`、素材展示时长等毫秒投影不能替代片段渲染时间范围。
240
+
241
+ ### 页面剪辑台必须复用已有素材身份
242
+
243
+ 当目标是让页面剪辑台显示画布中已经存在的素材时,不能只复用素材 URL,也不能为素材随意新造一套
244
+ `meta.materialId`。Timeline 里有两层 ID,职责不同:
245
+
246
+ - `materials.videos[].id`/`materials.images[].id` 是这份 Timeline 内部的材料键,轨道片段的
247
+ `segment.materialId` 必须引用它;它可以是本次请求生成的稳定本地键。
248
+ - `materials.*[].meta.materialId` 是页面查找已有画布素材的身份;对来自当前画布的素材,必须填实时 Graph
249
+ 中对应的源素材节点 ID,并保留该节点的可信 URL/元数据。Graph 返回的数值 `assetId` 只是素材回填元数据,
250
+ 不能在没有页面契约证据时替代源节点 ID。
251
+
252
+ 因此,写入前要先把每个 Timeline 材料唯一映射到实时 Graph 源节点,再按如下关系组装:
253
+
254
+ ```json
255
+ {
256
+ "materials": {
257
+ "videos": [{
258
+ "id": "video-local-1",
259
+ "url": "https://trusted.example/video-1.mp4",
260
+ "meta": {"materialId": "existing-video-node-1", "state": "ready"}
261
+ }]
262
+ },
263
+ "tracks": [{
264
+ "type": "video", "main": true,
265
+ "segments": [{"materialId": "video-local-1", "targetTimerange": {"start": 0, "duration": 1000000}}]
266
+ }]
267
+ }
268
+ ```
269
+
270
+ 如果只把 `meta.materialId` 填成数字资产 ID、临时 ID 或只填 URL,页面可能仍然画出时间轴片段,
271
+ 但无法把片段绑定到素材池中的已有卡片,最终显示“素材缺失”。遇到该提示应停止导出,重新按源节点 ID
272
+ 生成 Timeline;不要重复发送同一份未知结果的写请求。
273
+
274
+ 兼容旧 Timeline 缺少 `meta.materialId` 时,CLI 只会用材料条目的 `id` 或可信 URL 去匹配同媒体类型且已经
275
+ 连向目标 clip 的唯一源节点,并在写前补出 meta。没有入边、候选为零或候选不唯一都会在本地失败;不会把
276
+ 缺失身份的 Timeline 原样写入,也不会用未连接节点、名称或位置猜测。
277
+
278
+ 组合式 `export backend-submit` 的服务端入参更严格:发往 `/clip/export` 的每个
279
+ `sourceTimerange`/`targetTimerange` 只携带 `start`、`duration`。CLI 会在该请求边界把
280
+ `startUs`、`durationUs`、`start_us`、`duration_us` 别名转换/校验后删除,数值仍保持微秒;
281
+ `canvas.durationUs` 和素材的 `durationUs` 不会被删除或换算。若该幂等键已经形成 `FAILED`
282
+ 回执,修正入参后必须由用户显式使用新的幂等键提交,不能复用原键或自动重试。
283
+
284
+ 如果 `timeline web-write` 或 `timeline export-write` 返回成功但没有 `data`,CLI 会只读回读同一 clip 并比较 Timeline;只有回读内容与
285
+ 本次请求一致时才标记 `reconciled=true`,不会重试写入。回读失败或内容不一致时必须停止并保留原请求 ID。
286
+
287
+ ## 2. 准备成片承接结构
288
+
289
+ ### 合成输入的 Graph 依赖
290
+
291
+ Timeline 里的 `materials` 只描述渲染输入,不能替代画布上的资产依赖边。对“多个片段合成为一个视频”这类用户目标,
292
+ 在 Timeline 写入或 `backend-submit` 前必须先读取实时 Graph,并按节点 ID、`materialId`、任务产物 URL 或唯一素材元数据
293
+ 把每个输入映射到源节点;唯一映射到已有节点但缺少 `源节点 -> clip` 边时,用一次 Graph 变更补齐全部边,随后重新读取
294
+ Graph 核对边方向和数量。映射不到或存在多个候选时停止,不按节点名称、类型或位置猜测,也不能把“Timeline 已引用 URL”报告为
295
+ “画布已连线”。
296
+
297
+ 本次复测场景的预期结构是:
298
+
299
+ ```text
300
+ video-rabbit-wolf-redhood-10s-part1 -> clip-rabbit-wolf-redhood-20s
301
+ video-rabbit-wolf-redhood-10s-part2 -> clip-rabbit-wolf-redhood-20s
302
+ clip-rabbit-wolf-redhood-20s -> clip-export-video-<new-id>
303
+ ```
304
+
305
+ 其中最后一条可由受支持的 `backend-submit` Graph 写入创建;前两条必须在提交 Timeline/导出前由 Agent 显式确认或创建。
306
+
307
+ 多个片段的边只表达它们都是 `clip` 的输入,不表达片段在成片中的先后;先后仍以 Timeline 的 `segments` 和 `targetTimerange` 为准。
308
+
309
+ ```sh
310
+ nadou canvas media export prepare \
311
+ --canvas-id <canvas-id> \
312
+ --source-node-id <clip-node-id> \
313
+ --output-node-id <new-video-node-id> \
314
+ --output-name "成片视频" \
315
+ --timeline-file timeline.json \
316
+ --idempotency-key <unique-mutation-id> \
317
+ --profile <profile> --json
318
+ ```
319
+
320
+ - 源节点必须是实时 Graph 中已存在的 `clip`,输出 ID 必须尚未占用。
321
+ - 一次有序变更创建右侧 `video` 占位节点及 `clip -> video` 连线。
322
+ - 占位节点只写来源、尺寸、比例和标签,不写 `url`、`nodeStatus`、`taskStatus`。
323
+ - 保存返回的 `output_node_id`、`timeline_digest` 和 `mutation_id`。
324
+
325
+ 只有服务端响应明确确认创建了目标 `output_node_id` 和一条边时才可视为 `GRAPH_PREPARED`。
326
+ 响应成功但证据不完整时保持 `GRAPH_UNCONFIRMED`,先回读画布确认节点和连线,不能直接重试。
327
+
328
+ 省略 `--output-node-id` 时 CLI 生成唯一 ID。Agent 不得自行按节点名称猜测或复用已有 ID。
329
+
330
+ ## 3. 预览并提交平台合成
331
+
332
+ 提交前必须已经完成本节目标路径对应的 `timeline web-write → web-read` 或 `timeline export-write → export-read`,并保留回读证据;先预览精确请求:
333
+
334
+ ```sh
335
+ nadou canvas media export submit \
336
+ --canvas-id <canvas-id> \
337
+ --source-node-id <clip-node-id> \
338
+ --output-node-id <video-node-id> \
339
+ --timeline-digest <sha256:digest> \
340
+ --timeline-file timeline.json \
341
+ --dry-run --profile <profile> --json
342
+ ```
343
+
344
+ 确认目标和请求一致后,移除 `--dry-run`,仅执行一次。CLI 会先只读验证 `clip -> video` 结构和摘要,
345
+ 随后固定提交 `track_blueprint_render`;该身份是平台渲染协议,不从生成模型目录选择。Timeline 文件、
346
+ 摘要、画布或节点任何变化都必须重新校验,不可沿用旧预览。
347
+
348
+ ## 4. 分离观察渲染与回填
349
+
350
+ ```sh
351
+ nadou canvas media export observe \
352
+ --canvas-id <canvas-id> \
353
+ --source-node-id <clip-node-id> \
354
+ --output-node-id <video-node-id> \
355
+ --task-id <task-id> \
356
+ --timeout 5m \
357
+ --profile <profile> --json
358
+ ```
359
+
360
+ 分别判断:
361
+
362
+ - `render_status` / `render_terminal`:任务服务事实;
363
+ - `canvas_callback_status` / `canvas_callback_synced`:成片是否回填到指定视频节点;
364
+ - `product_url_status`:`PENDING`、`VERIFIED`、`MISSING`、`UNTRUSTED` 或 `UNKNOWN`;
365
+ - `product_url`:只在回调已对账且实时 Graph 返回可信公网 URL 时出现。
366
+
367
+ 任务完成但回调尚未同步时,保持渲染成功并报告 `PENDING`/超时,不更新节点、不伪造 URL。
368
+ 若回调已同步但 URL 回读或可信校验失败,命令会失败关闭,但错误详情仍保留已确认的
369
+ 渲染状态、回调状态和 `product_url_status`;Agent 应只重试观察,不得重提渲染任务。
370
+ 素材库入库、画布回填和空间交付是不同事实;本流程不自动执行空间交付,也不默认下载或本地转码。
371
+
372
+ ## 与本地媒体能力的区分
373
+
374
+ - 用户只要求把本地文件裁剪、拼接、加字幕或转码:读取 [media.md](media.md),不创建画布节点。
375
+ - 用户要求画布内时间轴合成及回填:使用本页四阶段流程。
376
+ - 用户随后明确要求额外保存到空间或下载:在成片 URL/任务证据确认后,作为新的显式动作处理,不能
377
+ 把它合并进 `prepare`、`submit` 或 `observe`。