@tuongaz/seeflow 0.1.84 → 0.1.87
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/dist/web/assets/{architectureDiagram-3BPJPVTR-I46aqv2T.js → architectureDiagram-3BPJPVTR-ClNXtQtx.js} +1 -1
- package/dist/web/assets/{blockDiagram-GPEHLZMM-C08px5xi.js → blockDiagram-GPEHLZMM-BhKGvPcQ.js} +1 -1
- package/dist/web/assets/{c4Diagram-AAUBKEIU-iyIMetcW.js → c4Diagram-AAUBKEIU-BKBm_0HA.js} +1 -1
- package/dist/web/assets/channel-Blg0ESf3.js +1 -0
- package/dist/web/assets/{chart-BGNzA0s8.js → chart-CBngRDiH.js} +1 -1
- package/dist/web/assets/{chunk-2J33WTMH-CQFLt-Og.js → chunk-2J33WTMH-WcUKw8RK.js} +1 -1
- package/dist/web/assets/{chunk-4BX2VUAB-M_HU7fhX.js → chunk-4BX2VUAB-B9RKcbcq.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-CZ6tcHFC.js → chunk-55IACEB6-B4GnCgpM.js} +1 -1
- package/dist/web/assets/{chunk-727SXJPM-ZXC_1s3s.js → chunk-727SXJPM-CHMq27YW.js} +1 -1
- package/dist/web/assets/{chunk-AQP2D5EJ-D1nyTSxR.js → chunk-AQP2D5EJ-D2ZFVUYL.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-D8IemyXd.js → chunk-FMBD7UC4-qG6SQBY6.js} +1 -1
- package/dist/web/assets/{chunk-ND2GUHAM-aT_PIEvu.js → chunk-ND2GUHAM-BQ9mDdTH.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-BKY6KT8K.js → chunk-QZHKN3VN-CIDw1jk1.js} +1 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-iwSPO53N.js +1 -0
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-iwSPO53N.js +1 -0
- package/dist/web/assets/{code-block-CMPt7Auf.js → code-block-DHA2onLV.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-Cr3EeHXE.js → cose-bilkent-S5V4N54A-CdkJxKQK.js} +1 -1
- package/dist/web/assets/{dagre-BM42HDAG-BfJiRz9t.js → dagre-BM42HDAG-B66Vessb.js} +1 -1
- package/dist/web/assets/{diagram-2AECGRRQ-CZ1Rti0o.js → diagram-2AECGRRQ-CTGbhRIQ.js} +1 -1
- package/dist/web/assets/{diagram-5GNKFQAL-COe7jS3C.js → diagram-5GNKFQAL-CXKhZ2RD.js} +1 -1
- package/dist/web/assets/{diagram-KO2AKTUF-lmIy3eJx.js → diagram-KO2AKTUF-Ciz8XXz9.js} +1 -1
- package/dist/web/assets/{diagram-LMA3HP47-Dv9UOOZz.js → diagram-LMA3HP47-CHwxluj7.js} +1 -1
- package/dist/web/assets/{diagram-OG6HWLK6-C8HoI5ul.js → diagram-OG6HWLK6-2HdAU1Uy.js} +1 -1
- package/dist/web/assets/{erDiagram-TEJ5UH35-CvqQcwx_.js → erDiagram-TEJ5UH35-CFuPdZHL.js} +1 -1
- package/dist/web/assets/{flowDiagram-I6XJVG4X-B0f8FFr8.js → flowDiagram-I6XJVG4X-D2SYUr84.js} +1 -1
- package/dist/web/assets/{ganttDiagram-6RSMTGT7-C0FgETUZ.js → ganttDiagram-6RSMTGT7-hi9oo-If.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PVQCEYII-BSUklsqu.js → gitGraphDiagram-PVQCEYII-CP4UpnDZ.js} +1 -1
- package/dist/web/assets/index-BM5xp_5O.js +8619 -0
- package/dist/web/assets/{index-fl8DS9WO.css → index-DzEkjMbu.css} +1 -1
- package/dist/web/assets/{index.es-CcTdlE2B.js → index.es-B100nNVg.js} +1 -1
- package/dist/web/assets/{infoDiagram-5YYISTIA-qq3OPeKx.js → infoDiagram-5YYISTIA-CWn2ZmPz.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-BxoH_vWZ.js → ishikawaDiagram-YF4QCWOH-BXG7Wqi5.js} +1 -1
- package/dist/web/assets/{journeyDiagram-JHISSGLW-ClnMLnWd.js → journeyDiagram-JHISSGLW-BYcudTZ3.js} +1 -1
- package/dist/web/assets/{jspdf.es.min-C17Fkx-5.js → jspdf.es.min-BjAnJa9n.js} +3 -3
- package/dist/web/assets/{kanban-definition-UN3LZRKU-BiBGcvgP.js → kanban-definition-UN3LZRKU-BPa8o2q1.js} +1 -1
- package/dist/web/assets/{linear-D--UMRYt.js → linear-DuxgdPQE.js} +1 -1
- package/dist/web/assets/{markdown-D-hxiBfP.js → markdown-CCL3i82k.js} +1 -1
- package/dist/web/assets/{mermaid.core-ClLm1p66.js → mermaid.core-BfL5QPbr.js} +4 -4
- package/dist/web/assets/{mindmap-definition-RKZ34NQL-CLSXYvAW.js → mindmap-definition-RKZ34NQL-CI-cniK5.js} +1 -1
- package/dist/web/assets/{pieDiagram-4H26LBE5-CjvKFGOn.js → pieDiagram-4H26LBE5-cf5aBEPi.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-W4KKPZXB-BUYqMtGH.js → quadrantDiagram-W4KKPZXB-DYUrOveY.js} +1 -1
- package/dist/web/assets/{requirementDiagram-4Y6WPE33-DNCHy1eI.js → requirementDiagram-4Y6WPE33-93ks8rhf.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-5OEKKPKP-zoL2eKAM.js → sankeyDiagram-5OEKKPKP-B_CejPlQ.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-3UESZ5HK-DePRNn1e.js → sequenceDiagram-3UESZ5HK-DZS5Ade2.js} +1 -1
- package/dist/web/assets/{stateDiagram-AJRCARHV-uLinqFcr.js → stateDiagram-AJRCARHV-BPN2DC-C.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-B_a13tqM.js +1 -0
- package/dist/web/assets/{time-C9xT3sm_.js → time-BBP2Hxfw.js} +1 -1
- package/dist/web/assets/{timeline-definition-PNZ67QCA-BnQVT-CY.js → timeline-definition-PNZ67QCA-DCAE7DJl.js} +1 -1
- package/dist/web/assets/{vennDiagram-CIIHVFJN-BUyqbvsU.js → vennDiagram-CIIHVFJN-Cicq6guF.js} +1 -1
- package/dist/web/assets/{wardley-L42UT6IY-zz-5TvX0.js → wardley-L42UT6IY-CAXHDzax.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-YWT4CUSO-DVnYIARL.js → wardleyDiagram-YWT4CUSO-DC5nEIz7.js} +1 -1
- package/dist/web/assets/{xychartDiagram-2RQKCTM6-BMxn2lA_.js → xychartDiagram-2RQKCTM6-DbZv6qnZ.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/api.ts +7 -95
- package/src/cli-manifest.ts +2 -2
- package/src/cli-ops.ts +2 -2
- package/src/events.ts +0 -1
- package/src/layout.ts +2 -0
- package/src/mcp.ts +6 -6
- package/src/merge.ts +0 -3
- package/src/operations.ts +2 -2
- package/src/proxy.ts +1 -193
- package/src/schema-catalog.ts +5 -3
- package/src/schema.ts +10 -11
- package/src/server.ts +1 -2
- package/dist/web/assets/channel-X0ALvlnb.js +0 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-mwGbzVrI.js +0 -1
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-mwGbzVrI.js +0 -1
- package/dist/web/assets/index-Cnz1Cpa9.js +0 -8619
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-hyQj-KY3.js +0 -1
package/src/mcp.ts
CHANGED
|
@@ -293,9 +293,9 @@ const buildTools = (ops: Operations, ctx: ToolContext): McpTool[] => [
|
|
|
293
293
|
"node variant; name='action', subname='playAction' → just the playAction " +
|
|
294
294
|
'shape). Use this to learn what a node, connector, action, component ' +
|
|
295
295
|
'spec, or flow envelope looks like before authoring writes. Categories: ' +
|
|
296
|
-
'`flow`, `node` (
|
|
297
|
-
'database/server/user/queue/cloud/image/html/icon/component), ' +
|
|
298
|
-
'`connector`, `action` (playAction/statusAction/
|
|
296
|
+
'`flow`, `node` (15 flat variants — rectangle/ellipse/sticky/text/' +
|
|
297
|
+
'database/server/user/queue/cloud/diamond/hexagon/image/html/icon/component), ' +
|
|
298
|
+
'`connector`, `action` (playAction/statusAction/statusReport/' +
|
|
299
299
|
"componentAction), `componentSpec` (sidecar shape for type:'component' " +
|
|
300
300
|
'nodes), `style`.',
|
|
301
301
|
inputSchema: {
|
|
@@ -310,8 +310,8 @@ const buildTools = (ops: Operations, ctx: ToolContext): McpTool[] => [
|
|
|
310
310
|
description:
|
|
311
311
|
'Optional named schema within the category (requires `name`). For ' +
|
|
312
312
|
"name='node': rectangle, ellipse, sticky, text, database, server, " +
|
|
313
|
-
'user, queue, cloud, image, html, icon, component. For ' +
|
|
314
|
-
"name='action': playAction, statusAction,
|
|
313
|
+
'user, queue, cloud, diamond, hexagon, image, html, icon, component. For ' +
|
|
314
|
+
"name='action': playAction, statusAction, statusReport, " +
|
|
315
315
|
"componentAction. For name='componentSpec': componentSpec, " +
|
|
316
316
|
'componentSpecElement.',
|
|
317
317
|
},
|
|
@@ -763,7 +763,7 @@ const buildTools = (ops: Operations, ctx: ToolContext): McpTool[] => [
|
|
|
763
763
|
{
|
|
764
764
|
name: 'seeflow_patch_node',
|
|
765
765
|
description:
|
|
766
|
-
"Update fields on an existing node (position, name, description, detail, icon, colors, border, font, dimensions, autoSize, plus type:'icon'-only color/strokeWidth/alt and capabilities playAction/statusAction/stateSource). `type` can flip a node between any of the
|
|
766
|
+
"Update fields on an existing node (position, name, description, detail, icon, colors, border, font, dimensions, autoSize, plus type:'icon'-only color/strokeWidth/alt and capabilities playAction/statusAction/stateSource). `type` can flip a node between any of the 14 visual variants (rectangle/ellipse/sticky/text/database/server/user/queue/cloud/diamond/hexagon/image/html/icon); the post-merge schema reparse gates required fields on the new type (image.data.path, icon.data.icon). Setting detail (every node) or html (type:'html') writes the content to <project>/nodes/<id>/{detail.md|view.html}; the file:// ref on the node persists. Empty-string detail empties the file but keeps the ref.",
|
|
767
767
|
inputSchema: inputSchemaFromZod(PatchNodeInputSchema),
|
|
768
768
|
handler: async (args) => {
|
|
769
769
|
const parsed = PatchNodeInputSchema.safeParse(args);
|
package/src/merge.ts
CHANGED
|
@@ -32,7 +32,6 @@ export function mergeFlowAndStyle(flow: Flow, style: Style): ResolvedFlow {
|
|
|
32
32
|
version: flow.version,
|
|
33
33
|
name: flow.name,
|
|
34
34
|
...(flow.description !== undefined ? { description: flow.description } : {}),
|
|
35
|
-
...(flow.resetAction ? { resetAction: flow.resetAction } : {}),
|
|
36
35
|
nodes: mergedNodes,
|
|
37
36
|
connectors: mergedConnectors,
|
|
38
37
|
} as ResolvedFlow;
|
|
@@ -114,7 +113,6 @@ export function splitFlow(resolved: {
|
|
|
114
113
|
version: number;
|
|
115
114
|
name: string;
|
|
116
115
|
description?: string;
|
|
117
|
-
resetAction?: unknown;
|
|
118
116
|
nodes: Array<Record<string, unknown>>;
|
|
119
117
|
connectors: Array<Record<string, unknown>>;
|
|
120
118
|
}): { flow: Record<string, unknown>; style: Record<string, unknown> } {
|
|
@@ -187,7 +185,6 @@ export function splitFlow(resolved: {
|
|
|
187
185
|
connectors: flowConnectors,
|
|
188
186
|
};
|
|
189
187
|
if (resolved.description !== undefined) flow.description = resolved.description;
|
|
190
|
-
if (resolved.resetAction !== undefined) flow.resetAction = resolved.resetAction;
|
|
191
188
|
|
|
192
189
|
const style: Record<string, unknown> = {};
|
|
193
190
|
if (Object.keys(styleNodes).length > 0) style.nodes = styleNodes;
|
package/src/operations.ts
CHANGED
|
@@ -212,6 +212,8 @@ const SEMANTIC_KEYS_BY_TYPE: Record<z.infer<typeof NodeTypeSchema>, ReadonlySet<
|
|
|
212
212
|
user: GEOMETRIC_SEMANTIC_KEYS,
|
|
213
213
|
queue: GEOMETRIC_SEMANTIC_KEYS,
|
|
214
214
|
cloud: GEOMETRIC_SEMANTIC_KEYS,
|
|
215
|
+
diamond: GEOMETRIC_SEMANTIC_KEYS,
|
|
216
|
+
hexagon: GEOMETRIC_SEMANTIC_KEYS,
|
|
215
217
|
image: new Set([
|
|
216
218
|
'name',
|
|
217
219
|
'description',
|
|
@@ -762,7 +764,6 @@ function readRawFlowAndStyle(flowPath: string): ReadRawResult {
|
|
|
762
764
|
type MutateMergedFlowMutator<E> = (flow: {
|
|
763
765
|
version: number;
|
|
764
766
|
name: string;
|
|
765
|
-
resetAction?: unknown;
|
|
766
767
|
nodes: Array<Record<string, unknown>>;
|
|
767
768
|
connectors: Array<Record<string, unknown>>;
|
|
768
769
|
}) => { kind: 'ok' } | E;
|
|
@@ -808,7 +809,6 @@ export async function mutateMergedFlow<E extends { kind: string }>(
|
|
|
808
809
|
const merged = inlinedFlow as unknown as {
|
|
809
810
|
version: number;
|
|
810
811
|
name: string;
|
|
811
|
-
resetAction?: unknown;
|
|
812
812
|
nodes: Array<Record<string, unknown>>;
|
|
813
813
|
connectors: Array<Record<string, unknown>>;
|
|
814
814
|
};
|
package/src/proxy.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { realpathSync } from 'node:fs';
|
|
|
16
16
|
import { join, resolve, sep } from 'node:path';
|
|
17
17
|
import type { EventBus } from './events.ts';
|
|
18
18
|
import { type ProcessSpawner, type SpawnHandle, defaultProcessSpawner } from './process-spawner.ts';
|
|
19
|
-
import type { PlayAction
|
|
19
|
+
import type { PlayAction } from './schema.ts';
|
|
20
20
|
import { shortId } from './short-id.ts';
|
|
21
21
|
|
|
22
22
|
export interface PlayResult {
|
|
@@ -73,31 +73,6 @@ function resolveScript(cwd: string, nodeId: string, scriptPath: string): Resolve
|
|
|
73
73
|
return { ok: true, absPath: realTarget };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// Legacy anchor for resetAction (kept until resetAction gets its own design
|
|
77
|
-
// round). Same realpath escape check as resolveScript, but rooted at the
|
|
78
|
-
// project root rather than a per-node folder.
|
|
79
|
-
function resolveResetScript(cwd: string, scriptPath: string): Resolved {
|
|
80
|
-
const projectRoot = cwd;
|
|
81
|
-
let realRoot: string;
|
|
82
|
-
try {
|
|
83
|
-
realRoot = realpathSync(projectRoot);
|
|
84
|
-
} catch {
|
|
85
|
-
return { ok: false };
|
|
86
|
-
}
|
|
87
|
-
const target = resolve(projectRoot, scriptPath);
|
|
88
|
-
let realTarget: string;
|
|
89
|
-
try {
|
|
90
|
-
realTarget = realpathSync(target);
|
|
91
|
-
} catch {
|
|
92
|
-
return { ok: false };
|
|
93
|
-
}
|
|
94
|
-
const rootWithSep = realRoot.endsWith(sep) ? realRoot : realRoot + sep;
|
|
95
|
-
if (realTarget !== realRoot && !realTarget.startsWith(rootWithSep)) {
|
|
96
|
-
return { ok: false };
|
|
97
|
-
}
|
|
98
|
-
return { ok: true, absPath: realTarget };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
76
|
// Copy `process.env` into a string-only record, then layer the per-run extras.
|
|
102
77
|
// Bun.spawn's env contract is `Record<string, string>` so the undefineds that
|
|
103
78
|
// `process.env` advertises in its type must be filtered out first.
|
|
@@ -130,54 +105,6 @@ async function writeStdinPayload(handle: SpawnHandle, input: unknown): Promise<v
|
|
|
130
105
|
}
|
|
131
106
|
}
|
|
132
107
|
|
|
133
|
-
// Live play-script handles indexed by flowId. Populated by runPlay() on spawn;
|
|
134
|
-
// entries are removed when each handle's `exited` promise resolves (success
|
|
135
|
-
// AND error paths). `stopAllPlays(flowId)` consults this map to terminate
|
|
136
|
-
// every in-flight play for a demo on /reset.
|
|
137
|
-
const livePlayHandles = new Map<string, Set<SpawnHandle>>();
|
|
138
|
-
|
|
139
|
-
function registerLiveHandle(flowId: string, handle: SpawnHandle): void {
|
|
140
|
-
let set = livePlayHandles.get(flowId);
|
|
141
|
-
if (!set) {
|
|
142
|
-
set = new Set();
|
|
143
|
-
livePlayHandles.set(flowId, set);
|
|
144
|
-
}
|
|
145
|
-
set.add(handle);
|
|
146
|
-
handle.exited.finally(() => {
|
|
147
|
-
const current = livePlayHandles.get(flowId);
|
|
148
|
-
if (!current) return;
|
|
149
|
-
current.delete(handle);
|
|
150
|
-
if (current.size === 0) livePlayHandles.delete(flowId);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async function killWithGrace(handle: SpawnHandle): Promise<void> {
|
|
155
|
-
handle.kill('SIGTERM');
|
|
156
|
-
let graceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
157
|
-
const gracePromise = new Promise<'grace'>((res) => {
|
|
158
|
-
graceTimer = setTimeout(() => res('grace'), SIGKILL_GRACE_MS);
|
|
159
|
-
});
|
|
160
|
-
const winner = await Promise.race([handle.exited.then(() => 'exited' as const), gracePromise]);
|
|
161
|
-
if (graceTimer) clearTimeout(graceTimer);
|
|
162
|
-
if (winner === 'grace') {
|
|
163
|
-
handle.kill('SIGKILL');
|
|
164
|
-
await handle.exited;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Kill every live play-script for `flowId` (SIGTERM → 2s grace → SIGKILL in
|
|
169
|
-
// parallel) and wait for each to exit. Idempotent on an unknown flowId. The
|
|
170
|
-
// map is keyed by flowId so a stop on demo A never touches demo B.
|
|
171
|
-
export async function stopAllPlays(flowId: string): Promise<void> {
|
|
172
|
-
const set = livePlayHandles.get(flowId);
|
|
173
|
-
if (!set || set.size === 0) return;
|
|
174
|
-
const handles = [...set];
|
|
175
|
-
// Clear eagerly so a parallel runPlay can't double-count an entry we're
|
|
176
|
-
// about to await on. The exited.finally() will no-op the second delete.
|
|
177
|
-
livePlayHandles.delete(flowId);
|
|
178
|
-
await Promise.all(handles.map((h) => killWithGrace(h)));
|
|
179
|
-
}
|
|
180
|
-
|
|
181
108
|
export async function runPlay(options: RunPlayOptions): Promise<PlayResult> {
|
|
182
109
|
const { events, flowId, nodeId, cwd, action } = options;
|
|
183
110
|
const spawner = options.spawner ?? defaultProcessSpawner;
|
|
@@ -229,8 +156,6 @@ export async function runPlay(options: RunPlayOptions): Promise<PlayResult> {
|
|
|
229
156
|
return { runId, error: message };
|
|
230
157
|
}
|
|
231
158
|
|
|
232
|
-
registerLiveHandle(flowId, handle);
|
|
233
|
-
|
|
234
159
|
// Drain stdout AND stderr CONCURRENTLY with the process running so OS pipe
|
|
235
160
|
// buffers (~64 KB) don't fill up and deadlock the child.
|
|
236
161
|
const stdoutPromise = new Response(handle.stdout).text();
|
|
@@ -303,120 +228,3 @@ export async function runPlay(options: RunPlayOptions): Promise<PlayResult> {
|
|
|
303
228
|
});
|
|
304
229
|
return { runId, error: message };
|
|
305
230
|
}
|
|
306
|
-
|
|
307
|
-
export interface RunResetOptions {
|
|
308
|
-
events: EventBus;
|
|
309
|
-
flowId: string;
|
|
310
|
-
/** Project root (`<repoPath>`). Script resolves under `<cwd>/`. */
|
|
311
|
-
cwd: string;
|
|
312
|
-
action: ResetAction;
|
|
313
|
-
/** Injectable for tests; defaults to `defaultProcessSpawner`. */
|
|
314
|
-
spawner?: ProcessSpawner;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export interface ResetResult {
|
|
318
|
-
ok: boolean;
|
|
319
|
-
body?: unknown;
|
|
320
|
-
error?: string;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Run the demo's one-shot `resetAction` script. Same spawn discipline as
|
|
324
|
-
// runPlay (realpath-guarded scriptPath, concurrent stdout/stderr drain,
|
|
325
|
-
// optional stdin payload, SIGTERM→2s→SIGKILL escalation on timeout) but the
|
|
326
|
-
// lifecycle SSE event is the single `demo:reset` broadcast that mirrors the
|
|
327
|
-
// returned shape. Callers (the /reset endpoint) decide what HTTP status to
|
|
328
|
-
// surface; this returns `{ ok }` plus body/error so the endpoint can map.
|
|
329
|
-
export async function runReset(options: RunResetOptions): Promise<ResetResult> {
|
|
330
|
-
const { events, flowId, cwd, action } = options;
|
|
331
|
-
const spawner = options.spawner ?? defaultProcessSpawner;
|
|
332
|
-
|
|
333
|
-
// resetAction is anchored at the project root — design defers per-node
|
|
334
|
-
// resetAction to a later round (decision #7).
|
|
335
|
-
const resolved = resolveResetScript(cwd, action.scriptPath);
|
|
336
|
-
if (!resolved.ok) {
|
|
337
|
-
events.broadcast({
|
|
338
|
-
type: 'demo:reset',
|
|
339
|
-
flowId,
|
|
340
|
-
payload: { ok: false, error: SCRIPT_PATH_ESCAPE },
|
|
341
|
-
});
|
|
342
|
-
return { ok: false, error: SCRIPT_PATH_ESCAPE };
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const wantsStdin = action.input !== undefined;
|
|
346
|
-
const env = buildChildEnv({ SEEFLOW_DEMO_ID: flowId });
|
|
347
|
-
|
|
348
|
-
let handle: SpawnHandle;
|
|
349
|
-
try {
|
|
350
|
-
handle = spawner.spawn({
|
|
351
|
-
cmd: [action.interpreter, ...(action.args ?? []), resolved.absPath],
|
|
352
|
-
cwd,
|
|
353
|
-
env,
|
|
354
|
-
stdin: wantsStdin ? 'pipe' : 'ignore',
|
|
355
|
-
});
|
|
356
|
-
} catch (err) {
|
|
357
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
358
|
-
events.broadcast({
|
|
359
|
-
type: 'demo:reset',
|
|
360
|
-
flowId,
|
|
361
|
-
payload: { ok: false, error: message },
|
|
362
|
-
});
|
|
363
|
-
return { ok: false, error: message };
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const stdoutPromise = new Response(handle.stdout).text();
|
|
367
|
-
const stderrPromise = new Response(handle.stderr).text();
|
|
368
|
-
|
|
369
|
-
if (wantsStdin) {
|
|
370
|
-
await writeStdinPayload(handle, action.input);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const timeoutMs = action.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
374
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
375
|
-
const timeoutPromise = new Promise<'timeout'>((res) => {
|
|
376
|
-
timer = setTimeout(() => res('timeout'), timeoutMs);
|
|
377
|
-
});
|
|
378
|
-
const exitPromise = handle.exited.then((code) => ({ code }) as const);
|
|
379
|
-
|
|
380
|
-
const race = await Promise.race([exitPromise, timeoutPromise]);
|
|
381
|
-
if (timer) clearTimeout(timer);
|
|
382
|
-
|
|
383
|
-
if (race === 'timeout') {
|
|
384
|
-
await killWithGrace(handle);
|
|
385
|
-
await Promise.allSettled([stdoutPromise, stderrPromise]);
|
|
386
|
-
const message = `reset script timed out after ${timeoutMs}ms`;
|
|
387
|
-
events.broadcast({
|
|
388
|
-
type: 'demo:reset',
|
|
389
|
-
flowId,
|
|
390
|
-
payload: { ok: false, error: message },
|
|
391
|
-
});
|
|
392
|
-
return { ok: false, error: message };
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const code = race.code;
|
|
396
|
-
const [stdout, stderr] = await Promise.all([stdoutPromise, stderrPromise]);
|
|
397
|
-
|
|
398
|
-
if (code === 0) {
|
|
399
|
-
let body: unknown;
|
|
400
|
-
try {
|
|
401
|
-
body = JSON.parse(stdout);
|
|
402
|
-
} catch {
|
|
403
|
-
body = stdout;
|
|
404
|
-
}
|
|
405
|
-
events.broadcast({
|
|
406
|
-
type: 'demo:reset',
|
|
407
|
-
flowId,
|
|
408
|
-
payload: { ok: true, body },
|
|
409
|
-
});
|
|
410
|
-
return { ok: true, body };
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const lastLine = lastNonEmptyLine(stderr);
|
|
414
|
-
const truncated = lastLine.slice(0, STDERR_TRUNCATE);
|
|
415
|
-
const message = truncated.length > 0 ? truncated : `reset script exited with code ${code}`;
|
|
416
|
-
events.broadcast({
|
|
417
|
-
type: 'demo:reset',
|
|
418
|
-
flowId,
|
|
419
|
-
payload: { ok: false, error: message },
|
|
420
|
-
});
|
|
421
|
-
return { ok: false, error: message };
|
|
422
|
-
}
|
package/src/schema-catalog.ts
CHANGED
|
@@ -15,8 +15,10 @@ import {
|
|
|
15
15
|
FlowComponentNodeSchema,
|
|
16
16
|
FlowConnectorSchema,
|
|
17
17
|
FlowDatabaseNodeSchema,
|
|
18
|
+
FlowDiamondNodeSchema,
|
|
18
19
|
FlowEllipseNodeSchema,
|
|
19
20
|
FlowEnvelopeSchema,
|
|
21
|
+
FlowHexagonNodeSchema,
|
|
20
22
|
FlowHtmlNodeSchema,
|
|
21
23
|
FlowIconNodeSchema,
|
|
22
24
|
FlowImageNodeSchema,
|
|
@@ -27,7 +29,6 @@ import {
|
|
|
27
29
|
FlowTextNodeSchema,
|
|
28
30
|
FlowUserNodeSchema,
|
|
29
31
|
PlayActionSchema,
|
|
30
|
-
ResetActionSchema,
|
|
31
32
|
StatusActionSchema,
|
|
32
33
|
StatusReportSchema,
|
|
33
34
|
StyleSchema,
|
|
@@ -63,7 +64,7 @@ const CATEGORIES: SchemaCategory[] = [
|
|
|
63
64
|
{
|
|
64
65
|
name: 'action',
|
|
65
66
|
description:
|
|
66
|
-
'playAction, statusAction,
|
|
67
|
+
'playAction, statusAction, statusReport, plus componentAction (the set | script discriminated union dispatched on component-node action handles).',
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
70
|
name: 'componentSpec',
|
|
@@ -89,6 +90,8 @@ const PAYLOADS: Record<string, SchemaPayload> = {
|
|
|
89
90
|
user: toJsonSchema(FlowUserNodeSchema),
|
|
90
91
|
queue: toJsonSchema(FlowQueueNodeSchema),
|
|
91
92
|
cloud: toJsonSchema(FlowCloudNodeSchema),
|
|
93
|
+
diamond: toJsonSchema(FlowDiamondNodeSchema),
|
|
94
|
+
hexagon: toJsonSchema(FlowHexagonNodeSchema),
|
|
92
95
|
image: toJsonSchema(FlowImageNodeSchema),
|
|
93
96
|
html: toJsonSchema(FlowHtmlNodeSchema),
|
|
94
97
|
icon: toJsonSchema(FlowIconNodeSchema),
|
|
@@ -112,7 +115,6 @@ const PAYLOADS: Record<string, SchemaPayload> = {
|
|
|
112
115
|
schemas: {
|
|
113
116
|
playAction: toJsonSchema(PlayActionSchema),
|
|
114
117
|
statusAction: toJsonSchema(StatusActionSchema),
|
|
115
|
-
resetAction: toJsonSchema(ResetActionSchema),
|
|
116
118
|
statusReport: toJsonSchema(StatusReportSchema),
|
|
117
119
|
componentAction: toJsonSchema(ComponentActionSchema),
|
|
118
120
|
},
|
package/src/schema.ts
CHANGED
|
@@ -18,6 +18,7 @@ export const ColorTokenSchema = z.enum([
|
|
|
18
18
|
// and edges aren't useful, and `'default'` already covers "inherit".
|
|
19
19
|
'none',
|
|
20
20
|
'default',
|
|
21
|
+
'white',
|
|
21
22
|
'slate',
|
|
22
23
|
'gray',
|
|
23
24
|
'red',
|
|
@@ -115,9 +116,6 @@ export const ScriptActionSchema = z.object({
|
|
|
115
116
|
|
|
116
117
|
export const PlayActionSchema = ScriptActionSchema;
|
|
117
118
|
|
|
118
|
-
// resetAction is a one-shot script with the same shape as a play script.
|
|
119
|
-
export const ResetActionSchema = ScriptActionSchema;
|
|
120
|
-
|
|
121
119
|
// Long-running status script. Same spawn shape as ScriptAction (interpreter +
|
|
122
120
|
// args + scriptPath) but no stdin payload and a much longer max lifetime since
|
|
123
121
|
// these processes tick continuously and stream StatusReports to stdout.
|
|
@@ -182,7 +180,7 @@ const NodeCapabilitiesShape = {
|
|
|
182
180
|
),
|
|
183
181
|
};
|
|
184
182
|
|
|
185
|
-
//
|
|
183
|
+
// 15 flat node types. The first 11 are geometric/illustrative and share
|
|
186
184
|
// GeometricNodeData. `image`, `html`, `icon`, `component` carry per-type
|
|
187
185
|
// fields. The renderer picks the SVG / chrome by `type`; the schema treats
|
|
188
186
|
// them (apart from the per-type fields below) as identical.
|
|
@@ -196,6 +194,8 @@ export const GEOMETRIC_NODE_TYPES = [
|
|
|
196
194
|
'user',
|
|
197
195
|
'queue',
|
|
198
196
|
'cloud',
|
|
197
|
+
'diamond',
|
|
198
|
+
'hexagon',
|
|
199
199
|
] as const;
|
|
200
200
|
|
|
201
201
|
export const NodeTypeSchema = z.enum([
|
|
@@ -331,6 +331,8 @@ const NodeSchema = z.discriminatedUnion('type', [
|
|
|
331
331
|
makeResolvedGeometricSchema('user'),
|
|
332
332
|
makeResolvedGeometricSchema('queue'),
|
|
333
333
|
makeResolvedGeometricSchema('cloud'),
|
|
334
|
+
makeResolvedGeometricSchema('diamond'),
|
|
335
|
+
makeResolvedGeometricSchema('hexagon'),
|
|
334
336
|
z.object({ ...NodeBaseShape, type: z.literal('image'), data: ResolvedImageNodeData }),
|
|
335
337
|
z.object({ ...NodeBaseShape, type: z.literal('html'), data: ResolvedHtmlNodeData }),
|
|
336
338
|
z.object({ ...NodeBaseShape, type: z.literal('icon'), data: ResolvedIconNodeData }),
|
|
@@ -395,10 +397,6 @@ export const ResolvedFlowSchema = z
|
|
|
395
397
|
description: z.string().optional(),
|
|
396
398
|
nodes: z.array(NodeSchema),
|
|
397
399
|
connectors: z.array(ConnectorSchema),
|
|
398
|
-
// Optional one-shot script the studio runs when the user clicks Restart.
|
|
399
|
-
// The studio kills every live play + status script for the flow BEFORE
|
|
400
|
-
// invoking this script, so the script sees no stragglers.
|
|
401
|
-
resetAction: ResetActionSchema.optional(),
|
|
402
400
|
})
|
|
403
401
|
.superRefine((resolved, ctx) => {
|
|
404
402
|
const nodeIds = new Set(resolved.nodes.map((n) => n.id));
|
|
@@ -476,7 +474,6 @@ export type EdgePinSide = z.infer<typeof EdgePinSideSchema>;
|
|
|
476
474
|
export type PlayAction = z.infer<typeof PlayActionSchema>;
|
|
477
475
|
export type StatusAction = z.infer<typeof StatusActionSchema>;
|
|
478
476
|
export type StatusReport = z.infer<typeof StatusReportSchema>;
|
|
479
|
-
export type ResetAction = z.infer<typeof ResetActionSchema>;
|
|
480
477
|
export type StateSource = z.infer<typeof StateSourceSchema>;
|
|
481
478
|
|
|
482
479
|
// =============================================================================
|
|
@@ -577,6 +574,8 @@ export const FlowServerNodeSchema = makeFlowGeometricSchema('server');
|
|
|
577
574
|
export const FlowUserNodeSchema = makeFlowGeometricSchema('user');
|
|
578
575
|
export const FlowQueueNodeSchema = makeFlowGeometricSchema('queue');
|
|
579
576
|
export const FlowCloudNodeSchema = makeFlowGeometricSchema('cloud');
|
|
577
|
+
export const FlowDiamondNodeSchema = makeFlowGeometricSchema('diamond');
|
|
578
|
+
export const FlowHexagonNodeSchema = makeFlowGeometricSchema('hexagon');
|
|
580
579
|
|
|
581
580
|
export const FlowImageNodeSchema = z
|
|
582
581
|
.object({
|
|
@@ -620,6 +619,8 @@ const FlowNodeSchema = z.discriminatedUnion('type', [
|
|
|
620
619
|
FlowUserNodeSchema,
|
|
621
620
|
FlowQueueNodeSchema,
|
|
622
621
|
FlowCloudNodeSchema,
|
|
622
|
+
FlowDiamondNodeSchema,
|
|
623
|
+
FlowHexagonNodeSchema,
|
|
623
624
|
FlowImageNodeSchema,
|
|
624
625
|
FlowHtmlNodeSchema,
|
|
625
626
|
FlowIconNodeSchema,
|
|
@@ -648,7 +649,6 @@ export const FlowSchema = z
|
|
|
648
649
|
version: z.literal(2),
|
|
649
650
|
name: z.string().min(1),
|
|
650
651
|
description: z.string().optional(),
|
|
651
|
-
resetAction: ResetActionSchema.optional(),
|
|
652
652
|
nodes: z.array(FlowNodeSchema),
|
|
653
653
|
connectors: z.array(FlowConnectorSchema),
|
|
654
654
|
})
|
|
@@ -687,7 +687,6 @@ export const FlowEnvelopeSchema = z
|
|
|
687
687
|
version: z.literal(2),
|
|
688
688
|
name: z.string().min(1),
|
|
689
689
|
description: z.string().optional(),
|
|
690
|
-
resetAction: ResetActionSchema.optional(),
|
|
691
690
|
nodes: z.array(z.unknown().describe('See `seeflow schema node`')),
|
|
692
691
|
connectors: z.array(z.unknown().describe('See `seeflow schema connector`')),
|
|
693
692
|
})
|
package/src/server.ts
CHANGED
|
@@ -52,8 +52,7 @@ export interface CreateAppOptions {
|
|
|
52
52
|
* proxy.ts pick `defaultProcessSpawner`. Tests use this to drive runPlay
|
|
53
53
|
* with an in-memory fake spawner. */
|
|
54
54
|
processSpawner?: ProcessSpawner;
|
|
55
|
-
/** Inject a ProxyFacade — tests use this to short-circuit runPlay
|
|
56
|
-
* runReset / stopAllPlays and assert call order. */
|
|
55
|
+
/** Inject a ProxyFacade — tests use this to short-circuit runPlay. */
|
|
57
56
|
proxy?: ProxyFacade;
|
|
58
57
|
/** Per-process token gating `Origin: null` requests (sandboxed MCP App
|
|
59
58
|
* iframe). Generated at studio boot; delivered to the iframe via
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,C as n}from"./mermaid.core-ClLm1p66.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM-ZXC_1s3s.js";import{a as i}from"./mermaid.core-ClLm1p66.js";import"./index-Cnz1Cpa9.js";import"./chunk-FMBD7UC4-D8IemyXd.js";import"./chunk-ND2GUHAM-aT_PIEvu.js";import"./chunk-55IACEB6-CZ6tcHFC.js";import"./chunk-2J33WTMH-CQFLt-Og.js";import"./purify.es-CLGrRn1w.js";import"./step-CWvwoXpJ.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM-ZXC_1s3s.js";import{a as i}from"./mermaid.core-ClLm1p66.js";import"./index-Cnz1Cpa9.js";import"./chunk-FMBD7UC4-D8IemyXd.js";import"./chunk-ND2GUHAM-aT_PIEvu.js";import"./chunk-55IACEB6-CZ6tcHFC.js";import"./chunk-2J33WTMH-CQFLt-Og.js";import"./purify.es-CLGrRn1w.js";import"./step-CWvwoXpJ.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};
|