@tangle-network/agent-runtime 0.69.0 → 0.70.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.
Files changed (67) hide show
  1. package/README.md +81 -13
  2. package/dist/agent.d.ts +4 -5
  3. package/dist/agent.js +3 -4
  4. package/dist/agent.js.map +1 -1
  5. package/dist/analyst-loop.d.ts +3 -4
  6. package/dist/{chunk-K4FQSEXQ.js → chunk-BGOLR66M.js} +6 -6
  7. package/dist/{chunk-G6U3GVK2.js → chunk-CRAH5EY2.js} +2 -2
  8. package/dist/{chunk-RTDI2DHD.js → chunk-HY4YOQM2.js} +6 -6
  9. package/dist/chunk-HY4YOQM2.js.map +1 -0
  10. package/dist/{chunk-QZ6FA5LM.js → chunk-LJZ5GC6C.js} +3 -3
  11. package/dist/{chunk-NLRA6434.js → chunk-YFOPWG74.js} +577 -525
  12. package/dist/chunk-YFOPWG74.js.map +1 -0
  13. package/dist/{coordination-Curpzeyc.d.ts → coordination-C7WxwHXq.d.ts} +8 -1
  14. package/dist/{delegates-CLFNAKyi.d.ts → delegates-DqAgo32T.d.ts} +105 -10
  15. package/dist/{improvement-adapter-BC4HhuAR.d.ts → improvement-adapter-CioiEE2z.d.ts} +1 -1
  16. package/dist/index.d.ts +439 -100
  17. package/dist/index.js +591 -130
  18. package/dist/index.js.map +1 -1
  19. package/dist/intelligence.d.ts +2 -3
  20. package/dist/{loop-runner-bin-B6dzNZC8.d.ts → loop-runner-bin-a8bu4O5-.d.ts} +4 -4
  21. package/dist/loop-runner-bin.d.ts +7 -10
  22. package/dist/loop-runner-bin.js +6 -7
  23. package/dist/loops.d.ts +3149 -16
  24. package/dist/loops.js +33 -60
  25. package/dist/mcp/bin.js +13 -14
  26. package/dist/mcp/bin.js.map +1 -1
  27. package/dist/mcp/index.d.ts +8 -12
  28. package/dist/mcp/index.js +10 -12
  29. package/dist/mcp/index.js.map +1 -1
  30. package/dist/{openai-tools-CA2N3-Ak.d.ts → openai-tools-DPx9Gzvn.d.ts} +1 -1
  31. package/dist/profiles.d.ts +94 -6
  32. package/dist/profiles.js +320 -9
  33. package/dist/profiles.js.map +1 -1
  34. package/dist/{router-client-30Y_pca8.d.ts → router-client-C7kp_ECN.d.ts} +37 -1
  35. package/dist/{substrate-CUgk7F7s.d.ts → substrate-BoRXgvka.d.ts} +52 -1
  36. package/dist/{types-p8dWBIXL.d.ts → types-BC3bZpH0.d.ts} +1 -1
  37. package/dist/{types-Crxftafi.d.ts → types-BYa2ZOAx.d.ts} +83 -2
  38. package/dist/{worktree-fanout-DUiKPApb.d.ts → worktree-fanout-gNfl0Byj.d.ts} +9 -37
  39. package/package.json +17 -37
  40. package/dist/audit.d.ts +0 -93
  41. package/dist/audit.js +0 -312
  42. package/dist/audit.js.map +0 -1
  43. package/dist/chunk-4B6U4CVQ.js +0 -15
  44. package/dist/chunk-4B6U4CVQ.js.map +0 -1
  45. package/dist/chunk-NLRA6434.js.map +0 -1
  46. package/dist/chunk-O2UPHN7X.js +0 -114
  47. package/dist/chunk-O2UPHN7X.js.map +0 -1
  48. package/dist/chunk-RTDI2DHD.js.map +0 -1
  49. package/dist/coder-2leJPOvC.d.ts +0 -52
  50. package/dist/improvement.d.ts +0 -208
  51. package/dist/improvement.js +0 -343
  52. package/dist/improvement.js.map +0 -1
  53. package/dist/local-harness-BE_h8szs.d.ts +0 -93
  54. package/dist/run-loop-D3PwlG7J.d.ts +0 -112
  55. package/dist/runtime-hooks-C7JwKb9E.d.ts +0 -70
  56. package/dist/runtime.d.ts +0 -3120
  57. package/dist/runtime.js +0 -263
  58. package/dist/runtime.js.map +0 -1
  59. package/dist/topology.d.ts +0 -126
  60. package/dist/topology.js +0 -333
  61. package/dist/topology.js.map +0 -1
  62. package/dist/workflow.d.ts +0 -551
  63. package/dist/workflow.js +0 -1781
  64. package/dist/workflow.js.map +0 -1
  65. /package/dist/{chunk-K4FQSEXQ.js.map → chunk-BGOLR66M.js.map} +0 -0
  66. /package/dist/{chunk-G6U3GVK2.js.map → chunk-CRAH5EY2.js.map} +0 -0
  67. /package/dist/{chunk-QZ6FA5LM.js.map → chunk-LJZ5GC6C.js.map} +0 -0
