@pippit-dev/cli 1.0.42 → 1.0.43
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.
- package/README.md +42 -11
- package/checksums.txt +6 -6
- package/cmd/auth/auth.go +19 -5
- package/cmd/auth/auth_test.go +23 -0
- package/cmd/canvas/canvas.go +7 -7
- package/cmd/download_result.go +3 -2
- package/cmd/marketing.go +19 -3
- package/cmd/marketing_test.go +11 -5
- package/cmd/model.go +5 -4
- package/cmd/root.go +13 -5
- package/cmd/short_drama_test.go +2 -0
- package/cmd/source_test.go +27 -4
- package/cmd/space.go +199 -0
- package/cmd/space_test.go +469 -0
- package/cmd/upload_file_test.go +3 -1
- package/dist/checksums.txt +6 -6
- package/internal/adaptercli/commands_test.go +9 -5
- package/internal/auth/space.go +26 -0
- package/internal/auth/space_test.go +42 -0
- package/internal/canvas/get.go +9 -2
- package/internal/commandnames/names.go +9 -4
- package/internal/common/client.go +23 -0
- package/internal/common/host_source.go +5 -0
- package/internal/common/host_source_test.go +9 -1
- package/internal/common/runner.go +5 -3
- package/internal/common/space.go +185 -0
- package/internal/common/space_test.go +132 -0
- package/internal/common/submit_run.go +2 -0
- package/internal/common/upload_file.go +2 -0
- package/internal/config/config.go +15 -12
- package/internal/generate_image/generate_image.go +3 -9
- package/internal/short_drama/submit_run.go +3 -9
- package/internal/space/session.go +153 -0
- package/internal/space/store.go +211 -0
- package/internal/space/store_test.go +246 -0
- package/package.json +1 -1
- package/scripts/canvas-command.js +37 -4
- package/scripts/install-wizard.js +1 -1
- package/scripts/run.js +2 -2
- package/scripts/telemetry.js +3 -1
- package/skills/short-drama/SKILL.md +12 -1
- package/skills/xyq-marketing-skill/SKILL.md +22 -3
- package/skills/xyq-marketing-skill/references/api.md +7 -1
- package/skills/xyq-marketing-skill/scripts/marketing.js +42 -18
- package/skills/xyq-nest-skill/SKILL.md +15 -4
- package/skills/xyq-nest-skill/commands/canvas-assets.md +1 -1
- package/skills/xyq-nest-skill/commands/canvas.md +5 -3
- package/skills/xyq-nest-skill/commands/get-credit-balance.md +2 -2
- package/skills/xyq-nest-skill/commands/model.md +1 -1
- package/skills/xyq-nest-skill/scripts/ensure-cli.js +8 -1
- package/skills/xyq-nest-skill/scripts/install.md +1 -1
- package/skills/xyq-nest-skill/workflows/canvas-edit.md +2 -2
|
@@ -48,13 +48,32 @@ const COMMAND_HELP = `用法:
|
|
|
48
48
|
list 返回简短索引;describe 按层展示字段和可选操作,使用 --path 展开 schema_path。
|
|
49
49
|
guide 按主题说明时间、引用和工作流;schema 显式导出完整 schema(可能很大)。
|
|
50
50
|
这些发现入口无需登录;run 需要目标画布的访问权限。
|
|
51
|
+
run 使用默认空间,可通过 --team-id <ID> 覆盖;0 为个人空间。
|
|
51
52
|
`;
|
|
52
53
|
|
|
54
|
+
function canvasSpaceArgs(args) {
|
|
55
|
+
const clean = [];
|
|
56
|
+
let teamID;
|
|
57
|
+
for (let i = 0; i < args.length; i++) {
|
|
58
|
+
if (args[i] === "--team-id" || args[i].startsWith("--team-id=")) {
|
|
59
|
+
const value = args[i] === "--team-id" ? args[++i] : args[i].slice("--team-id=".length);
|
|
60
|
+
if (teamID !== undefined || !/^\d+$/.test(value || "") || BigInt(value) > 9223372036854775807n) throw new Error("team-id 必须为唯一的 0 或正整数 ID");
|
|
61
|
+
teamID = BigInt(value).toString();
|
|
62
|
+
} else clean.push(args[i]);
|
|
63
|
+
}
|
|
64
|
+
return { args: clean, teamID };
|
|
65
|
+
}
|
|
66
|
+
|
|
53
67
|
function isCanvasCommand(args) {
|
|
54
|
-
|
|
68
|
+
// Global team-id may appear before or after the command. Other flags retain
|
|
69
|
+
// their existing parser and are never forwarded into canvas mutation JSON.
|
|
70
|
+
let start = 0;
|
|
71
|
+
while (args[start] === "--team-id" || (args[start] || "").startsWith("--team-id=")) start += args[start] === "--team-id" ? 2 : 1;
|
|
72
|
+
return args[start] === "canvas" && args[start + 1] === "command";
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
function parseCanvasCommandArgs(args) {
|
|
76
|
+
args = canvasSpaceArgs(args).args;
|
|
58
77
|
if (!isCanvasCommand(args)) throw new Error("仅支持 canvas command 命令");
|
|
59
78
|
const values = args.slice(2);
|
|
60
79
|
if (!values.length || values[0] === "--help" || values[0] === "-h") {
|
|
@@ -196,9 +215,12 @@ class NativeCanvasClient {
|
|
|
196
215
|
this.invocation = invocation;
|
|
197
216
|
this.cwd = options.cwd;
|
|
198
217
|
this.stderr = options.stderr || process.stderr;
|
|
218
|
+
this.teamID = options.teamID;
|
|
199
219
|
}
|
|
200
220
|
|
|
201
221
|
async runJSON(args, input) {
|
|
222
|
+
if (args[0] === "canvas" && this.teamID !== undefined) args = [...args, "--team-id", this.teamID];
|
|
223
|
+
if (args[0] === "canvas" && this.spaceContext) args = [...args, "--space-context", this.spaceContext];
|
|
202
224
|
const result = await spawnProcess(this.invocation, args, {
|
|
203
225
|
cwd: this.cwd,
|
|
204
226
|
input: input === undefined ? undefined : JSON.stringify(input),
|
|
@@ -207,6 +229,12 @@ class NativeCanvasClient {
|
|
|
207
229
|
let output;
|
|
208
230
|
try {
|
|
209
231
|
output = JSON.parse(result.stdout);
|
|
232
|
+
// The first canvas get resolves the space in Go. Reuse its binding for
|
|
233
|
+
// every SDK transport call, even if another process changes the default.
|
|
234
|
+
if (args[0] === "canvas" && output.team_id !== undefined) {
|
|
235
|
+
this.teamID = output.team_id;
|
|
236
|
+
this.spaceContext = output.space_context;
|
|
237
|
+
}
|
|
210
238
|
} catch (error) {
|
|
211
239
|
throw new Error(`原生 CLI 未返回有效 JSON(${args.join(" ")}):${error.message}`);
|
|
212
240
|
}
|
|
@@ -786,6 +814,7 @@ function executePublicCommand(route, definitions, input) {
|
|
|
786
814
|
}
|
|
787
815
|
|
|
788
816
|
async function runCanvasCommand(args, options = {}) {
|
|
817
|
+
const { teamID } = canvasSpaceArgs(args);
|
|
789
818
|
const parsed = parseCanvasCommandArgs(args);
|
|
790
819
|
const stdout = options.stdout || process.stdout;
|
|
791
820
|
const stderr = options.stderr || process.stderr;
|
|
@@ -842,8 +871,11 @@ async function runCanvasCommand(args, options = {}) {
|
|
|
842
871
|
const input = parseInputJSON(parsed, cwd);
|
|
843
872
|
const route = routes.get(parsed.commandName);
|
|
844
873
|
validatePublicCommandInput(route, input);
|
|
845
|
-
const nativeClient = new NativeCanvasClient(options.nativeInvocation, { cwd, stderr });
|
|
874
|
+
const nativeClient = new NativeCanvasClient(options.nativeInvocation, { cwd, stderr, teamID });
|
|
846
875
|
const authStatus = await nativeClient.ensureCanvasAccess(parsed.canvasId);
|
|
876
|
+
const credentialScope = authStatus.credential_scope && nativeClient.teamID && nativeClient.teamID !== "0"
|
|
877
|
+
? `${authStatus.credential_scope}:team:${nativeClient.teamID}`
|
|
878
|
+
: authStatus.credential_scope;
|
|
847
879
|
const requiresDurableCheckpoint = CHECKPOINT_COMMANDS.has(parsed.commandName) ||
|
|
848
880
|
(parsed.commandName === "apply_mutations" && input.checkpointBefore === true);
|
|
849
881
|
if (requiresDurableCheckpoint && !authStatus.credential_scope) {
|
|
@@ -853,7 +885,7 @@ async function runCanvasCommand(args, options = {}) {
|
|
|
853
885
|
const checkpointStore = authStatus.credential_scope
|
|
854
886
|
? createFileCheckpointStore({
|
|
855
887
|
canvasId: parsed.canvasId,
|
|
856
|
-
credentialScope
|
|
888
|
+
credentialScope,
|
|
857
889
|
stateDirectory: options.stateDirectory,
|
|
858
890
|
})
|
|
859
891
|
: undefined;
|
|
@@ -872,7 +904,7 @@ async function runCanvasCommand(args, options = {}) {
|
|
|
872
904
|
const persistence = authStatus.credential_scope
|
|
873
905
|
? createFilePersistence({
|
|
874
906
|
canvasId: parsed.canvasId,
|
|
875
|
-
credentialScope
|
|
907
|
+
credentialScope,
|
|
876
908
|
stateDirectory: options.stateDirectory,
|
|
877
909
|
})
|
|
878
910
|
: createMemoryPersistence();
|
|
@@ -963,6 +995,7 @@ module.exports = {
|
|
|
963
995
|
createSchemaFactory,
|
|
964
996
|
definitionToJSON,
|
|
965
997
|
ensureNodeRuntimeGlobals,
|
|
998
|
+
canvasSpaceArgs,
|
|
966
999
|
isCanvasCommand,
|
|
967
1000
|
parseCanvasCommandArgs,
|
|
968
1001
|
runCanvasCommand,
|
|
@@ -21,7 +21,7 @@ PIPPIT_CLI_INSTALL_PACKAGE can override the package/version to install.
|
|
|
21
21
|
|
|
22
22
|
Options:
|
|
23
23
|
--source HOST Real host identifier reported as host_platform; unknown hosts omit it
|
|
24
|
-
|
|
24
|
+
Missing or blank values default to PIPPIT_CLI_SOURCE, then known host runtime markers
|
|
25
25
|
-h, --help Show this help without installing, updating, or sending telemetry
|
|
26
26
|
`;
|
|
27
27
|
|
package/scripts/run.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { execFileSync } = require('child_process');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const { isCanvasCommand, parseCanvasCommandArgs, runCanvasCommand } = require('./canvas-command');
|
|
6
|
+
const { isCanvasCommand, parseCanvasCommandArgs, runCanvasCommand, canvasSpaceArgs } = require('./canvas-command');
|
|
7
7
|
const { maybeWarnNewVersion } = require('./version-check');
|
|
8
8
|
|
|
9
9
|
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
@@ -45,7 +45,7 @@ function main() {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const helpRequested = args.includes('--help') || args.includes('-h') || args[0] === 'help';
|
|
48
|
-
if (isCanvasCommand(args) && (args[2] !== 'run' || helpRequested)) {
|
|
48
|
+
if (isCanvasCommand(args) && (canvasSpaceArgs(args).args[2] !== 'run' || helpRequested)) {
|
|
49
49
|
// Discovery commands also need update notices. Keep help and invalid
|
|
50
50
|
// commands free of network checks and cache writes.
|
|
51
51
|
if (!helpRequested) {
|
package/scripts/telemetry.js
CHANGED
|
@@ -21,12 +21,14 @@ function telemetryBaseURL() {
|
|
|
21
21
|
|
|
22
22
|
// Keep the same attribution rules as native CLI common.DetectHostSource.
|
|
23
23
|
function resolveHostSource(explicit) {
|
|
24
|
-
if (explicit !== undefined) return explicit.trim();
|
|
24
|
+
if (explicit !== undefined && explicit.trim()) return explicit.trim();
|
|
25
25
|
if ((process.env.PIPPIT_CLI_SOURCE || "").trim()) return process.env.PIPPIT_CLI_SOURCE.trim();
|
|
26
26
|
const hosts = new Set();
|
|
27
27
|
for (const [key, host] of [
|
|
28
28
|
["CODEX_THREAD_ID", "codex"], ["CODEX_SESSION_ID", "codex"],
|
|
29
29
|
["CLAUDECODE", "claude_code"], ["CURSOR_AGENT", "cursor"], ["GEMINI_CLI", "gemini_cli"],
|
|
30
|
+
["OPENCODE", "opencode"], ["QWEN_CODE", "qwen_code"], ["CLINE_ACTIVE", "cline"],
|
|
31
|
+
["COPILOT_CLI", "github_copilot_cli"], ["COPILOT_AGENT_SESSION_ID", "github_copilot_cli"],
|
|
30
32
|
]) {
|
|
31
33
|
const value = (process.env[key] || "").trim().toLowerCase();
|
|
32
34
|
if (value && value !== "0" && value !== "false") hosts.add(host);
|
|
@@ -16,6 +16,17 @@ metadata:
|
|
|
16
16
|
2. 需要业务调用时先按 [授权](commands/auth.md) 执行 `status`,已有登录可复用。
|
|
17
17
|
3. 按下表读取命中的命令说明。提交、续接和处理后端问题必须读 [创作与会话续接](workflows/creation.md);查询或取得产物必须读 [轮询与文件交付](workflows/poll-and-deliver.md)。
|
|
18
18
|
|
|
19
|
+
## Space Selection
|
|
20
|
+
|
|
21
|
+
业务命令支持个人和团队空间,复用同一个 CLI 登录凭据。执行前先检查 `pippit-tool-cli space --help` 和业务命令的 `--team-id`;旧版不支持时先更新 CLI,不能忽略团队选择后继续收费操作。
|
|
22
|
+
|
|
23
|
+
- `space list` 统一输出 JSON,列出个人和当前账号的团队;顶层 `current` 表示已保存的默认空间,列表项 `current: true` 标记当前选择,无法识别本地账号时顶层为 `null`。`team_id` 保留字符串,`0` 为个人。列表中的团队不代表有生成权限、有效订阅或可用积分,最终由服务端判断。
|
|
24
|
+
- 用户明确要求长期切换时,运行 `space use TEAM_ID`;`space use 0` 保存个人空间。`use` 必须指定 ID,成功后返回保存的空间,不等待交互输入。只为本次任务选择空间时使用 `--team-id TEAM_ID`,不修改用户默认值;不能按模糊名称或剩余积分自动选团队。
|
|
25
|
+
- 新创作未指定空间时,读取并沿用保存的默认空间,首次使用为个人。向用户说明本次空间与积分账户,不重复索要已有授权。一次工作流开始后保存 TeamID,分开的上传、提交、查询和余额命令均显式传相同 `--team-id`,不能中途重新读取默认值。
|
|
26
|
+
- 已有任务优先沿用提交结果中的 `team_id` 或 CLI 的任务记录;切换默认团队后可以直接按原 thread/run 查询,CLI 自动恢复原空间。不要把当前默认 TeamID 强加给旧任务。跨设备或旧任务没有记录时,使用已知原空间;未知且用户也未指定时先核实,不能轮流试团队。
|
|
27
|
+
- 保存上传结果的资产 ID 和 `team_id`,提交结果的 thread/run ID 和 `team_id`。跨空间资产或任务冲突时停止;无权限、会员失效或余额不足不回退个人或其它团队。提交成功但本地记录写入失败时,保留返回 ID,用原 `--team-id` 查询,不重新生成。
|
|
28
|
+
- CLI 向同源 API 统一透传当前团队的 TeamID;模型接口内部继续按个人身份查询;模型列表成功不代表团队有生成权限。Canvas 同样使用所选空间;操作已有画布时沿用该画布原空间,切换默认空间后仍显式传入原 `--team-id`。
|
|
29
|
+
|
|
19
30
|
## 意图路由
|
|
20
31
|
|
|
21
32
|
| 用户意图 | CLI | 必读文档 |
|
|
@@ -44,7 +55,7 @@ metadata:
|
|
|
44
55
|
|
|
45
56
|
## 宿主来源统计
|
|
46
57
|
|
|
47
|
-
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source
|
|
58
|
+
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source`;不要仅因字段可选就跳过。未传 `--source`、显式空值或纯空白时,CLI 依次尝试 `PIPPIT_CLI_SOURCE` 和已核实的宿主运行标记。只上报稳定的平台名,不上报标记中的会话 ID;来源冲突或仍无法确认则省略,不询问用户、不扫描登录凭据或安装目录。
|
|
48
59
|
|
|
49
60
|
仅 `short-drama +submit-run` 静默附加可选 `--source`,用于统计:豆包办公 `doubao_office`、WorkBuddy `workbuddy`、Codex `codex`;其它宿主使用可信环境中的真实稳定标识,无法确认则省略。不从创作文本猜来源,不附带版本、会话 ID、用户信息或 prompt,不向用户询问,不改写 `--message`。上传、查询、下载不附加此参数;旧 CLI 的 `--help` 不支持时省略,不为统计字段重提任务。
|
|
50
61
|
|
|
@@ -22,6 +22,25 @@ metadata:
|
|
|
22
22
|
|
|
23
23
|
先按 [接口契约](references/api.md) 准备请求;需要完整执行示例时读 [商品图到营销视频](examples/product-video.md)。
|
|
24
24
|
|
|
25
|
+
## Space Selection
|
|
26
|
+
|
|
27
|
+
业务命令支持个人和团队空间,复用同一个 CLI 登录凭据。执行前先检查 `pippit-tool-cli space --help` 和业务命令的 `--team-id`;旧版不支持时先更新 CLI,不能忽略团队选择后继续收费操作。
|
|
28
|
+
|
|
29
|
+
- `space list` 统一输出 JSON,列出个人和当前账号的团队;顶层 `current` 表示已保存的默认空间,列表项 `current: true` 标记当前选择,无法识别本地账号时顶层为 `null`。`team_id` 保留字符串,`0` 为个人。列表中的团队不代表有生成权限、有效订阅或可用积分,最终由服务端判断。
|
|
30
|
+
- 用户明确要求长期切换时,运行 `space use TEAM_ID`;`space use 0` 保存个人空间。`use` 必须指定 ID,成功后返回保存的空间,不等待交互输入。只为本次任务选择空间时使用 `--team-id TEAM_ID`,不修改用户默认值;不能按模糊名称或剩余积分自动选团队。
|
|
31
|
+
- 新创作未指定空间时,读取并沿用保存的默认空间,首次使用为个人。向用户说明本次空间与积分账户,不重复索要已有授权。一次工作流开始后保存 TeamID,分开的上传、提交、查询和余额命令均显式传相同 `--team-id`,不能中途重新读取默认值。
|
|
32
|
+
- 已有任务优先沿用提交结果中的 `team_id` 或 CLI 的任务记录;切换默认团队后可以直接按原 thread/run 查询,CLI 自动恢复原空间。不要把当前默认 TeamID 强加给旧任务。跨设备或旧任务没有记录时,使用已知原空间;未知且用户也未指定时先核实,不能轮流试团队。
|
|
33
|
+
- 保存上传结果的资产 ID 和 `team_id`,提交结果的 thread/run ID 和 `team_id`。跨空间资产或任务冲突时停止;无权限、会员失效或余额不足不回退个人或其它团队。提交成功但本地记录写入失败时,保留返回 ID,用原 `--team-id` 查询,不重新生成。
|
|
34
|
+
- CLI 向同源 API 统一透传当前团队的 TeamID;模型接口内部继续按个人身份查询;模型列表成功不代表团队有生成权限。Canvas 同样使用所选空间;操作已有画布时沿用该画布原空间,切换默认空间后仍显式传入原 `--team-id`。
|
|
35
|
+
|
|
36
|
+
营销脚本的 `upload / generate / query / balance` 都支持 `--team-id TEAM_ID`。预览也读取同一空间;`query --wait` 固定 TeamID,本地账号可识别时同时固定账号和 API origin,切换账号则停止。无本地账号记录时,显式传入原 `--team-id` 仍可轮询,由 API 按当前凭据鉴权;不能读取默认值代替原任务空间。不要手工构造内部 `space_context`;使用原任务查询命令恢复。不同脚本调用之间仍需由宿主保留任务原 TeamID。
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node scripts/marketing.js upload --file /path/to/product.png --team-id TEAM_ID
|
|
40
|
+
node scripts/marketing.js generate --request /path/to/request.json --execute --team-id TEAM_ID
|
|
41
|
+
node scripts/marketing.js query --thread-id THREAD_ID --run-id RUN_ID --wait --team-id TEAM_ID
|
|
42
|
+
```
|
|
43
|
+
|
|
25
44
|
## Workflow
|
|
26
45
|
|
|
27
46
|
1. 确认用户要生成的营销内容与商品素材。保留用户原始指令,不主动扩写或加入未经提供的卖点。仅查询、接入咨询或估算不提交生成;明确要求生成即可执行,不重复询问已给出的授权。必要的补充信息用宿主当前允许的 `request_user_input_async`、`request_user_input` 或 `ask_user_question` 询问,没有工具时用普通聊天。
|
|
@@ -42,9 +61,9 @@ node scripts/marketing.js balance
|
|
|
42
61
|
|
|
43
62
|
## Source Attribution
|
|
44
63
|
|
|
45
|
-
仅营销生成命令(`marketing generate` 或 `marketing.js generate`)静默附加可选 `--source`,由 CLI 映射为请求体 `platform`,不写入创作文本或请求文件。豆包办公填 `doubao_office`,WorkBuddy 填 `workbuddy`,Codex 填 `codex`;其它宿主使用可信环境中的真实稳定标识,未知则省略,不询问用户。不附带版本、会话 ID、用户信息或 prompt
|
|
64
|
+
仅营销生成命令(`marketing generate` 或 `marketing.js generate`)静默附加可选 `--source`,由 CLI 映射为请求体 `platform`,不写入创作文本或请求文件。豆包办公填 `doubao_office`,WorkBuddy 填 `workbuddy`,Codex 填 `codex`;其它宿主使用可信环境中的真实稳定标识,未知则省略,不询问用户。不附带版本、会话 ID、用户信息或 prompt。首尾空白去除,未传或空值时先读取 `PIPPIT_CLI_SOURCE`、再尝试已核实的宿主运行标记,仍无法识别时省略;首次生成和同一会话继续提交均适用。上传、查询、下载、余额不附加。旧 CLI 不支持时省略,不为来源统计重提任务。
|
|
46
65
|
|
|
47
|
-
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source
|
|
66
|
+
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source`;不要仅因字段可选就跳过。未传 `--source`、显式空值或纯空白时,CLI 依次尝试 `PIPPIT_CLI_SOURCE` 和已核实的宿主运行标记。只上报稳定的平台名,不上报标记中的会话 ID;来源冲突或仍无法确认则省略,不询问用户、不扫描登录凭据或安装目录。
|
|
48
67
|
|
|
49
68
|
## Completion and Recovery
|
|
50
69
|
|
|
@@ -58,4 +77,4 @@ node scripts/marketing.js balance
|
|
|
58
77
|
|
|
59
78
|
## Scope
|
|
60
79
|
|
|
61
|
-
本 Skill
|
|
80
|
+
本 Skill 使用 CLI 登录和服务端空间授权,通过 `--team-id` 选择个人或团队,CLI 将其写入 HTTP Header;不向营销请求 JSON 添加 `TeamID` / `team_id`,不跨账号复用资产或任务。沉浸式短片、火山引擎服务不在此脚本范围。
|
|
@@ -22,7 +22,7 @@ Base URL:`https://xyq.jianying.com`。全部使用 POST,`Accept: application
|
|
|
22
22
|
| `general_agent_settings` | object | 必传,且必须包含非空 `video_model` |
|
|
23
23
|
| `thread_id` | string | 可选,只在继续已有营销会话时使用 |
|
|
24
24
|
|
|
25
|
-
来源统计由生成命令的可选 `--source HOST` 提供,CLI 在提交及预览的请求体中映射为 `platform`
|
|
25
|
+
来源统计由生成命令的可选 `--source HOST` 提供,CLI 在提交及预览的请求体中映射为 `platform` 字符串;不传或去除首尾空白后为空时,依次尝试 `PIPPIT_CLI_SOURCE` 和已核实的宿主运行标记,仍未知则省略。请求文件仍只填写上表中的创作字段,不直接添加 `source` 或 `platform`。
|
|
26
26
|
|
|
27
27
|
设置块必须传对象,且 `video_model` 必填。2026-09-22 实际调用及服务端 `validateMarketingGeneralAgentSettings` 均确认:`{}` 或仅有比例/时长会返回 `ret=2`、缺少 `video_model`。不再按文档中的默认策略说明发送空对象;预览和提交都先本地校验。用户未指定模型时先询问,已有明确选择授权时按授权选择,不隐式降级。
|
|
28
28
|
|
|
@@ -63,3 +63,9 @@ HTTP 成功还需检查 `ret` 为 `"0"` 或 `0`;失败保留 `errmsg` 和 `log
|
|
|
63
63
|
查询接口透传 Run 状态;仅在 3 时提取媒体,4/5 时提取失败原因,其它状态返回空媒体数组。因此 9 的空 `video_urls` 不能解释为生成失败。状态 3 也不保证有视频;以真实媒体列表判断交付。未知数值保留原始响应并停止,不自动重提或无期限轮询。
|
|
64
64
|
|
|
65
65
|
一条 thread 可以有多个 Run。问卷、达人图或工具执行确认会产生后续 Run,原 `run_id` 不会自动变成最新运行。确认后从网页或可用的 `pippit-tool-cli get-thread --thread-id THREAD_ID` 读取新的真实 run_id,再传给营销查询命令;不要猜 ID 或为查询创建新 Run。
|
|
66
|
+
|
|
67
|
+
## Space Context
|
|
68
|
+
|
|
69
|
+
原生 CLI 和 Skill 脚本均支持 `--team-id TEAM_ID`;`0` 为个人,正整数为团队。空间通过 API origin 上的 `X-Team-Id` Header 传递,保持本文件中的 JSON 请求字段不变。非 Canvas 业务默认使用 `space use` 保存的空间;旧任务按本地记录恢复原空间。团队列表为 `space list`,由 CLI 使用同一 AK 调用 `/api/biz/v1/skill/get_lite_team_list`,不直连 commerce Web 接口。
|
|
70
|
+
|
|
71
|
+
营销响应增加 `team_id` 和供脚本固定轮询使用的 `space_context`;无可用本地账号记录时 `space_context` 为空,脚本通过显式 `--team-id` 固定轮询空间。二者只是本地路由信息,不能替代服务端鉴权。预览增加 `team_id`,不发送生成请求。权限或积分错误不自动切空间重试。
|
|
@@ -116,10 +116,13 @@ function invokeCLI(args, input, timeout, invocation = resolveCLI()) {
|
|
|
116
116
|
let result;
|
|
117
117
|
try { result = args.includes('--help') ? stdout : JSON.parse(stdout); }
|
|
118
118
|
catch (_) { return reject(new Error('CLI 未返回有效 JSON;提交结果可能不明确,请勿自动重提')); }
|
|
119
|
-
//
|
|
119
|
+
// Relay successful update and space notices; backend logs stay buffered.
|
|
120
120
|
for (const notice of stderr.split(/\r?\n/)) {
|
|
121
121
|
if (notice.startsWith('[pippit-tool-cli] New version available:') ||
|
|
122
|
-
notice === '[pippit-tool-cli] If browser authorization fails, update the CLI and run pippit-tool-cli login again.'
|
|
122
|
+
notice === '[pippit-tool-cli] If browser authorization fails, update the CLI and run pippit-tool-cli login again.' ||
|
|
123
|
+
notice.startsWith('本次空间:') ||
|
|
124
|
+
notice.startsWith('请求已成功,但空间记录保存失败:') ||
|
|
125
|
+
notice === '本地空间记录不可用,将使用显式 --team-id;本次不保存空间记录。') {
|
|
123
126
|
process.stderr.write(`${notice}\n`);
|
|
124
127
|
}
|
|
125
128
|
}
|
|
@@ -129,7 +132,10 @@ function invokeCLI(args, input, timeout, invocation = resolveCLI()) {
|
|
|
129
132
|
});
|
|
130
133
|
}
|
|
131
134
|
|
|
132
|
-
function createClient({ request = https.request, timeout = 60000, invoke = invokeCLI } = {}) {
|
|
135
|
+
function createClient({ request = https.request, timeout = 60000, invoke = invokeCLI, teamID, spaceContext } = {}) {
|
|
136
|
+
const scopeArgs = [];
|
|
137
|
+
if (teamID !== undefined) scopeArgs.push('--team-id', normalizeTeamID(teamID));
|
|
138
|
+
if (spaceContext) scopeArgs.push('--space-context', spaceContext);
|
|
133
139
|
function open(url, method, headers, body) {
|
|
134
140
|
return new Promise((resolve, reject) => {
|
|
135
141
|
const target = new URL(url);
|
|
@@ -150,13 +156,14 @@ function createClient({ request = https.request, timeout = 60000, invoke = invok
|
|
|
150
156
|
});
|
|
151
157
|
}
|
|
152
158
|
|
|
153
|
-
async function api(action, body, source) {
|
|
159
|
+
async function api(action, body, source, execute = true) {
|
|
154
160
|
requireValue(['generate', 'query', 'balance'].includes(action), '无效营销 API 操作');
|
|
155
|
-
const args = ['marketing', action, '--timeout', `${timeout}ms
|
|
161
|
+
const args = ['marketing', action, '--timeout', `${timeout}ms`, ...scopeArgs];
|
|
156
162
|
let input;
|
|
157
163
|
if (action === 'generate') {
|
|
158
164
|
validate(body);
|
|
159
|
-
args.push('--request', '-'
|
|
165
|
+
args.push('--request', '-');
|
|
166
|
+
if (execute) args.push('--execute');
|
|
160
167
|
if (source !== undefined) {
|
|
161
168
|
// Probe before submitting; optional attribution must not break older CLIs.
|
|
162
169
|
let help = '';
|
|
@@ -166,13 +173,14 @@ function createClient({ request = https.request, timeout = 60000, invoke = invok
|
|
|
166
173
|
input = JSON.stringify(body);
|
|
167
174
|
}
|
|
168
175
|
if (action === 'query') args.push('--thread-id', body.thread_id, '--run-id', body.run_id);
|
|
169
|
-
|
|
176
|
+
const result = await invoke(args, input, timeout);
|
|
177
|
+
return action === 'generate' && !execute ? result : checkResponse(action, result, body);
|
|
170
178
|
}
|
|
171
179
|
|
|
172
180
|
async function upload(file) {
|
|
173
181
|
const stat = await fs.promises.stat(file);
|
|
174
182
|
requireValue(stat.isFile() && stat.size > 0 && stat.size < 500000000, '上传需要非空文件且小于 500 MB');
|
|
175
|
-
return checkResponse('upload', await invoke(['marketing', 'upload', '--file', path.resolve(file), '--timeout', `${timeout}ms
|
|
183
|
+
return checkResponse('upload', await invoke(['marketing', 'upload', '--file', path.resolve(file), '--timeout', `${timeout}ms`, ...scopeArgs], undefined, timeout));
|
|
176
184
|
}
|
|
177
185
|
|
|
178
186
|
async function download(url, destination) {
|
|
@@ -213,7 +221,8 @@ const HELP = `小云雀营销 Skill(Node.js >= 16)
|
|
|
213
221
|
node marketing.js query --thread-id ID --run-id ID [--wait] [--max-wait 900] [--output-dir DIR]
|
|
214
222
|
node marketing.js balance
|
|
215
223
|
所有 API 调用复用 pippit-tool-cli 登录态;未登录先运行 pippit-tool-cli login,无需提供 access_token。generate 默认仅预览。
|
|
216
|
-
--source HOST:仅生成提交使用,映射为请求体 platform
|
|
224
|
+
--source HOST:仅生成提交使用,映射为请求体 platform;未传或空值时尝试环境识别,来源未知则省略。
|
|
225
|
+
--team-id ID:本次使用团队;0 为个人,不改变 space use 保存的默认空间。轮询固定使用原任务空间。
|
|
217
226
|
--timeout 秒数:单请求总时限,默认 60;--max-wait:轮询总时限,默认 900。
|
|
218
227
|
query 输出 API 原始响应;有 --output-dir 时成功结果附带 downloaded_files。
|
|
219
228
|
退出码:0 成功/单次查询进行中;1 输入或接口错误;2 生成失败/取消/无视频;3 等待超时;4 等待用户交互;5 未知或未指定状态。
|
|
@@ -221,12 +230,14 @@ query 输出 API 原始响应;有 --output-dir 时成功结果附带 downloade
|
|
|
221
230
|
|
|
222
231
|
// Keep runtime marker semantics aligned with internal/common/host_source.go.
|
|
223
232
|
function resolveHostSource(explicit, env = process.env) {
|
|
224
|
-
if (explicit !== undefined) return explicit.trim();
|
|
233
|
+
if (explicit !== undefined && explicit.trim()) return explicit.trim();
|
|
225
234
|
if ((env.PIPPIT_CLI_SOURCE || '').trim()) return env.PIPPIT_CLI_SOURCE.trim();
|
|
226
235
|
const hosts = new Set();
|
|
227
236
|
for (const [key, host] of [
|
|
228
237
|
['CODEX_THREAD_ID', 'codex'], ['CODEX_SESSION_ID', 'codex'],
|
|
229
238
|
['CLAUDECODE', 'claude_code'], ['CURSOR_AGENT', 'cursor'], ['GEMINI_CLI', 'gemini_cli'],
|
|
239
|
+
['OPENCODE', 'opencode'], ['QWEN_CODE', 'qwen_code'], ['CLINE_ACTIVE', 'cline'],
|
|
240
|
+
['COPILOT_CLI', 'github_copilot_cli'], ['COPILOT_AGENT_SESSION_ID', 'github_copilot_cli'],
|
|
230
241
|
]) {
|
|
231
242
|
const value = (env[key] || '').trim().toLowerCase();
|
|
232
243
|
if (value && value !== '0' && value !== 'false') hosts.add(host);
|
|
@@ -234,12 +245,18 @@ function resolveHostSource(explicit, env = process.env) {
|
|
|
234
245
|
return hosts.size === 1 ? [...hosts][0] : '';
|
|
235
246
|
}
|
|
236
247
|
|
|
248
|
+
function normalizeTeamID(value) {
|
|
249
|
+
requireValue(typeof value === 'string' && /^\d+$/.test(value), 'team-id 必须为 0 或正整数');
|
|
250
|
+
requireValue(BigInt(value) <= 9223372036854775807n, 'team-id 超出 int64 范围');
|
|
251
|
+
return BigInt(value).toString();
|
|
252
|
+
}
|
|
253
|
+
|
|
237
254
|
function parseArgs(argv) {
|
|
238
255
|
const [action, ...rest] = argv;
|
|
239
256
|
requireValue(Object.hasOwnProperty.call(PATHS, action), '操作必须是 generate/upload/query/balance');
|
|
240
257
|
const options = {};
|
|
241
258
|
const flags = ['execute', 'dry-run', 'wait'];
|
|
242
|
-
const allowed = { generate: ['request', 'execute', 'dry-run', 'source'], upload: ['file'], query: ['thread-id', 'run-id', 'wait', 'max-wait', 'output-dir'], balance: [] }[action].concat('timeout');
|
|
259
|
+
const allowed = { generate: ['request', 'execute', 'dry-run', 'source'], upload: ['file'], query: ['thread-id', 'run-id', 'wait', 'max-wait', 'output-dir'], balance: [] }[action].concat('timeout', 'team-id');
|
|
243
260
|
for (let i = 0; i < rest.length; i++) {
|
|
244
261
|
const name = rest[i].replace(/^--/, '');
|
|
245
262
|
requireValue(rest[i].startsWith('--') && allowed.includes(name) && !(name in options), `无效或重复参数:${rest[i]}`);
|
|
@@ -249,6 +266,7 @@ function parseArgs(argv) {
|
|
|
249
266
|
options[name] = rest[++i];
|
|
250
267
|
}
|
|
251
268
|
}
|
|
269
|
+
if (options['team-id'] !== undefined) options['team-id'] = normalizeTeamID(options['team-id']);
|
|
252
270
|
requireValue(!(options.execute && options['dry-run']), '--execute 和 --dry-run 不能同时使用');
|
|
253
271
|
for (const [name, fallback, max] of [['timeout', 60, 1800], ['max-wait', 900, 86400]]) {
|
|
254
272
|
const value = options[name] === undefined ? fallback : Number(options[name]);
|
|
@@ -267,26 +285,32 @@ async function main(argv, { out = console.log, clientFactory = createClient, now
|
|
|
267
285
|
if (options.source !== undefined || source) options.source = source;
|
|
268
286
|
requireValue(options.request, 'generate 需要 --request JSON 文件');
|
|
269
287
|
body = validate(JSON.parse(await fs.promises.readFile(options.request, 'utf8')));
|
|
270
|
-
if (!options.execute) {
|
|
271
|
-
const source = (options.source || '').trim();
|
|
272
|
-
out(JSON.stringify({ dry_run: true, url: BASE + PATHS.generate, body: source ? { ...body, platform: source } : body }));
|
|
273
|
-
return 0;
|
|
274
|
-
}
|
|
275
288
|
}
|
|
276
289
|
if (action === 'query') {
|
|
277
290
|
requireValue(nonempty(options['thread-id']) && nonempty(options['run-id']), 'query 需要 thread-id 和 run-id');
|
|
278
291
|
body = { thread_id: options['thread-id'], run_id: options['run-id'] };
|
|
279
292
|
}
|
|
280
293
|
if (action === 'upload') requireValue(nonempty(options.file), 'upload 需要 --file');
|
|
281
|
-
const client = clientFactory({ timeout: options.timeout * 1000 });
|
|
294
|
+
const client = clientFactory({ timeout: options.timeout * 1000, teamID: options['team-id'] });
|
|
295
|
+
if (action === 'generate' && !options.execute) {
|
|
296
|
+
out(JSON.stringify(await client.api(action, body, options.source, false)));
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
let fixedScope;
|
|
300
|
+
let fixedTeamID = options['team-id'];
|
|
282
301
|
let result;
|
|
283
302
|
const deadline = now() + options['max-wait'] * 1000;
|
|
284
303
|
do {
|
|
285
304
|
// A poll request cannot overrun the remaining wait budget.
|
|
286
305
|
const pollClient = action === 'query' && options.wait
|
|
287
|
-
? clientFactory({ timeout: Math.min(options.timeout * 1000, Math.max(1, deadline - now())) }) : client;
|
|
306
|
+
? clientFactory({ timeout: Math.min(options.timeout * 1000, Math.max(1, deadline - now())), teamID: fixedTeamID, spaceContext: fixedScope }) : client;
|
|
288
307
|
result = action === 'upload' ? await client.upload(options.file) : await pollClient.api(action, body, options.source);
|
|
308
|
+
if (action === 'query' && options.wait && fixedTeamID !== undefined) requireValue(result.team_id === fixedTeamID, '任务空间发生变化,已停止轮询');
|
|
309
|
+
if (action === 'query' && options.wait && fixedScope) requireValue(result.space_context === fixedScope, '任务空间或账号发生变化,已停止轮询');
|
|
289
310
|
if (action !== 'query' || !options.wait || !WAIT_STATES.includes(String(result.data.run_state))) break;
|
|
311
|
+
requireValue(nonempty(result.team_id) && (nonempty(result.space_context) || fixedTeamID !== undefined), 'CLI 未返回固定空间信息,已停止轮询;请使用原 --team-id 查询同一任务,不要重提');
|
|
312
|
+
fixedScope = result.space_context;
|
|
313
|
+
fixedTeamID = result.team_id;
|
|
290
314
|
if (now() >= deadline) {
|
|
291
315
|
out(JSON.stringify({ ...result, wait_timed_out: true })); return 3;
|
|
292
316
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: xyq-skill
|
|
3
|
-
description: 使用小云雀 pippit-tool-cli
|
|
3
|
+
description: 使用小云雀 pippit-tool-cli 生成或编辑图片、生成视频、超分和擦字幕,查询结果并交付媒体;操作小云雀个人或团队 Canvas 画布、节点、布局、连线、角色/场景、生成提示词、3D 导演台与多轨草稿;查询积分及管理授权。用户提到小云雀、xyq 并需要这些操作时使用。
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata:
|
|
6
6
|
{"openclaw": {"emoji": "💬", "requires": {"bins": ["node"]}}}
|
|
@@ -18,6 +18,17 @@ metadata:
|
|
|
18
18
|
|
|
19
19
|
参数是否存在、命令语法以当前 `cli_path` 对应的 `--help` 为准;返回字段和成功判断按命令文档及真实响应核对。文档与实际不一致时说明差异,不猜参数、不绕过 CLI 自行调用 HTTP。
|
|
20
20
|
|
|
21
|
+
## Space Selection
|
|
22
|
+
|
|
23
|
+
业务命令支持个人和团队空间,复用同一个 CLI 登录凭据。执行前先检查 `pippit-tool-cli space --help` 和业务命令的 `--team-id`;旧版不支持时先更新 CLI,不能忽略团队选择后继续收费操作。
|
|
24
|
+
|
|
25
|
+
- `space list` 统一输出 JSON,列出个人和当前账号的团队;顶层 `current` 表示已保存的默认空间,列表项 `current: true` 标记当前选择,无法识别本地账号时顶层为 `null`。`team_id` 保留字符串,`0` 为个人。列表中的团队不代表有生成权限、有效订阅或可用积分,最终由服务端判断。
|
|
26
|
+
- 用户明确要求长期切换时,运行 `space use TEAM_ID`;`space use 0` 保存个人空间。`use` 必须指定 ID,成功后返回保存的空间,不等待交互输入。只为本次任务选择空间时使用 `--team-id TEAM_ID`,不修改用户默认值;不能按模糊名称或剩余积分自动选团队。
|
|
27
|
+
- 新创作未指定空间时,读取并沿用保存的默认空间,首次使用为个人。向用户说明本次空间与积分账户,不重复索要已有授权。一次工作流开始后保存 TeamID,分开的上传、提交、查询和余额命令均显式传相同 `--team-id`,不能中途重新读取默认值。
|
|
28
|
+
- 已有任务优先沿用提交结果中的 `team_id` 或 CLI 的任务记录;切换默认团队后可以直接按原 thread/run 查询,CLI 自动恢复原空间。不要把当前默认 TeamID 强加给旧任务。跨设备或旧任务没有记录时,使用已知原空间;未知且用户也未指定时先核实,不能轮流试团队。
|
|
29
|
+
- 保存上传结果的资产 ID 和 `team_id`,提交结果的 thread/run ID 和 `team_id`。跨空间资产或任务冲突时停止;无权限、会员失效或余额不足不回退个人或其它团队。提交成功但本地记录写入失败时,保留返回 ID,用原 `--team-id` 查询,不重新生成。
|
|
30
|
+
- CLI 向同源 API 统一透传当前团队的 TeamID;模型接口内部继续按个人身份查询;模型列表成功不代表团队有生成权限。Canvas 同样使用所选空间;操作已有画布时沿用该画布原空间,切换默认空间后仍显式传入原 `--team-id`。
|
|
31
|
+
|
|
21
32
|
## 意图路由
|
|
22
33
|
|
|
23
34
|
按用户要做的操作选择命令,不能只看素材类型。有任务标识且用户只要求查询或取件时,复用该任务,不重新生成。
|
|
@@ -25,14 +36,14 @@ metadata:
|
|
|
25
36
|
| 用户意图 | CLI | 必读文档 |
|
|
26
37
|
| --- | --- | --- |
|
|
27
38
|
| 查看登录状态、登录、退出或切换账号 | `status` / `login` / `logout` | [授权](commands/auth.md) |
|
|
28
|
-
|
|
|
39
|
+
| 创建或查询小云雀个人或团队画布,编辑节点、布局、连线、角色/场景、提示词、3D 或多轨草稿 | `canvas` | [Canvas 能力与命令发现](commands/canvas.md) |
|
|
29
40
|
| 生成图片,或基于参考图修改图片 | `generate-image` | [生图与图片编辑](commands/generate-image.md) |
|
|
30
41
|
| 查询当前可用的图片/视频模型、比例、分辨率及推理强度等参数配置 | `model list` / `model describe` | [模型发现](commands/model.md) |
|
|
31
42
|
| 生成视频、参考生成、视频编辑、视频延长、首尾帧生成、Draft 样片及转成片 | `generate-video` | [生视频](commands/generate-video.md) |
|
|
32
43
|
| 提升已有视频分辨率、视频超分 | `video-super-resolution` | [超分](commands/video-super-resolution.md) |
|
|
33
44
|
| 去除已有视频字幕 | `erase-video-subtitle` | [擦字幕](commands/erase-video-subtitle.md) |
|
|
34
45
|
| 查询已有任务进度、下载生成结果 | `query-result` | [查询结果](commands/query-result.md) |
|
|
35
|
-
|
|
|
46
|
+
| 查询当前空间积分余额、剩余 credits | `get-credit-balance` | [积分](commands/get-credit-balance.md) |
|
|
36
47
|
|
|
37
48
|
- 普通生图、生视频也走对应生成命令,无需用户额外声明“模型直出”。
|
|
38
49
|
- 明确要求修改现有画布或其中节点时优先走 Canvas;普通生图、生视频不自动创建画布。“修改节点提示词”只修改配置,不隐含生成;指定节点生成或导出须先确认当前命令目录有对应能力。
|
|
@@ -59,7 +70,7 @@ metadata:
|
|
|
59
70
|
- 不向用户询问、不增加确认步骤,不为此改写 prompt。无法确认来源时直接省略;不传或空值均不阻塞提交。
|
|
60
71
|
- 来源只随本次提交发送,不加入上传、查询、下载或 Canvas 命令。使用已有旧版 CLI 时先按 `--help` 确认是否支持;不支持则省略,不因统计字段中断任务或在未知提交结果时重提。
|
|
61
72
|
|
|
62
|
-
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source
|
|
73
|
+
优先从宿主的系统身份、当前工具运行环境和明确的平台元数据确认真实宿主,并在每次提交主动填写 `--source`;不要仅因字段可选就跳过。未传 `--source`、显式空值或纯空白时,CLI 依次尝试 `PIPPIT_CLI_SOURCE` 和已核实的宿主运行标记。只上报稳定的平台名,不上报标记中的会话 ID;来源冲突或仍无法确认则省略,不询问用户、不扫描登录凭据或安装目录。
|
|
63
74
|
|
|
64
75
|
## 按需参考的完整场景
|
|
65
76
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Canvas 原生资产命令
|
|
2
2
|
|
|
3
|
-
本页命令通过 `cli_path`
|
|
3
|
+
本页命令通过 `cli_path` 执行。支持个人和团队画布,复用默认空间或 `--team-id TEAM_ID`;创建、上传、查询和修改须使用同一空间。所有 ID 保持原始字符串,不能转换成 JavaScript Number;`project_id`、`canvas_asset_id`、节点 ID 和媒体 `pippit_asset_id` 不可混用。
|
|
4
4
|
|
|
5
5
|
| 命令 | 输入 | 返回与完成判断 |
|
|
6
6
|
| --- | --- | --- |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Canvas
|
|
1
|
+
# Canvas:画布空间与命令发现
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
用于小云雀个人或团队漫剧画布操作,不适用于其他产品的画布。与 [生图](generate-image.md)、[生视频](generate-video.md) 区分:修改画布文档不等于生成媒体,独立生成也不会自动写回指定节点。
|
|
4
4
|
|
|
5
5
|
## 两个入口
|
|
6
6
|
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
- SDK 语义命令:`node "CANVAS_ENTRY" canvas command ...`,`CANVAS_ENTRY` 替换为返回的 `canvas_entry`。不要把 Go 二进制的帮助输出当作语义命令可执行的证明。
|
|
15
15
|
- 切换 shell 时仍使用保存的绝对路径;Windows PowerShell 原生命令用 `& "CLI_PATH" ...`,Node 命令用 `node "CANVAS_ENTRY" ...`。授权复用 [CLI 凭据](auth.md)。
|
|
16
16
|
|
|
17
|
+
原生命令和 `canvas command run` 均复用 `space use TEAM_ID` 保存的默认空间,也可加 `--team-id TEAM_ID` 单次覆盖,`0` 表示个人。沿用 [Space Selection](../SKILL.md#space-selection) 规则,创建、上传、编辑和回读使用同一 TeamID。操作已有画布必须使用其原空间;不按画布 ID 自动查找所属团队,也不在失败后改用个人空间。一次 `run` 内部会固定首次查询确定的空间;多个独立命令仍须显式使用相同 `--team-id`。
|
|
18
|
+
|
|
17
19
|
## 按用户意图发现操作
|
|
18
20
|
|
|
19
21
|
先读取精简目录,仅展开要用的命令;以下名称用于定位,以当前安装版本返回的目录为准。
|
|
@@ -29,7 +31,7 @@
|
|
|
29
31
|
| 图片/视频节点提示词和已有引用 | `xyq.generation.update_prompt` | 先读 `guide prompt-references`;保留其他生成参数,不触发生成 |
|
|
30
32
|
| 3D 导演台对象、摄像机、关键帧、动作 | `xyq.scene3d.query` / `xyq.scene3d.apply` | 先读 `guide scene3d` 和 `guide time` |
|
|
31
33
|
| 多轨草稿、轨道、片段、输出尺寸 | `xyq.timeline.query` / `xyq.timeline.apply` | 先读 `guide timeline` 和 `guide time`,使用最新 `expectedRevision` |
|
|
32
|
-
| 检查点创建、列表、比较、恢复 | `create_checkpoint`、`list_checkpoints`、`compare_checkpoint`、`restore_checkpoint` | 需要网页登录的 credential_scope
|
|
34
|
+
| 检查点创建、列表、比较、恢复 | `create_checkpoint`、`list_checkpoints`、`compare_checkpoint`、`restore_checkpoint` | 需要网页登录的 credential_scope;本地检查点按账号、团队与画布隔离,不是跨机器备份 |
|
|
33
35
|
|
|
34
36
|
```bash
|
|
35
37
|
node "CANVAS_ENTRY" canvas command list
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# get-credit-balance
|
|
1
|
+
# get-credit-balance:当前空间积分余额
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
用于查询本次选择的个人或团队空间有效积分余额。默认沿用已保存的空间(通过 `space list` 查看),单次覆盖使用 `--team-id TEAM_ID`(`0` 为个人)。无需用户 ID 或任务 ID,不创建生成任务、不轮询,也不需要消耗积分的确认。
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
pippit-tool-cli get-credit-balance
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# model:发现可用图片与视频模型
|
|
2
2
|
|
|
3
|
-
需要有效登录或 `XYQ_ACCESS_KEY`。生成前可查询当前账号可用的模型及参数配置。`--type image` 查询图片,`--type video` 查询视频;省略时保持查询视频。两类查询共用 Skill 模型接口,图片请求的 `scene=web_image_agent`,视频请求的 `scene=web_turbo_video_generator`,`source_model_key`
|
|
3
|
+
需要有效登录或 `XYQ_ACCESS_KEY`。生成前可查询当前账号可用的模型及参数配置。`--type image` 查询图片,`--type video` 查询视频;省略时保持查询视频。两类查询共用 Skill 模型接口,图片请求的 `scene=web_image_agent`,视频请求的 `scene=web_turbo_video_generator`,`source_model_key` 为空。身份沿用当前 AK;团队空间请求携带 `X-Team-Id`(可用 `--team-id` 单次指定),API 内部仍按个人身份查询,模型列表不代表团队生成权限。
|
|
4
4
|
|
|
5
5
|
使用旧版 CLI 时先检查 `model --help` 是否支持图片名称查询,并确认 `generate-image --help` 的 `--model` 接受完整名称;仅支持视频或仍要求图片 key 时先升级,不能用视频结果回答图片模型问题。
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ const path = require("path");
|
|
|
8
8
|
|
|
9
9
|
const REQUIRED_COMMANDS = [
|
|
10
10
|
"status", "login", "logout", "query-result",
|
|
11
|
+
"space list", "space use",
|
|
11
12
|
"generate-image", "generate-video", "video-super-resolution",
|
|
12
13
|
"erase-video-subtitle", "get-credit-balance", "model list", "model describe",
|
|
13
14
|
];
|
|
@@ -85,7 +86,13 @@ function ensureCLI({ canvas = false } = {}) {
|
|
|
85
86
|
}
|
|
86
87
|
for (const command of commands) {
|
|
87
88
|
try {
|
|
88
|
-
run(cliPath, [...command, "--help"], `检查 ${command.join(" ")} 命令`, true);
|
|
89
|
+
const help = run(cliPath, [...command, "--help"], `检查 ${command.join(" ")} 命令`, true).toString();
|
|
90
|
+
// --team-id is inherited from the root; reuse an existing business help check.
|
|
91
|
+
if (command[0] === "generate-image" && !/(?:^|\s)--team-id(?:[=\s,]|$)/m.test(help)) {
|
|
92
|
+
const failure = new Error("CLI 缺少 --team-id 参数。");
|
|
93
|
+
failure.missingCommand = "generate-image --team-id";
|
|
94
|
+
throw failure;
|
|
95
|
+
}
|
|
89
96
|
} catch (err) {
|
|
90
97
|
if (Number.isInteger(err.exitStatus) && err.exitStatus !== 0) {
|
|
91
98
|
err.missingCommand = command.join(" ");
|
|
@@ -12,7 +12,7 @@ node "{baseDir}/scripts/ensure-cli.js"
|
|
|
12
12
|
|
|
13
13
|
## 查找与复用
|
|
14
14
|
|
|
15
|
-
脚本依次检查 PATH 中的 CLI 和自身缓存,验证版本及本 Skill 使用命令的 `--help`;命令集合维护在脚本的 `REQUIRED_COMMANDS`,包含 `model list` 和 `
|
|
15
|
+
脚本依次检查 PATH 中的 CLI 和自身缓存,验证版本及本 Skill 使用命令的 `--help`;命令集合维护在脚本的 `REQUIRED_COMMANDS`,包含 `model list`、`model describe`、`space list` 和 `space use`。同时从 `generate-image --help` 检查各业务命令共用的全局 `--team-id` 参数;缺少该参数时沿用缺少必需命令的升级流程。帮助检查不调用生成服务,也不需要凭据,不证明账号权限或服务端运行状态。
|
|
16
16
|
|
|
17
17
|
命令齐全则直接复用,不检查最新版本;不存在或缺少必需命令时,获取 `@pippit-dev/cli@latest`。PATH 旧版本缺少命令但缓存完整时复用缓存,避免每次升级。版本命令不能运行或检查超时则报告运行错误。
|
|
18
18
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
适用于 [Canvas](../commands/canvas.md) 任务。该流程以画布状态为交付对象,创建、编辑不会自动产生可交付媒体文件。
|
|
4
4
|
|
|
5
|
-
1. **准备入口**:执行 Canvas 安装检查,保存 `cli_path` 和 `canvas_entry
|
|
5
|
+
1. **准备入口**:执行 Canvas 安装检查,保存 `cli_path` 和 `canvas_entry`,按授权文档确认身份,并按 Space Selection 确定 TeamID。后续独立命令均显式使用同一 `--team-id TEAM_ID`,个人为 `0`;已有画布沿用原空间。只查命令目录和离线指南无需登录;查询真实画布、执行编辑需要授权。
|
|
6
6
|
2. **确定目标**:已有画布使用真实 `canvas_asset_id` 作为语义命令的 `--canvas-id`。用户提供的信息无法唯一定位时先补齐,不创建替代画布。新画布仅在用户要求创建时使用原生 `canvas create`,检查其返回状态。
|
|
7
7
|
3. **发现与查询**:`list → describe/schema` 定位操作。用 `get_snapshot` 查节点,用 `get_asset` 查具体资产;3D/多轨再查询其独立文档。`run` 是统一执行入口,其中 query/get 类操作是读取,不等于所有 run 都是写入。
|
|
8
8
|
4. **准备输入**:使用查询所得的节点、子对象和资产 ID。多轨 `expectedRevision` 来自最新查询。复杂输入写入 JSON 文件后传 `--file`;不要同时传 `--file` 和 `--input`。只操作用户指定范围。
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
语义执行骨架(占位符替换为当前目录中的命令、真实 ID 和已准备的输入文件):
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
node "CANVAS_ENTRY" canvas command run COMMAND_NAME --canvas-id CANVAS_ASSET_ID --file "/path/to/input.json"
|
|
16
|
+
node "CANVAS_ENTRY" canvas command run COMMAND_NAME --canvas-id CANVAS_ASSET_ID --team-id TEAM_ID --file "/path/to/input.json"
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
写请求失败或返回“未确认事务已隔离”时保留错误上下文,先回读状态,不自动重跑、不删除本地恢复记录。多轨版本冲突需重新查询并基于新状态准备操作;检查点恢复会改变画布,不能作为所有失败的自动回滚方式。
|