@lokvis/schema 0.1.0 → 0.2.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.
@@ -67,6 +67,15 @@ export interface CapabilityImplementation {
67
67
  capability: CapabilityName;
68
68
  /** 实现该能力的引擎名 */
69
69
  engine: string;
70
+ /**
71
+ * 实现状态:
72
+ * - `'stable'`(默认):可正常执行
73
+ * - `'stub'`:占位实现,调用 execute 会抛出异常
74
+ *
75
+ * CapabilityRegistry.resolve() 会跳过 stub 实现,
76
+ * 避免运行时出现 "not implemented" 错误。
77
+ */
78
+ status?: 'stable' | 'stub';
70
79
  /**
71
80
  * 该引擎的性能等级(可选)。缺省时使用能力声明的 performance。
72
81
  * 用于 EngineSelectionStrategy('fastest'/'balanced')排序选择。
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,aAAa;AACb,MAAM,MAAM,mBAAmB,GAC3B,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,CAAC;AAEb,aAAa;AACb,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,mBAAmB,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,aAAa;AACb,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvE,wBAAwB;AACxB,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,qBAAqB;IACrB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,gBAAgB;IAChB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,yBAAyB;IACzB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IAClD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iCAAiC;AACjC,MAAM,WAAW,wBAAwB;IACvC,uBAAuB;IACvB,UAAU,EAAE,cAAc,CAAC;IAC3B,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,aAAa;IACb,OAAO,EAAE,CACP,MAAM,EAAE,OAAO,YAAY,EAAE,KAAK,EAAE,EACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,gBAAgB,KACtB,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;CAC5C;AAED,cAAc;AACd,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,MAAM,EAAE,WAAW,CAAC;IACpB,gBAAgB;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,WAAW;IACX,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE"}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,aAAa;AACb,MAAM,MAAM,mBAAmB,GAC3B,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,CAAC;AAEb,aAAa;AACb,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,mBAAmB,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,aAAa;AACb,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvE,wBAAwB;AACxB,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,qBAAqB;IACrB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,gBAAgB;IAChB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,yBAAyB;IACzB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IAClD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iCAAiC;AACjC,MAAM,WAAW,wBAAwB;IACvC,uBAAuB;IACvB,UAAU,EAAE,cAAc,CAAC;IAC3B,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,aAAa;IACb,OAAO,EAAE,CACP,MAAM,EAAE,OAAO,YAAY,EAAE,KAAK,EAAE,EACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,gBAAgB,KACtB,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;CAC5C;AAED,cAAc;AACd,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,MAAM,EAAE,WAAW,CAAC;IACpB,gBAAgB;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,WAAW;IACX,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE"}
package/dist/event.d.ts CHANGED
@@ -58,6 +58,8 @@ export type LokvisEvent = {
58
58
  type: 'history:changed';
59
59
  workflowId: string;
60
60
  entries: HistoryEntry[];
61
+ /** 当前游标(指向最后一条已应用的 entry;-1 表示无已应用条目) */
62
+ currentIndex: number;
61
63
  } | {
62
64
  type: 'capability:registered';
63
65
  capability: string;
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
@@ -288,8 +288,13 @@ export declare const pluginManifestSchema: z.ZodObject<{
288
288
  permissions: string[];
289
289
  icon?: string | undefined;
290
290
  }>;
291
- /** 校验 Workflow JSON */
292
- export declare function validateWorkflow(data: unknown): z.SafeParseReturnType<{
291
+ /** 校验 Workflow JSON
292
+ *
293
+ * 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
294
+ * 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
295
+ * 现增加结构层校验,让错误在入口处暴露。
296
+ */
297
+ export declare function validateWorkflow(data: unknown): z.SafeParseError<{
293
298
  id: string;
294
299
  version: string;
295
300
  name: string;
@@ -325,43 +330,57 @@ export declare function validateWorkflow(data: unknown): z.SafeParseReturnType<{
325
330
  official?: boolean | undefined;
326
331
  createdAt?: number | undefined;
327
332
  updatedAt?: number | undefined;
328
- }, {
329
- id: string;
330
- version: string;
331
- name: string;
332
- description: string;
333
- author: {
334
- id: string;
335
- name: string;
333
+ }> | {
334
+ success: false;
335
+ error: {
336
+ issues: {
337
+ code: "custom";
338
+ message: string;
339
+ path: never[];
340
+ }[];
336
341
  };
337
- category: string;
338
- tags: string[];
339
- nodes: {
340
- type: "load" | "transform" | "export";
342
+ data?: undefined;
343
+ } | {
344
+ success: true;
345
+ data: {
341
346
  id: string;
342
- params?: Record<string, unknown> | undefined;
343
- capability?: string | undefined;
344
- label?: string | undefined;
345
- }[];
346
- edges: {
347
- from: string;
348
- to: string;
349
- }[];
350
- inputs: {
351
- type: "image" | "video" | "audio" | "pdf" | "text" | "data" | "unknown";
352
- multiple: boolean;
353
- maxCount?: number | undefined;
354
- accept?: string[] | undefined;
355
- };
356
- outputs: {
357
- type: "image" | "video" | "audio" | "pdf" | "text" | "data" | "unknown" | "archive";
358
- format?: string | undefined;
347
+ version: string;
348
+ name: string;
349
+ description: string;
350
+ author: {
351
+ id: string;
352
+ name: string;
353
+ };
354
+ category: string;
355
+ tags: string[];
356
+ nodes: {
357
+ type: "load" | "transform" | "export";
358
+ id: string;
359
+ params?: Record<string, unknown> | undefined;
360
+ capability?: string | undefined;
361
+ label?: string | undefined;
362
+ }[];
363
+ edges: {
364
+ from: string;
365
+ to: string;
366
+ }[];
367
+ inputs: {
368
+ type: "image" | "video" | "audio" | "pdf" | "text" | "data" | "unknown";
369
+ multiple: boolean;
370
+ maxCount?: number | undefined;
371
+ accept?: string[] | undefined;
372
+ };
373
+ outputs: {
374
+ type: "image" | "video" | "audio" | "pdf" | "text" | "data" | "unknown" | "archive";
375
+ format?: string | undefined;
376
+ };
377
+ $schema?: string | undefined;
378
+ official?: boolean | undefined;
379
+ createdAt?: number | undefined;
380
+ updatedAt?: number | undefined;
359
381
  };
360
- $schema?: string | undefined;
361
- official?: boolean | undefined;
362
- createdAt?: number | undefined;
363
- updatedAt?: number | undefined;
364
- }>;
382
+ error?: undefined;
383
+ };
365
384
  /** 校验 Plugin Manifest */
366
385
  export declare function validatePluginManifest(data: unknown): z.SafeParseReturnType<{
367
386
  version: string;
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe,0EAQ1B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW/B,CAAC;AAEH,uBAAuB;AACvB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAE7C;AAED,yBAAyB;AACzB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;GAEnD"}
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe,0EAQ1B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW/B,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4G7C;AAED,yBAAyB;AACzB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;GAEnD"}
@@ -72,9 +72,103 @@ export const pluginManifestSchema = z.object({
72
72
  engines: z.object({ 'lokvis-runtime': z.string() }),
73
73
  permissions: z.array(z.string()),
74
74
  });
75
- /** 校验 Workflow JSON */
75
+ /** 校验 Workflow JSON
76
+ *
77
+ * 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
78
+ * 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
79
+ * 现增加结构层校验,让错误在入口处暴露。
80
+ */
76
81
  export function validateWorkflow(data) {
77
- return workflowSchema.safeParse(data);
82
+ const parsed = workflowSchema.safeParse(data);
83
+ if (!parsed.success) {
84
+ return parsed;
85
+ }
86
+ const wf = parsed.data;
87
+ const errors = [];
88
+ // 1. 保留字哨兵:禁止 __input__ / __output__ 出现在 nodes 或 edges
89
+ // (executor 不支持哨兵节点,输入资产注入到入度 0 的首节点)
90
+ const RESERVED_IDS = new Set(['__input__', '__output__', '__start__', '__end__']);
91
+ for (const node of wf.nodes) {
92
+ if (RESERVED_IDS.has(node.id)) {
93
+ errors.push(`Node id "${node.id}" is reserved; use a non-reserved id.`);
94
+ }
95
+ }
96
+ for (const edge of wf.edges) {
97
+ if (RESERVED_IDS.has(edge.from)) {
98
+ errors.push(`Edge from "${edge.from}" references a reserved sentinel id; ` +
99
+ `the executor injects input assets into the first in-degree-0 node, ` +
100
+ `no explicit __input__ edge is needed.`);
101
+ }
102
+ if (RESERVED_IDS.has(edge.to)) {
103
+ errors.push(`Edge to "${edge.to}" references a reserved sentinel id.`);
104
+ }
105
+ }
106
+ // 2. node id 唯一性
107
+ const seenIds = new Set();
108
+ for (const node of wf.nodes) {
109
+ if (seenIds.has(node.id)) {
110
+ errors.push(`Duplicate node id: "${node.id}".`);
111
+ }
112
+ seenIds.add(node.id);
113
+ }
114
+ // 3. edge.from / edge.to 必须引用已声明节点
115
+ const nodeIds = new Set(wf.nodes.map((n) => n.id));
116
+ for (const edge of wf.edges) {
117
+ if (!nodeIds.has(edge.from)) {
118
+ errors.push(`Edge from "${edge.from}" to "${edge.to}" references unknown source node "${edge.from}".`);
119
+ }
120
+ if (!nodeIds.has(edge.to)) {
121
+ errors.push(`Edge from "${edge.from}" to "${edge.to}" references unknown target node "${edge.to}".`);
122
+ }
123
+ if (edge.from === edge.to) {
124
+ errors.push(`Edge from "${edge.from}" to itself is a self-loop (cycle).`);
125
+ }
126
+ }
127
+ // 4. DAG 合法性:无环(拓扑排序能覆盖所有节点)
128
+ if (errors.length === 0) {
129
+ const inDegree = new Map();
130
+ const adjacency = new Map();
131
+ for (const node of wf.nodes) {
132
+ inDegree.set(node.id, 0);
133
+ adjacency.set(node.id, []);
134
+ }
135
+ for (const edge of wf.edges) {
136
+ inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
137
+ adjacency.get(edge.from)?.push(edge.to);
138
+ }
139
+ const queue = [];
140
+ for (const [id, deg] of inDegree) {
141
+ if (deg === 0)
142
+ queue.push(id);
143
+ }
144
+ let visited = 0;
145
+ while (queue.length > 0) {
146
+ const id = queue.shift();
147
+ visited++;
148
+ for (const next of adjacency.get(id) ?? []) {
149
+ const newDeg = (inDegree.get(next) ?? 0) - 1;
150
+ inDegree.set(next, newDeg);
151
+ if (newDeg === 0)
152
+ queue.push(next);
153
+ }
154
+ }
155
+ if (visited !== wf.nodes.length) {
156
+ errors.push(`Workflow contains a cycle: only ${visited}/${wf.nodes.length} nodes are reachable.`);
157
+ }
158
+ }
159
+ if (errors.length > 0) {
160
+ return {
161
+ success: false,
162
+ error: {
163
+ issues: errors.map((message) => ({
164
+ code: 'custom',
165
+ message,
166
+ path: [],
167
+ })),
168
+ },
169
+ };
170
+ }
171
+ return { success: true, data: wf };
78
172
  }
79
173
  /** 校验 Plugin Manifest */
80
174
  export function validatePluginManifest(data) {
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokvis/schema",
3
- "version": "0.1.0",
3
+ "version": "0.2.0-beta.0",
4
4
  "description": "Lokvis Schema - Workflow / Asset / Plugin type definitions and validators",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/capability.ts CHANGED
@@ -83,6 +83,15 @@ export interface CapabilityImplementation {
83
83
  capability: CapabilityName;
84
84
  /** 实现该能力的引擎名 */
85
85
  engine: string;
86
+ /**
87
+ * 实现状态:
88
+ * - `'stable'`(默认):可正常执行
89
+ * - `'stub'`:占位实现,调用 execute 会抛出异常
90
+ *
91
+ * CapabilityRegistry.resolve() 会跳过 stub 实现,
92
+ * 避免运行时出现 "not implemented" 错误。
93
+ */
94
+ status?: 'stable' | 'stub';
86
95
  /**
87
96
  * 该引擎的性能等级(可选)。缺省时使用能力声明的 performance。
88
97
  * 用于 EngineSelectionStrategy('fastest'/'balanced')排序选择。
package/src/event.ts CHANGED
@@ -39,7 +39,13 @@ export type LokvisEvent =
39
39
  format: string;
40
40
  size: number;
41
41
  }
42
- | { type: 'history:changed'; workflowId: string; entries: HistoryEntry[] }
42
+ | {
43
+ type: 'history:changed';
44
+ workflowId: string;
45
+ entries: HistoryEntry[];
46
+ /** 当前游标(指向最后一条已应用的 entry;-1 表示无已应用条目) */
47
+ currentIndex: number;
48
+ }
43
49
  | { type: 'capability:registered'; capability: string; engine: string }
44
50
  | { type: 'plugin:loaded'; name: string; version: string };
45
51
 
package/src/validators.ts CHANGED
@@ -83,9 +83,120 @@ export const pluginManifestSchema = z.object({
83
83
  permissions: z.array(z.string()),
84
84
  });
85
85
 
86
- /** 校验 Workflow JSON */
86
+ /** 校验 Workflow JSON
87
+ *
88
+ * 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
89
+ * 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
90
+ * 现增加结构层校验,让错误在入口处暴露。
91
+ */
87
92
  export function validateWorkflow(data: unknown) {
88
- return workflowSchema.safeParse(data);
93
+ const parsed = workflowSchema.safeParse(data);
94
+ if (!parsed.success) {
95
+ return parsed;
96
+ }
97
+
98
+ const wf = parsed.data;
99
+ const errors: string[] = [];
100
+
101
+ // 1. 保留字哨兵:禁止 __input__ / __output__ 出现在 nodes 或 edges
102
+ // (executor 不支持哨兵节点,输入资产注入到入度 0 的首节点)
103
+ const RESERVED_IDS = new Set(['__input__', '__output__', '__start__', '__end__']);
104
+ for (const node of wf.nodes) {
105
+ if (RESERVED_IDS.has(node.id)) {
106
+ errors.push(
107
+ `Node id "${node.id}" is reserved; use a non-reserved id.`
108
+ );
109
+ }
110
+ }
111
+ for (const edge of wf.edges) {
112
+ if (RESERVED_IDS.has(edge.from)) {
113
+ errors.push(
114
+ `Edge from "${edge.from}" references a reserved sentinel id; ` +
115
+ `the executor injects input assets into the first in-degree-0 node, ` +
116
+ `no explicit __input__ edge is needed.`
117
+ );
118
+ }
119
+ if (RESERVED_IDS.has(edge.to)) {
120
+ errors.push(
121
+ `Edge to "${edge.to}" references a reserved sentinel id.`
122
+ );
123
+ }
124
+ }
125
+
126
+ // 2. node id 唯一性
127
+ const seenIds = new Set<string>();
128
+ for (const node of wf.nodes) {
129
+ if (seenIds.has(node.id)) {
130
+ errors.push(`Duplicate node id: "${node.id}".`);
131
+ }
132
+ seenIds.add(node.id);
133
+ }
134
+
135
+ // 3. edge.from / edge.to 必须引用已声明节点
136
+ const nodeIds = new Set(wf.nodes.map((n) => n.id));
137
+ for (const edge of wf.edges) {
138
+ if (!nodeIds.has(edge.from)) {
139
+ errors.push(
140
+ `Edge from "${edge.from}" to "${edge.to}" references unknown source node "${edge.from}".`
141
+ );
142
+ }
143
+ if (!nodeIds.has(edge.to)) {
144
+ errors.push(
145
+ `Edge from "${edge.from}" to "${edge.to}" references unknown target node "${edge.to}".`
146
+ );
147
+ }
148
+ if (edge.from === edge.to) {
149
+ errors.push(`Edge from "${edge.from}" to itself is a self-loop (cycle).`);
150
+ }
151
+ }
152
+
153
+ // 4. DAG 合法性:无环(拓扑排序能覆盖所有节点)
154
+ if (errors.length === 0) {
155
+ const inDegree = new Map<string, number>();
156
+ const adjacency = new Map<string, string[]>();
157
+ for (const node of wf.nodes) {
158
+ inDegree.set(node.id, 0);
159
+ adjacency.set(node.id, []);
160
+ }
161
+ for (const edge of wf.edges) {
162
+ inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
163
+ adjacency.get(edge.from)?.push(edge.to);
164
+ }
165
+ const queue: string[] = [];
166
+ for (const [id, deg] of inDegree) {
167
+ if (deg === 0) queue.push(id);
168
+ }
169
+ let visited = 0;
170
+ while (queue.length > 0) {
171
+ const id = queue.shift()!;
172
+ visited++;
173
+ for (const next of adjacency.get(id) ?? []) {
174
+ const newDeg = (inDegree.get(next) ?? 0) - 1;
175
+ inDegree.set(next, newDeg);
176
+ if (newDeg === 0) queue.push(next);
177
+ }
178
+ }
179
+ if (visited !== wf.nodes.length) {
180
+ errors.push(
181
+ `Workflow contains a cycle: only ${visited}/${wf.nodes.length} nodes are reachable.`
182
+ );
183
+ }
184
+ }
185
+
186
+ if (errors.length > 0) {
187
+ return {
188
+ success: false as const,
189
+ error: {
190
+ issues: errors.map((message) => ({
191
+ code: 'custom' as const,
192
+ message,
193
+ path: [],
194
+ })),
195
+ },
196
+ };
197
+ }
198
+
199
+ return { success: true as const, data: wf };
89
200
  }
90
201
 
91
202
  /** 校验 Plugin Manifest */