关于 cawcut-ad-video
CawCut Ad Video 是一项技能,引导 Agent 使用 `cawcut` 命令行制作商品广告视频。五阶段向导涵盖商品分析、配置、创意选择、分镜制作和视频生成,并提供轮询及平台专用辅助脚本。
主要功能
- 01引导完成五阶段广告视频向导
- 02分析商品信息和图片
- 03配置视频选项并选择创意
- 04审阅和编辑分镜
- 05生成、轮询并下载视频
适用场景
- 01根据商品 URL 制作广告视频
- 02在制作视频前调整商品信息
- 03生成视频前修改分镜
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cawcut/ skill --skill cawcut-ad-video安装后在 Claude Code 中输入/cawcut-ad-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdcharacter-scene.mdscript-editing.mdstages.mdstoryboard-stage.mdtroubleshooting.mdscripts/download_media.ps1download_media.shpoll.ps1poll.shscript_plan.mjsscript_plan.ps1script_plan.shstoryboard_review.mjsstoryboard_review.ps1storyboard_review.sh详细介绍
CawCut 广告视频
通过 5 阶段 AD Video 向导创建完整的产品广告视频:Product → Config → Idea → Storyboard → Video。每个阶段都对应针对开发者 API 的 cawcut ad-video 命令。完整的命令标志表位于 references/api.md;各阶段的含义和失效矩阵位于 references/stages.md;脚本编辑的编写方法位于 references/script-editing.md;错误恢复方法位于 references/troubleshooting.md。请使用本技能正文顶部打印的基础目录,在 <base_dir>/references/<file>.md 中读取这些文件;不要用 find/grep 查找它们。
回复语言。 所有实时回复——包括文本、状态更新、AskUserQuestion / AskQuestion 中的问题和选项标签——都应遵循用户本轮使用的语言。判断依据是用户本轮实际聊天消息的内容,而不是 Skill 工具调用是否带有 args 参数;后者只是无关的可选传递字段。隐式触发也适用:如果用户的消息匹配了触发短语(例如“广告视频”“商品广告”“make an ad for …”),而不是输入了字面的 /cawcut-ad-video 命令,那么该触发短语就是用户本轮聊天消息的内容——从首次回复起就应使用对应语言,包括询问缺失的产品 URL 时。只有在调用完全没有语言信号时,才默认使用英语(例如用户只输入 /cawcut-ad-video,没有其他文本);用户一旦用其他语言提出实际请求,本会话后续回复都应遵循该语言。无论回复语言为何,CLI 命令/标志、JSON 键、URL 和原始错误代码都应保持原样;切勿将原始英文 CLI 输出直接粘贴为面向用户的答复,而应使用 reply_language 概述其内容。
步骤 0 — 初始化
根据执行环境选择登录模式
根据命令实际运行的位置进行选择。在用户自己的计算机上,运行 cawcut auth login --browser --json;CLI 会打开浏览器并等待批准。在无法访问用户浏览器的远程环境、VM 或容器中,运行 cawcut auth login --device-auth --json,并将 authorization_url 发送给用户,让他们在自己的计算机上打开并批准。两种模式都支持 JSON;需要结构化输出并不是选择设备授权的理由。Agent 名称、非 TTY shell 和 localhost URL 本身都无法确定命令的运行位置。根据已知的执行环境使用明确的模式标志,以覆盖 CLI 自动检测。
对于设备登录,随后运行 cawcut auth login --complete --wait --timeout 60 --json。如果你的工具执行超时时间较短,则改为多次单独调用 --complete --json,并遵循 next_poll_after_seconds。设备登录中断或返回 wait_timeout 后,应恢复已保存的当前请求,而不是创建新链接。浏览器登录使用旧版 loopback 回调;如果中断,请重新运行 cawcut auth login --browser --json,不要使用 --complete。status=pending 不代表身份验证成功。只有在 status=authenticated 后,才能重试原始操作。拒绝或过期会结束此请求;不要悄悄创建无休止的授权链接。绝不要索要密码、令牌或从网页复制回来的代码。
将 bootstrap 作为静默防护措施运行,而不是面向用户的阶段。
- 每个 AI 会话最多运行一次。 如果此 AI 会话中已有任何
cawcut命令成功运行,则跳过所有 bootstrap 检查并继续。 - 只使用一条明确的检查命令:
cawcut upgrade check --json。- 如果
"update_available": true,请在宿主 shell 中自行运行cawcut upgrade(不要让用户输入该命令)。成功后,从步骤 1 继续此技能。 - 如果
"ahead_of_registry": true,则不升级,继续执行。 - 如果找不到
cawcut,请让用户安装:npm install -g @ubnt/cawcut。然后继续 bootstrap。 - 如果检查因其他原因失败,则继续执行;只有后续 CLI 命令失败时才提及此警告。
- 如果
- 不要输出“bootstrap 检查已通过”——直接进入步骤 1。
- 让第一个实际命令验证身份验证状态。如果因令牌或身份验证错误(包括
Token expired)而失败,请遵循上述登录步骤。根据执行环境选择合适的模式,并且只有在status=authenticated后才能重试失败的命令一次。请自行运行 CLI 命令;用户只需在浏览器中批准。 - 结构化用户提问工具(每个会话都检查)。 在 Claude Code 中,对每项可枚举选择都使用
AskUserQuestion;在 Cursor 中使用AskQuestion。如果其中任一工具可用,你必须将其用于此技能中的所有可枚举决策——平台、分辨率、时长、视频类型、分镜风格、语言、创意候选项、积分确认——即使候选列表比弹窗可容纳的内容更长也一样:列表较长时仍要打开该工具,并将前面的选项作为选项展示,同时在旁边列出完整的编号列表,以便用户输入后续条目(参见“交互式选择”)。
向导概览
① Product create → analyze run → poll → review/confirm analysis
② Config options → pick settings → config set
③ Idea idea run → poll → pick candidate (or custom) → idea select
④ Storyboard storyboard run → poll → (optional edit / regenerate) → image quote → confirm → image run (×2 if hand-drawn)
⑤ Video video quote → confirm → video run → poll → download
一个项目对应一个 video_ad_id。每个耗时较长的阶段都不带 --wait 触发,然后使用随附脚本轮询(参见“轮询”)。cawcut ad-video detail <id> --json 是唯一的轮询入口——只有它会返回 outputs 映射。
脚本打包运行器
项目操作和详情检查请直接使用 cawcut CLI 命令。根据主机平台选择打包的辅助脚本。Windows 辅助脚本需要 PowerShell 和已安装的 cawcut CLI,不需要 Python、jq、bash 或外部 curl;不要要求 Windows 用户为此技能安装这些工具。macOS/Linux 的 .sh 辅助脚本需要 jq;这两个平台都不使用 Python。
- macOS/Linux:
bash <base_dir>/scripts/<name>.sh … - Windows PowerShell:
powershell -ExecutionPolicy Bypass -File "<base_dir>\scripts\<name>.ps1" …
四个辅助脚本(poll、script_plan、storyboard_review、download_media)都有功能等效的 .sh 和 .ps1 实现。一次运行中请使用匹配的扩展名和平台专属标志;例如,bash 中的 --kind video 在 PowerShell 中是 -Kind video。
阶段 ① — 产品
- 收集产品 URL(Amazon、Shopify 或官方网站页面均可)。如果用户没有提供,请用纯文本开放式询问。不要询问项目名称——后端会在分析/导出后根据产品信息自动命名项目。
cawcut ad-video create --url "<url>" --json→ 记录id。创建时--url是可选的(允许创建空草稿),但只要用户提供了 URL,就应传入——之后analyze run无论如何都需要它。--category是可选的;省略后,后端会在分析后自动检测。只有用户明确要求指定标题时,才传入--name。cawcut ad-video analyze run <id> --url "<the product URL from step 1>" --json(不要加--wait;API 要求在请求体中提供url),然后使用平台对应的运行脚本轮询:macOS/Linux 上运行poll.sh <id> '.status' stage_completed 600 15,Windows 上运行poll.ps1 <id> '.status' stage_completed 600 15。- 读取
detail <id> --json并呈现分析结果:- 产品信息原文照录 — 展示每个已填充的
product_info字段:name、description、selling_points[](逐条完整列出并编号)、target_audience、brand_style、promotional_info、source_platform、category。不得总结、截断或翻译产品内容本身——这些是用户的营销文案,必须按返回内容展示;只有外围标签和说明遵循 reply_language。 - 产品图片 — 先使用平台对应的
download_media辅助脚本下载:<id> --kind product。然后按类别呈现(标签遵循 reply_language):- Logo(
logo_images)和主图(primary_images):使用宿主提供的文件发送工具(例如 Claude 的SendUserFile),并附上刚下载的本地路径(例如~/Downloads/ad-video-<name>/product/logo-1.jpg、primary-1.jpg),逐张内嵌预览——Markdown 链接只会显示为可点击的文本行,而不会显示图片。 - 其他产品图片(
images[]):如果支持内嵌预览,逐张列出,每张都标记为Product Image #n并内嵌发送图片;最多显示前 9 张——如果图片更多,说明还有多少张(例如…and N–9 more),并告知用户其余图片位于<dest>/product/文件夹。如果不支持内嵌预览,则用表格列出本地路径(#+ 路径),并指出同一文件夹位置。 - 两种呈现方式中都不得包含
asset_id列——本地路径仅用于预览。这些文件是为了让用户查看图片;绝不能将它们交给 CLI。 然后通过 AskUserQuestion 让用户确认或更正:
- Logo(
✅ Looks good→ 继续到阶段 ②✏️ Edit product info→ 收集更改,并将仅这些字段传给cawcut ad-video product set <id> …:该命令会先读取项目,并保留所有未传入的字段。(API 会整体替换product_info,因此如果只传--product-name,描述、图片和卖点都会被清除。)如果 URL 或产品发生了实质性变化,则之后重新运行analyze run。- 传入图片列表会替换原列表,因此
--logo/--primary-image/--asset必须提供要保留的完整列表;删除图片也要通过这种方式实现。列表被替换后,其自身的选择也会被清除,后端将恢复默认选择(--asset会选择所有候选项,logo/主图会选择第一个候选项)。绝不要重新发送已下载的文件:已保存的引用会以asset_id形式返回。 - 只有用户提供的项目外图片才传入本地路径;CLI 会将其上传为全新的资源(有效期为 7 天)。
--description ""会清空描述,--clear-selling-points会清空卖点——空列表是一种有效状态,不等于“未设置”。
- 传入图片列表会替换原列表,因此
- 产品信息原文照录 — 展示每个已填充的
- 如果用户想中止正在运行的分析:
cawcut ad-video analyze cancel <id>。 素材权利(用户提供自己的图像时说明一次)。 通过 CLI 上传的图像不会经过素材合规检查,而是会按原样接受——不像 Web 门户,无需完成权利声明步骤。该检查旨在发现第三方徽标和名人肖像;在此流程中,用户有责任确保自己拥有素材的相关权利。请在上传前用一句话明确说明,以免有人误以为工具已对此进行审核。这仅适用于用户提供的新文件:项目中已有的图像(爬虫提取的产品图像)从未受此检查约束。
Stage ② — 配置(所有选项均在运行时获取,不会硬编码)
-
cawcut ad-video options --video-ad-id <id> --json→ 读取video_settings(publish_to、languages、aspect_ratios、resolutions、duration_ranges、video_types、storyboard_styles、video_models、defaults)。 -
按以下顺序询问各项——先询问视频类型,因为它决定是否需要询问字幕,以及哪些模型/分辨率组合合法。
- 视频类型 —
video_types中每项对应一个选项。 - 视频模型 — 仅当
video_models非空时询问。 候选项为video_models[].value,默认值为defaults.video_model。展示列表的表格除#外还应包含三列:模型、其supported_resolutions,以及标记defaults.video_model的默认标记——应展示分辨率,因为选择模型会决定下一项中哪些分辨率仍然合法。若恰好只有一个候选项,用文字说明后继续(一个选项不构成选择);若没有候选项,则完全跳过此项。 - 分辨率 — 默认值为
defaults.resolution,然后将其限制在所选模型的supported_resolutions范围内(与服务端验证时使用的列表相同)。绝不要提供该模型不支持的分辨率:config set会拒绝。若未选择模型,则提供完整的resolutions列表。 - 自动字幕 — 仅适用于
product_with_voiceover和talking_video。 字幕会从旁白/对话音轨中烧录,因此product_showcase没有可加字幕的内容;不要询问,并明确传入--auto-captions false(与强制将此类型的该值关闭的 Web 门户保持一致)。 - 平台 — 在每个选项的描述中显示其
default_aspect_ratio(例如,TikTok — 9:16)、语言、时长、分镜脚本风格(说明:手绘风格会在照片写实风格的画面板前增加一轮草图绘制)。 - 宽高比不是要询问的问题。 它由平台决定(与没有宽高比选择器的 Web 门户保持一致):自动采用所选
publish_to选项的default_aspect_ratio。绝不要单独询问宽高比;仅当用户明确要求覆盖时,才偏离平台默认值。
将各项合并到一次 AskUserQuestion 调用中——每项对应一个问题,每次最多四个问题。较长的选项列表(平台、语言、视频模型)遵循 Interactive selection 的溢出格式:在消息正文中以带编号的表格列出完整列表——
#加上该项实际包含的内容:平台标签及其default_aspect_ratio、语言标签,或模型标签及其supported_resolutions和默认标记。问题本身应为一句简短的话,弹窗中将靠前的条目作为带编号的选项,超出部分则通过自由文本框按编号或名称作答。每项都使用自己的表格和编号——答案写入该项自己的字段,因此绝不要一次询问两个编号(1 + 10)。 - 视频类型 —
-
cawcut ad-video config set <id> --publish-to … --language … --aspect-ratio <the platform's default_aspect_ratio> --resolution … --duration-seconds … --video-type … --video-model … --storyboard-style … --auto-captions … --json
video_model 是影响成本的实际选项——提供选择时要说明这一点(可能有更便宜的模型),但绝不要展示该端点未返回的模型。
阶段 ③ — 创意
- 运行
cawcut ad-video idea run <id> --json,轮询直到outputs.generated_marketing_messages.status === "succeeded"。 - 最多展示八条,然后停止。 一次运行最多生成 16 条候选,但
detail每次只返回一页(4 条),所以重新读取时只会显示前四条。读取outputs.generated_marketing_messages,并调用cawcut ad-video idea load-more <id> --json(每次都重新读取detail),直到显示八条或has_more === false——以先发生者为准:load-more只会显示已生成的候选,不会调用 LLM,也不会消耗额度。- 八条是上限,不是目标。 如果项目中的候选少于八条,就显示实际数量;一旦显示八条,即使
has_more仍为true,也要停止继续显示。此流程没有“再加载一批”的步骤。 - 说明你展示的数量;如果项目中还有其他候选,绝不能暗示已展示全部内容。
- 以表格形式完整、逐字呈现候选——每条候选占一行:
#、标题、内容。不得总结、改写、截断或翻译:这是用户的营销文案,他们要从完整候选集中做选择。开头注明数量(例如:“正在展示 8 条候选:”)。#列是弹窗中的索引——用户需要在此表格中输入弹窗无法容纳的数字。 - 一个决定,一个问题。 选择必须通过一个 AskUserQuestion 完成——绝不能先询问候选,再追加第二个问题询问如何处理答案。提供四个选项,并按以下顺序排列:
1. <title>、2. <title>、3. <title>——前三条候选,每条标注编号✏️ Write my own→ 使用idea select <id> --custom "<text>"提交用户或 Agent 撰写的创意文本(60–10000 个字符,与网页端自定义创意限制一致)。这遵循门户网站的自定义路径:CLI 会将该文本作为custom_content发送,并设置is_custom: true;不要将其转换为生成候选的选择,也不要添加标题包装。- 第四至第八条候选可在自由文本框中输入编号或标题来选择;在问题正文中用
reply_language明确说明这一点,让用户根据问题中列出的候选集作答,而不是猜测。
- 用户选定后:运行
cawcut ad-video idea select <id> --message-id <mm-N> --title "<title>" --content "<content>" --json。提交前可提供对标题和内容进行轻微修改的选项。 - 只能由用户发起生成新批次。
idea regenerate不是菜单选项:当用户用自己的话提出此需求(“换一批”/“regenerate”)时,运行cawcut ad-video idea regenerate <id> --json并轮询——它会清除当前选择,因此须先发出警告——然后重新展示候选(步骤 2)并再次询问(步骤 4)。
阶段 ④ — 分镜
顺序与 Web 门户一致:实体 → 费用 → 角色 → 场景 → 脚本 → 图像(视觉方向包含在图像步骤中)。 首次编辑前,先阅读 <base_dir>/references/storyboard-stage.md;实体命令见 <base_dir>/references/character-scene.md,脚本编辑见 <base_dir>/references/script-editing.md。不支持角色/场景功能的旧项目跳过步骤 1–4 和视觉方向问题,沿用原有流程。
-
有哪些实体? 确认创意后,运行:
character estimate <id> --wait --json。告知用户脚本是否需要角色、场景、两者都需要或都不需要(character.needed/location.needed)。两者都不需要 → 队列中只有脚本。 -
费用提示(必需)。 显示
estimated_credits(0 = 免费),并通过 AskUserQuestion 询问:✅ 确认并生成/⏸ 暂不。只有用户确认后,才运行storyboard run <id> --confirmation-token <token> --json——该命令会开始生成角色/场景图像并扣除积分。用户回答前绝不能运行。 -
审核队列 — 让 CLI 选择项目。 运行
storyboard_review脚本(等待 → 图像 → 脚本表格),然后运行cawcut ad-video review next <id> --json,每轮只展示它指定的项目:character→location→script。wait→ 继续轮询;done→ 执行步骤 4。用户批准某个项目后,运行review approve <id> --item <item>,然后再次运行review next。批准与已展示的内容绑定:重新生成的脚本或图像(新的创意、新提示词、编辑)会重新进入审核;在review next返回done之前,image quote/run会被拒绝。- character / location: 名称、图像、图像提示词(
entities[].names/prompts)、状态。询问:✅ 这个角色没问题/📝 使用新提示词重新生成(场景:✅ 这个场景没问题)。新提示词按references/storyboard-stage.md中的流程处理,然后展示新图像并再次询问。暂不支持上传自己的图像和选择声音:绝不能提供这些选项。 - script: 展示
script_table(绝不展示shot_prompt/video_prompt),并附上原样的portal_url(ad-video url <id> --json)。询问:✅ 看起来不错/✏️ 修改脚本/🔁 重新生成脚本。编辑和重新生成遵循references/script-editing.md;重新生成会丢弃所有编辑内容 — 先警告用户。
- character / location: 名称、图像、图像提示词(
-
图像 — 让 CLI 指示下一步。 运行
cawcut ad-video image next <id> --json,并严格执行其next_step;每次处理完或收到回答后都再次运行。sketch→image quote --generation-type hand_drawn→ 确认积分 →image run(引用阶段)→ 轮询 → 预览草图。然后询问:✅ 继续/✏️ 编辑脚本。visual_direction→ 询问自定义提示词问题(见下文)。在用户回答前,CLI 会拒绝image quote/run --generation-type photo_realistic。photo→image quote --generation-type photo_realistic→ 确认 →image run,在 3600 截止时间内轮询,通过download_media <id> --kind storyboard预览。done→ 阶段 ⑤。
视觉方向问题(一条自定义提示词会为写实分镜和最终视频设置风格;只询问一次,在写实图像阶段开始前——如果有草图,则在草图之后;否则紧接脚本之后)。展示已保存的文本(
instruction)并询问:✅ 不添加额外方向→instruction confirm <id>/🎨 添加或更改视觉方向→instruction set(references/storyboard-stage.md)。如果图像或视频已存在,保存将把它们标记为过期(need_regenerate)——先警告用户并征得同意。
每轮结束时都必须有待回答的问题或正在运行的轮询——生成完成后,按上述顺序展示下一项并询问。生成失败的实体(next_step: fix_failed)必须展示,不能跳过;只有征得同意后才能重试。
第 ⑤ 阶段 — 视频
- 执行
cawcut ad-video video quote <id> --json→ 使用 AskUserQuestion 确认额度 → 立即执行cawcut ad-video video run <id> --confirmation-token <token> --json(仅当用户明确要求重新渲染未更改的结果时,才添加--force)。 - 轮询,直到
final_video/voiceover_final_video/talking_video中的某一项状态为succeeded— 遵循轮询表中的 3600 秒截止时间。 - 成功后:执行
cawcut ad-video video deliver <id> --json,将视频下载到项目文件夹,并返回report(本地路径 + 可直接使用的 Markdown 链接形式的 Portal 链接)、local_path和portal_url。 - 先发送交接消息 — 单独发送文件不算报告。 发送一条以
report开头的文本消息,Markdown 链接单独占一行,标签使用reply_language;提及 Portal 时,必须在同一条消息中附上 URL。无需提供结果 URL。发送后,无条件交接给cawcut-vn,并传入local_path— 不显示 VN 菜单,不自行运行cawcut vn命令(一次决定:VN 决策由接收方技能负责,绝不重新检查)。
媒体预览与下载
API 返回的所有媒体 URL(产品图片、分镜草图/网格、最终视频)都经过预签名 — 直接使用普通 curl 下载,无需额外签名步骤。如果某个 URL 返回 403,请重新读取 detail 并使用更新后的 URL 重试(每次调用 detail 时,产品图片 URL 都会重新签名)。
预览优先级(产品标志/主图、分镜草图/网格):
- 如果宿主提供向用户发送文件的工具(例如 Claude 的
SendUserFile),先下载文件,再发送,这样用户就能在聊天中内联预览。 - 否则,使用
open打开已下载的文件(macOS),或直接报告本地路径。
始终使用内置下载器(角色/场景图片:cawcut ad-video entities download <id>,storyboard_review 已完成此操作),不要手动编写 curl/jq 管道 — 也不要将 shell 变量命名为 status(在 zsh 中为只读):
# macOS/Linux
bash <base_dir>/scripts/download_media.sh <id> [--kind product|entities|storyboard|video|all] [dest_dir]
# Windows PowerShell
powershell -ExecutionPolicy Bypass -File "<base_dir>\scripts\download_media.ps1" <id> [-Kind product|entities|storyboard|video|all] [-Destination <dir>]
默认目标路径:~/Downloads/ad-video-<product-name>(项目尚未命名时,回退为 ad-video-<id>)。目录结构:product/(标志 + 主图 + 其他图片)、entities/(character-N / location-N)、storyboard/(草图 + 分镜网格),最终视频位于文件夹根目录。下载器会打印每个已保存路径 — 使用 reply_language 将这些路径转达给用户。
失效语义(强制 — 与 Web 门户保持一致)
每次变更(product set、config set、idea select、storyboard set)之后:
- 立即运行
cawcut ad-video detail <id> --json。首先区分已清除的产物与保留但已过时的产物;绝不能根据项目历史推断其中任一种情况。- 对任何创意配置字段进行变更 —
--duration-seconds、--language、--video-type、--storyboard-style或--publish-to— 都会清除下游内容。如果outputs.generated_marketing_messages不再包含可用的、状态为 succeeded 的value/selection,则先前的 Idea 不存在于当前项目状态中。**不要询问用户是否要重用、保留或继续使用该 Idea;不要将其作为选项提供。**从阶段 ③ 继续,运行cawcut ad-video idea run <id>,轮询直至成功,选择一个新的 Idea,然后生成新的分镜。 - 只有仍存在且
status: "succeeded"、并且need_regenerate === true的输出,才属于保留但已过时的内容,可供用户决定重新生成或稍后处理。已清除的输出既不是过时内容,也不能重用。
- 对任何创意配置字段进行变更 —
- 收集所有
need_regenerate === true的保留但已过时的outputs.<key>。如果存在任何此类内容:在一条消息中向用户列出受影响的产物,然后只调用一次 AskUserQuestion:🔄 Regenerate affected→ 按流水线顺序重新运行受影响的阶段(storyboard run→image quote/run→video quote/run),每个生成阶段都要重新报价并确认积分⏸ Later→ 继续操作,不重新生成;注明过时的产物
- 绝不要在编辑过程中重新生成 — 先完成所有用户编辑,然后一次性重新生成。保存脚本时只能显示哪些输出需要重新生成,绝不能触发图像或视频的报价/运行。运行
image run/video run只能在用户明确确认该阶段的新报价后进行;如果上游输出的need_regenerate=true,则会被拒绝(VIDEO_AD_NEEDS_REGENERATION)。
报价时机(强制)
confirmation_token 会在报价后 5 分钟过期。始终按以下顺序操作:报价 → AskUserQuestion 确认 → 运行,中间不得与用户讨论。如果 run 因令牌/确认错误(已过期或失效)而失败,则重新报价、再次询问、重新运行 — 每次尝试一次,不得静默重试。
在询问用户是否要花费积分前检查余额(强制)。image quote / video quote 除了报告 estimated_credits,还会报告 credits_balance、credits_shortfall 和 credits_sufficient。在确认问题之前查看这些信息:
credits_sufficient === false→ 明确说明具体数字(“需要 X,你的余额为 Y,还差 Z”),并引导用户前往 Web 门户充值。确认菜单应提供💳 Top up credits/⏸ Not now,而不是常规的确认并运行选项 — 不要引导用户进行其无力支付的扣费。credits_sufficient === true,或余额不可用(credits_balance_error— 余额查询是尽力而为,绝不能因此阻塞流程)→ 正常确认。- 绝不要事后将余额不足说成一般性失败。关键是在运行前告知用户。
- 充值所需时间会超过令牌的 5 分钟有效期:用户充值返回后,重新报价 → 再次确认 → 运行。绝不要重复使用已过期的令牌。
轮询(内置脚本 — 必须使用)
不带 --wait 触发,然后使用平台专用的内置脚本进行轮询。绝不要自行编写轮询循环——临时写的 echo "$var" | jq 循环会在 zsh 下破坏 JSON(echo 会解析 \n 转义),而且由于无法匹配终止状态,会一直运行。
bash <base_dir>/scripts/poll.sh <id> '<json_path>' <success_value> <timeout_s> [interval_s=30]
# Windows PowerShell
powershell -ExecutionPolicy Bypass -File "<base_dir>\scripts\poll.ps1" <id> '<json_path>' <success_value> <timeout_s> [interval_s=30]
| 阶段 | json_path | success_value | timeout_s |
|---|---|---|---|
| ① 分析 | .status | stage_completed | 600 |
| ③ 创意 | .outputs.generated_marketing_messages.status | succeeded | 600 |
| ④ 规划 | .outputs.storyboard_plan.status | succeeded | 3600 |
| ④ 提示词 | .outputs.storyboard_plan.prompt_status | succeeded | 600 |
| ④ 草图 | .outputs.storyboard_sketch.status | succeeded | 3600 |
| ④ 分镜 | .outputs.storyboard_image.status | succeeded | 3600 |
| ⑤ 视频 | .outputs.final_video.status // .outputs.voiceover_final_video.status // .outputs.talking_video.status | succeeded | 3600 |
Windows 辅助脚本会在内部解析这些点分隔路径和 // 回退值;Windows 上的 json_path 不需要 jq。
退出代码:0 成功 · 2 失败(从 detail --json 的输出中报告 error;参见 references/troubleshooting.md)· 3 超时 → 询问用户问题 ⏳ 继续等待(再次运行脚本)/ ❌ 停止(项目会保留;稍后使用 cawcut ad-video detail <id> 继续)· 4 输出无法解析 → 停止轮询,运行一次 cawcut ad-video detail <id> --json 并检查(身份验证/CLI 问题)。
脚本不会发送通知——宿主工具会。 poll.sh 只会以退出代码结束,不会做其他事情。绝不要从 shell 发送操作系统通知(osascript、notify-send、BurntToast),绝不要将通知功能加回脚本,也绝不要主动在用户的机器上注册通知权限:从 shell 命令触发的 toast 与应用自身的通知属于不同渠道,并非用户要求的内容。
告知用户需要多长时间
绝不要自行估算生成时间,也绝不要把截止时间说成持续时长。 服务端会计算运行时间,并通过 detail 提供 estimated_running_ms(毫秒,阶段运行期间提供)。poll.sh 会在首次轮询时读取该值,并打印一行 estimated: about Nm——如果有,就转告用户这一时长,仅此而已。如果需要直接获取,可查看任意一次 detail --json 的结果。
API 未提供估算值时(字段缺失或为零——尽力查询也可能获取不到),应按数量级说明,绝不要参考截止时间:这些阶段通常需要几分钟(其背后的节点估算时间从几秒到一两分钟不等),因此可以说“大概几分钟”,并补充说明完成后会立即告知。不要说时间未知,也不要把时长往长了说。
timeout_s 列表示放弃等待的截止时间,不是运行时长。 因为该行写着 3600 就说“最多大约一小时”,与凭空编造时间范围是同样的错误:这只是脚本停止等待的时间点,通常比实际运行时长高一个数量级。回复中绝不要提及截止时间,甚至不要加上“最多”之类的模糊说法。
耗时较长的阶段——告知用户可以暂时离开
storyboard_plan、sketch、panels 和 video 耗时以分钟计,而非秒。轮询其中一个阶段前,先告知用户一次预计所需时间:如果有服务器提供的 estimated_running_ms,就用这个值;否则说“几分钟”。并告诉他们可以暂时离开,任务完成后会第一时间通知他们。之后轮询时,无须逐次播报。
通知由宿主自己的工具发出。 在 Claude Code 中,该工具是 PushNotification,需要提供一行 message 和 status: "proactive";如果其架构尚未加载(延迟加载),先用 ToolSearch 加载(select:PushNotification),因为缺少架构或 status 的调用会导致验证失败。由于用户正在终端中活动而返回“未发送”,这是预期情况:不要重试,也不要将其视为错误。通知会发送到用户当前正在使用的应用;如果已连接 Remote Control,也会发送到他们的手机——这就是他们能在下一分钟而不是明天注意到结果的区别。阶段完成时,发送一次通知,注明阶段名称和项目 ID。如果宿主没有提供此类工具,就静默跳过,拿到结果后直接呈现即可:不要改用 shell 级别的 toast,也不要将其添加到 poll.sh。
短阶段(analyze、idea、prompts)无需通知——它们会在一轮内完成。
交互式选择(必须遵守——先调用工具)
如果用户刚刚拒绝了 AskUserQuestion / AskQuestion 调用: 工具结果中会包含 harness 自动添加的说明,告诉你“停止当前操作并等待用户告知如何继续”。运行时会自动将这句话附加到每一次被拒绝的工具调用中——这不是用户在发言,也不是停止使用该工具的指令。应将其理解为:停止你当时正在进行的那一项具体操作(不要重试完全相同的问题,也不要根据未经确认的选项继续),然后查看用户接下来的实际消息。单凭这句话,不能让你在下一个可枚举的选择中改用编号文本;下一个选择仍必须先调用工具,就像从未发生过拒绝一样。只有用户明确以纯文本提出要求(例如“别再弹出菜单了”“直接用文字问我”),才可以在整个会话中改用文本提问。
默认行为: 对于每一个可枚举的选择,始终先调用 AskUserQuestion(Claude Code)或 AskQuestion(Cursor),再展示编号文本菜单。纯文本菜单仅作为回退方案使用。
只有一个选项就不构成选择。 每次调用都必须包含至少两个可行选项。如果实际上只有一个可行选项——例如某个配置维度的选项列表中只有一个值,或只有一个值得提供的创意候选项——就用文字说明这个选择并继续:切勿弹出只有一个选项的菜单,也不要用占位选项凑数,让它看起来像是一个选择。
| 宿主 | 工具名称 |
|---|---|
| Claude Code | AskUserQuestion |
| Cursor | AskQuestion |
| 会话检查清单(本轮首次显示菜单前): |
-
**发送任何回复前先自检:**如果你准备发送的句子要求用户从固定选项中选择——即使它藏在一句还询问了开放式问题的、更友好的句子里——也要停下。禁止将该句作为纯文本发送。把它拆开:现在就为可枚举的部分调用工具;只把开放式部分作为单独提问的文字内容。
-
工具是否可用?如果可用,每当需要做可枚举的决策时,必须使用该工具——包括候选列表长于弹出窗口可容纳数量的情况(见第 3 条)。
-
如果没有工具(仅限 CLI 的宿主),请使用
reply_language指定语言编写带编号的文本。 -
如果候选项数量超过单个问题的 4 个选项(例如较长的类别、模型或候选列表),仍要打开工具,并为答案的各部分分别安排位置:
- 完整列表 → 消息正文中的带编号文本表格,每个条目占一行:
#加上该条目实际包含的列——平台的default_aspect_ratio、语言的标签、模型的supported_resolutions和默认标记、候选项的标题和内容。绝不要把列表直接塞进问题文本:将 22 个模型的列表粘贴到问题标题中会难以阅读,也会掩盖问题。表格和调用必须同时发送。 - 问题文本 → 一句简短的话,说明要做的决定,并指出弹出窗口无法容纳的选项在哪里(例如:“可在下方按编号或名称输入第 4–22 项”,使用
reply_language指定的语言)。 - 弹出窗口 → 将靠前的条目作为选项列出,并标明编号;在为必须保持可点击的操作(例如自定义输入)留出位置的同时,尽可能多地放入选项。
- 自由文本字段 → 输入弹出窗口无法容纳的选项:可按编号或名称输入后续条目。
编号是表格与弹出窗口之间的对应依据。弹出窗口能容纳的选项都必须保持可点击;只有弹出窗口无法容纳的选项才通过输入回答。每个决策只问一个问题——绝不要再问一个问题来询问用户要如何处理第一个问题的答案。
- 完整列表 → 消息正文中的带编号文本表格,每个条目占一行:
工具可用时禁止:用带编号的文本菜单代替工具调用;没有弹出窗口支持时要求用户“回复编号或名称”;或要求用户凭记忆输入枚举值。较长列表的带编号表格不是文本菜单,而是工具调用的索引,且绝不能单独发送。
绝不要硬编码选项值。平台、分辨率、时长、视频类型、视频模型、分镜风格、语言和风格 ID 均须取自本次会话中 cawcut ad-video options --json 的输出——不得取自本文档或训练数据。
UX 规则
- 简洁明了。默认输出结果 URL 和本地路径。除非是在调试,否则不要输出原始 JSON(轮询脚本使用
--json)。 - 回复语言:请参阅文件顶部的规则——每条回复(包括第一条回复,以及所有 AskUserQuestion 问题和标签)都遵循用户使用的语言,并使用
reply_language总结 CLI 输出,而不是直接粘贴英文原文。 - 不要使用 curl 调用 CawCut HTTP API——CLI 会处理身份验证和令牌。
- 优先选择——所有可枚举的决策(配置选项、创意候选项、积分确认、重新生成确认)都通过 AskUserQuestion/AskQuestion 进行,遵循交互式选择流程。
- 每个请求只处理一个项目。 如果用户请求制作多个广告视频,应先完成一个向导,再开始下一个。
- 依据项目能力,而不是客户端版本。 同时支持旧版和 v2 项目。不要强行为旧项目添加实体、等待缺失的键,或迁移其 W3。使用
storyboard status区分缺失/不支持与运行中/失败。 - 积分:在
image run/video run之前,务必先报价并确认。未经用户在本次会话中明确确认,绝不消耗积分;并且先读取报价中的余额数据——如果余额不足,必须在确认问题之前说明,而不是等运行失败后才发现(见报价时机)。 - 耗时较长的阶段(
storyboard_plan、sketch、panels、video)需要几分钟,而不是几秒:只说明一次这一点——引用服务端的estimated_running_ms,若无此数据则说“几分钟”(见轮询);绝不要提截止时间。告诉用户可以先离开,之后由通知提醒他们回来。不要逐次描述轮询进度。
CLI 快速参考
cawcut ad-video create [--url <u>] [--name <n>] [--category <c>] [--json]
cawcut ad-video detail <id> [--json]
cawcut ad-video options [--video-ad-id <id>] [--language <l>] [--json]
cawcut ad-video product set <id> [--product-name …] [--description …] [--selling-point …] [--clear-selling-points] [--logo <ref>] [--primary-image <ref>] [--asset <ref>…] [--target-audience …] [--promo-*] [--json] # only the fields passed change
cawcut ad-video config set <id> [--publish-to …] [--language …] [--aspect-ratio …] [--resolution …] [--duration-seconds …] [--video-type …] [--video-model …] [--storyboard-style …] [--auto-captions …] [--json]
cawcut ad-video analyze run <id> --url <u> [--wait] [--json] · analyze cancel <id>
cawcut ad-video idea run <id> [--wait] [--json] · idea select <id> (--message-id <m> | --custom <text>) · idea regenerate <id> · idea load-more <id>
cawcut ad-video storyboard run <id> [--style-id <s>] [--force] [--wait] [--json] · storyboard set <id> --base-revision <n> (--plan <json> | --plan-file <path>) [--update-prompts --prompt-target <shot_id>:<fields>…] # run --force rewrites the script, discarding saved edits
cawcut ad-video image quote <id> --generation-type <hand_drawn|photo_realistic> · image run <id> [--confirmation-token <t>] [--generation-type <t>] [--force] [--wait] [--download]
cawcut ad-video video quote <id> · video run <id> [--confirmation-token <t>] [--force] [--wait] [--download] · video deliver <id> [--dest <dir>]
错误
| 症状 | 操作 |
|---|---|
Token expired | 按照第 0 步中的登录步骤操作;在 status=authenticated 后重试失败的命令一次 |
VIDEO_AD_NEEDS_REGENERATION / 308000414 | 上游输出已过期——先重新运行被标记的阶段(见失效语义) |
| 确认令牌已过期/无效 | 重新报价,征得用户确认后再次运行(见报价时机) |
storyboard set 返回 409 | 版本不匹配——重新读取 detail,并使用最新的 value.revision 重试 |
并发运行返回 409 | 另一阶段正在运行——轮询 detail,直到该阶段结束,再重试 |
config set 返回 400 | 枚举值无效、未满足阶段门槛,或所选 video_model 不支持该分辨率——重新读取 ad-video options |
| 报价显示积分不足 | credits_sufficient: false——说明积分缺口并让用户充值;用户充值后重新报价(见报价时机) |
| 找不到 CLI | npm install -g @ubnt/cawcut(第 0 步) |
完整的故障恢复流程:references/troubleshooting.md。