@aswless_854771076/ai_short_studio_cli 0.1.43 → 0.1.45

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.
@@ -3,6 +3,50 @@ import { BaseCommand } from '../../../base-command.js';
3
3
  import { commandApi, projectFlag, readJsonInput } from '../../../command-helpers.js';
4
4
  export default class CanvasNodeUpdate extends BaseCommand {
5
5
  static args = { nodeId: Args.string({ required: true }) };
6
- static flags = { ...BaseCommand.baseFlags, project: projectFlag, config: Flags.string({ description: '配置 JSON 文件;省略时读取 stdin' }) };
7
- async run() { const { args, flags } = await this.parse(CanvasNodeUpdate); const { api } = await commandApi(flags); this.print(await api.updateNode(flags.project, args.nodeId, await readJsonInput(flags.config))); }
6
+ static flags = {
7
+ ...BaseCommand.baseFlags,
8
+ project: projectFlag,
9
+ config: Flags.string({ description: '配置 patch JSON 文件;无字段参数时省略可读取 stdin' }),
10
+ set: Flags.string({ description: '设置配置字段:key=<JSON>,可重复指定', multiple: true }),
11
+ unset: Flags.string({ description: '删除可选配置字段,可重复指定', multiple: true }),
12
+ title: Flags.string({ description: '修改节点标题' }),
13
+ x: Flags.integer({ description: '修改节点横坐标' }),
14
+ y: Flags.integer({ description: '修改节点纵坐标' }),
15
+ };
16
+ async run() {
17
+ const { args, flags } = await this.parse(CanvasNodeUpdate);
18
+ const hasFieldFlags = Boolean(flags.set?.length || flags.unset?.length || flags.title !== undefined || flags.x !== undefined || flags.y !== undefined);
19
+ const filePatch = flags.config || !hasFieldFlags ? await readJsonInput(flags.config) : {};
20
+ const set = { ...filePatch, ...parseAssignments(flags.set ?? []) };
21
+ const unset = flags.unset ?? [];
22
+ const overlap = unset.find((key) => Object.prototype.hasOwnProperty.call(set, key));
23
+ if (overlap)
24
+ throw new Error(`字段不能同时 set 和 unset:${overlap}`);
25
+ const { api } = await commandApi(flags);
26
+ this.print(await api.updateNodeFields(flags.project, {
27
+ nodeId: args.nodeId,
28
+ set,
29
+ unset,
30
+ title: flags.title,
31
+ x: flags.x,
32
+ y: flags.y,
33
+ }));
34
+ }
35
+ }
36
+ function parseAssignments(assignments) {
37
+ return Object.fromEntries(assignments.map((assignment) => {
38
+ const separator = assignment.indexOf('=');
39
+ if (separator < 1)
40
+ throw new Error(`--set 必须使用 key=<JSON>:${assignment}`);
41
+ const key = assignment.slice(0, separator).trim();
42
+ const source = assignment.slice(separator + 1);
43
+ if (!key)
44
+ throw new Error('--set 字段名不能为空');
45
+ try {
46
+ return [key, JSON.parse(source)];
47
+ }
48
+ catch {
49
+ return [key, source];
50
+ }
51
+ }));
8
52
  }
@@ -1,9 +1,11 @@
1
1
  import { BaseCommand } from '../../base-command.js';
