@aswless_854771076/ai_short_studio_cli 0.1.0-beta.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.
- package/README.md +56 -0
- package/bin/run.js +5 -0
- package/dist/auth/credential-store.d.ts +6 -0
- package/dist/auth/credential-store.js +27 -0
- package/dist/auth/google-oauth.d.ts +2 -0
- package/dist/auth/google-oauth.js +72 -0
- package/dist/auth/session-manager.d.ts +44 -0
- package/dist/auth/session-manager.js +100 -0
- package/dist/base-command.d.ts +11 -0
- package/dist/base-command.js +39 -0
- package/dist/client/api-client.d.ts +23 -0
- package/dist/client/api-client.js +64 -0
- package/dist/client/errors.d.ts +14 -0
- package/dist/client/errors.js +34 -0
- package/dist/command-helpers.d.ts +10 -0
- package/dist/command-helpers.js +24 -0
- package/dist/commands/auth/login.d.ts +14 -0
- package/dist/commands/auth/login.js +32 -0
- package/dist/commands/auth/logout.d.ts +11 -0
- package/dist/commands/auth/logout.js +12 -0
- package/dist/commands/auth/status.d.ts +11 -0
- package/dist/commands/auth/status.js +12 -0
- package/dist/commands/canvas/apply.d.ts +12 -0
- package/dist/commands/canvas/apply.js +7 -0
- package/dist/commands/canvas/asset/download.d.ts +16 -0
- package/dist/commands/canvas/asset/download.js +34 -0
- package/dist/commands/canvas/asset/get.d.ts +14 -0
- package/dist/commands/canvas/asset/get.js +12 -0
- package/dist/commands/canvas/asset/list.d.ts +13 -0
- package/dist/commands/canvas/asset/list.js +7 -0
- package/dist/commands/canvas/asset/select.d.ts +15 -0
- package/dist/commands/canvas/asset/select.js +8 -0
- package/dist/commands/canvas/asset/upload.d.ts +14 -0
- package/dist/commands/canvas/asset/upload.js +10 -0
- package/dist/commands/canvas/edge/connect.d.ts +13 -0
- package/dist/commands/canvas/edge/connect.js +9 -0
- package/dist/commands/canvas/edge/disconnect.d.ts +15 -0
- package/dist/commands/canvas/edge/disconnect.js +8 -0
- package/dist/commands/canvas/edge/list.d.ts +11 -0
- package/dist/commands/canvas/edge/list.js +10 -0
- package/dist/commands/canvas/get.d.ts +11 -0
- package/dist/commands/canvas/get.js +6 -0
- package/dist/commands/canvas/node/add.d.ts +18 -0
- package/dist/commands/canvas/node/add.js +8 -0
- package/dist/commands/canvas/node/delete.d.ts +15 -0
- package/dist/commands/canvas/node/delete.js +8 -0
- package/dist/commands/canvas/node/get.d.ts +14 -0
- package/dist/commands/canvas/node/get.js +12 -0
- package/dist/commands/canvas/node/list.d.ts +11 -0
- package/dist/commands/canvas/node/list.js +10 -0
- package/dist/commands/canvas/node/run.d.ts +16 -0
- package/dist/commands/canvas/node/run.js +11 -0
- package/dist/commands/canvas/node/types.d.ts +13 -0
- package/dist/commands/canvas/node/types.js +8 -0
- package/dist/commands/canvas/node/update.d.ts +15 -0
- package/dist/commands/canvas/node/update.js +8 -0
- package/dist/commands/config/get.d.ts +10 -0
- package/dist/commands/config/get.js +6 -0
- package/dist/commands/config/set.d.ts +11 -0
- package/dist/commands/config/set.js +7 -0
- package/dist/commands/project/create.d.ts +12 -0
- package/dist/commands/project/create.js +7 -0
- package/dist/commands/project/delete.d.ts +14 -0
- package/dist/commands/project/delete.js +8 -0
- package/dist/commands/project/get.d.ts +13 -0
- package/dist/commands/project/get.js +8 -0
- package/dist/commands/project/list.d.ts +14 -0
- package/dist/commands/project/list.js +13 -0
- package/dist/commands/project/update.d.ts +15 -0
- package/dist/commands/project/update.js +9 -0
- package/dist/commands/skill/install.d.ts +13 -0
- package/dist/commands/skill/install.js +8 -0
- package/dist/commands/skill/path.d.ts +10 -0
- package/dist/commands/skill/path.js +6 -0
- package/dist/commands/skill/status.d.ts +12 -0
- package/dist/commands/skill/status.js +7 -0
- package/dist/commands/skill/update.d.ts +1 -0
- package/dist/commands/skill/update.js +1 -0
- package/dist/commands/task/cancel.d.ts +14 -0
- package/dist/commands/task/cancel.js +8 -0
- package/dist/commands/task/get.d.ts +13 -0
- package/dist/commands/task/get.js +8 -0
- package/dist/commands/task/wait.d.ts +14 -0
- package/dist/commands/task/wait.js +9 -0
- package/dist/config/profiles.d.ts +15 -0
- package/dist/config/profiles.js +47 -0
- package/dist/domain/vvicat-api.d.ts +84 -0
- package/dist/domain/vvicat-api.js +144 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/output/formatter.d.ts +1 -0
- package/dist/output/formatter.js +3 -0
- package/dist/runtime.d.ts +14 -0
- package/dist/runtime.js +45 -0
- package/dist/skill/command-flags.d.ts +8 -0
- package/dist/skill/command-flags.js +9 -0
- package/dist/skill/skill-manager.d.ts +24 -0
- package/dist/skill/skill-manager.js +100 -0
- package/dist/terminal/prompt.d.ts +2 -0
- package/dist/terminal/prompt.js +49 -0
- package/package.json +55 -0
- package/skills/using-vvicat-cli/SKILL.md +49 -0
- package/skills/using-vvicat-cli/agents/openai.yaml +4 -0
- package/skills/using-vvicat-cli/references/commands.md +90 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { cp, mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join, relative } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
const BUNDLED_SKILL = fileURLToPath(new URL('../../skills/using-vvicat-cli', import.meta.url));
|
|
7
|
+
const PACKAGE_JSON = fileURLToPath(new URL('../../package.json', import.meta.url));
|
|
8
|
+
const MANIFEST = '.vvicat-skill.json';
|
|
9
|
+
export function bundledSkillPath() {
|
|
10
|
+
return BUNDLED_SKILL;
|
|
11
|
+
}
|
|
12
|
+
export function defaultSkillTarget(target) {
|
|
13
|
+
return join(homedir(), target === 'codex' ? '.codex' : '.agents', 'skills', 'using-vvicat-cli');
|
|
14
|
+
}
|
|
15
|
+
export async function skillStatus(target) {
|
|
16
|
+
const packageVersion = await readPackageVersion();
|
|
17
|
+
const bundledChecksum = await directoryChecksum(BUNDLED_SKILL);
|
|
18
|
+
const installed = await exists(target);
|
|
19
|
+
const manifest = installed ? await readManifest(target) : null;
|
|
20
|
+
const installedChecksum = installed ? await directoryChecksum(target) : null;
|
|
21
|
+
return {
|
|
22
|
+
target,
|
|
23
|
+
installed,
|
|
24
|
+
managed: Boolean(manifest),
|
|
25
|
+
current: Boolean(manifest && manifest.packageVersion === packageVersion && installedChecksum === bundledChecksum),
|
|
26
|
+
packageVersion,
|
|
27
|
+
installedVersion: manifest?.packageVersion ?? null,
|
|
28
|
+
modified: Boolean(manifest && installedChecksum !== manifest.checksum),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export async function installSkill(input) {
|
|
32
|
+
const current = await skillStatus(input.target);
|
|
33
|
+
if (current.installed && !input.force) {
|
|
34
|
+
if (!current.managed)
|
|
35
|
+
throw new Error('目标目录不是 CLI 管理的 Skill;使用 --force 才能替换');
|
|
36
|
+
if (current.modified)
|
|
37
|
+
throw new Error('已安装 Skill 已被修改;使用 --force 才能替换');
|
|
38
|
+
}
|
|
39
|
+
const checksum = await directoryChecksum(BUNDLED_SKILL);
|
|
40
|
+
const packageVersion = await readPackageVersion();
|
|
41
|
+
const temporary = `${input.target}.tmp-${process.pid}`;
|
|
42
|
+
const backup = `${input.target}.backup-${process.pid}`;
|
|
43
|
+
await mkdir(dirname(input.target), { recursive: true });
|
|
44
|
+
await rm(temporary, { recursive: true, force: true });
|
|
45
|
+
await cp(BUNDLED_SKILL, temporary, { recursive: true });
|
|
46
|
+
await writeFile(join(temporary, MANIFEST), `${JSON.stringify({ packageVersion, checksum }, null, 2)}\n`, 'utf8');
|
|
47
|
+
const hadTarget = await exists(input.target);
|
|
48
|
+
try {
|
|
49
|
+
if (hadTarget)
|
|
50
|
+
await rename(input.target, backup);
|
|
51
|
+
await rename(temporary, input.target);
|
|
52
|
+
if (hadTarget)
|
|
53
|
+
await rm(backup, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
await rm(temporary, { recursive: true, force: true });
|
|
57
|
+
if (hadTarget && await exists(backup) && !await exists(input.target))
|
|
58
|
+
await rename(backup, input.target);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
return skillStatus(input.target);
|
|
62
|
+
}
|
|
63
|
+
async function directoryChecksum(root) {
|
|
64
|
+
const files = await filesBelow(root);
|
|
65
|
+
const hash = createHash('sha256');
|
|
66
|
+
for (const file of files.filter((item) => relative(root, item) !== MANIFEST).sort()) {
|
|
67
|
+
hash.update(relative(root, file));
|
|
68
|
+
hash.update(await readFile(file));
|
|
69
|
+
}
|
|
70
|
+
return hash.digest('hex');
|
|
71
|
+
}
|
|
72
|
+
async function filesBelow(root) {
|
|
73
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
74
|
+
const files = [];
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const path = join(root, entry.name);
|
|
77
|
+
if (entry.isDirectory())
|
|
78
|
+
files.push(...await filesBelow(path));
|
|
79
|
+
else if (entry.isFile())
|
|
80
|
+
files.push(path);
|
|
81
|
+
}
|
|
82
|
+
return files;
|
|
83
|
+
}
|
|
84
|
+
async function readManifest(root) {
|
|
85
|
+
try {
|
|
86
|
+
const value = JSON.parse(await readFile(join(root, MANIFEST), 'utf8'));
|
|
87
|
+
return typeof value.packageVersion === 'string' && typeof value.checksum === 'string'
|
|
88
|
+
? { packageVersion: value.packageVersion, checksum: value.checksum }
|
|
89
|
+
: null;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function readPackageVersion() {
|
|
96
|
+
return JSON.parse(await readFile(PACKAGE_JSON, 'utf8')).version;
|
|
97
|
+
}
|
|
98
|
+
async function exists(path) {
|
|
99
|
+
return stat(path).then(() => true, () => false);
|
|
100
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline/promises';
|
|
2
|
+
export async function promptLine(label) {
|
|
3
|
+
const terminal = createInterface({ input: process.stdin, output: process.stderr });
|
|
4
|
+
try {
|
|
5
|
+
const value = (await terminal.question(label)).trim();
|
|
6
|
+
if (!value)
|
|
7
|
+
throw new Error('输入不能为空');
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
terminal.close();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function promptPassword(label) {
|
|
15
|
+
if (!process.stdin.isTTY || typeof process.stdin.setRawMode !== 'function') {
|
|
16
|
+
throw new Error('非交互终端请使用 --password-stdin');
|
|
17
|
+
}
|
|
18
|
+
process.stderr.write(label);
|
|
19
|
+
process.stdin.setRawMode(true);
|
|
20
|
+
process.stdin.resume();
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let value = '';
|
|
23
|
+
const finish = (error) => {
|
|
24
|
+
process.stdin.off('data', onData);
|
|
25
|
+
process.stdin.setRawMode(false);
|
|
26
|
+
process.stdin.pause();
|
|
27
|
+
process.stderr.write('\n');
|
|
28
|
+
if (error)
|
|
29
|
+
reject(error);
|
|
30
|
+
else if (!value)
|
|
31
|
+
reject(new Error('密码不能为空'));
|
|
32
|
+
else
|
|
33
|
+
resolve(value);
|
|
34
|
+
};
|
|
35
|
+
const onData = (chunk) => {
|
|
36
|
+
const text = chunk.toString('utf8');
|
|
37
|
+
if (text === '\u0003')
|
|
38
|
+
return finish(new Error('已取消'));
|
|
39
|
+
if (text === '\r' || text === '\n')
|
|
40
|
+
return finish();
|
|
41
|
+
if (text === '\u007f') {
|
|
42
|
+
value = value.slice(0, -1);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
value += text;
|
|
46
|
+
};
|
|
47
|
+
process.stdin.on('data', onData);
|
|
48
|
+
});
|
|
49
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aswless_854771076/ai_short_studio_cli",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "VVICAT 无限画布项目命令行工具",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/854771076/waoowaoo.git",
|
|
10
|
+
"directory": "packages/ai_short_studio_cli"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/854771076/waoowaoo#readme",
|
|
13
|
+
"bugs": "https://github.com/854771076/waoowaoo/issues",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"bin": {
|
|
19
|
+
"vvicat": "bin/run.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"dist",
|
|
24
|
+
"skills",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "node scripts/clean.mjs && tsc -p tsconfig.json",
|
|
32
|
+
"prepack": "npm run build",
|
|
33
|
+
"release:dry-run": "node scripts/publish.mjs --dry-run",
|
|
34
|
+
"release:test": "node scripts/publish.mjs --name @aswless_854771076/ai_short_studio_cli --tag beta",
|
|
35
|
+
"release": "node scripts/publish.mjs --tag latest",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
41
|
+
"@oclif/core": "^4.12.0",
|
|
42
|
+
"@supabase/supabase-js": "^2.110.7"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.19.43",
|
|
46
|
+
"typescript": "^5.9.3",
|
|
47
|
+
"vitest": "^2.1.9"
|
|
48
|
+
},
|
|
49
|
+
"oclif": {
|
|
50
|
+
"bin": "vvicat",
|
|
51
|
+
"dirname": "vvicat",
|
|
52
|
+
"commands": "./dist/commands",
|
|
53
|
+
"topicSeparator": " "
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: using-vvicat-cli
|
|
3
|
+
description: Use when an agent needs to inspect or operate VVICAT infinite-canvas projects, nodes, edges, assets, tasks, or model configuration through the vvicat CLI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 使用 VVICAT CLI
|
|
7
|
+
|
|
8
|
+
## 核心原则
|
|
9
|
+
|
|
10
|
+
把 `vvicat` 当作机器可读的远程控制接口。先读取服务端节点目录和实时画布,再构造写操作;不要猜测节点类型、端口或数据结构。
|
|
11
|
+
|
|
12
|
+
## 工作流
|
|
13
|
+
|
|
14
|
+
1. 运行 `vvicat auth status --json`。未登录时优先运行 `vvicat auth login --google`;非交互环境才通过 stdin 传密码。
|
|
15
|
+
若 Skill 来自 CLI 安装,先运行 `vvicat skill status --json`;`current` 为 false 时提示用户运行 `vvicat skill update`。
|
|
16
|
+
2. 运行 `vvicat project list --json`,确认目标是 `INFINITE_CANVAS`。创建测试项目时使用唯一前缀,并记录项目 ID。
|
|
17
|
+
3. 操作节点前运行 `vvicat canvas node types --json`。严格按返回的 `inputSchema`、`outputSchema`、`configSchema` 和 `defaultConfig` 构造数据。
|
|
18
|
+
4. 写入前运行 `vvicat canvas get --project <id> --json` 获取当前结构;优先使用专用 node/edge 命令,批量变更才用 `canvas apply`。
|
|
19
|
+
5. 执行节点后读取返回的任务 ID,并用 `vvicat task wait <taskId> --json` 等待终态。不要使用固定时长 sleep。
|
|
20
|
+
6. 下载前读取资产及所选版本,再使用 `canvas asset download` 写入明确目录。
|
|
21
|
+
7. 对临时项目始终在结束路径中执行 `vvicat project delete <id> --yes`,包括命令失败时。
|
|
22
|
+
|
|
23
|
+
详细命令按需读取 [references/commands.md](references/commands.md),或运行 `vvicat <topic> --help`。
|
|
24
|
+
|
|
25
|
+
## 安全边界
|
|
26
|
+
|
|
27
|
+
- 不把密码、access token、refresh token 或 API Key 放入参数、日志、Skill 或仓库。
|
|
28
|
+
- 密码登录使用 `printf`/管道以外的安全 stdin 来源;自动化环境使用秘密管理器注入 stdin。
|
|
29
|
+
- `config get` 只应返回 `hasApiKey`,不得依赖或要求服务端回显密钥。
|
|
30
|
+
- 删除用户既有项目、覆盖完整画布或修改模型配置前,先明确目标和影响;没有授权就停在读取或生成变更计划。
|
|
31
|
+
- 对版本冲突重新读取画布后重算变更,不盲目重试旧的 `expectedVersion`。
|
|
32
|
+
|
|
33
|
+
## 示例
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
vvicat canvas node types --json
|
|
37
|
+
vvicat project create --name "agent-draft-20260722" --json
|
|
38
|
+
vvicat canvas node add text --project "$PROJECT_ID" --config ./node.json --json
|
|
39
|
+
vvicat canvas node list --project "$PROJECT_ID" --json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
从 JSON 输出中取得真实 ID;示例中的环境变量仅表示调用方已安全解析并保存结果。
|
|
43
|
+
|
|
44
|
+
## 常见错误
|
|
45
|
+
|
|
46
|
+
- 节点类型写死:先读 `canvas node types`,服务端目录才是事实来源。
|
|
47
|
+
- 只检查任务创建响应:必须 `task wait` 并检查终态和错误字段。
|
|
48
|
+
- 下载列表中的任意 URL:先确认资产的 selected version,再下载。
|
|
49
|
+
- 测试创建资源但未清理:用调用方的 `finally`/trap 删除唯一前缀项目。
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# 命令参考
|
|
2
|
+
|
|
3
|
+
所有命令支持 `--base-url`、`--profile`、`--locale zh|en` 和 `--json`。默认档案保存服务地址与默认项目;refresh token 仅保存在系统钥匙串。
|
|
4
|
+
|
|
5
|
+
## Skill 管理
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
vvicat skill path --json
|
|
9
|
+
vvicat skill install --target codex --json
|
|
10
|
+
vvicat skill status --target codex --json
|
|
11
|
+
vvicat skill update --target codex --json
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`--target agents` 安装到 `~/.agents/skills`,`--directory` 可指定其他目录。更新不会覆盖用户修改,除非显式传入 `--force`。
|
|
15
|
+
|
|
16
|
+
## 认证
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
vvicat auth login --google
|
|
20
|
+
vvicat auth login --email user@example.com --password-stdin
|
|
21
|
+
vvicat auth status --json
|
|
22
|
+
vvicat auth logout
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Google 登录会打开浏览器并通过本机环回地址完成 PKCE 回调。
|
|
26
|
+
|
|
27
|
+
## 项目
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
vvicat project list --json
|
|
31
|
+
vvicat project get <projectId> --json
|
|
32
|
+
vvicat project create --name <name> [--description <text>] --json
|
|
33
|
+
vvicat project update <projectId> [--name <name>] [--description <text>] --json
|
|
34
|
+
vvicat project delete <projectId> --yes --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
创建操作固定写入 `INFINITE_CANVAS`;列表也只返回该类型。
|
|
38
|
+
|
|
39
|
+
## 画布和节点
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
vvicat canvas get --project <projectId> --json
|
|
43
|
+
vvicat canvas apply --project <projectId> --file <patch.json> --json
|
|
44
|
+
vvicat canvas node types --json
|
|
45
|
+
vvicat canvas node list --project <projectId> --json
|
|
46
|
+
vvicat canvas node get <nodeId> --project <projectId> --json
|
|
47
|
+
vvicat canvas node add <kind> --project <projectId> [--x N] [--y N] [--title <text>] [--config <config.json>] --json
|
|
48
|
+
vvicat canvas node update <nodeId> --project <projectId> --config <config.json> --json
|
|
49
|
+
vvicat canvas node delete <nodeId> --project <projectId> --yes --json
|
|
50
|
+
vvicat canvas node run <nodeId> --project <projectId> --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`canvas apply` 的 JSON 可以通过 `--file` 读取;省略文件时从 stdin 读取。提交批量变更时携带最近读取到的 `canvasId` 与 `expectedVersion`。
|
|
54
|
+
|
|
55
|
+
## 连线
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
vvicat canvas edge list --project <projectId> --json
|
|
59
|
+
vvicat canvas edge connect --project <projectId> --source-node <id> --source-handle <name> --target-node <id> --target-handle <name> --json
|
|
60
|
+
vvicat canvas edge disconnect <edgeId> --project <projectId> --yes --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
handle 名称来自节点类型目录中的输入输出 schema,不要自行推断。
|
|
64
|
+
|
|
65
|
+
## 资产与下载
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
vvicat canvas asset list --project <projectId> --json
|
|
69
|
+
vvicat canvas asset get <assetId> --project <projectId> --json
|
|
70
|
+
vvicat canvas asset upload <file> --project <projectId> --json
|
|
71
|
+
vvicat canvas asset select <assetId> <versionId> --project <projectId> --json
|
|
72
|
+
vvicat canvas asset download <assetId> --project <projectId> --output <directory>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 异步任务
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
vvicat task get <taskId> --json
|
|
79
|
+
vvicat task wait <taskId> [--interval 1000] --json
|
|
80
|
+
vvicat task cancel <taskId> --yes --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 模型配置
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
vvicat config get --json
|
|
87
|
+
vvicat config set --file <config.json> --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`config set` 接受 `models`、`providers`、`defaultModels`、`capabilityDefaults`、`workflowConcurrency` 的部分对象。provider 的 `apiKey` 缺省时保留现有密钥,空字符串表示清除;敏感配置文件不要提交到版本库。
|