@tangle-network/sandbox-ui 0.75.0 → 0.77.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.
@@ -1,344 +0,0 @@
1
- // src/workflows/provider-label.ts
2
- var PROVIDER_LABELS = {
3
- github: "GitHub",
4
- gitlab: "GitLab",
5
- slack: "Slack",
6
- stripe: "Stripe",
7
- notion: "Notion",
8
- linear: "Linear",
9
- discord: "Discord"
10
- };
11
- function providerLabel(provider) {
12
- const key = provider.toLowerCase();
13
- return PROVIDER_LABELS[key] ?? provider.charAt(0).toUpperCase() + provider.slice(1);
14
- }
15
-
16
- // src/workflows/model.ts
17
- import { parse as parseYaml } from "yaml";
18
- var NODE_W = 244;
19
- var RANK_SEP = 76;
20
- var CROSS_SEP = 22;
21
- var CARD_CHROME = 18;
22
- var HEADER_ROW = 28;
23
- var TEXT_ROW = 20;
24
- var META_ROW = 46;
25
- var OUTPUT_ROW = 44;
26
- var FOOTER_ROW = 26;
27
- var COMPACT_NODE_SIZE = { width: 240, height: 64 };
28
- function nodeHeight(data, withRunState) {
29
- let h = CARD_CHROME + HEADER_ROW;
30
- if (data.subtitle) h += TEXT_ROW;
31
- if (data.provider) h += TEXT_ROW;
32
- if (withRunState || data.model) h += META_ROW;
33
- if (withRunState) h += OUTPUT_ROW + FOOTER_ROW;
34
- return h;
35
- }
36
- function asRecord(v) {
37
- return v && typeof v === "object" && !Array.isArray(v) ? v : {};
38
- }
39
- function str(v) {
40
- return typeof v === "string" && v.trim() !== "" ? v : void 0;
41
- }
42
- function urlHost(url) {
43
- try {
44
- return new URL(url).host;
45
- } catch {
46
- return url;
47
- }
48
- }
49
- function pickDetail(cfg, keys) {
50
- const out = {};
51
- for (const key of keys) {
52
- const v = cfg[key];
53
- if (v === void 0 || v === null) continue;
54
- const text = typeof v === "string" ? v : typeof v === "number" || typeof v === "boolean" ? String(v) : Array.isArray(v) ? `${v.length} item${v.length === 1 ? "" : "s"}` : "\u2026";
55
- out[key] = text.length > 200 ? `${text.slice(0, 200)}\u2026` : text;
56
- }
57
- return Object.keys(out).length > 0 ? out : void 0;
58
- }
59
- function describeActionBase(action) {
60
- const rec = asRecord(action);
61
- const [kind] = Object.keys(rec);
62
- const cfg = asRecord(rec[kind]);
63
- switch (kind) {
64
- case "sandbox.spawn":
65
- return {
66
- title: "Spawn sandbox",
67
- kind,
68
- subtitle: str(cfg.template),
69
- detail: pickDetail(cfg, ["template", "size", "region"]),
70
- isRoot: false,
71
- tone: "action"
72
- };
73
- case "integration.invoke": {
74
- const path = str(cfg.path);
75
- return {
76
- title: "Integration",
77
- kind,
78
- subtitle: path,
79
- path,
80
- provider: path?.split(".")[0],
81
- detail: pickDetail(cfg, ["path"]),
82
- isRoot: false,
83
- tone: "action"
84
- };
85
- }
86
- case "notify": {
87
- const url = str(cfg.url);
88
- return {
89
- title: "Notify",
90
- kind,
91
- subtitle: url ? urlHost(url) : void 0,
92
- detail: pickDetail(cfg, ["url"]),
93
- isRoot: false,
94
- tone: "action"
95
- };
96
- }
97
- case "agent.run":
98
- return {
99
- title: "Run agent",
100
- kind,
101
- // The prompt says what the agent does; the model is shown as its own
102
- // chip, so it's not duplicated here.
103
- subtitle: str(cfg.prompt) ?? str(cfg.profile),
104
- model: str(cfg.model),
105
- detail: pickDetail(cfg, [
106
- "profile",
107
- "model",
108
- "maxRounds",
109
- "size",
110
- "prompt"
111
- ]),
112
- isRoot: false,
113
- tone: "action"
114
- };
115
- case "parallel": {
116
- const branches = Array.isArray(cfg.branches) ? cfg.branches : [];
117
- return {
118
- title: "Parallel",
119
- kind,
120
- subtitle: `${branches.length} branch${branches.length === 1 ? "" : "es"}`,
121
- badge: branches.length > 0 ? `\xD7${branches.length}` : void 0,
122
- isRoot: false,
123
- tone: "structural"
124
- };
125
- }
126
- case "foreach":
127
- return {
128
- title: "For each",
129
- kind,
130
- subtitle: typeof cfg.items === "string" ? cfg.items : "list",
131
- detail: pickDetail(cfg, ["items"]),
132
- // Only fans out when a `do` template is actually present.
133
- isRoot: false,
134
- tone: "structural"
135
- };
136
- default:
137
- return {
138
- title: kind ? kind : "Action",
139
- kind: kind ?? "action",
140
- isRoot: false,
141
- tone: "action"
142
- };
143
- }
144
- }
145
- var MAX_CONFIG_DEPTH = 100;
146
- function toJsonSafe(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
147
- if (value === null) return null;
148
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
149
- if (typeof value === "string" || typeof value === "boolean") return value;
150
- if (typeof value !== "object") return void 0;
151
- if (value instanceof Date) return value.toISOString();
152
- if (seen.has(value)) return "[Circular]";
153
- if (depth >= MAX_CONFIG_DEPTH) return "[Max depth exceeded]";
154
- seen.add(value);
155
- let out;
156
- if (Array.isArray(value)) {
157
- out = value.map((v) => {
158
- const s = toJsonSafe(v, seen, depth + 1);
159
- return s === void 0 ? null : s;
160
- });
161
- } else {
162
- const obj = {};
163
- for (const [k, v] of Object.entries(value)) {
164
- const s = toJsonSafe(v, seen, depth + 1);
165
- if (s !== void 0) obj[k] = s;
166
- }
167
- out = obj;
168
- }
169
- seen.delete(value);
170
- return out;
171
- }
172
- function withConfig(base, cfg) {
173
- return Object.keys(cfg).length > 0 ? { ...base, config: toJsonSafe(cfg) } : base;
174
- }
175
- function describeAction(action) {
176
- const rec = asRecord(action);
177
- const [kind] = Object.keys(rec);
178
- return withConfig(describeActionBase(action), asRecord(rec[kind]));
179
- }
180
- function describeTrigger(on) {
181
- const rec = asRecord(on);
182
- if (rec.provider_event) {
183
- const ev = asRecord(rec.provider_event);
184
- const connection = str(ev.connection);
185
- const event = str(ev.event);
186
- const actions = Array.isArray(ev.actions) ? ev.actions.filter((a) => typeof a === "string") : [];
187
- const repo = str(ev.repo);
188
- let subtitle = connection ? providerLabel(connection) : "Event";
189
- if (event) subtitle += ` \xB7 ${event}`;
190
- if (actions.length > 0) subtitle += ` (${actions.join("/")})`;
191
- if (repo) subtitle += ` on ${repo}`;
192
- return withConfig(
193
- {
194
- title: "Trigger",
195
- kind: "provider_event",
196
- subtitle,
197
- provider: connection,
198
- isRoot: true,
199
- tone: "trigger"
200
- },
201
- ev
202
- );
203
- }
204
- if (rec.schedule) {
205
- const sch = asRecord(rec.schedule);
206
- const cron = str(sch.cron);
207
- const tz = str(sch.timezone);
208
- return withConfig(
209
- {
210
- title: "Schedule",
211
- kind: "schedule",
212
- subtitle: cron ? tz ? `${cron} (${tz})` : cron : void 0,
213
- isRoot: true,
214
- tone: "trigger"
215
- },
216
- sch
217
- );
218
- }
219
- const [kind] = Object.keys(rec);
220
- return withConfig(
221
- {
222
- title: "Trigger",
223
- kind: "trigger",
224
- isRoot: true,
225
- tone: "trigger"
226
- },
227
- asRecord(kind ? rec[kind] : void 0)
228
- );
229
- }
230
- function layoutLayers(nodes, direction) {
231
- const isLR = direction === "LR";
232
- const mainSize = (n) => isLR ? n.width : n.height;
233
- const crossSize = (n) => isLR ? n.height : n.width;
234
- const byRank = /* @__PURE__ */ new Map();
235
- for (const n of nodes) {
236
- const arr = byRank.get(n.rank);
237
- if (arr) arr.push(n);
238
- else byRank.set(n.rank, [n]);
239
- }
240
- const ranks = [...byRank.keys()].sort((a, b) => a - b);
241
- const mainStart = /* @__PURE__ */ new Map();
242
- let cursor = 0;
243
- for (const r of ranks) {
244
- mainStart.set(r, cursor);
245
- cursor += Math.max(...byRank.get(r).map(mainSize)) + RANK_SEP;
246
- }
247
- const out = [];
248
- for (const r of ranks) {
249
- const layer = byRank.get(r);
250
- const extent = Math.max(...layer.map(mainSize));
251
- const span = layer.reduce((s, n) => s + crossSize(n), 0) + CROSS_SEP * (layer.length - 1);
252
- let cross = -span / 2;
253
- for (const n of layer) {
254
- const main = mainStart.get(r) + (extent - mainSize(n)) / 2;
255
- out.push({
256
- id: n.id,
257
- position: isLR ? { x: main, y: cross } : { x: cross, y: main },
258
- width: n.width,
259
- height: n.height,
260
- data: n.data
261
- });
262
- cross += crossSize(n) + CROSS_SEP;
263
- }
264
- }
265
- const minX = Math.min(...out.map((n) => n.position.x));
266
- const minY = Math.min(...out.map((n) => n.position.y));
267
- for (const n of out) {
268
- n.position = { x: n.position.x - minX, y: n.position.y - minY };
269
- }
270
- return out;
271
- }
272
- function buildWorkflowGraph(yaml, options) {
273
- const reserveRunState = options?.reserveRunState ?? false;
274
- const direction = options?.direction ?? "LR";
275
- const measure = options?.measure;
276
- if (!yaml || yaml.trim() === "") {
277
- return { nodes: [], edges: [], error: "No definition" };
278
- }
279
- let parsed;
280
- try {
281
- parsed = parseYaml(yaml);
282
- } catch {
283
- return { nodes: [], edges: [], error: "Invalid YAML" };
284
- }
285
- const def = asRecord(parsed);
286
- const actions = Array.isArray(def.do) ? def.do : [];
287
- if (!def.on && actions.length === 0) {
288
- return { nodes: [], edges: [], error: "Empty workflow" };
289
- }
290
- const logical = [];
291
- const edges = [];
292
- const addNode = (id, data, rank2, withRunState) => {
293
- const dims = measure ? measure(data, withRunState) : { width: NODE_W, height: nodeHeight(data, withRunState) };
294
- logical.push({ id, data, width: dims.width, height: dims.height, rank: rank2 });
295
- };
296
- const addEdge = (source, target, kind) => {
297
- edges.push({ id: `${source}->${target}`, source, target, kind });
298
- };
299
- let rank = 0;
300
- let prevExits = [];
301
- const branchLeafIds = /* @__PURE__ */ new Set();
302
- if (def.on) {
303
- addNode("trigger", describeTrigger(def.on), rank, false);
304
- prevExits = ["trigger"];
305
- rank += 1;
306
- }
307
- actions.forEach((action, i) => {
308
- const id = `a${i}`;
309
- const data = describeAction(action);
310
- if (i === 0 && !def.on) data.isRoot = true;
311
- addNode(id, data, rank, reserveRunState);
312
- for (const from of prevExits) {
313
- addEdge(from, id, branchLeafIds.has(from) ? "join" : "spine");
314
- }
315
- const rec = asRecord(action);
316
- const children = "parallel" in rec ? Array.isArray(asRecord(rec.parallel).branches) ? asRecord(rec.parallel).branches : [] : "foreach" in rec ? (
317
- // A foreach with no `do` template has no child to render.
318
- [asRecord(rec.foreach).do].filter(Boolean)
319
- ) : [];
320
- if (children.length > 0) {
321
- const branchRank = rank + 1;
322
- const branchIds = [];
323
- children.forEach((child, j) => {
324
- const cid = `${id}-b${j}`;
325
- addNode(cid, describeAction(child), branchRank, reserveRunState);
326
- addEdge(id, cid, "fork");
327
- branchIds.push(cid);
328
- branchLeafIds.add(cid);
329
- });
330
- prevExits = branchIds;
331
- rank = branchRank + 1;
332
- } else {
333
- prevExits = [id];
334
- rank += 1;
335
- }
336
- });
337
- return { nodes: layoutLayers(logical, direction), edges, error: null };
338
- }
339
-
340
- export {
341
- providerLabel,
342
- COMPACT_NODE_SIZE,
343
- buildWorkflowGraph
344
- };