2
2
  export default class TaskWait extends BaseCommand {
3
3
  static args: {
4
- taskId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ taskId: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
5
  };
6
6
  static flags: {
7
+ task: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ concurrency: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
7
9
  interval: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
10
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
11
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -1,9 +1,23 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import { BaseCommand } from '../../base-command.js';
3
- import { commandApi } from '../../command-helpers.js';
3
+ import { commandApi, mapConcurrent } from '../../command-helpers.js';
4
4
  export default class TaskWait extends BaseCommand {
5
- static args = { taskId: Args.string({ required: true }) };
6
- static flags = { ...BaseCommand.baseFlags, interval: Flags.integer({ default: 1000 }) };
7
- async run() { const { args, flags } = await this.parse(TaskWait); const { api } = await commandApi(flags); const task = await api.waitTask(args.taskId, flags.interval); this.print(task); if (task.status !== 'completed')
8
- this.error(`任务结束:${task.status}`, { exit: 8 }); }
5
+ static args = { taskId: Args.string({ required: false }) };
6
+ static flags = {
7
+ ...BaseCommand.baseFlags,
8
+ task: Flags.string({ description: '任务 ID,可重复指定以批量等待', multiple: true }),
9
+ concurrency: Flags.integer({ description: '批量轮询并发数', default: 4, min: 1, max: 16 }),
10
+ interval: Flags.integer({ default: 1000 }),
11
+ };
12
+ async run() {
13
+ const { args, flags } = await this.parse(TaskWait);
14
+ const taskIds = [...new Set([...(args.taskId ? [args.taskId] : []), ...(flags.task ?? [])])];
15
+ if (!taskIds.length)
16
+ throw new Error('请提供 taskId 或至少一个 --task');
17
+ const { api } = await commandApi(flags);
18
+ const tasks = await mapConcurrent(taskIds, flags.concurrency, async (taskId) => await api.waitTask(taskId, flags.interval));
19
+ this.print(tasks.length === 1 ? tasks[0] : { tasks });
20
+ if (tasks.some((task) => task.status !== 'completed'))
21
+ this.error('部分任务未成功完成', { exit: 8 });
22
+ }
9
23
  }
@@ -5,6 +5,7 @@ export interface CliProfile {
5
5
  supabaseUrl?: string;
6
6
  supabasePublishableKey?: string;
7
7
  }
8
+ export declare function defaultConfigDirectory(environment: NodeJS.ProcessEnv): string;
8
9
  export declare class ProfileStore {
9
10
  readonly path: string;
10
11
  constructor(directory?: string);
@@ -1,7 +1,7 @@
1
1
  import { homedir } from 'node:os';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
4
- function defaultConfigDirectory(environment) {
4
+ export function defaultConfigDirectory(environment) {
5
5
  if (environment.VVICAT_CONFIG_DIR)
6
6
  return environment.VVICAT_CONFIG_DIR;
7
7
  if (process.platform === 'win32')
@@ -28,6 +28,23 @@ interface NodeType extends JsonObject {
28
28
  defaultConfig: JsonObject;
29
29
  configSchema: JsonObject;
30
30
  }
31
+ export interface CanvasInspectOptions {
32
+ includes: Array<'summary' | 'nodes' | 'edges' | 'assets' | 'settings' | 'node-types'>;
33
+ kinds?: string[];
34
+ statuses?: string[];
35
+ search?: string;
36
+ operation?: string;
37
+ resourceType?: string;
38
+ producerNodeId?: string;
39
+ }
40
+ export interface NodeFieldUpdate {
41
+ nodeId: string;
42
+ set?: JsonObject;
43
+ unset?: string[];
44
+ title?: string;
45
+ x?: number;
46
+ y?: number;
47
+ }
31
48
  export declare class VvicatApi {
32
49
  private readonly client;
33
50
  private readonly sleep;
@@ -55,6 +72,7 @@ export declare class VvicatApi {
55
72
  listNodes(projectId: string): Promise<CanvasNode[]>;
56
73
  node(projectId: string, nodeId: string): Promise<CanvasNode>;
57
74
  listEdges(projectId: string): Promise<JsonObject[]>;
75
+ inspectCanvas(projectId: string, options: CanvasInspectOptions): Promise<JsonObject>;
58
76
  continuityAnalysis(projectId: string): Promise<JsonObject>;
59
77
  applyContinuity(projectId: string, input: {
60
78
  expectedVersion: number;
@@ -77,6 +95,8 @@ export declare class VvicatApi {
77
95
  config?: JsonObject;
78
96
  }): Promise<JsonObject>;
79
97
  updateNode(projectId: string, nodeId: string, config: JsonObject): Promise<JsonObject>;
98
+ updateNodeFields(projectId: string, update: NodeFieldUpdate): Promise<JsonObject>;
99
+ updateNodes(projectId: string, updates: NodeFieldUpdate[]): Promise<JsonObject>;
80
100
  deleteNode(projectId: string, nodeId: string): Promise<JsonObject>;
81
101
  connect(projectId: string, input: {
82
102
  sourceNodeId: string;
@@ -49,6 +49,15 @@ function validateConfigSchema(nodeType, config, requiredValues = config ?? {}) {
49
49
  }
50
50
  }
51
51
  }
52
+ function validateUnsetConfigFields(nodeType, fields) {
53
+ const properties = nodeType.configSchema?.properties;
54
+ if (!properties || typeof properties !== 'object' || Array.isArray(properties))
55
+ return;
56
+ for (const field of fields) {
57
+ if (!(field in properties))
58
+ throw new Error(`节点 ${nodeType.kind} 的 ${field} 不在实时 schema 中`);
59
+ }
60
+ }
52
61
  export class VvicatApi {
53
62
  client;
54
63
  sleep;
@@ -111,6 +120,29 @@ export class VvicatApi {
111
120
  async listEdges(projectId) {
112
121
  return (await this.canvas(projectId)).edges;
113
122
  }
123
+ async inspectCanvas(projectId, options) {
124
+ const canvas = await this.canvas(projectId);
125
+ const nodes = canvas.nodes.filter((node) => matchesInspectNode(node, options));
126
+ const nodeIds = new Set(nodes.map((node) => node.id));
127
+ const filtered = hasInspectFilter(options);
128
+ const edges = filtered
129
+ ? canvas.edges.filter((edge) => nodeIds.has(String(edge.sourceNodeId)) || nodeIds.has(String(edge.targetNodeId)))
130
+ : canvas.edges;
131
+ const [assets, settings, nodeTypes] = await Promise.all([
132
+ options.includes.includes('assets') ? this.listAssets(projectId) : undefined,
133
+ options.includes.includes('settings') ? this.canvasSettings(projectId) : undefined,
134
+ options.includes.includes('node-types') ? this.nodeTypes() : undefined,
135
+ ]);
136
+ return {
137
+ canvas: { id: canvas.id, version: canvas.version, viewport: canvas.viewport },
138
+ ...(options.includes.includes('summary') ? { summary: canvasSummary(canvas, nodes) } : {}),
139
+ ...(options.includes.includes('nodes') ? { nodes } : {}),
140
+ ...(options.includes.includes('edges') ? { edges } : {}),
141
+ ...(assets === undefined ? {} : { assets }),
142
+ ...(settings === undefined ? {} : { settings }),
143
+ ...(nodeTypes === undefined ? {} : { nodeTypes }),
144
+ };
145
+ }
114
146
  async continuityAnalysis(projectId) {
115
147
  const payload = await this.client.request(`/api/projects/${projectId}/canvas/continuity`);
116
148
  return payload.data.analysis;
@@ -163,22 +195,48 @@ export class VvicatApi {
163
195
  });
164
196
  }
165
197
  async updateNode(projectId, nodeId, config) {
166
- const canvas = await this.canvas(projectId);
167
- const node = canvas.nodes.find((item) => item.id === nodeId);
168
- if (!node)
169
- throw new Error(`节点不存在:${nodeId}`);
170
- const catalog = await this.nodeTypes();
171
- const definitionVersionId = typeof node.data.definitionVersionId === 'string' ? node.data.definitionVersionId : null;
172
- const definition = catalog.nodeTypes.find((item) => item.kind === node.kind)
173
- ?? (definitionVersionId ? canvas.nodeTypesByVersionId?.[definitionVersionId] : undefined);
174
- if (!definition)
175
- throw new Error(`未知节点类型:${node.kind}`);
176
- const nextConfig = { ...node.data.config, ...config };
177
- validateConfigSchema(definition, config, nextConfig);
198
+ return this.updateNodeFields(projectId, { nodeId, set: config });
199
+ }
200
+ async updateNodeFields(projectId, update) {
201
+ return this.updateNodes(projectId, [update]);
202
+ }
203
+ async updateNodes(projectId, updates) {
204
+ if (!updates.length)
205
+ throw new Error('updates 不能为空');
206
+ if (new Set(updates.map((update) => update.nodeId)).size !== updates.length)
207
+ throw new Error('同一节点不能在一个批次中重复更新');
208
+ const [canvas, catalog] = await Promise.all([this.canvas(projectId), this.nodeTypes()]);
209
+ const upsertNodes = updates.map((update) => {
210
+ const node = canvas.nodes.find((item) => item.id === update.nodeId);
211
+ if (!node)
212
+ throw new Error(`节点不存在:${update.nodeId}`);
213
+ const definitionVersionId = typeof node.data.definitionVersionId === 'string' ? node.data.definitionVersionId : null;
214
+ const definition = catalog.nodeTypes.find((item) => item.kind === node.kind)
215
+ ?? (definitionVersionId ? canvas.nodeTypesByVersionId?.[definitionVersionId] : undefined);
216
+ if (!definition)
217
+ throw new Error(`未知节点类型:${node.kind}`);
218
+ const configPatch = update.set ?? {};
219
+ const unsetFields = update.unset ?? [];
220
+ const overlappingFields = unsetFields.filter((key) => Object.prototype.hasOwnProperty.call(configPatch, key));
221
+ if (overlappingFields.length)
222
+ throw new Error(`字段不能同时设置和移除:${overlappingFields.join(', ')}`);
223
+ const nextConfig = { ...node.data.config, ...configPatch };
224
+ for (const key of unsetFields)
225
+ delete nextConfig[key];
226
+ validateUnsetConfigFields(definition, unsetFields);
227
+ validateConfigSchema(definition, configPatch, nextConfig);
228
+ return {
229
+ ...node,
230
+ ...(update.title === undefined ? {} : { title: update.title }),
231
+ ...(update.x === undefined ? {} : { x: update.x }),
232
+ ...(update.y === undefined ? {} : { y: update.y }),
233
+ data: { ...node.data, config: nextConfig },
234
+ };
235
+ });
178
236
  return this.patchCanvas(projectId, {
179
237
  canvasId: canvas.id,
180
238
  expectedVersion: canvas.version,
181
- upsertNodes: [{ ...node, data: { ...node.data, config: nextConfig } }],
239
+ upsertNodes,
182
240
  });
183
241
  }
184
242
  async deleteNode(projectId, nodeId) {
@@ -247,3 +305,48 @@ export class VvicatApi {
247
305
  return this.client.request(path, options);
248
306
  }
249
307
  }
308
+ function matchesInspectNode(node, options) {
309
+ const artifact = node.data.artifact && typeof node.data.artifact === 'object' && !Array.isArray(node.data.artifact)
310
+ ? node.data.artifact
311
+ : {};
312
+ if (options.kinds?.length && !options.kinds.includes(node.kind))
313
+ return false;
314
+ if (options.statuses?.length && !options.statuses.includes(String(node.status ?? 'idle')))
315
+ return false;
316
+ if (options.operation && artifact.operation !== options.operation)
317
+ return false;
318
+ if (options.resourceType && artifact.resourceType !== options.resourceType)
319
+ return false;
320
+ if (options.producerNodeId && artifact.producerNodeId !== options.producerNodeId)
321
+ return false;
322
+ if (options.search) {
323
+ const query = options.search.toLocaleLowerCase();
324
+ const candidates = [node.id, node.title, artifact.name, artifact.resourceKey];
325
+ if (!candidates.some((value) => typeof value === 'string' && value.toLocaleLowerCase().includes(query)))
326
+ return false;
327
+ }
328
+ return true;
329
+ }
330
+ function hasInspectFilter(options) {
331
+ return Boolean(options.kinds?.length || options.statuses?.length || options.search || options.operation || options.resourceType || options.producerNodeId);
332
+ }
333
+ function canvasSummary(canvas, matchedNodes) {
334
+ const nodesByKind = {};
335
+ const nodesByStatus = {};
336
+ for (const node of canvas.nodes) {
337
+ nodesByKind[node.kind] = (nodesByKind[node.kind] ?? 0) + 1;
338
+ const status = String(node.status ?? 'idle');
339
+ nodesByStatus[status] = (nodesByStatus[status] ?? 0) + 1;
340
+ }
341
+ const nodeIds = new Set(canvas.nodes.map((node) => node.id));
342
+ return {
343
+ nodeCount: canvas.nodes.length,
344
+ matchedNodeCount: matchedNodes.length,
345
+ edgeCount: canvas.edges.length,
346
+ danglingEdgeIds: canvas.edges
347
+ .filter((edge) => !nodeIds.has(String(edge.sourceNodeId)) || !nodeIds.has(String(edge.targetNodeId)))
348
+ .map((edge) => edge.id),
349
+ nodesByKind,
350
+ nodesByStatus,
351
+ };
352
+ }
package/dist/runtime.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { ApiClient } from './client/api-client.js';
2
+ import { join } from 'node:path';
2
3
  import { KeyringCredentialStore } from './auth/credential-store.js';
3
4
  import { SessionManager, SupabaseAuthProvider } from './auth/session-manager.js';
4
- import { ProfileStore } from './config/profiles.js';
5
+ import { FileAccessTokenCache } from './auth/session-cache.js';
6
+ import { defaultConfigDirectory, ProfileStore } from './config/profiles.js';
5
7
  import { fetchBootstrap } from './preflight.js';
6
8
  export const DEFAULT_BASE_URL = 'https://ai-short-studio.vvicat.dev';
7
9
  export async function createRuntime(flags) {
@@ -28,6 +30,7 @@ export async function createRuntime(flags) {
28
30
  const session = new SessionManager({
29
31
  profile: profile.name,
30
32
  credentials: new KeyringCredentialStore(),
33
+ cache: new FileAccessTokenCache(join(defaultConfigDirectory(process.env), 'sessions')),
31
34
  provider: new SupabaseAuthProvider(profile.supabaseUrl, profile.supabasePublishableKey),
32
35
  });
33
36
  return {
@@ -1,4 +1,4 @@
1
- export declare const BUNDLED_SKILL_NAMES: readonly ["using-vvicat-ai-short-studio-cli", "short-drama"];
1
+ export declare const BUNDLED_SKILL_NAMES: readonly ["using-vvicat-ai-short-studio-cli", "short-drama", "humanizer"];
2
2
  export type BundledSkillName = typeof BUNDLED_SKILL_NAMES[number];
3
3
  export type SkillTarget = 'codex' | 'agents';
4
4
  export declare function bundledSkillPath(name?: BundledSkillName): string;
@@ -6,7 +6,7 @@ export declare function defaultSkillsRoot(target: SkillTarget): string;
6
6
  export declare function defaultSkillTarget(target: SkillTarget): string;
7
7
  export declare function normalizeSkillsRoot(path: string): string;
8
8
  export declare function skillStatus(target: string): Promise<{
9
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
9
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
10
10
  target: string;
11
11
  installed: boolean;
12
12
  managed: boolean;
@@ -24,7 +24,7 @@ export declare function installSkills(input: {
24
24
  current: boolean;
25
25
  skills: ({
26
26
  action: "unchanged";
27
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
27
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
28
28
  target: string;
29
29
  installed: boolean;
30
30
  managed: boolean;
@@ -34,7 +34,7 @@ export declare function installSkills(input: {
34
34
  modified: boolean;
35
35
  } | {
36
36
  action: "skipped";
37
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
37
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
38
38
  target: string;
39
39
  installed: boolean;
40
40
  managed: boolean;
@@ -44,7 +44,7 @@ export declare function installSkills(input: {
44
44
  modified: boolean;
45
45
  } | {
46
46
  action: "updated" | "installed";
47
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
47
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
48
48
  target: string;
49
49
  installed: boolean;
50
50
  managed: boolean;
@@ -59,7 +59,7 @@ export declare function autoInstallSkills(root: string): Promise<{
59
59
  current: boolean;
60
60
  skills: ({
61
61
  action: "unchanged";
62
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
62
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
63
63
  target: string;
64
64
  installed: boolean;
65
65
  managed: boolean;
@@ -69,7 +69,7 @@ export declare function autoInstallSkills(root: string): Promise<{
69
69
  modified: boolean;
70
70
  } | {
71
71
  action: "skipped";
72
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
72
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
73
73
  target: string;
74
74
  installed: boolean;
75
75
  managed: boolean;
@@ -79,7 +79,7 @@ export declare function autoInstallSkills(root: string): Promise<{
79
79
  modified: boolean;
80
80
  } | {
81
81
  action: "updated" | "installed";
82
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
82
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
83
83
  target: string;
84
84
  installed: boolean;
85
85
  managed: boolean;
@@ -93,7 +93,7 @@ export declare function skillStatuses(rootInput: string): Promise<{
93
93
  root: string;
94
94
  current: boolean;
95
95
  skills: {
96
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
96
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
97
97
  target: string;
98
98
  installed: boolean;
99
99
  managed: boolean;
@@ -107,7 +107,7 @@ export declare function installSkill(input: {
107
107
  target: string;
108
108
  force?: boolean;
109
109
  }): Promise<{
110
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
110
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
111
111
  target: string;
112
112
  installed: boolean;
113
113
  managed: boolean;
@@ -117,7 +117,7 @@ export declare function installSkill(input: {
117
117
  modified: boolean;
118
118
  }>;
119
119
  export declare function autoInstallSkill(target: string): Promise<{
120
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
120
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
121
121
  target: string;
122
122
  installed: boolean;
123
123
  managed: boolean;
@@ -127,7 +127,7 @@ export declare function autoInstallSkill(target: string): Promise<{
127
127
  modified: boolean;
128
128
  action: "unchanged";
129
129
  } | {
130
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
130
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
131
131
  target: string;
132
132
  installed: boolean;
133
133
  managed: boolean;
@@ -137,7 +137,7 @@ export declare function autoInstallSkill(target: string): Promise<{
137
137
  modified: boolean;
138
138
  action: "skipped";
139
139
  } | {
140
- name: "using-vvicat-ai-short-studio-cli" | "short-drama";
140
+ name: "using-vvicat-ai-short-studio-cli" | "short-drama" | "humanizer";
141
141
  target: string;
142
142
  installed: boolean;
143
143
  managed: boolean;
@@ -3,7 +3,7 @@ import { cp, mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:
3
3
  import { homedir } from 'node:os';
4
4
  import { basename, dirname, join, relative } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
- export const BUNDLED_SKILL_NAMES = ['using-vvicat-ai-short-studio-cli', 'short-drama'];
6
+ export const BUNDLED_SKILL_NAMES = ['using-vvicat-ai-short-studio-cli', 'short-drama', 'humanizer'];
7
7
  const PACKAGE_JSON = fileURLToPath(new URL('../../package.json', import.meta.url));
8
8
  const MANIFEST = '.vvicat-skill.json';
9
9
  export function bundledSkillPath(name = BUNDLED_SKILL_NAMES[0]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aswless_854771076/ai_short_studio_cli",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "description": "VVICAT 无限画布项目命令行工具",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -37,6 +37,7 @@
37
37
  "release:ci": "npm test && npm run typecheck && node scripts/publish.mjs --tag latest --verify",
38
38
  "release": "node scripts/publish.mjs --tag latest",
39
39
  "test": "vitest run",
40
+ "test:local-e2e": "npm run build && node scripts/local-e2e.mjs",
40
41
  "typecheck": "tsc -p tsconfig.json --noEmit"
41
42
  },
42
43
  "dependencies": {
@@ -11,14 +11,14 @@ export function shouldAutoInstallSkill(environment = process.env) {
11
11
  export async function main(environment = process.env) {
12
12
  if (!shouldAutoInstallSkill(environment)) return
13
13
  try {
14
- const { autoInstallSkill, autoInstallSkills, defaultSkillsRoot, installSkills } = await import('../dist/skill/skill-manager.js')
14
+ const { BUNDLED_SKILL_NAMES, autoInstallSkill, autoInstallSkills, defaultSkillsRoot, installSkills } = await import('../dist/skill/skill-manager.js')
15
15
  const result = environment.VVICAT_SKILL_DIRECTORY
16
16
  ? {
17
17
  skills: [
18
18
  await autoInstallSkill(environment.VVICAT_SKILL_DIRECTORY),
19
19
  ...(await installSkills({
20
20
  root: dirname(environment.VVICAT_SKILL_DIRECTORY),
21
- skills: ['short-drama'],
21
+ skills: BUNDLED_SKILL_NAMES.slice(1),
22
22
  })).skills,
23
23
  ],
24
24
  }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Siqi Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.