@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.
Files changed (104) hide show
  1. package/README.md +56 -0
  2. package/bin/run.js +5 -0
  3. package/dist/auth/credential-store.d.ts +6 -0
  4. package/dist/auth/credential-store.js +27 -0
  5. package/dist/auth/google-oauth.d.ts +2 -0
  6. package/dist/auth/google-oauth.js +72 -0
  7. package/dist/auth/session-manager.d.ts +44 -0
  8. package/dist/auth/session-manager.js +100 -0
  9. package/dist/base-command.d.ts +11 -0
  10. package/dist/base-command.js +39 -0
  11. package/dist/client/api-client.d.ts +23 -0
  12. package/dist/client/api-client.js +64 -0
  13. package/dist/client/errors.d.ts +14 -0
  14. package/dist/client/errors.js +34 -0
  15. package/dist/command-helpers.d.ts +10 -0
  16. package/dist/command-helpers.js +24 -0
  17. package/dist/commands/auth/login.d.ts +14 -0
  18. package/dist/commands/auth/login.js +32 -0
  19. package/dist/commands/auth/logout.d.ts +11 -0
  20. package/dist/commands/auth/logout.js +12 -0
  21. package/dist/commands/auth/status.d.ts +11 -0
  22. package/dist/commands/auth/status.js +12 -0
  23. package/dist/commands/canvas/apply.d.ts +12 -0
  24. package/dist/commands/canvas/apply.js +7 -0
  25. package/dist/commands/canvas/asset/download.d.ts +16 -0
  26. package/dist/commands/canvas/asset/download.js +34 -0
  27. package/dist/commands/canvas/asset/get.d.ts +14 -0
  28. package/dist/commands/canvas/asset/get.js +12 -0
  29. package/dist/commands/canvas/asset/list.d.ts +13 -0
  30. package/dist/commands/canvas/asset/list.js +7 -0
  31. package/dist/commands/canvas/asset/select.d.ts +15 -0
  32. package/dist/commands/canvas/asset/select.js +8 -0
  33. package/dist/commands/canvas/asset/upload.d.ts +14 -0
  34. package/dist/commands/canvas/asset/upload.js +10 -0
  35. package/dist/commands/canvas/edge/connect.d.ts +13 -0
  36. package/dist/commands/canvas/edge/connect.js +9 -0
  37. package/dist/commands/canvas/edge/disconnect.d.ts +15 -0
  38. package/dist/commands/canvas/edge/disconnect.js +8 -0
  39. package/dist/commands/canvas/edge/list.d.ts +11 -0
  40. package/dist/commands/canvas/edge/list.js +10 -0
  41. package/dist/commands/canvas/get.d.ts +11 -0
  42. package/dist/commands/canvas/get.js +6 -0
  43. package/dist/commands/canvas/node/add.d.ts +18 -0
  44. package/dist/commands/canvas/node/add.js +8 -0
  45. package/dist/commands/canvas/node/delete.d.ts +15 -0
  46. package/dist/commands/canvas/node/delete.js +8 -0
  47. package/dist/commands/canvas/node/get.d.ts +14 -0
  48. package/dist/commands/canvas/node/get.js +12 -0
  49. package/dist/commands/canvas/node/list.d.ts +11 -0
  50. package/dist/commands/canvas/node/list.js +10 -0
  51. package/dist/commands/canvas/node/run.d.ts +16 -0
  52. package/dist/commands/canvas/node/run.js +11 -0
  53. package/dist/commands/canvas/node/types.d.ts +13 -0
  54. package/dist/commands/canvas/node/types.js +8 -0
  55. package/dist/commands/canvas/node/update.d.ts +15 -0
  56. package/dist/commands/canvas/node/update.js +8 -0
  57. package/dist/commands/config/get.d.ts +10 -0
  58. package/dist/commands/config/get.js +6 -0
  59. package/dist/commands/config/set.d.ts +11 -0
  60. package/dist/commands/config/set.js +7 -0
  61. package/dist/commands/project/create.d.ts +12 -0
  62. package/dist/commands/project/create.js +7 -0
  63. package/dist/commands/project/delete.d.ts +14 -0
  64. package/dist/commands/project/delete.js +8 -0
  65. package/dist/commands/project/get.d.ts +13 -0
  66. package/dist/commands/project/get.js +8 -0
  67. package/dist/commands/project/list.d.ts +14 -0
  68. package/dist/commands/project/list.js +13 -0
  69. package/dist/commands/project/update.d.ts +15 -0
  70. package/dist/commands/project/update.js +9 -0
  71. package/dist/commands/skill/install.d.ts +13 -0
  72. package/dist/commands/skill/install.js +8 -0
  73. package/dist/commands/skill/path.d.ts +10 -0
  74. package/dist/commands/skill/path.js +6 -0
  75. package/dist/commands/skill/status.d.ts +12 -0
  76. package/dist/commands/skill/status.js +7 -0
  77. package/dist/commands/skill/update.d.ts +1 -0
  78. package/dist/commands/skill/update.js +1 -0
  79. package/dist/commands/task/cancel.d.ts +14 -0
  80. package/dist/commands/task/cancel.js +8 -0
  81. package/dist/commands/task/get.d.ts +13 -0
  82. package/dist/commands/task/get.js +8 -0
  83. package/dist/commands/task/wait.d.ts +14 -0
  84. package/dist/commands/task/wait.js +9 -0
  85. package/dist/config/profiles.d.ts +15 -0
  86. package/dist/config/profiles.js +47 -0
  87. package/dist/domain/vvicat-api.d.ts +84 -0
  88. package/dist/domain/vvicat-api.js +144 -0
  89. package/dist/index.d.ts +1 -0
  90. package/dist/index.js +1 -0
  91. package/dist/output/formatter.d.ts +1 -0
  92. package/dist/output/formatter.js +3 -0
  93. package/dist/runtime.d.ts +14 -0
  94. package/dist/runtime.js +45 -0
  95. package/dist/skill/command-flags.d.ts +8 -0
  96. package/dist/skill/command-flags.js +9 -0
  97. package/dist/skill/skill-manager.d.ts +24 -0
  98. package/dist/skill/skill-manager.js +100 -0
  99. package/dist/terminal/prompt.d.ts +2 -0
  100. package/dist/terminal/prompt.js +49 -0
  101. package/package.json +55 -0
  102. package/skills/using-vvicat-cli/SKILL.md +49 -0
  103. package/skills/using-vvicat-cli/agents/openai.yaml +4 -0
  104. 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,2 @@
1
+ export declare function promptLine(label: string): Promise<string>;
2
+ export declare function promptPassword(label: string): Promise<string>;
@@ -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,4 @@
1
+ interface:
2
+ display_name: "使用 VVICAT CLI"
3
+ short_description: "通过命令行安全操作 VVICAT 无限画布项目与产物"
4
+ default_prompt: "使用 $using-vvicat-cli 安全地完成 VVICAT 无限画布项目、节点、任务、产物或模型配置操作。"
@@ -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` 缺省时保留现有密钥,空字符串表示清除;敏感配置文件不要提交到版本库。