lyu-extension-workflow 0.0.0-stage → 0.1.1
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/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +482 -0
- package/dist/index.js.map +1 -0
- package/frontend/dist/index.html +686 -0
- package/package.json +31 -4
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension for lyu-code
|
|
3
|
+
*
|
|
4
|
+
* /workflow — 打开本地前端页面,可视化编排多 agent 工作流
|
|
5
|
+
*
|
|
6
|
+
* 架构:
|
|
7
|
+
* - 命令启动本地 HTTP 服务(默认 18789)+ WebSocket
|
|
8
|
+
* - serve frontend/dist/ 下的静态文件(用户自行提供)
|
|
9
|
+
* - WebSocket 通道让前端和 Pi 通信
|
|
10
|
+
* - 前端发指令(addNode, connect, run, stop, ...)
|
|
11
|
+
* - 扩展执行操作,回传状态和结果
|
|
12
|
+
*
|
|
13
|
+
* 用法:
|
|
14
|
+
* /workflow — 打开编辑器
|
|
15
|
+
* /workflow stop — 关闭服务
|
|
16
|
+
*/
|
|
17
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
export default function (pi: ExtensionAPI): void;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAGb,MAAM,iCAAiC,CAAC;AAkbzC,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAoDxC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Extension for lyu-code
|
|
3
|
+
*
|
|
4
|
+
* /workflow — 打开本地前端页面,可视化编排多 agent 工作流
|
|
5
|
+
*
|
|
6
|
+
* 架构:
|
|
7
|
+
* - 命令启动本地 HTTP 服务(默认 18789)+ WebSocket
|
|
8
|
+
* - serve frontend/dist/ 下的静态文件(用户自行提供)
|
|
9
|
+
* - WebSocket 通道让前端和 Pi 通信
|
|
10
|
+
* - 前端发指令(addNode, connect, run, stop, ...)
|
|
11
|
+
* - 扩展执行操作,回传状态和结果
|
|
12
|
+
*
|
|
13
|
+
* 用法:
|
|
14
|
+
* /workflow — 打开编辑器
|
|
15
|
+
* /workflow stop — 关闭服务
|
|
16
|
+
*/
|
|
17
|
+
import * as http from "node:http";
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { URL } from "node:url";
|
|
21
|
+
const DEFAULT_PORT = 18789;
|
|
22
|
+
// ─── 简易 WebSocket (RFC 6455, 最小实现) ──────────────────────────
|
|
23
|
+
function wsAcceptKey(key) {
|
|
24
|
+
const crypto = require("node:crypto");
|
|
25
|
+
return crypto.createHash("sha1").update(key + "258EAFA5-E914-47DA-95CA-5AB5DC828B12").digest("base64");
|
|
26
|
+
}
|
|
27
|
+
// ─── 全局状态 ──────────────────────────────────────────────────────
|
|
28
|
+
let server = null;
|
|
29
|
+
let port = DEFAULT_PORT;
|
|
30
|
+
let piRef = null;
|
|
31
|
+
const workflows = new Map();
|
|
32
|
+
const runStates = new Map();
|
|
33
|
+
const wsClients = [];
|
|
34
|
+
// ─── 广播 ──────────────────────────────────────────────────────────
|
|
35
|
+
function broadcast(type, data) {
|
|
36
|
+
const msg = JSON.stringify({ type, data });
|
|
37
|
+
for (const c of wsClients) {
|
|
38
|
+
try {
|
|
39
|
+
c.send(msg);
|
|
40
|
+
}
|
|
41
|
+
catch { /* ignore */ }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ─── 前端静态文件 ──────────────────────────────────────────────────
|
|
45
|
+
const MIME = {
|
|
46
|
+
".html": "text/html", ".js": "application/javascript", ".mjs": "application/javascript",
|
|
47
|
+
".css": "text/css", ".json": "application/json", ".png": "image/png",
|
|
48
|
+
".jpg": "image/jpeg", ".svg": "image/svg+xml", ".ico": "image/x-icon",
|
|
49
|
+
".woff": "font/woff", ".woff2": "font/woff2",
|
|
50
|
+
};
|
|
51
|
+
function getFrontendDir() {
|
|
52
|
+
const thisDir = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
|
|
53
|
+
return path.join(thisDir, "..", "frontend", "dist");
|
|
54
|
+
}
|
|
55
|
+
function serveStatic(req, res) {
|
|
56
|
+
const frontendDir = getFrontendDir();
|
|
57
|
+
let urlPath = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
58
|
+
// API 路由
|
|
59
|
+
if (urlPath.startsWith("/api/")) {
|
|
60
|
+
handleApi(req, res, urlPath);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// 静态文件
|
|
64
|
+
if (urlPath === "/")
|
|
65
|
+
urlPath = "/index.html";
|
|
66
|
+
const filePath = path.join(frontendDir, urlPath);
|
|
67
|
+
try {
|
|
68
|
+
if (!filePath.startsWith(frontendDir)) {
|
|
69
|
+
res.writeHead(403);
|
|
70
|
+
res.end();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const stat = fs.statSync(filePath);
|
|
74
|
+
if (!stat.isFile())
|
|
75
|
+
throw new Error("not file");
|
|
76
|
+
const ext = path.extname(filePath);
|
|
77
|
+
res.writeHead(200, { "Content-Type": (MIME[ext] || "application/octet-stream") + "; charset=utf-8" });
|
|
78
|
+
res.end(fs.readFileSync(filePath));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// SPA fallback
|
|
82
|
+
try {
|
|
83
|
+
const fallback = path.join(frontendDir, "index.html");
|
|
84
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
85
|
+
res.end(fs.readFileSync(fallback));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
res.writeHead(404);
|
|
89
|
+
res.end("Not found — put frontend files in frontend/dist/");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function handleApi(_req, res, urlPath) {
|
|
94
|
+
const ok = (d) => { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(d)); };
|
|
95
|
+
if (urlPath === "/api/workflows") {
|
|
96
|
+
ok([...workflows.values()].map(w => ({ id: w.id, name: w.name, nodeCount: w.nodes.length, globalMaxLoops: w.globalMaxLoops })));
|
|
97
|
+
}
|
|
98
|
+
else if (urlPath === "/api/status") {
|
|
99
|
+
ok({ ok: true, workflows: workflows.size, clients: wsClients.length });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
ok({ error: "not found" });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ─── WebSocket 消息处理 ────────────────────────────────────────────
|
|
106
|
+
function handleWsMessage(raw) {
|
|
107
|
+
let msg;
|
|
108
|
+
try {
|
|
109
|
+
msg = JSON.parse(raw);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
switch (msg.type) {
|
|
115
|
+
case "workflow:create": {
|
|
116
|
+
const wf = {
|
|
117
|
+
id: msg.data?.id ?? `wf-${Date.now()}`,
|
|
118
|
+
name: msg.data?.name ?? "Untitled Workflow",
|
|
119
|
+
nodes: msg.data?.nodes ?? [],
|
|
120
|
+
edges: msg.data?.edges ?? [],
|
|
121
|
+
globalMaxLoops: msg.data?.globalMaxLoops ?? 10,
|
|
122
|
+
createdAt: Date.now(),
|
|
123
|
+
updatedAt: Date.now(),
|
|
124
|
+
};
|
|
125
|
+
workflows.set(wf.id, wf);
|
|
126
|
+
runStates.set(wf.id, { status: "idle", iteration: 0, results: {} });
|
|
127
|
+
broadcast("workflow:created", wf);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case "workflow:update": {
|
|
131
|
+
const wf = workflows.get(msg.data?.id);
|
|
132
|
+
if (wf) {
|
|
133
|
+
Object.assign(wf, msg.data, { updatedAt: Date.now() });
|
|
134
|
+
broadcast("workflow:updated", wf);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "workflow:delete": {
|
|
139
|
+
workflows.delete(msg.data?.id);
|
|
140
|
+
runStates.delete(msg.data?.id);
|
|
141
|
+
broadcast("workflow:deleted", { id: msg.data?.id });
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case "node:add": {
|
|
145
|
+
const wf = workflows.get(msg.data?.workflowId);
|
|
146
|
+
if (wf) {
|
|
147
|
+
wf.nodes.push(msg.data.node);
|
|
148
|
+
wf.updatedAt = Date.now();
|
|
149
|
+
broadcast("workflow:updated", wf);
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case "node:update": {
|
|
154
|
+
const wf = workflows.get(msg.data?.workflowId);
|
|
155
|
+
if (wf) {
|
|
156
|
+
const i = wf.nodes.findIndex(n => n.id === msg.data.node.id);
|
|
157
|
+
if (i >= 0) {
|
|
158
|
+
wf.nodes[i] = { ...wf.nodes[i], ...msg.data.node };
|
|
159
|
+
wf.updatedAt = Date.now();
|
|
160
|
+
broadcast("workflow:updated", wf);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case "node:remove": {
|
|
166
|
+
const wf = workflows.get(msg.data?.workflowId);
|
|
167
|
+
if (wf) {
|
|
168
|
+
wf.nodes = wf.nodes.filter(n => n.id !== msg.data.nodeId);
|
|
169
|
+
wf.edges = wf.edges.filter(e => e.source !== msg.data.nodeId && e.target !== msg.data.nodeId);
|
|
170
|
+
wf.updatedAt = Date.now();
|
|
171
|
+
broadcast("workflow:updated", wf);
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case "edge:add": {
|
|
176
|
+
const wf = workflows.get(msg.data?.workflowId);
|
|
177
|
+
if (wf) {
|
|
178
|
+
wf.edges.push(msg.data.edge);
|
|
179
|
+
wf.updatedAt = Date.now();
|
|
180
|
+
broadcast("workflow:updated", wf);
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "edge:remove": {
|
|
185
|
+
const wf = workflows.get(msg.data?.workflowId);
|
|
186
|
+
if (wf) {
|
|
187
|
+
wf.edges = wf.edges.filter(e => e.id !== msg.data.edgeId);
|
|
188
|
+
wf.updatedAt = Date.now();
|
|
189
|
+
broadcast("workflow:updated", wf);
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "workflow:run": {
|
|
194
|
+
const wfId = msg.data?.workflowId;
|
|
195
|
+
const wf = workflows.get(wfId);
|
|
196
|
+
const state = runStates.get(wfId);
|
|
197
|
+
if (!wf || !state || state.status === "running")
|
|
198
|
+
break;
|
|
199
|
+
state.status = "running";
|
|
200
|
+
state.iteration = 0;
|
|
201
|
+
state.results = {};
|
|
202
|
+
for (const n of wf.nodes)
|
|
203
|
+
state.results[n.id] = { status: "pending" };
|
|
204
|
+
broadcast("run:state", { workflowId: wfId, state });
|
|
205
|
+
runWorkflow(wf, state).catch(err => {
|
|
206
|
+
state.status = "error";
|
|
207
|
+
broadcast("run:state", { workflowId: wfId, state, error: String(err) });
|
|
208
|
+
});
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case "workflow:stop": {
|
|
212
|
+
const state = runStates.get(msg.data?.workflowId);
|
|
213
|
+
if (state) {
|
|
214
|
+
state.status = "idle";
|
|
215
|
+
broadcast("run:state", { workflowId: msg.data?.workflowId, state });
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
case "agent:send": {
|
|
220
|
+
if (piRef) {
|
|
221
|
+
piRef.sendUserMessage(msg.data?.message ?? "", { deliverAs: "followUp" });
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ─── Workflow 执行引擎 ─────────────────────────────────────────────
|
|
228
|
+
async function runWorkflow(wf, state) {
|
|
229
|
+
const sorted = topoSort(wf.nodes, wf.edges);
|
|
230
|
+
for (let iter = 0; iter < wf.globalMaxLoops; iter++) {
|
|
231
|
+
state.iteration = iter + 1;
|
|
232
|
+
broadcast("run:state", { workflowId: wf.id, state });
|
|
233
|
+
for (const node of sorted) {
|
|
234
|
+
const ns = state.results[node.id];
|
|
235
|
+
if (!ns)
|
|
236
|
+
continue;
|
|
237
|
+
ns.status = "running";
|
|
238
|
+
state.currentStep = node.id;
|
|
239
|
+
broadcast("run:state", { workflowId: wf.id, state });
|
|
240
|
+
// 收集上游输出
|
|
241
|
+
const upstream = wf.edges
|
|
242
|
+
.filter(e => e.target === node.id)
|
|
243
|
+
.map(e => state.results[e.source]?.output ?? "")
|
|
244
|
+
.filter(Boolean)
|
|
245
|
+
.join("\n\n");
|
|
246
|
+
// 通过 Pi 驱动 agent
|
|
247
|
+
if (piRef) {
|
|
248
|
+
const prompt = upstream
|
|
249
|
+
? `[上游输入]\n${upstream}\n\n[请处理以上输入并输出结果]`
|
|
250
|
+
: node.config.systemPrompt ?? "请开始工作";
|
|
251
|
+
piRef.sendUserMessage(prompt, { deliverAs: "followUp" });
|
|
252
|
+
}
|
|
253
|
+
// 等待一小段时间让 Pi 处理(实际结果由 agent_end 事件回填)
|
|
254
|
+
await new Promise(r => setTimeout(r, 500));
|
|
255
|
+
ns.status = "done";
|
|
256
|
+
ns.iterations = (ns.iterations ?? 0) + 1;
|
|
257
|
+
broadcast("run:state", { workflowId: wf.id, state });
|
|
258
|
+
}
|
|
259
|
+
// 无回边则不循环
|
|
260
|
+
const hasBack = wf.edges.some(e => {
|
|
261
|
+
const si = sorted.findIndex(n => n.id === e.source);
|
|
262
|
+
const ti = sorted.findIndex(n => n.id === e.target);
|
|
263
|
+
return ti <= si;
|
|
264
|
+
});
|
|
265
|
+
if (!hasBack)
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
state.status = "done";
|
|
269
|
+
state.currentStep = undefined;
|
|
270
|
+
broadcast("run:state", { workflowId: wf.id, state });
|
|
271
|
+
}
|
|
272
|
+
function topoSort(nodes, edges) {
|
|
273
|
+
const nodeMap = new Map(nodes.map(n => [n.id, n]));
|
|
274
|
+
const deg = new Map(nodes.map(n => [n.id, 0]));
|
|
275
|
+
const adj = new Map(nodes.map(n => [n.id, []]));
|
|
276
|
+
for (const e of edges) {
|
|
277
|
+
adj.get(e.source)?.push(e.target);
|
|
278
|
+
deg.set(e.target, (deg.get(e.target) ?? 0) + 1);
|
|
279
|
+
}
|
|
280
|
+
const q = [];
|
|
281
|
+
for (const [id, d] of deg)
|
|
282
|
+
if (d === 0)
|
|
283
|
+
q.push(id);
|
|
284
|
+
const result = [];
|
|
285
|
+
while (q.length) {
|
|
286
|
+
const id = q.shift();
|
|
287
|
+
const n = nodeMap.get(id);
|
|
288
|
+
if (n)
|
|
289
|
+
result.push(n);
|
|
290
|
+
for (const next of adj.get(id) ?? []) {
|
|
291
|
+
const d = (deg.get(next) ?? 1) - 1;
|
|
292
|
+
deg.set(next, d);
|
|
293
|
+
if (d === 0)
|
|
294
|
+
q.push(next);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
for (const n of nodes)
|
|
298
|
+
if (!result.find(r => r.id === n.id))
|
|
299
|
+
result.push(n);
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
// ─── 启停 ──────────────────────────────────────────────────────────
|
|
303
|
+
function startServer() {
|
|
304
|
+
return new Promise((resolve, reject) => {
|
|
305
|
+
server = http.createServer(serveStatic);
|
|
306
|
+
// WebSocket upgrade (简易实现)
|
|
307
|
+
server.on("upgrade", (req, socket, head) => {
|
|
308
|
+
if (!(req.url ?? "/").startsWith("/ws")) {
|
|
309
|
+
socket.destroy();
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const key = req.headers["sec-websocket-key"];
|
|
313
|
+
if (!key) {
|
|
314
|
+
socket.destroy();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
|
|
318
|
+
"Upgrade: websocket\r\n" +
|
|
319
|
+
"Connection: Upgrade\r\n" +
|
|
320
|
+
`Sec-WebSocket-Accept: ${wsAcceptKey(key)}\r\n\r\n`);
|
|
321
|
+
const client = {
|
|
322
|
+
socket,
|
|
323
|
+
send(data) {
|
|
324
|
+
// 简易:发 text frame (opcode 0x1), 无掩码, 不分片
|
|
325
|
+
const buf = Buffer.from(data, "utf-8");
|
|
326
|
+
const len = buf.length;
|
|
327
|
+
const frames = [];
|
|
328
|
+
if (len < 126) {
|
|
329
|
+
frames.push(Buffer.from([0x81, len]));
|
|
330
|
+
}
|
|
331
|
+
else if (len < 65536) {
|
|
332
|
+
const h = Buffer.alloc(4);
|
|
333
|
+
h[0] = 0x81;
|
|
334
|
+
h[1] = 126;
|
|
335
|
+
h.writeUInt16BE(len, 2);
|
|
336
|
+
frames.push(h);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
const h = Buffer.alloc(10);
|
|
340
|
+
h[0] = 0x81;
|
|
341
|
+
h[1] = 127;
|
|
342
|
+
h.writeBigUInt64BE(BigInt(len), 2);
|
|
343
|
+
frames.push(h);
|
|
344
|
+
}
|
|
345
|
+
frames.push(buf);
|
|
346
|
+
socket.write(Buffer.concat(frames));
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
wsClients.push(client);
|
|
350
|
+
// 接收帧(简易:只处理小 text 帧)
|
|
351
|
+
let buf = Buffer.alloc(0);
|
|
352
|
+
socket.on("data", (chunk) => {
|
|
353
|
+
buf = Buffer.concat([buf, chunk]);
|
|
354
|
+
// 解析 text frame
|
|
355
|
+
if (buf.length < 2)
|
|
356
|
+
return;
|
|
357
|
+
const opcode = buf[0] & 0x0f;
|
|
358
|
+
const masked = !!(buf[1] & 0x80);
|
|
359
|
+
let payloadLen = buf[1] & 0x7f;
|
|
360
|
+
let offset = 2;
|
|
361
|
+
if (payloadLen === 126) {
|
|
362
|
+
if (buf.length < 4)
|
|
363
|
+
return;
|
|
364
|
+
payloadLen = buf.readUInt16BE(2);
|
|
365
|
+
offset = 4;
|
|
366
|
+
}
|
|
367
|
+
else if (payloadLen === 127) {
|
|
368
|
+
if (buf.length < 10)
|
|
369
|
+
return;
|
|
370
|
+
payloadLen = Number(buf.readBigUInt64BE(2));
|
|
371
|
+
offset = 10;
|
|
372
|
+
}
|
|
373
|
+
if (masked)
|
|
374
|
+
offset += 4;
|
|
375
|
+
if (buf.length < offset + payloadLen)
|
|
376
|
+
return;
|
|
377
|
+
let payload = buf.subarray(offset, offset + payloadLen);
|
|
378
|
+
if (masked) {
|
|
379
|
+
const mask = buf.subarray(offset - 4, offset);
|
|
380
|
+
payload = Buffer.from(payload.map((b, i) => b ^ mask[i % 4]));
|
|
381
|
+
}
|
|
382
|
+
buf = buf.subarray(offset + payloadLen);
|
|
383
|
+
if (opcode === 0x1) { // text
|
|
384
|
+
handleWsMessage(payload.toString("utf-8"));
|
|
385
|
+
}
|
|
386
|
+
else if (opcode === 0x8) { // close
|
|
387
|
+
const idx = wsClients.indexOf(client);
|
|
388
|
+
if (idx >= 0)
|
|
389
|
+
wsClients.splice(idx, 1);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
socket.on("close", () => {
|
|
393
|
+
const idx = wsClients.indexOf(client);
|
|
394
|
+
if (idx >= 0)
|
|
395
|
+
wsClients.splice(idx, 1);
|
|
396
|
+
});
|
|
397
|
+
// 发送初始状态
|
|
398
|
+
client.send(JSON.stringify({
|
|
399
|
+
type: "connected",
|
|
400
|
+
data: { workflows: [...workflows.values()], port },
|
|
401
|
+
}));
|
|
402
|
+
});
|
|
403
|
+
server.on("error", (err) => {
|
|
404
|
+
if (err.code === "EADDRINUSE") {
|
|
405
|
+
port++;
|
|
406
|
+
server.listen(port, "127.0.0.1");
|
|
407
|
+
}
|
|
408
|
+
else
|
|
409
|
+
reject(err);
|
|
410
|
+
});
|
|
411
|
+
server.on("listening", () => resolve(port));
|
|
412
|
+
server.listen(port, "127.0.0.1");
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
function stopServer() {
|
|
416
|
+
for (const c of wsClients)
|
|
417
|
+
try {
|
|
418
|
+
c.socket.destroy();
|
|
419
|
+
}
|
|
420
|
+
catch { /* ok */ }
|
|
421
|
+
wsClients.length = 0;
|
|
422
|
+
server?.close();
|
|
423
|
+
server = null;
|
|
424
|
+
}
|
|
425
|
+
// ─── 扩展入口 ──────────────────────────────────────────────────────
|
|
426
|
+
export default function (pi) {
|
|
427
|
+
piRef = pi;
|
|
428
|
+
pi.registerCommand("workflow", {
|
|
429
|
+
description: "Open workflow editor — visually compose multi-agent pipelines",
|
|
430
|
+
handler: async (args, _ctx) => {
|
|
431
|
+
if (args.trim() === "stop") {
|
|
432
|
+
stopServer();
|
|
433
|
+
pi.sendMessage({ customType: "workflow", content: "Workflow server stopped", display: true });
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (!server) {
|
|
437
|
+
const actualPort = await startServer();
|
|
438
|
+
const url = `http://127.0.0.1:${actualPort}`;
|
|
439
|
+
// 打开浏览器
|
|
440
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
441
|
+
try {
|
|
442
|
+
require("node:child_process").execSync(`${cmd} "${url}"`, { stdio: "ignore" });
|
|
443
|
+
}
|
|
444
|
+
catch { /* ok */ }
|
|
445
|
+
pi.sendMessage({
|
|
446
|
+
customType: "workflow",
|
|
447
|
+
content: `Workflow editor: ${url}`,
|
|
448
|
+
display: true,
|
|
449
|
+
details: { url, port: actualPort },
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
const url = `http://127.0.0.1:${port}`;
|
|
454
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
455
|
+
try {
|
|
456
|
+
require("node:child_process").execSync(`${cmd} "${url}"`, { stdio: "ignore" });
|
|
457
|
+
}
|
|
458
|
+
catch { /* ok */ }
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
// agent_end 事件回填节点结果
|
|
463
|
+
pi.on("agent_end", (event) => {
|
|
464
|
+
for (const [wfId, state] of runStates) {
|
|
465
|
+
if (state.status !== "running" || !state.currentStep)
|
|
466
|
+
continue;
|
|
467
|
+
const lastMsg = event.messages[event.messages.length - 1];
|
|
468
|
+
if (lastMsg?.role === "assistant") {
|
|
469
|
+
const content = lastMsg.content;
|
|
470
|
+
const text = Array.isArray(content)
|
|
471
|
+
? content.filter((b) => b.type === "text").map((b) => b.text).join("\n")
|
|
472
|
+
: typeof content === "string" ? content : "";
|
|
473
|
+
const ns = state.results[state.currentStep];
|
|
474
|
+
if (ns)
|
|
475
|
+
ns.output = text;
|
|
476
|
+
broadcast("run:nodeResult", { workflowId: wfId, nodeId: state.currentStep, output: text });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
console.error("[workflow] Extension loaded — /workflow to open editor");
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Lyu-Code Workflow</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
9
|
+
<style>
|
|
10
|
+
/* ===========================================
|
|
11
|
+
CSS CUSTOM PROPERTIES (NEON CYBER THEME)
|
|
12
|
+
=========================================== */
|
|
13
|
+
:root {
|
|
14
|
+
--bg-primary: #0a0f1c;
|
|
15
|
+
--bg-secondary: #111827;
|
|
16
|
+
--bg-tertiary: #1a2332;
|
|
17
|
+
--text-primary: #e2e8f0;
|
|
18
|
+
--text-secondary: #94a3b8;
|
|
19
|
+
--text-muted: #64748b;
|
|
20
|
+
--accent: #22d3ee;
|
|
21
|
+
--accent-glow: rgba(34, 211, 238, 0.3);
|
|
22
|
+
--accent2: #a78bfa;
|
|
23
|
+
--accent2-glow: rgba(167, 139, 250, 0.3);
|
|
24
|
+
--success: #4ade80;
|
|
25
|
+
--warning: #fbbf24;
|
|
26
|
+
--danger: #f87171;
|
|
27
|
+
--border: rgba(148, 163, 184, 0.12);
|
|
28
|
+
--border-active: rgba(34, 211, 238, 0.4);
|
|
29
|
+
--font-display: "Space Grotesk", sans-serif;
|
|
30
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
31
|
+
--radius: 10px;
|
|
32
|
+
--radius-sm: 6px;
|
|
33
|
+
--shadow: 0 4px 24px rgba(0,0,0,0.4);
|
|
34
|
+
--shadow-glow: 0 0 20px var(--accent-glow);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
38
|
+
|
|
39
|
+
html, body {
|
|
40
|
+
height: 100%;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
font-family: var(--font-display);
|
|
43
|
+
background: var(--bg-primary);
|
|
44
|
+
color: var(--text-primary);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* ===========================================
|
|
48
|
+
LAYOUT
|
|
49
|
+
=========================================== */
|
|
50
|
+
#app {
|
|
51
|
+
display: grid;
|
|
52
|
+
grid-template-rows: 48px 1fr;
|
|
53
|
+
grid-template-columns: 240px 1fr 280px;
|
|
54
|
+
height: 100vh;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ─── Header ──────────────────────────────── */
|
|
58
|
+
header {
|
|
59
|
+
grid-column: 1 / -1;
|
|
60
|
+
background: var(--bg-secondary);
|
|
61
|
+
border-bottom: 1px solid var(--border);
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
padding: 0 16px;
|
|
65
|
+
gap: 12px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
header .logo {
|
|
69
|
+
font-weight: 700;
|
|
70
|
+
font-size: 14px;
|
|
71
|
+
letter-spacing: -0.3px;
|
|
72
|
+
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
|
73
|
+
-webkit-background-clip: text;
|
|
74
|
+
-webkit-text-fill-color: transparent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
header .wf-name {
|
|
78
|
+
font-size: 13px;
|
|
79
|
+
color: var(--text-secondary);
|
|
80
|
+
border: 1px solid var(--border);
|
|
81
|
+
border-radius: var(--radius-sm);
|
|
82
|
+
padding: 3px 8px;
|
|
83
|
+
background: transparent;
|
|
84
|
+
outline: none;
|
|
85
|
+
font-family: var(--font-display);
|
|
86
|
+
width: 180px;
|
|
87
|
+
}
|
|
88
|
+
header .wf-name:focus { border-color: var(--accent); }
|
|
89
|
+
|
|
90
|
+
.toolbar {
|
|
91
|
+
display: flex;
|
|
92
|
+
gap: 4px;
|
|
93
|
+
margin-left: auto;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.btn {
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
gap: 5px;
|
|
100
|
+
padding: 5px 10px;
|
|
101
|
+
border: 1px solid var(--border);
|
|
102
|
+
border-radius: var(--radius-sm);
|
|
103
|
+
background: transparent;
|
|
104
|
+
color: var(--text-secondary);
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
font-family: var(--font-display);
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
transition: all 0.15s;
|
|
109
|
+
}
|
|
110
|
+
.btn:hover { background: var(--bg-tertiary); color: var(--text-primary); border-color: var(--text-muted); }
|
|
111
|
+
.btn.primary { background: rgba(34,211,238,0.12); color: var(--accent); border-color: var(--accent); }
|
|
112
|
+
.btn.primary:hover { background: rgba(34,211,238,0.22); box-shadow: var(--shadow-glow); }
|
|
113
|
+
.btn.danger { color: var(--danger); border-color: rgba(248,113,113,0.3); }
|
|
114
|
+
.btn.danger:hover { background: rgba(248,113,113,0.1); }
|
|
115
|
+
|
|
116
|
+
.status-pill {
|
|
117
|
+
font-size: 11px;
|
|
118
|
+
padding: 2px 8px;
|
|
119
|
+
border-radius: 99px;
|
|
120
|
+
font-family: var(--font-mono);
|
|
121
|
+
}
|
|
122
|
+
.status-pill.idle { background: rgba(100,116,139,0.15); color: var(--text-muted); }
|
|
123
|
+
.status-pill.running { background: rgba(74,222,128,0.15); color: var(--success); animation: pulse 1.5s infinite; }
|
|
124
|
+
.status-pill.done { background: rgba(34,211,238,0.15); color: var(--accent); }
|
|
125
|
+
.status-pill.error { background: rgba(248,113,113,0.15); color: var(--danger); }
|
|
126
|
+
|
|
127
|
+
@keyframes pulse { 0%,100%{ opacity:1 } 50%{ opacity:0.6 } }
|
|
128
|
+
|
|
129
|
+
/* ─── Sidebar (Node Palette) ──────────────── */
|
|
130
|
+
aside {
|
|
131
|
+
background: var(--bg-secondary);
|
|
132
|
+
border-right: 1px solid var(--border);
|
|
133
|
+
padding: 12px;
|
|
134
|
+
overflow-y: auto;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
aside h3 {
|
|
138
|
+
font-size: 11px;
|
|
139
|
+
text-transform: uppercase;
|
|
140
|
+
letter-spacing: 1px;
|
|
141
|
+
color: var(--text-muted);
|
|
142
|
+
margin-bottom: 10px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.palette-item {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
gap: 8px;
|
|
149
|
+
padding: 8px 10px;
|
|
150
|
+
margin-bottom: 4px;
|
|
151
|
+
border-radius: var(--radius-sm);
|
|
152
|
+
border: 1px solid var(--border);
|
|
153
|
+
cursor: grab;
|
|
154
|
+
transition: all 0.15s;
|
|
155
|
+
font-size: 13px;
|
|
156
|
+
}
|
|
157
|
+
.palette-item:hover {
|
|
158
|
+
border-color: var(--accent);
|
|
159
|
+
background: rgba(34,211,238,0.06);
|
|
160
|
+
}
|
|
161
|
+
.palette-item .icon {
|
|
162
|
+
width: 28px;
|
|
163
|
+
height: 28px;
|
|
164
|
+
border-radius: 6px;
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
justify-content: center;
|
|
168
|
+
font-size: 14px;
|
|
169
|
+
}
|
|
170
|
+
.palette-item.agent .icon { background: rgba(34,211,238,0.15); }
|
|
171
|
+
|
|
172
|
+
.config-section { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }
|
|
173
|
+
.config-section label {
|
|
174
|
+
display: block;
|
|
175
|
+
font-size: 11px;
|
|
176
|
+
color: var(--text-muted);
|
|
177
|
+
margin-bottom: 4px;
|
|
178
|
+
margin-top: 8px;
|
|
179
|
+
text-transform: uppercase;
|
|
180
|
+
letter-spacing: 0.5px;
|
|
181
|
+
}
|
|
182
|
+
.config-section input, .config-section textarea, .config-section select {
|
|
183
|
+
width: 100%;
|
|
184
|
+
padding: 5px 8px;
|
|
185
|
+
background: var(--bg-primary);
|
|
186
|
+
border: 1px solid var(--border);
|
|
187
|
+
border-radius: var(--radius-sm);
|
|
188
|
+
color: var(--text-primary);
|
|
189
|
+
font-size: 12px;
|
|
190
|
+
font-family: var(--font-display);
|
|
191
|
+
outline: none;
|
|
192
|
+
}
|
|
193
|
+
.config-section input:focus, .config-section textarea:focus, .config-section select:focus {
|
|
194
|
+
border-color: var(--accent);
|
|
195
|
+
}
|
|
196
|
+
.config-section textarea { min-height: 60px; resize: vertical; font-family: var(--font-mono); font-size: 11px; }
|
|
197
|
+
|
|
198
|
+
/* ─── Canvas ──────────────────────────────── */
|
|
199
|
+
.canvas-wrap {
|
|
200
|
+
position: relative;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
background:
|
|
203
|
+
radial-gradient(ellipse at 30% 70%, rgba(34,211,238,0.04) 0%, transparent 50%),
|
|
204
|
+
radial-gradient(ellipse at 70% 30%, rgba(167,139,250,0.04) 0%, transparent 50%),
|
|
205
|
+
var(--bg-primary);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Grid pattern */
|
|
209
|
+
.canvas-wrap::before {
|
|
210
|
+
content: '';
|
|
211
|
+
position: absolute;
|
|
212
|
+
inset: 0;
|
|
213
|
+
background-image:
|
|
214
|
+
linear-gradient(rgba(148,163,184,0.04) 1px, transparent 1px),
|
|
215
|
+
linear-gradient(90deg, rgba(148,163,184,0.04) 1px, transparent 1px);
|
|
216
|
+
background-size: 40px 40px;
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#canvas {
|
|
221
|
+
position: absolute;
|
|
222
|
+
inset: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* SVG arrows */
|
|
226
|
+
.canvas-wrap svg {
|
|
227
|
+
position: absolute;
|
|
228
|
+
inset: 0;
|
|
229
|
+
width: 100%;
|
|
230
|
+
height: 100%;
|
|
231
|
+
pointer-events: none;
|
|
232
|
+
}
|
|
233
|
+
.canvas-wrap svg path {
|
|
234
|
+
fill: none;
|
|
235
|
+
stroke: var(--accent);
|
|
236
|
+
stroke-width: 2;
|
|
237
|
+
stroke-dasharray: 8 4;
|
|
238
|
+
opacity: 0.5;
|
|
239
|
+
filter: drop-shadow(0 0 4px var(--accent-glow));
|
|
240
|
+
}
|
|
241
|
+
.canvas-wrap svg path.active {
|
|
242
|
+
stroke: var(--success);
|
|
243
|
+
opacity: 1;
|
|
244
|
+
stroke-dasharray: none;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* ─── Nodes on canvas ─────────────────────── */
|
|
248
|
+
.node {
|
|
249
|
+
position: absolute;
|
|
250
|
+
width: 180px;
|
|
251
|
+
background: var(--bg-secondary);
|
|
252
|
+
border: 1px solid var(--border);
|
|
253
|
+
border-radius: var(--radius);
|
|
254
|
+
box-shadow: var(--shadow);
|
|
255
|
+
cursor: move;
|
|
256
|
+
user-select: none;
|
|
257
|
+
transition: box-shadow 0.15s, border-color 0.15s;
|
|
258
|
+
}
|
|
259
|
+
.node:hover { border-color: var(--text-muted); }
|
|
260
|
+
.node.selected { border-color: var(--accent); box-shadow: var(--shadow), var(--shadow-glow); }
|
|
261
|
+
.node.running { border-color: var(--success); animation: pulse 1.5s infinite; }
|
|
262
|
+
.node.done { border-color: rgba(74,222,128,0.4); }
|
|
263
|
+
|
|
264
|
+
.node-header {
|
|
265
|
+
display: flex;
|
|
266
|
+
align-items: center;
|
|
267
|
+
gap: 6px;
|
|
268
|
+
padding: 8px 10px;
|
|
269
|
+
border-bottom: 1px solid var(--border);
|
|
270
|
+
font-size: 12px;
|
|
271
|
+
font-weight: 600;
|
|
272
|
+
}
|
|
273
|
+
.node-header .dot {
|
|
274
|
+
width: 8px;
|
|
275
|
+
height: 8px;
|
|
276
|
+
border-radius: 50%;
|
|
277
|
+
background: var(--accent);
|
|
278
|
+
}
|
|
279
|
+
.node.running .node-header .dot { background: var(--success); }
|
|
280
|
+
.node.done .node-header .dot { background: var(--success); opacity: 0.5; }
|
|
281
|
+
|
|
282
|
+
.node-body {
|
|
283
|
+
padding: 8px 10px;
|
|
284
|
+
font-size: 11px;
|
|
285
|
+
color: var(--text-muted);
|
|
286
|
+
}
|
|
287
|
+
.node-body .model-tag {
|
|
288
|
+
display: inline-block;
|
|
289
|
+
padding: 1px 6px;
|
|
290
|
+
background: rgba(167,139,250,0.12);
|
|
291
|
+
color: var(--accent2);
|
|
292
|
+
border-radius: 4px;
|
|
293
|
+
font-family: var(--font-mono);
|
|
294
|
+
font-size: 10px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* Connection ports */
|
|
298
|
+
.port {
|
|
299
|
+
width: 10px;
|
|
300
|
+
height: 10px;
|
|
301
|
+
border-radius: 50%;
|
|
302
|
+
background: var(--bg-tertiary);
|
|
303
|
+
border: 2px solid var(--text-muted);
|
|
304
|
+
position: absolute;
|
|
305
|
+
cursor: crosshair;
|
|
306
|
+
transition: all 0.15s;
|
|
307
|
+
}
|
|
308
|
+
.port:hover { border-color: var(--accent); background: var(--accent-glow); transform: scale(1.3); }
|
|
309
|
+
.port.in { left: -5px; top: 50%; margin-top: -5px; }
|
|
310
|
+
.port.out { right: -5px; top: 50%; margin-top: -5px; }
|
|
311
|
+
|
|
312
|
+
/* ─── Right Panel (Run & Debug) ───────────── */
|
|
313
|
+
.panel {
|
|
314
|
+
background: var(--bg-secondary);
|
|
315
|
+
border-left: 1px solid var(--border);
|
|
316
|
+
padding: 12px;
|
|
317
|
+
overflow-y: auto;
|
|
318
|
+
font-size: 12px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.panel h3 {
|
|
322
|
+
font-size: 11px;
|
|
323
|
+
text-transform: uppercase;
|
|
324
|
+
letter-spacing: 1px;
|
|
325
|
+
color: var(--text-muted);
|
|
326
|
+
margin-bottom: 10px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.run-log {
|
|
330
|
+
font-family: var(--font-mono);
|
|
331
|
+
font-size: 11px;
|
|
332
|
+
line-height: 1.6;
|
|
333
|
+
}
|
|
334
|
+
.run-log .entry {
|
|
335
|
+
padding: 4px 6px;
|
|
336
|
+
margin-bottom: 2px;
|
|
337
|
+
border-radius: 4px;
|
|
338
|
+
background: var(--bg-primary);
|
|
339
|
+
}
|
|
340
|
+
.run-log .entry.error { color: var(--danger); }
|
|
341
|
+
.run-log .entry.success { color: var(--success); }
|
|
342
|
+
|
|
343
|
+
.iter-badge {
|
|
344
|
+
display: inline-block;
|
|
345
|
+
padding: 1px 6px;
|
|
346
|
+
background: rgba(251,191,36,0.12);
|
|
347
|
+
color: var(--warning);
|
|
348
|
+
border-radius: 4px;
|
|
349
|
+
font-family: var(--font-mono);
|
|
350
|
+
font-size: 10px;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* ─── Empty State ─────────────────────────── */
|
|
354
|
+
.empty-state {
|
|
355
|
+
position: absolute;
|
|
356
|
+
inset: 0;
|
|
357
|
+
display: flex;
|
|
358
|
+
flex-direction: column;
|
|
359
|
+
align-items: center;
|
|
360
|
+
justify-content: center;
|
|
361
|
+
color: var(--text-muted);
|
|
362
|
+
gap: 8px;
|
|
363
|
+
}
|
|
364
|
+
.empty-state .big-icon { font-size: 48px; opacity: 0.3; }
|
|
365
|
+
.empty-state p { font-size: 14px; }
|
|
366
|
+
.empty-state .hint { font-size: 11px; color: var(--text-muted); opacity: 0.6; }
|
|
367
|
+
|
|
368
|
+
/* ─── Connection line being drawn ─────────── */
|
|
369
|
+
.temp-line {
|
|
370
|
+
stroke: var(--accent);
|
|
371
|
+
stroke-width: 2;
|
|
372
|
+
stroke-dasharray: 4 4;
|
|
373
|
+
opacity: 0.6;
|
|
374
|
+
}
|
|
375
|
+
</style>
|
|
376
|
+
</head>
|
|
377
|
+
<body>
|
|
378
|
+
<div id="app">
|
|
379
|
+
<!-- Header -->
|
|
380
|
+
<header>
|
|
381
|
+
<span class="logo">⚡ lyu-code</span>
|
|
382
|
+
<span style="color:var(--text-muted);font-size:12px">/</span>
|
|
383
|
+
<input class="wf-name" id="wfName" value="Untitled Workflow" placeholder="Workflow name" />
|
|
384
|
+
<span class="status-pill idle" id="statusP#ill">IDLE</span>
|
|
385
|
+
<div class="toolbar">
|
|
386
|
+
<button class="btn" onclick="addNode('agent')">+ Agent</button>
|
|
387
|
+
<button class="btn primary" id="runBtn" onclick="runWorkflow()">▶ Run</button>
|
|
388
|
+
<button class="btn" onclick="stopWorkflow()">■ Stop</button>
|
|
389
|
+
<button class="btn danger" onclick="clearAll()">✕ Clear</button>
|
|
390
|
+
</div>
|
|
391
|
+
</header>
|
|
392
|
+
|
|
393
|
+
<!-- Left Sidebar: Palette & Config -->
|
|
394
|
+
<aside>
|
|
395
|
+
<h3>Nodes</h3>
|
|
396
|
+
<div class="palette-item agent" onclick="addNode('agent')">
|
|
397
|
+
<div class="icon">🤖</div>
|
|
398
|
+
<span>Agent</span>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<div class="config-section" id="nodeConfig" style="display:none">
|
|
402
|
+
<h3>Selected Node</h3>
|
|
403
|
+
<label>Label</label>
|
|
404
|
+
<input type="text" id="cfgLabel" oninput="updateSelectedNode()" />
|
|
405
|
+
<label>Model</label>
|
|
406
|
+
<select id="cfgModel" onchange="updateSelectedNode()">
|
|
407
|
+
<option value="">default</option>
|
|
408
|
+
<option value="gpt-6-sol">GPT-6 Sol</option>
|
|
409
|
+
<option value="gpt-5.6-luna">GPT-5.6 Luna</option>
|
|
410
|
+
<option value="deepseek-v4-pro">DeepSeek V4 Pro</option>
|
|
411
|
+
<option value="glm-5.3">GLM 5.3</option>
|
|
412
|
+
</select>
|
|
413
|
+
<label>System Prompt</label>
|
|
414
|
+
<textarea id="cfgPrompt" oninput="updateSelectedNode()" placeholder="You are a helpful agent..."></textarea>
|
|
415
|
+
<label>Max Loops</label>
|
|
416
|
+
<input type="number" id="cfgMaxLoops" value="1" min="1" max="100" oninput="updateSelectedNode()" />
|
|
417
|
+
<label style="margin-top:12px">Global Max Loops</label>
|
|
418
|
+
<input type="number" id="cfgGlobalLoops" value="10" min="1" max="100" />
|
|
419
|
+
<div style="margin-top:12px">
|
|
420
|
+
<button class="btn danger" onclick="deleteSelectedNode()" style="width:100%">Delete Node</button>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
</aside>
|
|
424
|
+
|
|
425
|
+
<!-- Canvas -->
|
|
426
|
+
<div class="canvas-wrap">
|
|
427
|
+
<div class="empty-state" id="emptyState">
|
|
428
|
+
<div class="big-icon">⚡</div>
|
|
429
|
+
<p>Drag an Agent node to start</p>
|
|
430
|
+
<span class="hint">or click "+ Agent" in the toolbar</span>
|
|
431
|
+
</div>
|
|
432
|
+
<div id="canvas"></div>
|
|
433
|
+
<svg id="arrows"></svg>
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<!-- Right Panel: Run Log -->
|
|
437
|
+
<div class="panel">
|
|
438
|
+
<h3>Run Log</h3>
|
|
439
|
+
<div style="margin-bottom:8px">
|
|
440
|
+
<span style="color:var(--text-muted);font-size:11px">Iteration:</span>
|
|
441
|
+
<span class="iter-badge" id="iterBadge">0</span>
|
|
442
|
+
</div>
|
|
443
|
+
<div class="run-log" id="runLog">
|
|
444
|
+
<div class="entry" style="color:var(--text-muted)">Ready.</div>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<script>
|
|
450
|
+
// ─── State ──────────────────────────────────────────
|
|
451
|
+
let ws = null;
|
|
452
|
+
let nodes = [];
|
|
453
|
+
let edges = [];
|
|
454
|
+
let selectedNodeId = null;
|
|
455
|
+
let dragging = null; // { nodeId, offsetX, offsetY }
|
|
456
|
+
let connecting = null; // { fromNodeId, startX, startY }
|
|
457
|
+
let nextId = 1;
|
|
458
|
+
|
|
459
|
+
// ─── WebSocket ──────────────────────────────────────
|
|
460
|
+
function connectWS() {
|
|
461
|
+
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
462
|
+
ws = new WebSocket(`${proto}//${location.host}/ws`);
|
|
463
|
+
ws.onopen = () => log('Connected to workflow server', 'success');
|
|
464
|
+
ws.onclose = () => { log('Disconnected, reconnecting…', 'error'); setTimeout(connectWS, 2000); };
|
|
465
|
+
ws.onmessage = (e) => handleMsg(JSON.parse(e.data));
|
|
466
|
+
}
|
|
467
|
+
function send(type, data = {}) {
|
|
468
|
+
if (!ws || ws.readyState !== 1) return;
|
|
469
|
+
ws.send(JSON.stringify({ type, data, id: String(++nextId) }));
|
|
470
|
+
}
|
|
471
|
+
function handleMsg(msg) {
|
|
472
|
+
switch (msg.type) {
|
|
473
|
+
case 'workflow:updated':
|
|
474
|
+
nodes = msg.data.nodes || nodes;
|
|
475
|
+
edges = msg.data.edges || edges;
|
|
476
|
+
render();
|
|
477
|
+
break;
|
|
478
|
+
case 'run:state':
|
|
479
|
+
updateRunState(msg.data);
|
|
480
|
+
break;
|
|
481
|
+
case 'run:nodeResult':
|
|
482
|
+
log(`✓ ${msg.data.nodeId}: ${String(msg.data.output).slice(0, 80)}…`, 'success');
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ─── Node operations ────────────────────────────────
|
|
488
|
+
function addNode(type) {
|
|
489
|
+
const id = `n${Date.now()}`;
|
|
490
|
+
const cx = 200 + Math.random() * 300;
|
|
491
|
+
const cy = 100 + Math.random() * 200;
|
|
492
|
+
const node = {
|
|
493
|
+
id, type, label: `Agent ${nodes.length + 1}`,
|
|
494
|
+
config: { systemPrompt: '', model: '', maxLoops: 1 },
|
|
495
|
+
position: { x: cx, y: cy },
|
|
496
|
+
};
|
|
497
|
+
nodes.push(node);
|
|
498
|
+
send('node:add', { workflowId: currentWfId(), node });
|
|
499
|
+
selectedNodeId = id;
|
|
500
|
+
render();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function deleteSelectedNode() {
|
|
504
|
+
if (!selectedNodeId) return;
|
|
505
|
+
nodes = nodes.filter(n => n.id !== selectedNodeId);
|
|
506
|
+
edges = edges.filter(e => e.source !== selectedNodeId && e.target !== selectedNodeId);
|
|
507
|
+
send('node:remove', { workflowId: currentWfId(), nodeId: selectedNodeId });
|
|
508
|
+
selectedNodeId = null;
|
|
509
|
+
render();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function updateSelectedNode() {
|
|
513
|
+
const n = nodes.find(n => n.id === selectedNodeId);
|
|
514
|
+
if (!n) return;
|
|
515
|
+
n.label = document.getElementById('cfgLabel').value;
|
|
516
|
+
n.config.model = document.getElementById('cfgModel').value;
|
|
517
|
+
n.config.systemPrompt = document.getElementById('cfgPrompt').value;
|
|
518
|
+
n.config.maxLoops = parseInt(document.getElementById('cfgMaxLoops').value) || 1;
|
|
519
|
+
send('node:update', { workflowId: currentWfId(), node: n });
|
|
520
|
+
render();
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function currentWfId() { return 'wf-current'; }
|
|
524
|
+
|
|
525
|
+
// ─── Rendering ──────────────────────────────────────
|
|
526
|
+
function render() {
|
|
527
|
+
const canvas = document.getElementById('canvas');
|
|
528
|
+
const empty = document.getElementById('emptyState');
|
|
529
|
+
empty.style.display = nodes.length ? 'none' : 'flex';
|
|
530
|
+
|
|
531
|
+
canvas.innerHTML = '';
|
|
532
|
+
for (const n of nodes) {
|
|
533
|
+
const el = document.createElement('div');
|
|
534
|
+
el.className = `node${n.id === selectedNodeId ? ' selected' : ''}${n._status || ''}`;
|
|
535
|
+
el.style.left = n.position.x + 'px';
|
|
536
|
+
el.style.top = n.position.y + 'px';
|
|
537
|
+
el.dataset.id = n.id;
|
|
538
|
+
el.innerHTML = `
|
|
539
|
+
<div class="port in" data-port="in" data-node="${n.id}"></div>
|
|
540
|
+
<div class="port out" data-port="out" data-node="${n.id}"></div>
|
|
541
|
+
<div class="node-header"><span class="dot"></span>${n.label}</div>
|
|
542
|
+
<div class="node-body">
|
|
543
|
+
${n.config.model ? `<span class="model-tag">${n.config.model}</span>` : '<span style="opacity:0.4">no model</span>'}
|
|
544
|
+
<div style="margin-top:4px">loops: ${n.config.maxLoops ?? 1}</div>
|
|
545
|
+
</div>`;
|
|
546
|
+
canvas.appendChild(el);
|
|
547
|
+
|
|
548
|
+
// Drag
|
|
549
|
+
el.addEventListener('mousedown', (e) => {
|
|
550
|
+
if (e.target.classList.contains('port')) return;
|
|
551
|
+
selectedNodeId = n.id;
|
|
552
|
+
dragging = { nodeId: n.id, offsetX: e.clientX - n.position.x, offsetY: e.clientY - n.position.y };
|
|
553
|
+
render();
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Select on click
|
|
558
|
+
canvas.addEventListener('mousedown', (e) => {
|
|
559
|
+
const node = e.target.closest('.node');
|
|
560
|
+
if (node) {
|
|
561
|
+
selectedNodeId = node.dataset.id;
|
|
562
|
+
showConfig();
|
|
563
|
+
render();
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
drawArrows();
|
|
568
|
+
showConfig();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function showConfig() {
|
|
572
|
+
const panel = document.getElementById('nodeConfig');
|
|
573
|
+
const n = nodes.find(n => n.id === selectedNodeId);
|
|
574
|
+
if (!n) { panel.style.display = 'none'; return; }
|
|
575
|
+
panel.style.display = 'block';
|
|
576
|
+
document.getElementById('cfgLabel').value = n.label;
|
|
577
|
+
document.getElementById('cfgModel').value = n.config.model || '';
|
|
578
|
+
document.getElementById('cfgPrompt').value = n.config.systemPrompt || '';
|
|
579
|
+
document.getElementById('cfgMaxLoops').value = n.config.maxLoops || 1;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function drawArrows() {
|
|
583
|
+
const svg = document.getElementById('arrows');
|
|
584
|
+
svg.innerHTML = '';
|
|
585
|
+
for (const e of edges) {
|
|
586
|
+
const src = nodes.find(n => n.id === e.source);
|
|
587
|
+
const tgt = nodes.find(n => n.id === e.target);
|
|
588
|
+
if (!src || !tgt) continue;
|
|
589
|
+
const x1 = src.position.x + 180, y1 = src.position.y + 25;
|
|
590
|
+
const x2 = tgt.position.x, y2 = tgt.position.y + 25;
|
|
591
|
+
const mx = (x1 + x2) / 2;
|
|
592
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
593
|
+
path.setAttribute('d', `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`);
|
|
594
|
+
if (e._active) path.classList.add('active');
|
|
595
|
+
svg.appendChild(path);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ─── Drag ───────────────────────────────────────────
|
|
600
|
+
document.addEventListener('mousemove', (e) => {
|
|
601
|
+
if (dragging) {
|
|
602
|
+
const n = nodes.find(n => n.id === dragging.nodeId);
|
|
603
|
+
if (n) {
|
|
604
|
+
n.position.x = e.clientX - dragging.offsetX;
|
|
605
|
+
n.position.y = e.clientY - dragging.offsetY;
|
|
606
|
+
render();
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
document.addEventListener('mouseup', () => { dragging = null; });
|
|
611
|
+
|
|
612
|
+
// ─── Port connections ───────────────────────────────
|
|
613
|
+
document.addEventListener('mousedown', (e) => {
|
|
614
|
+
const port = e.target.closest('.port');
|
|
615
|
+
if (!port) return;
|
|
616
|
+
e.stopPropagation();
|
|
617
|
+
if (port.dataset.port === 'out') {
|
|
618
|
+
connecting = { fromNodeId: port.dataset.node };
|
|
619
|
+
} else if (port.dataset.port === 'in' && connecting) {
|
|
620
|
+
const edgeId = `e${Date.now()}`;
|
|
621
|
+
edges.push({ id: edgeId, source: connecting.fromNodeId, target: port.dataset.node });
|
|
622
|
+
send('edge:add', { workflowId: currentWfId(), edge: edges[edges.length - 1] });
|
|
623
|
+
connecting = null;
|
|
624
|
+
render();
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
// ─── Run / Stop ─────────────────────────────────────
|
|
629
|
+
function runWorkflow() {
|
|
630
|
+
// Ensure workflow exists
|
|
631
|
+
send('workflow:create', {
|
|
632
|
+
id: currentWfId(),
|
|
633
|
+
name: document.getElementById('wfName').value,
|
|
634
|
+
nodes, edges,
|
|
635
|
+
globalMaxLoops: parseInt(document.getElementById('cfgGlobalLoops').value) || 10,
|
|
636
|
+
});
|
|
637
|
+
setTimeout(() => {
|
|
638
|
+
send('workflow:run', { workflowId: currentWfId() });
|
|
639
|
+
log('▶ Workflow started', 'success');
|
|
640
|
+
}, 100);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function stopWorkflow() {
|
|
644
|
+
send('workflow:stop', { workflowId: currentWfId() });
|
|
645
|
+
log('■ Stopped', 'error');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function clearAll() {
|
|
649
|
+
nodes = [];
|
|
650
|
+
edges = [];
|
|
651
|
+
selectedNodeId = null;
|
|
652
|
+
send('workflow:delete', { id: currentWfId() });
|
|
653
|
+
render();
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function updateRunState(data) {
|
|
657
|
+
const state = data.state;
|
|
658
|
+
if (!state) return;
|
|
659
|
+
const pill = document.getElementById('statusP#ill');
|
|
660
|
+
pill.className = `status-pill ${state.status}`;
|
|
661
|
+
pill.textContent = state.status.toUpperCase();
|
|
662
|
+
document.getElementById('iterBadge').textContent = state.iteration;
|
|
663
|
+
|
|
664
|
+
// Update node visual states
|
|
665
|
+
for (const n of nodes) {
|
|
666
|
+
const ns = state.results?.[n.id];
|
|
667
|
+
n._status = ns ? ns.status : '';
|
|
668
|
+
}
|
|
669
|
+
render();
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function log(text, cls = '') {
|
|
673
|
+
const el = document.getElementById('runLog');
|
|
674
|
+
const entry = document.createElement('div');
|
|
675
|
+
entry.className = `entry ${cls}`;
|
|
676
|
+
entry.textContent = text;
|
|
677
|
+
el.appendChild(entry);
|
|
678
|
+
el.scrollTop = el.scrollHeight;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// ─── Init ───────────────────────────────────────────
|
|
682
|
+
connectWS();
|
|
683
|
+
render();
|
|
684
|
+
</script>
|
|
685
|
+
</body>
|
|
686
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lyu-extension-workflow",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Workflow extension for lyu-code — visually compose multi-agent pipelines",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"frontend/dist"
|
|
13
|
+
],
|
|
14
|
+
"pi": {
|
|
15
|
+
"extensions": [
|
|
16
|
+
"dist/index.js"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
21
|
+
"@earendil-works/pi-ai": "^0.87.1"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.8.0",
|
|
25
|
+
"@types/node": "^22.0.0"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/WeeeeeKdY/lyu-code.git",
|
|
31
|
+
"directory": "packages/extensions/workflow"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/README.md
DELETED