package/dist/topology.js DELETED
@@ -1,333 +0,0 @@
1
- import "./chunk-DGUM43GV.js";
2
-
3
- // src/topology/replay.ts
4
- function spendTokens(s) {
5
- if (!s?.tokens) return 0;
6
- return (s.tokens.input ?? 0) + (s.tokens.output ?? 0);
7
- }
8
- function createReplayRecorder() {
9
- const events = [];
10
- let runId = "run";
11
- const onEvent = (e) => {
12
- if (e.runId) runId = e.runId;
13
- const t = e.timestamp;
14
- const p = e.payload ?? {};
15
- switch (e.target) {
16
- case "agent.run": {
17
- if (e.phase === "before") {
18
- events.push({
19
- t,
20
- kind: "root",
21
- id: e.runId,
22
- label: String(p.driver ?? "root"),
23
- depth: 0,
24
- status: "running"
25
- });
26
- } else if (e.phase === "after" || e.phase === "error") {
27
- events.push({
28
- t,
29
- kind: "settle",
30
- id: e.runId,
31
- status: e.phase === "error" ? "down" : "done"
32
- });
33
- }
34
- break;
35
- }
36
- case "agent.spawn": {
37
- events.push({
38
- t,
39
- kind: "spawn",
40
- id: String(p.childId ?? e.id),
41
- ...e.parentId ? { parentId: e.parentId } : {},
42
- label: String(p.label ?? p.childId ?? "?"),
43
- ...p.runtime ? { runtime: String(p.runtime) } : {},
44
- ...typeof p.depth === "number" ? { depth: p.depth } : {},
45
- status: "running"
46
- });
47
- break;
48
- }
49
- case "agent.child": {
50
- const spent = p.spent;
51
- events.push({
52
- t,
53
- kind: "settle",
54
- id: String(p.childId ?? e.id),
55
- status: p.status ?? "done",
56
- ...typeof p.valid === "boolean" ? { valid: p.valid } : {},
57
- ...typeof p.score === "number" ? { score: p.score } : {},
58
- ...p.reason ? { reason: String(p.reason) } : {},
59
- tokens: spendTokens(spent),
60
- usd: spent?.usd ?? 0
61
- });
62
- break;
63
- }
64
- default: {
65
- const owner = e.parentId ?? e.runId;
66
- if (owner) events.push({ t, kind: "step", id: owner });
67
- }
68
- }
69
- };
70
- return {
71
- hooks: { onEvent },
72
- events,
73
- timeline(rid) {
74
- const ts = events.map((e) => e.t);
75
- const t0 = ts.length ? Math.min(...ts) : 0;
76
- const t1 = ts.length ? Math.max(...ts) : 0;
77
- const defined = new Set(
78
- events.filter((e) => e.kind === "spawn" || e.kind === "root").map((e) => e.id)
79
- );
80
- const synthetic = [];
81
- for (const id of new Set(events.map((e) => e.parentId).filter((p) => !!p))) {
82
- if (!defined.has(id))
83
- synthetic.push({
84
- t: t0,
85
- kind: "root",
86
- id,
87
- label: shortRoot(id),
88
- depth: 0,
89
- status: "running"
90
- });
91
- }
92
- return { runId: rid ?? runId, events: [...synthetic, ...events], t0, t1 };
93
- }
94
- };
95
- }
96
- function renderReplayHtml(timeline, opts) {
97
- const title = opts?.title ?? `agent replay \xB7 ${timeline.runId}`;
98
- const data = JSON.stringify(timeline);
99
- return `<!doctype html>
100
- <html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/>
101
- <title>${escapeHtml(title)}</title>
102
- <style>
103
- :root { --bg:#0b0e14; --panel:#11161f; --line:#2a3340; --txt:#c9d4e3; --dim:#6b7787;
104
- --run:#e0a73a; --done:#3ad17a; --undeliv:#e0a73a; --down:#e25d5d; --edge:#33405200; }
105
- * { box-sizing:border-box; }
106
- body { margin:0; background:var(--bg); color:var(--txt); font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; }
107
- header { padding:10px 16px; border-bottom:1px solid var(--line); display:flex; gap:18px; align-items:center; flex-wrap:wrap; }
108
- header b { color:#fff; font-weight:600; } .stat { color:var(--dim); } .stat span { color:var(--txt); }
109
- #wrap { display:flex; height:calc(100vh - 112px); }
110
- #stage { flex:1; overflow:auto; }
111
- #side { width:280px; border-left:1px solid var(--line); padding:14px; overflow:auto; background:var(--panel); }
112
- #side h3 { margin:0 0 8px; font-size:12px; color:var(--dim); text-transform:uppercase; letter-spacing:.08em; }
113
- #side .k { color:var(--dim); } #side .row { margin:3px 0; }
114
- svg { display:block; } .node circle { stroke:#0b0e14; stroke-width:2; cursor:pointer; }
115
- .node text { fill:var(--txt); font-size:11px; } .node .sub { fill:var(--dim); font-size:9px; }
116
- .edge { stroke:#2a3340; stroke-width:1.5; fill:none; }
117
- .hidden { opacity:0; } .node, .edge { transition:opacity .25s ease, fill .25s, stroke .25s; }
118
- footer { padding:10px 16px; border-top:1px solid var(--line); display:flex; gap:14px; align-items:center; }
119
- button { background:#1b2433; color:var(--txt); border:1px solid var(--line); border-radius:6px; padding:6px 14px; cursor:pointer; font:inherit; }
120
- button:hover { background:#243047; } input[type=range] { flex:1; accent-color:#3ad17a; }
121
- select { background:#1b2433; color:var(--txt); border:1px solid var(--line); border-radius:6px; padding:5px; }
122
- .legend i { display:inline-block; width:9px; height:9px; border-radius:50%; margin:0 4px 0 10px; vertical-align:middle; }
123
- </style></head><body>
124
- <header>
125
- <b>${escapeHtml(title)}</b>
126
- <span class="legend"><i style="background:var(--run)"></i>running<i style="background:var(--done)"></i>delivered<i style="background:var(--down)"></i>failed</span>
127
- <span class="stat">t <span id="clock">0.0s</span></span>
128
- <span class="stat">nodes <span id="cNodes">0</span></span>
129
- <span class="stat">delivered <span id="cDeliv">0</span></span>
130
- <span class="stat">tokens <span id="cTok">0</span></span>
131
- <span class="stat">$<span id="cUsd">0.000</span></span>
132
- </header>
133
- <div id="wrap"><div id="stage"><svg id="svg"></svg></div>
134
- <div id="side"><h3>node</h3><div id="detail" class="stat">hover a node\u2026</div></div></div>
135
- <footer>
136
- <button id="play">\u25B6 play</button>
137
- <button id="restart">\u27F2</button>
138
- <input type="range" id="scrub" min="0" max="1000" value="0"/>
139
- <select id="speed"><option value="1">1\xD7</option><option value="2">2\xD7</option><option value="4" selected>4\xD7</option><option value="8">8\xD7</option><option value="20">20\xD7</option></select>
140
- </footer>
141
- <script>
142
- const TL = ${data};
143
- const EV = TL.events.slice().sort((a,b)=>a.t-b.t);
144
- const span = Math.max(1, TL.t1 - TL.t0);
145
- // \u2500\u2500 build the full tree (nodes known from spawn/root events) \u2500\u2500
146
- const nodes = new Map();
147
- for (const e of EV) {
148
- if (e.kind==='root' || e.kind==='spawn') {
149
- if (!nodes.has(e.id)) nodes.set(e.id, { id:e.id, parentId:e.parentId, label:e.label||e.id, runtime:e.runtime, depth:e.depth??0, tSpawn:e.t, children:[] });
150
- }
151
- }
152
- for (const n of nodes.values()) { if (n.parentId && nodes.has(n.parentId)) nodes.get(n.parentId).children.push(n); }
153
- const roots = [...nodes.values()].filter(n=>!n.parentId || !nodes.has(n.parentId));
154
- // \u2500\u2500 tidy layout: post-order leaf slotting; x=avg(children), y=depth \u2500\u2500
155
- let leaf=0; const VGAP=78, HGAP=120;
156
- function layout(n, d){ n.y = 40 + d*VGAP; if(!n.children.length){ n.x = 40 + (leaf++)*HGAP; } else { n.children.forEach(c=>layout(c,d+1)); n.x = (n.children[0].x + n.children[n.children.length-1].x)/2; } }
157
- roots.forEach(r=>layout(r,0));
158
- const W = Math.max(900, 80 + leaf*HGAP), H = 80 + (Math.max(0,...[...nodes.values()].map(n=>n.depth||0))+1)*VGAP;
159
- const svg = document.getElementById('svg'); svg.setAttribute('viewBox','0 0 '+W+' '+H); svg.setAttribute('width',W); svg.setAttribute('height',H);
160
- const NS='http://www.w3.org/2000/svg';
161
- function el(t,a){ const x=document.createElementNS(NS,t); for(const k in a) x.setAttribute(k,a[k]); return x; }
162
- // edges
163
- const edgeEls=new Map();
164
- for (const n of nodes.values()) if (n.parentId && nodes.has(n.parentId)) { const p=nodes.get(n.parentId);
165
- const path=el('path',{class:'edge hidden', d:'M'+p.x+','+(p.y)+' C'+p.x+','+((p.y+n.y)/2)+' '+n.x+','+((p.y+n.y)/2)+' '+n.x+','+n.y}); svg.appendChild(path); edgeEls.set(n.id,path); }
166
- // nodes
167
- const nodeEls=new Map();
168
- for (const n of nodes.values()) { const g=el('g',{class:'node hidden'});
169
- const c=el('circle',{cx:n.x,cy:n.y,r:14,fill:'var(--dim)'});
170
- const t=el('text',{x:n.x,y:n.y-20,'text-anchor':'middle'}); t.textContent=n.label.slice(0,18);
171
- const s=el('text',{class:'sub',x:n.x,y:n.y+26,'text-anchor':'middle'}); s.textContent=n.runtime||'';
172
- g.appendChild(c); g.appendChild(t); g.appendChild(s); svg.appendChild(g); nodeEls.set(n.id,{g,c,s});
173
- g.addEventListener('mouseenter',()=>showDetail(n)); }
174
- function showDetail(n){ const st=state.get(n.id)||{}; document.getElementById('detail').innerHTML =
175
- '<div class="row"><span class="k">id</span> '+n.id+'</div>'+
176
- '<div class="row"><span class="k">label</span> '+esc(n.label)+'</div>'+
177
- '<div class="row"><span class="k">runtime</span> '+(n.runtime||'\u2014')+'</div>'+
178
- '<div class="row"><span class="k">depth</span> '+(n.depth??0)+'</div>'+
179
- '<div class="row"><span class="k">status</span> '+(st.status||'\u2014')+(st.valid===false?' (not delivered)':st.valid?' (delivered)':'')+'</div>'+
180
- '<div class="row"><span class="k">score</span> '+(st.score!=null?st.score.toFixed(2):'\u2014')+'</div>'+
181
- (st.reason?'<div class="row"><span class="k">reason</span> '+esc(st.reason)+'</div>':'')+
182
- '<div class="row"><span class="k">tokens</span> '+(st.tokens||0)+'</div>'; }
183
- function esc(x){ return String(x).replace(/[<>&]/g,c=>({'<':'&lt;','>':'&gt;','&':'&amp;'}[c])); }
184
- // \u2500\u2500 playback \u2500\u2500
185
- const state=new Map();
186
- function colorOf(st){ if(!st||st.status==='running'||!st.status) return 'var(--run)'; if(st.status==='down') return 'var(--down)'; return st.valid===false ? 'var(--undeliv)' : 'var(--done)'; }
187
- function applyTo(ms){ const clk=TL.t0+ms; state.clear();
188
- let deliv=0, tok=0, usd=0, shown=0;
189
- // reset visibility
190
- for (const [,v] of nodeEls){ v.g.classList.add('hidden'); }
191
- for (const [,p] of edgeEls){ p.classList.add('hidden'); }
192
- for (const e of EV){ if (e.t>clk) break;
193
- if (e.kind==='spawn'||e.kind==='root'){ const ne=nodeEls.get(e.id); if(ne){ ne.g.classList.remove('hidden'); shown++; const ed=edgeEls.get(e.id); if(ed) ed.classList.remove('hidden'); } state.set(e.id, Object.assign(state.get(e.id)||{}, {status:'running'})); }
194
- else if (e.kind==='settle'){ const st=Object.assign(state.get(e.id)||{}, {status:e.status, valid:e.valid, score:e.score, reason:e.reason, tokens:e.tokens, usd:e.usd}); state.set(e.id,st); }
195
- }
196
- for (const [id,st] of state){ const ne=nodeEls.get(id); if(ne) ne.c.setAttribute('fill', colorOf(st)); if(st.status&&st.status!=='running'){ if(st.status==='done'&&st.valid!==false) deliv++; tok+=st.tokens||0; usd+=st.usd||0; } }
197
- document.getElementById('clock').textContent=(ms/1000).toFixed(1)+'s';
198
- document.getElementById('cNodes').textContent=shown;
199
- document.getElementById('cDeliv').textContent=deliv;
200
- document.getElementById('cTok').textContent=tok;
201
- document.getElementById('cUsd').textContent=usd.toFixed(3);
202
- }
203
- const scrub=document.getElementById('scrub'); let playing=false, raf=0, last=0;
204
- function setMs(ms){ ms=Math.max(0,Math.min(span,ms)); scrub.value=(ms/span*1000)|0; applyTo(ms); }
205
- scrub.addEventListener('input',()=>setMs(scrub.value/1000*span));
206
- document.getElementById('play').addEventListener('click',()=>{ playing=!playing; document.getElementById('play').textContent=playing?'\u23F8 pause':'\u25B6 play'; if(playing){ last=performance.now(); if((scrub.value/1000*span)>=span) setMs(0); tick(); } });
207
- document.getElementById('restart').addEventListener('click',()=>{ setMs(0); });
208
- function tick(){ if(!playing) return; const now=performance.now(); const sp=+document.getElementById('speed').value; let ms=scrub.value/1000*span + (now-last)*sp; last=now; if(ms>=span){ ms=span; playing=false; document.getElementById('play').textContent='\u25B6 play'; } setMs(ms); if(playing) raf=requestAnimationFrame(tick); }
209
- setMs(0);
210
- </script></body></html>`;
211
- }
212
- function shortRoot(id) {
213
- const seg = id.split("/").pop() ?? id;
214
- return seg.length > 22 ? `\u2026${seg.slice(-21)}` : seg;
215
- }
216
- function escapeHtml(s) {
217
- return s.replace(
218
- /[<>&"]/g,
219
- (c) => ({ "<": "&lt;", ">": "&gt;", "&": "&amp;", '"': "&quot;" })[c] ?? c
220
- );
221
- }
222
-
223
- // src/topology/tree.ts
224
- var stepTargets = /* @__PURE__ */ new Set(["agent.turn", "agent.tool_call", "agent.plan", "agent.decision"]);
225
- function createTopologyView() {
226
- const byId = /* @__PURE__ */ new Map();
227
- const ensure = (id, seed = {}) => {
228
- const existing = byId.get(id);
229
- if (existing) return existing;
230
- const node = {
231
- id,
232
- label: seed.label ?? id,
233
- depth: seed.depth ?? 0,
234
- status: "running",
235
- steps: 0,
236
- childIds: [],
237
- ...seed
238
- };
239
- byId.set(id, node);
240
- return node;
241
- };
242
- const str = (v) => typeof v === "string" ? v : void 0;
243
- const num = (v) => typeof v === "number" ? v : void 0;
244
- const ingest = (event) => {
245
- const p = event.payload ?? {};
246
- if (event.target === "agent.spawn" && event.phase === "after") {
247
- const id = str(p.childId);
248
- if (!id) return;
249
- const parent = event.parentId ? ensure(event.parentId) : void 0;
250
- const node = ensure(id, {
251
- label: str(p.label) ?? id,
252
- runtime: str(p.runtime),
253
- parentId: event.parentId,
254
- depth: num(p.depth) ?? (parent ? parent.depth + 1 : 0)
255
- });
256
- if (parent && !parent.childIds.includes(id)) parent.childIds.push(id);
257
- node.status = "running";
258
- return;
259
- }
260
- if (event.target === "agent.child" && event.phase === "after") {
261
- const id = str(p.childId);
262
- if (!id) return;
263
- const node = ensure(id, { parentId: event.parentId });
264
- node.status = str(p.status) === "down" ? "down" : "done";
265
- node.score = num(p.score);
266
- node.reason = str(p.reason);
267
- return;
268
- }
269
- if (event.target === "agent.run") {
270
- const node = ensure(event.runId, {
271
- label: str(p.driver) ?? event.runId,
272
- parentId: event.parentId
273
- });
274
- if (event.phase === "before") node.status = "running";
275
- else if (event.phase === "error") node.status = "down";
276
- else if (event.phase === "after" && node.status === "running") node.status = "done";
277
- return;
278
- }
279
- if (stepTargets.has(event.target) && (event.phase === "after" || event.phase === "event")) {
280
- const owner = event.parentId && byId.get(event.parentId) || byId.get(event.runId) || void 0;
281
- if (owner) owner.steps += 1;
282
- }
283
- };
284
- const nodes = () => [...byId.values()];
285
- const roots = () => nodes().filter((n) => n.parentId === void 0 || !byId.has(n.parentId));
286
- return {
287
- hooks: { onEvent: (e) => ingest(e) },
288
- ingest,
289
- nodes,
290
- roots,
291
- node: (id) => byId.get(id),
292
- render: (opts) => renderTopologyTree({ roots: roots(), node: (id) => byId.get(id) }, opts)
293
- };
294
- }
295
- var glyph = { running: "\u25D0", done: "\u2713", down: "\u2717" };
296
- function renderTopologyTree(tree, opts = {}) {
297
- const lines = [];
298
- const detail = (n) => {
299
- if (opts.compact) return "";
300
- const parts = [];
301
- if (n.runtime) parts.push(n.runtime);
302
- if (n.steps > 0) parts.push(`${n.steps} ${n.steps === 1 ? "step" : "steps"}`);
303
- if (n.childIds.length > 0) parts.push(`${n.childIds.length} children`);
304
- if (n.status === "done" && n.score !== void 0) parts.push(`score ${n.score.toFixed(2)}`);
305
- if (n.status === "down" && n.reason) parts.push(`down: ${n.reason}`);
306
- return parts.length ? ` (${parts.join(" \xB7 ")})` : "";
307
- };
308
- const walk = (n, prefix, isLast, depth) => {
309
- const branch = depth === 0 ? "" : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
310
- lines.push(`${prefix}${branch}${glyph[n.status]} ${n.label}${detail(n)}`);
311
- if (opts.maxDepth !== void 0 && depth >= opts.maxDepth && n.childIds.length > 0) {
312
- const childPrefix2 = prefix + (depth === 0 ? "" : isLast ? " " : "\u2502 ");
313
- lines.push(`${childPrefix2}\u2514\u2500 \u2026 ${n.childIds.length} more`);
314
- return;
315
- }
316
- const childPrefix = prefix + (depth === 0 ? "" : isLast ? " " : "\u2502 ");
317
- const kids = n.childIds.map((id) => tree.node(id)).filter((c) => !!c);
318
- kids.forEach((c, i) => {
319
- walk(c, childPrefix, i === kids.length - 1, depth + 1);
320
- });
321
- };
322
- tree.roots.forEach((r, i) => {
323
- walk(r, "", i === tree.roots.length - 1, 0);
324
- });
325
- return lines.join("\n");
326
- }
327
- export {
328
- createReplayRecorder,
329
- createTopologyView,
330
- renderReplayHtml,
331
- renderTopologyTree
332
- };
333
- //# sourceMappingURL=topology.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/topology/replay.ts","../src/topology/tree.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Run replay — the visual, animated record of a recursive agent run.\n *\n * The runtime emits ONE event stream (`agent.spawn`/`agent.child`/`agent.run`/`agent.turn`)\n * through `RuntimeHooks`; the topology tree + waterfall already fold it into ASCII. This module\n * folds the SAME stream into a normalized, timestamped `ReplayEvent[]` (the recorder) and renders\n * a self-contained, animated HTML player (`renderReplayHtml`) — a timeline scrubber over the live\n * recursive tree where every node colors by the completion-oracle: delivered (valid) green, ran-\n * but-not-delivered amber, failed red. No server, no build, no external deps — one HTML file you\n * open in a browser. The same `ReplayEvent[]` is the portable timeline a hosted plane viewer reads.\n */\n\nimport type { RuntimeHookEvent, RuntimeHooks } from '../runtime-hooks'\n\n/** One normalized animation frame — a node appearing, settling, or stepping, at a wall-clock ms. */\nexport interface ReplayEvent {\n t: number\n kind: 'root' | 'spawn' | 'settle' | 'step'\n id: string\n parentId?: string\n label?: string\n runtime?: string\n depth?: number\n status?: 'running' | 'done' | 'down'\n /** The completion-oracle signal: delivered ⟺ a deployable check passed (not self-report). */\n valid?: boolean\n score?: number\n reason?: string\n tokens?: number\n usd?: number\n}\n\nexport interface ReplayTimeline {\n runId: string\n events: ReplayEvent[]\n /** Wall-clock window [t0, t1] the player scrubs over. */\n t0: number\n t1: number\n}\n\ninterface RecordedSpend {\n tokens?: { input?: number; output?: number }\n usd?: number\n}\n\nfunction spendTokens(s: RecordedSpend | undefined): number {\n if (!s?.tokens) return 0\n return (s.tokens.input ?? 0) + (s.tokens.output ?? 0)\n}\n\n/**\n * A `RuntimeHooks` sink that records every lifecycle event in arrival order as `ReplayEvent`s.\n * Attach it to `SupervisorOpts.hooks` (or merge with another hooks object) and read `timeline()`\n * after the run. Pure capture — no I/O, no throwing; an unrecognized event is ignored.\n */\nexport function createReplayRecorder(): {\n hooks: RuntimeHooks\n events: ReplayEvent[]\n timeline(runId?: string): ReplayTimeline\n} {\n const events: ReplayEvent[] = []\n let runId = 'run'\n\n const onEvent = (e: RuntimeHookEvent): void => {\n if (e.runId) runId = e.runId\n const t = e.timestamp\n const p = (e.payload ?? {}) as Record<string, unknown>\n switch (e.target) {\n case 'agent.run': {\n // The root driver's lifecycle. `before` plants the root node; `after`/`error` settle it.\n if (e.phase === 'before') {\n events.push({\n t,\n kind: 'root',\n id: e.runId,\n label: String(p.driver ?? 'root'),\n depth: 0,\n status: 'running',\n })\n } else if (e.phase === 'after' || e.phase === 'error') {\n events.push({\n t,\n kind: 'settle',\n id: e.runId,\n status: e.phase === 'error' ? 'down' : 'done',\n })\n }\n break\n }\n case 'agent.spawn': {\n events.push({\n t,\n kind: 'spawn',\n id: String(p.childId ?? e.id),\n ...(e.parentId ? { parentId: e.parentId } : {}),\n label: String(p.label ?? p.childId ?? '?'),\n ...(p.runtime ? { runtime: String(p.runtime) } : {}),\n ...(typeof p.depth === 'number' ? { depth: p.depth } : {}),\n status: 'running',\n })\n break\n }\n case 'agent.child': {\n const spent = p.spent as RecordedSpend | undefined\n events.push({\n t,\n kind: 'settle',\n id: String(p.childId ?? e.id),\n status: (p.status as 'done' | 'down') ?? 'done',\n ...(typeof p.valid === 'boolean' ? { valid: p.valid } : {}),\n ...(typeof p.score === 'number' ? { score: p.score } : {}),\n ...(p.reason ? { reason: String(p.reason) } : {}),\n tokens: spendTokens(spent),\n usd: spent?.usd ?? 0,\n })\n break\n }\n default: {\n // agent.turn / agent.plan / agent.decision / agent.tool_call → a step pulse on the owner.\n const owner = e.parentId ?? e.runId\n if (owner) events.push({ t, kind: 'step', id: owner })\n }\n }\n }\n\n return {\n hooks: { onEvent },\n events,\n timeline(rid?: string): ReplayTimeline {\n const ts = events.map((e) => e.t)\n const t0 = ts.length ? Math.min(...ts) : 0\n const t1 = ts.length ? Math.max(...ts) : 0\n // Synthesize any node referenced as a parent but never spawned (the supervisor's root\n // driver, and each nested driver's tree root, run via `act`, not `spawn`) so the player\n // renders the WHOLE recursion — driver → worker — not just the spawned leaves.\n const defined = new Set(\n events.filter((e) => e.kind === 'spawn' || e.kind === 'root').map((e) => e.id),\n )\n const synthetic: ReplayEvent[] = []\n for (const id of new Set(events.map((e) => e.parentId).filter((p): p is string => !!p))) {\n if (!defined.has(id))\n synthetic.push({\n t: t0,\n kind: 'root',\n id,\n label: shortRoot(id),\n depth: 0,\n status: 'running',\n })\n }\n return { runId: rid ?? runId, events: [...synthetic, ...events], t0, t1 }\n },\n }\n}\n\n/** Render a self-contained animated HTML replay player for a timeline. Open the file in a browser. */\nexport function renderReplayHtml(timeline: ReplayTimeline, opts?: { title?: string }): string {\n const title = opts?.title ?? `agent replay · ${timeline.runId}`\n const data = JSON.stringify(timeline)\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"/><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n<title>${escapeHtml(title)}</title>\n<style>\n :root { --bg:#0b0e14; --panel:#11161f; --line:#2a3340; --txt:#c9d4e3; --dim:#6b7787;\n --run:#e0a73a; --done:#3ad17a; --undeliv:#e0a73a; --down:#e25d5d; --edge:#33405200; }\n * { box-sizing:border-box; }\n body { margin:0; background:var(--bg); color:var(--txt); font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; }\n header { padding:10px 16px; border-bottom:1px solid var(--line); display:flex; gap:18px; align-items:center; flex-wrap:wrap; }\n header b { color:#fff; font-weight:600; } .stat { color:var(--dim); } .stat span { color:var(--txt); }\n #wrap { display:flex; height:calc(100vh - 112px); }\n #stage { flex:1; overflow:auto; }\n #side { width:280px; border-left:1px solid var(--line); padding:14px; overflow:auto; background:var(--panel); }\n #side h3 { margin:0 0 8px; font-size:12px; color:var(--dim); text-transform:uppercase; letter-spacing:.08em; }\n #side .k { color:var(--dim); } #side .row { margin:3px 0; }\n svg { display:block; } .node circle { stroke:#0b0e14; stroke-width:2; cursor:pointer; }\n .node text { fill:var(--txt); font-size:11px; } .node .sub { fill:var(--dim); font-size:9px; }\n .edge { stroke:#2a3340; stroke-width:1.5; fill:none; }\n .hidden { opacity:0; } .node, .edge { transition:opacity .25s ease, fill .25s, stroke .25s; }\n footer { padding:10px 16px; border-top:1px solid var(--line); display:flex; gap:14px; align-items:center; }\n button { background:#1b2433; color:var(--txt); border:1px solid var(--line); border-radius:6px; padding:6px 14px; cursor:pointer; font:inherit; }\n button:hover { background:#243047; } input[type=range] { flex:1; accent-color:#3ad17a; }\n select { background:#1b2433; color:var(--txt); border:1px solid var(--line); border-radius:6px; padding:5px; }\n .legend i { display:inline-block; width:9px; height:9px; border-radius:50%; margin:0 4px 0 10px; vertical-align:middle; }\n</style></head><body>\n<header>\n <b>${escapeHtml(title)}</b>\n <span class=\"legend\"><i style=\"background:var(--run)\"></i>running<i style=\"background:var(--done)\"></i>delivered<i style=\"background:var(--down)\"></i>failed</span>\n <span class=\"stat\">t <span id=\"clock\">0.0s</span></span>\n <span class=\"stat\">nodes <span id=\"cNodes\">0</span></span>\n <span class=\"stat\">delivered <span id=\"cDeliv\">0</span></span>\n <span class=\"stat\">tokens <span id=\"cTok\">0</span></span>\n <span class=\"stat\">$<span id=\"cUsd\">0.000</span></span>\n</header>\n<div id=\"wrap\"><div id=\"stage\"><svg id=\"svg\"></svg></div>\n<div id=\"side\"><h3>node</h3><div id=\"detail\" class=\"stat\">hover a node…</div></div></div>\n<footer>\n <button id=\"play\">▶ play</button>\n <button id=\"restart\">⟲</button>\n <input type=\"range\" id=\"scrub\" min=\"0\" max=\"1000\" value=\"0\"/>\n <select id=\"speed\"><option value=\"1\">1×</option><option value=\"2\">2×</option><option value=\"4\" selected>4×</option><option value=\"8\">8×</option><option value=\"20\">20×</option></select>\n</footer>\n<script>\nconst TL = ${data};\nconst EV = TL.events.slice().sort((a,b)=>a.t-b.t);\nconst span = Math.max(1, TL.t1 - TL.t0);\n// ── build the full tree (nodes known from spawn/root events) ──\nconst nodes = new Map();\nfor (const e of EV) {\n if (e.kind==='root' || e.kind==='spawn') {\n if (!nodes.has(e.id)) nodes.set(e.id, { id:e.id, parentId:e.parentId, label:e.label||e.id, runtime:e.runtime, depth:e.depth??0, tSpawn:e.t, children:[] });\n }\n}\nfor (const n of nodes.values()) { if (n.parentId && nodes.has(n.parentId)) nodes.get(n.parentId).children.push(n); }\nconst roots = [...nodes.values()].filter(n=>!n.parentId || !nodes.has(n.parentId));\n// ── tidy layout: post-order leaf slotting; x=avg(children), y=depth ──\nlet leaf=0; const VGAP=78, HGAP=120;\nfunction layout(n, d){ n.y = 40 + d*VGAP; if(!n.children.length){ n.x = 40 + (leaf++)*HGAP; } else { n.children.forEach(c=>layout(c,d+1)); n.x = (n.children[0].x + n.children[n.children.length-1].x)/2; } }\nroots.forEach(r=>layout(r,0));\nconst W = Math.max(900, 80 + leaf*HGAP), H = 80 + (Math.max(0,...[...nodes.values()].map(n=>n.depth||0))+1)*VGAP;\nconst svg = document.getElementById('svg'); svg.setAttribute('viewBox','0 0 '+W+' '+H); svg.setAttribute('width',W); svg.setAttribute('height',H);\nconst NS='http://www.w3.org/2000/svg';\nfunction el(t,a){ const x=document.createElementNS(NS,t); for(const k in a) x.setAttribute(k,a[k]); return x; }\n// edges\nconst edgeEls=new Map();\nfor (const n of nodes.values()) if (n.parentId && nodes.has(n.parentId)) { const p=nodes.get(n.parentId);\n const path=el('path',{class:'edge hidden', d:'M'+p.x+','+(p.y)+' C'+p.x+','+((p.y+n.y)/2)+' '+n.x+','+((p.y+n.y)/2)+' '+n.x+','+n.y}); svg.appendChild(path); edgeEls.set(n.id,path); }\n// nodes\nconst nodeEls=new Map();\nfor (const n of nodes.values()) { const g=el('g',{class:'node hidden'});\n const c=el('circle',{cx:n.x,cy:n.y,r:14,fill:'var(--dim)'});\n const t=el('text',{x:n.x,y:n.y-20,'text-anchor':'middle'}); t.textContent=n.label.slice(0,18);\n const s=el('text',{class:'sub',x:n.x,y:n.y+26,'text-anchor':'middle'}); s.textContent=n.runtime||'';\n g.appendChild(c); g.appendChild(t); g.appendChild(s); svg.appendChild(g); nodeEls.set(n.id,{g,c,s});\n g.addEventListener('mouseenter',()=>showDetail(n)); }\nfunction showDetail(n){ const st=state.get(n.id)||{}; document.getElementById('detail').innerHTML =\n '<div class=\"row\"><span class=\"k\">id</span> '+n.id+'</div>'+\n '<div class=\"row\"><span class=\"k\">label</span> '+esc(n.label)+'</div>'+\n '<div class=\"row\"><span class=\"k\">runtime</span> '+(n.runtime||'—')+'</div>'+\n '<div class=\"row\"><span class=\"k\">depth</span> '+(n.depth??0)+'</div>'+\n '<div class=\"row\"><span class=\"k\">status</span> '+(st.status||'—')+(st.valid===false?' (not delivered)':st.valid?' (delivered)':'')+'</div>'+\n '<div class=\"row\"><span class=\"k\">score</span> '+(st.score!=null?st.score.toFixed(2):'—')+'</div>'+\n (st.reason?'<div class=\"row\"><span class=\"k\">reason</span> '+esc(st.reason)+'</div>':'')+\n '<div class=\"row\"><span class=\"k\">tokens</span> '+(st.tokens||0)+'</div>'; }\nfunction esc(x){ return String(x).replace(/[<>&]/g,c=>({'<':'&lt;','>':'&gt;','&':'&amp;'}[c])); }\n// ── playback ──\nconst state=new Map();\nfunction colorOf(st){ if(!st||st.status==='running'||!st.status) return 'var(--run)'; if(st.status==='down') return 'var(--down)'; return st.valid===false ? 'var(--undeliv)' : 'var(--done)'; }\nfunction applyTo(ms){ const clk=TL.t0+ms; state.clear();\n let deliv=0, tok=0, usd=0, shown=0;\n // reset visibility\n for (const [,v] of nodeEls){ v.g.classList.add('hidden'); }\n for (const [,p] of edgeEls){ p.classList.add('hidden'); }\n for (const e of EV){ if (e.t>clk) break;\n if (e.kind==='spawn'||e.kind==='root'){ const ne=nodeEls.get(e.id); if(ne){ ne.g.classList.remove('hidden'); shown++; const ed=edgeEls.get(e.id); if(ed) ed.classList.remove('hidden'); } state.set(e.id, Object.assign(state.get(e.id)||{}, {status:'running'})); }\n else if (e.kind==='settle'){ const st=Object.assign(state.get(e.id)||{}, {status:e.status, valid:e.valid, score:e.score, reason:e.reason, tokens:e.tokens, usd:e.usd}); state.set(e.id,st); }\n }\n for (const [id,st] of state){ const ne=nodeEls.get(id); if(ne) ne.c.setAttribute('fill', colorOf(st)); if(st.status&&st.status!=='running'){ if(st.status==='done'&&st.valid!==false) deliv++; tok+=st.tokens||0; usd+=st.usd||0; } }\n document.getElementById('clock').textContent=(ms/1000).toFixed(1)+'s';\n document.getElementById('cNodes').textContent=shown;\n document.getElementById('cDeliv').textContent=deliv;\n document.getElementById('cTok').textContent=tok;\n document.getElementById('cUsd').textContent=usd.toFixed(3);\n}\nconst scrub=document.getElementById('scrub'); let playing=false, raf=0, last=0;\nfunction setMs(ms){ ms=Math.max(0,Math.min(span,ms)); scrub.value=(ms/span*1000)|0; applyTo(ms); }\nscrub.addEventListener('input',()=>setMs(scrub.value/1000*span));\ndocument.getElementById('play').addEventListener('click',()=>{ playing=!playing; document.getElementById('play').textContent=playing?'⏸ pause':'▶ play'; if(playing){ last=performance.now(); if((scrub.value/1000*span)>=span) setMs(0); tick(); } });\ndocument.getElementById('restart').addEventListener('click',()=>{ setMs(0); });\nfunction tick(){ if(!playing) return; const now=performance.now(); const sp=+document.getElementById('speed').value; let ms=scrub.value/1000*span + (now-last)*sp; last=now; if(ms>=span){ ms=span; playing=false; document.getElementById('play').textContent='▶ play'; } setMs(ms); if(playing) raf=requestAnimationFrame(tick); }\nsetMs(0);\n</script></body></html>`\n}\n\n/** A readable label for a synthesized root node (the last path segment of a nested tree key). */\nfunction shortRoot(id: string): string {\n const seg = id.split('/').pop() ?? id\n return seg.length > 22 ? `…${seg.slice(-21)}` : seg\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(\n /[<>&\"]/g,\n (c) => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;', '\"': '&quot;' })[c] ?? c,\n )\n}\n","/**\n * @experimental\n *\n * TOPOLOGY VIEW — the live recursive agent tree, folded from the ONE lifecycle stream\n * (`src/runtime-hooks.ts`). It is a pure projection: feed it the `RuntimeHookEvent`s that\n * `runLoop`, `toolLoop`, and the keystone `Scope` already emit, and it maintains the tree of\n * agents + renders it. Attach `view.hooks` to a `Supervisor`/`runLoop` and the tree updates live.\n *\n * Two node sources, ONE stream:\n * - an agent node is born from `agent.spawn` (id = `childId`, parent = the spawner) or the root\n * `agent.run` (id = `runId`); `agent.child`/`agent.run:after` settle it (status + score/reason).\n * - a STEP (`agent.{turn,tool_call,plan,decision}`) is not a node — it advances the step count of\n * the agent it belongs to (matched by `runId`/`parentId`).\n *\n * No I/O, no timers, no backend coupling — the same projection drives a CLI render, a TUI, or a\n * web tree. Rendering is deterministic given the event order (the stream is the source of truth).\n */\n\nimport type { RuntimeHookEvent, RuntimeHooks } from '../runtime-hooks'\n\nexport type TopologyStatus = 'running' | 'done' | 'down'\n\n/** One agent in the tree. A leaf never spawns; a driver's `childIds` is non-empty. */\nexport interface TopologyNode {\n readonly id: string\n /** Display label (spawn `label`, or the driver name on the root). */\n label: string\n /** Leaf runtime (`router`/`sandbox`/`cli`) when known. */\n runtime?: string\n /** Parent agent id; undefined ⇒ a root. */\n parentId?: string\n /** Recursion depth (root = 0). */\n depth: number\n status: TopologyStatus\n /** Count of in-agent steps (turns + tool calls + plan/decision rounds) folded so far. */\n steps: number\n /** Deployable score in [0,1] once settled `done`. */\n score?: number\n /** Failure reason once settled `down`. */\n reason?: string\n /** Children in spawn order. */\n readonly childIds: string[]\n}\n\nexport interface RenderOptions {\n /** Cap the rendered depth (deeper nodes collapse to a `… N more` line). Default: no cap. */\n readonly maxDepth?: number\n /** Drop the per-node detail suffix (steps/children/score) — labels only. Default: false. */\n readonly compact?: boolean\n}\n\nexport interface TopologyView {\n /** The `RuntimeHooks` sink — attach to `SupervisorOpts.hooks` / `runLoop` options. */\n readonly hooks: RuntimeHooks\n /** Fold one event into the tree (the same call `hooks.onEvent` makes — exposed for replay). */\n ingest(event: RuntimeHookEvent): void\n /** Every node, insertion order. */\n nodes(): TopologyNode[]\n /** Nodes with no in-tree parent (the run roots). */\n roots(): TopologyNode[]\n /** One node by id. */\n node(id: string): TopologyNode | undefined\n /** Render the tree as an aligned ASCII forest. */\n render(opts?: RenderOptions): string\n}\n\nconst stepTargets = new Set(['agent.turn', 'agent.tool_call', 'agent.plan', 'agent.decision'])\n\n/** Build a live topology view. Stateful — one per run (or per replay). */\nexport function createTopologyView(): TopologyView {\n // Insertion-ordered so render is stable and roots() reflects spawn order.\n const byId = new Map<string, TopologyNode>()\n\n const ensure = (id: string, seed: Partial<TopologyNode> = {}): TopologyNode => {\n const existing = byId.get(id)\n if (existing) return existing\n const node: TopologyNode = {\n id,\n label: seed.label ?? id,\n depth: seed.depth ?? 0,\n status: 'running',\n steps: 0,\n childIds: [],\n ...seed,\n }\n byId.set(id, node)\n return node\n }\n\n const str = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\n const num = (v: unknown): number | undefined => (typeof v === 'number' ? v : undefined)\n\n const ingest = (event: RuntimeHookEvent): void => {\n const p = (event.payload ?? {}) as Record<string, unknown>\n\n if (event.target === 'agent.spawn' && event.phase === 'after') {\n const id = str(p.childId)\n if (!id) return\n const parent = event.parentId ? ensure(event.parentId) : undefined\n const node = ensure(id, {\n label: str(p.label) ?? id,\n runtime: str(p.runtime),\n parentId: event.parentId,\n depth: num(p.depth) ?? (parent ? parent.depth + 1 : 0),\n })\n if (parent && !parent.childIds.includes(id)) parent.childIds.push(id)\n node.status = 'running'\n return\n }\n\n if (event.target === 'agent.child' && event.phase === 'after') {\n const id = str(p.childId)\n if (!id) return\n const node = ensure(id, { parentId: event.parentId })\n node.status = str(p.status) === 'down' ? 'down' : 'done'\n node.score = num(p.score)\n node.reason = str(p.reason)\n return\n }\n\n if (event.target === 'agent.run') {\n const node = ensure(event.runId, {\n label: str(p.driver) ?? event.runId,\n parentId: event.parentId,\n })\n if (event.phase === 'before') node.status = 'running'\n else if (event.phase === 'error') node.status = 'down'\n else if (event.phase === 'after' && node.status === 'running') node.status = 'done'\n return\n }\n\n // A step advances the agent it belongs to: tool-loop/run-loop key the agent by `runId`,\n // a within-agent sub-event names it via `parentId`. Only count `after`/`event` phases so a\n // before/after pair is one step, not two. An unknown owner is dropped (no phantom node).\n if (stepTargets.has(event.target) && (event.phase === 'after' || event.phase === 'event')) {\n const owner =\n (event.parentId && byId.get(event.parentId)) || byId.get(event.runId) || undefined\n if (owner) owner.steps += 1\n }\n }\n\n const nodes = (): TopologyNode[] => [...byId.values()]\n const roots = (): TopologyNode[] =>\n nodes().filter((n) => n.parentId === undefined || !byId.has(n.parentId))\n\n return {\n hooks: { onEvent: (e) => ingest(e) },\n ingest,\n nodes,\n roots,\n node: (id) => byId.get(id),\n render: (opts) => renderTopologyTree({ roots: roots(), node: (id) => byId.get(id) }, opts),\n }\n}\n\nconst glyph: Record<TopologyStatus, string> = { running: '◐', done: '✓', down: '✗' }\n\n/** Render a forest of `TopologyNode`s to an aligned ASCII tree. Pure — given the same roots +\n * node lookup it returns the same string. Exposed so a caller can render a tree it folded\n * itself (e.g. from a journal replay) without the live view. */\nexport function renderTopologyTree(\n tree: { roots: TopologyNode[]; node: (id: string) => TopologyNode | undefined },\n opts: RenderOptions = {},\n): string {\n const lines: string[] = []\n\n const detail = (n: TopologyNode): string => {\n if (opts.compact) return ''\n const parts: string[] = []\n if (n.runtime) parts.push(n.runtime)\n if (n.steps > 0) parts.push(`${n.steps} ${n.steps === 1 ? 'step' : 'steps'}`)\n if (n.childIds.length > 0) parts.push(`${n.childIds.length} children`)\n if (n.status === 'done' && n.score !== undefined) parts.push(`score ${n.score.toFixed(2)}`)\n if (n.status === 'down' && n.reason) parts.push(`down: ${n.reason}`)\n return parts.length ? ` (${parts.join(' · ')})` : ''\n }\n\n const walk = (n: TopologyNode, prefix: string, isLast: boolean, depth: number): void => {\n const branch = depth === 0 ? '' : isLast ? '└─ ' : '├─ '\n lines.push(`${prefix}${branch}${glyph[n.status]} ${n.label}${detail(n)}`)\n\n if (opts.maxDepth !== undefined && depth >= opts.maxDepth && n.childIds.length > 0) {\n const childPrefix = prefix + (depth === 0 ? '' : isLast ? ' ' : '│ ')\n lines.push(`${childPrefix}└─ … ${n.childIds.length} more`)\n return\n }\n const childPrefix = prefix + (depth === 0 ? '' : isLast ? ' ' : '│ ')\n const kids = n.childIds.map((id) => tree.node(id)).filter((c): c is TopologyNode => !!c)\n kids.forEach((c, i) => {\n walk(c, childPrefix, i === kids.length - 1, depth + 1)\n })\n }\n\n tree.roots.forEach((r, i) => {\n walk(r, '', i === tree.roots.length - 1, 0)\n })\n return lines.join('\\n')\n}\n"],"mappings":"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","names":["childPrefix"]}