@directive-run/ai 1.22.0 → 1.23.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/anthropic.d.cts +1 -1
- package/dist/anthropic.d.ts +1 -1
- package/dist/{chunk-TH2D22JP.cjs → chunk-2FPL5W2H.cjs} +7 -7
- package/dist/chunk-2FPL5W2H.cjs.map +1 -0
- package/dist/{chunk-G7CRWJT7.js → chunk-4VP67W7L.js} +15 -15
- package/dist/chunk-4VP67W7L.js.map +1 -0
- package/dist/{chunk-IR3IHBVQ.cjs → chunk-7JTR4QBA.cjs} +2 -2
- package/dist/{chunk-IR3IHBVQ.cjs.map → chunk-7JTR4QBA.cjs.map} +1 -1
- package/dist/{chunk-5JQ2A3JK.js → chunk-BZB3RDI2.js} +2 -2
- package/dist/{chunk-5JQ2A3JK.js.map → chunk-BZB3RDI2.js.map} +1 -1
- package/dist/{chunk-RHJAMXLS.js → chunk-EW77VF5K.js} +3 -3
- package/dist/{chunk-RHJAMXLS.js.map → chunk-EW77VF5K.js.map} +1 -1
- package/dist/{chunk-7EJN6TYX.cjs → chunk-F73AKFDB.cjs} +15 -15
- package/dist/chunk-F73AKFDB.cjs.map +1 -0
- package/dist/{chunk-VSVR4RFK.js → chunk-FSSCGRAM.js} +2 -2
- package/dist/chunk-FSSCGRAM.js.map +1 -0
- package/dist/{chunk-XGHNOSXT.cjs → chunk-JMG5GZAH.cjs} +4 -4
- package/dist/{chunk-XGHNOSXT.cjs.map → chunk-JMG5GZAH.cjs.map} +1 -1
- package/dist/{chunk-GTB6HTZV.js → chunk-MRKU3UXH.js} +2 -2
- package/dist/chunk-MRKU3UXH.js.map +1 -0
- package/dist/{chunk-ZGJ2XHGI.cjs → chunk-QMSLWAMH.cjs} +2 -2
- package/dist/chunk-QMSLWAMH.cjs.map +1 -0
- package/dist/{chunk-QRDBUGPO.js → chunk-XGOTVPN6.js} +3 -3
- package/dist/chunk-XGOTVPN6.js.map +1 -0
- package/dist/{chunk-MDXDPECP.cjs → chunk-Y4A4UJPU.cjs} +2 -2
- package/dist/chunk-Y4A4UJPU.cjs.map +1 -0
- package/dist/{debug-timeline-L13P-U2I.d.ts → debug-timeline-C5Dzs2r_.d.ts} +1 -1
- package/dist/{debug-timeline-DpnRMnLU.d.cts → debug-timeline-Sc9cxgxV.d.cts} +1 -1
- package/dist/devtools.cjs +1 -1
- package/dist/devtools.d.cts +5 -5
- package/dist/devtools.d.ts +5 -5
- package/dist/devtools.js +1 -1
- package/dist/evals.d.cts +2 -2
- package/dist/evals.d.ts +2 -2
- package/dist/gemini.d.cts +1 -1
- package/dist/gemini.d.ts +1 -1
- package/dist/{guardrails-export-CxCOi3sd.d.ts → guardrails-export-BL8ozXSj.d.ts} +5 -5
- package/dist/{guardrails-export-D3pKHiPp.d.cts → guardrails-export-ByaYNGvG.d.cts} +5 -5
- package/dist/guardrails.cjs +1 -1
- package/dist/guardrails.d.cts +2 -2
- package/dist/guardrails.d.ts +2 -2
- package/dist/guardrails.js +1 -1
- package/dist/{health-monitor-C6xoXrQz.d.cts → health-monitor-C9v10_tj.d.cts} +1 -1
- package/dist/{health-monitor-qL9RNMH3.d.ts → health-monitor-J2eKmP--.d.ts} +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +1 -1
- package/dist/multi-agent-orchestrator-DUMT67N5.cjs +2 -0
- package/dist/{multi-agent-orchestrator-OX2TKD5Y.cjs.map → multi-agent-orchestrator-DUMT67N5.cjs.map} +1 -1
- package/dist/{multi-agent-orchestrator-RMTLPKB4.js → multi-agent-orchestrator-ZZ63F75F.js} +2 -2
- package/dist/{multi-agent-orchestrator-RMTLPKB4.js.map → multi-agent-orchestrator-ZZ63F75F.js.map} +1 -1
- package/dist/multi-agent.cjs +1 -1
- package/dist/multi-agent.d.cts +6 -6
- package/dist/multi-agent.d.ts +6 -6
- package/dist/multi-agent.js +1 -1
- package/dist/ollama.d.cts +1 -1
- package/dist/ollama.d.ts +1 -1
- package/dist/openai.d.cts +1 -1
- package/dist/openai.d.ts +1 -1
- package/dist/{orchestrator-types-DxWn77qo.d.cts → orchestrator-types-BT-NIFOe.d.cts} +3 -3
- package/dist/{orchestrator-types-BxOJllSa.d.ts → orchestrator-types-DMuSD8Vq.d.ts} +3 -3
- package/dist/predicate.cjs +1 -1
- package/dist/predicate.d.cts +2 -2
- package/dist/predicate.d.ts +2 -2
- package/dist/predicate.js +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +4 -4
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +1 -1
- package/dist/{types-DJ09LjZX.d.cts → types-6NoeLyrD.d.cts} +1 -0
- package/dist/{types-DJ09LjZX.d.ts → types-6NoeLyrD.d.ts} +1 -0
- package/package.json +2 -2
- package/dist/chunk-7EJN6TYX.cjs.map +0 -1
- package/dist/chunk-G7CRWJT7.js.map +0 -1
- package/dist/chunk-GTB6HTZV.js.map +0 -1
- package/dist/chunk-MDXDPECP.cjs.map +0 -1
- package/dist/chunk-QRDBUGPO.js.map +0 -1
- package/dist/chunk-TH2D22JP.cjs.map +0 -1
- package/dist/chunk-VSVR4RFK.js.map +0 -1
- package/dist/chunk-ZGJ2XHGI.cjs.map +0 -1
- package/dist/multi-agent-orchestrator-OX2TKD5Y.cjs +0 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';function L(o){let{transport:c,timeline:v,healthMonitor:i,getSnapshot:f,getBreakpointState:h,onResumeBreakpoint:p,onCancelBreakpoint:b,getScratchpadState:k,getDerivedState:T,onForkFromSnapshot:g,batchSize:M=1,batchIntervalMs:E=50,healthPushIntervalMs:O=0,authenticate:C}=o,w=o.maxClients??50,R=`devtools_${crypto.randomUUID()}`,s=new Set,d=new Set,y=[],D=null,_=null;function t(e,a){try{e.send(JSON.stringify(a));}catch{s.delete(e);}}function l(e){let a=JSON.stringify(e),n=[...s];for(let m of n)try{m.send(a);}catch{s.delete(m);}}function A(){y.length!==0&&(y.length===1?l({type:"event",event:y[0]}):l({type:"event_batch",events:y}),y=[]);}let N=v.subscribe(e=>{if(s.size!==0){if(M<=1){l({type:"event",event:e});return}y.push(e),y.length>=M&&A();}});M>1&&E>0&&(D=setInterval(A,E)),O>0&&i&&(_=setInterval(()=>{s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},O));function B(e,a){let n;try{n=JSON.parse(a);}catch{t(e,{type:"error",code:"INVALID_JSON",message:"Could not parse message"});return}if(!n||typeof n!="object"||typeof n.type!="string"){t(e,{type:"error",code:"INVALID_MESSAGE",message:"Missing type field"});return}let m=Date.now(),x=I.get(e)??0;if(m-x<P){t(e,{type:"error",code:"RATE_LIMITED",message:"Too many requests"});return}if(I.set(e,m),n.type==="authenticate"){if(!C){t(e,{type:"error",code:"UNKNOWN_COMMAND",message:"Authentication not configured on this server"});return}if(!d.has(e)){t(e,{type:"error",code:"ALREADY_AUTHENTICATED",message:"Already authenticated"});return}if(typeof n.token!="string"){t(e,{type:"error",code:"AUTH_FAILED",message:"Missing token"}),e.close(),d.delete(e);return}let r=C(n.token),u=S=>{S?(d.delete(e),s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})):(t(e,{type:"error",code:"AUTH_FAILED",message:"Invalid token"}),d.delete(e),e.close());};r instanceof Promise?r.then(u).catch(()=>{t(e,{type:"error",code:"AUTH_FAILED",message:"Authentication error"}),d.delete(e),e.close();}):u(r);return}if(d.has(e)){t(e,{type:"error",code:"AUTH_REQUIRED",message:"Authentication required"});return}switch(n.type){case "ping":t(e,{type:"pong",timestamp:Date.now()});break;case "request_snapshot":f?t(e,{type:"snapshot",data:f()}):t(e,{type:"error",code:"NO_SNAPSHOT",message:"Snapshot provider not configured"});break;case "request_health":i?t(e,{type:"health",metrics:i.getAllMetrics()}):t(e,{type:"error",code:"NO_HEALTH",message:"Health monitor not configured"});break;case "request_events":{let r=v.getEvents(),u=n.since,S=u!=null?r.filter(H=>H.id>u):r;t(e,{type:"event_batch",events:S});break}case "request_breakpoints":h?t(e,{type:"breakpoints",state:h()}):t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint provider not configured"});break;case "resume_breakpoint":if(p&&typeof n.breakpointId=="string"){let r=n.modifications?{input:n.modifications.input,skip:n.modifications.skip}:void 0;p(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint resume not configured"});break;case "cancel_breakpoint":if(b&&typeof n.breakpointId=="string"){let r=typeof n.reason=="string"?n.reason:void 0;b(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint cancel not configured"});break;case "export_session":t(e,{type:"event_batch",events:v.getEvents()});break;case "import_session":{if(typeof n.data!="string")t(e,{type:"error",code:"INVALID_DATA",message:"Missing data field for import"});else if(n.data.length>10485760)t(e,{type:"error",code:"IMPORT_TOO_LARGE",message:`Import data exceeds ${10485760/1024/1024} MB limit`});else try{v.import(n.data),t(e,{type:"event_batch",events:v.getEvents()});}catch(u){let S=u instanceof Error?u.message:String(u);t(e,{type:"error",code:"IMPORT_FAILED",message:S});}break}case "request_scratchpad":k?t(e,{type:"scratchpad_state",data:k()}):t(e,{type:"error",code:"NO_SCRATCHPAD",message:"Scratchpad provider not configured"});break;case "request_derived":T?t(e,{type:"derived_state",data:T()}):t(e,{type:"error",code:"NO_DERIVED",message:"Derived state provider not configured"});break;case "fork_from_snapshot":{if(g&&typeof n.eventId=="number")try{let r=g(n.eventId);t(e,{type:"fork_complete",eventId:n.eventId,newEventCount:r.newEventCount});}catch(r){let u=r instanceof Error?r.message:String(r);t(e,{type:"error",code:"FORK_FAILED",message:u});}else t(e,{type:"error",code:"NO_FORK",message:"Fork provider not configured"});break}default:t(e,{type:"error",code:"UNKNOWN_COMMAND",message:`Unknown message type: ${String(n.type).slice(0,100)}`});}}let I=new Map,P=50;return c.onConnection((e,a,n)=>{if(s.size+d.size>=w){try{let m={type:"error",code:"MAX_CLIENTS",message:"Connection limit reached"};e.send(JSON.stringify(m));}catch{}e.close();return}C?d.add(e):(s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})),a(m=>B(e,m)),n(()=>{s.delete(e),d.delete(e),I.delete(e);});}),{get clientCount(){return s.size},broadcast(e){l(e);},pushHealth(){i&&s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},pushBreakpoints(){h&&s.size>0&&l({type:"breakpoints",state:h()});},pushScratchpadUpdate(e,a){s.size>0&&l({type:"scratchpad_update",key:e,value:a});},pushDerivedUpdate(e,a){s.size>0&&l({type:"derived_update",id:e,value:a});},pushTokenStream(e,a,n){s.size>0&&l({type:"token_stream",agentId:e,tokens:a,tokenCount:n});},pushStreamDone(e,a){s.size>0&&l({type:"stream_done",agentId:e,totalTokens:a});},close(){N(),D&&(clearInterval(D),D=null),_&&(clearInterval(_),_=null),A();for(let e of s)try{e.close();}catch{}for(let e of d)try{e.close();}catch{}s.clear(),d.clear(),I.clear(),c.close();}}}async function z(o,c={}){if(!o.timeline)throw new Error("[Directive DevTools] Orchestrator must have debug: true to use DevTools");let v=await F({port:c.port??4040,host:c.host??"localhost"});return L({transport:v,timeline:o.timeline,healthMonitor:o.healthMonitor,healthPushIntervalMs:c.healthPushIntervalMs??5e3,batchSize:c.batchSize,authenticate:c.authenticate,getSnapshot:o.getAllAgentStates?()=>{let i=o.getAllAgentStates();return {timestamp:Date.now(),agents:i,eventCount:o.timeline.getEvents().length}}:void 0,getBreakpointState:o.getPendingBreakpoints?()=>({pending:o.getPendingBreakpoints(),resolved:[],cancelled:[]}):void 0,onResumeBreakpoint:o.resumeBreakpoint,onCancelBreakpoint:o.cancelBreakpoint,getScratchpadState:o.getScratchpadState,getDerivedState:o.getDerivedState,onForkFromSnapshot:o.timeline?.forkFrom?i=>(o.timeline.forkFrom(i),{newEventCount:o.timeline.getEvents().length}):void 0})}async function F(o={}){let c=o.port??4040,v=o.host??"localhost",{WebSocketServer:i}=await import('ws'),f=new i({port:c,host:v,maxPayload:o.maxPayloadBytes??1048576}),h=null;return f.on("connection",p=>{let b=null,k=null,T={send(g){p.readyState===p.OPEN&&p.send(g);},close(){p.close();}};p.on("message",g=>{b&&b(g.toString());}),p.on("close",()=>{k&&k();}),h?.(T,g=>{b=g;},g=>{k=g;});}),{onConnection(p){h=p;},close(){f.close();}}}exports.a=L;exports.b=z;exports.c=F;//# sourceMappingURL=chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
'use strict';function L(o){let{transport:c,timeline:v,healthMonitor:i,getSnapshot:f,getBreakpointState:h,onResumeBreakpoint:p,onCancelBreakpoint:b,getScratchpadState:k,getDerivedState:T,onForkFromSnapshot:g,batchSize:M=1,batchIntervalMs:E=50,healthPushIntervalMs:O=0,authenticate:C}=o,w=o.maxClients??50,R=`devtools_${crypto.randomUUID()}`,s=new Set,d=new Set,y=[],D=null,_=null;function t(e,a){try{e.send(JSON.stringify(a));}catch{s.delete(e);}}function l(e){let a=JSON.stringify(e),n=[...s];for(let m of n)try{m.send(a);}catch{s.delete(m);}}function A(){y.length!==0&&(y.length===1?l({type:"event",event:y[0]}):l({type:"event_batch",events:y}),y=[]);}let N=v.subscribe(e=>{if(s.size!==0){if(M<=1){l({type:"event",event:e});return}y.push(e),y.length>=M&&A();}});M>1&&E>0&&(D=setInterval(A,E)),O>0&&i&&(_=setInterval(()=>{s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},O));function B(e,a){let n;try{n=JSON.parse(a);}catch{t(e,{type:"error",code:"INVALID_JSON",message:"Could not parse message"});return}if(!n||typeof n!="object"||typeof n.type!="string"){t(e,{type:"error",code:"INVALID_MESSAGE",message:"Missing type field"});return}let m=Date.now(),x=I.get(e)??0;if(m-x<P){t(e,{type:"error",code:"RATE_LIMITED",message:"Too many requests"});return}if(I.set(e,m),n.type==="authenticate"){if(!C){t(e,{type:"error",code:"UNKNOWN_COMMAND",message:"Authentication not configured on this server"});return}if(!d.has(e)){t(e,{type:"error",code:"ALREADY_AUTHENTICATED",message:"Already authenticated"});return}if(typeof n.token!="string"){t(e,{type:"error",code:"AUTH_FAILED",message:"Missing token"}),e.close(),d.delete(e);return}let r=C(n.token),u=S=>{S?(d.delete(e),s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})):(t(e,{type:"error",code:"AUTH_FAILED",message:"Invalid token"}),d.delete(e),e.close());};r instanceof Promise?r.then(u).catch(()=>{t(e,{type:"error",code:"AUTH_FAILED",message:"Authentication error"}),d.delete(e),e.close();}):u(r);return}if(d.has(e)){t(e,{type:"error",code:"AUTH_REQUIRED",message:"Authentication required"});return}switch(n.type){case "ping":t(e,{type:"pong",timestamp:Date.now()});break;case "request_snapshot":f?t(e,{type:"snapshot",data:f()}):t(e,{type:"error",code:"NO_SNAPSHOT",message:"Snapshot provider not configured"});break;case "request_health":i?t(e,{type:"health",metrics:i.getAllMetrics()}):t(e,{type:"error",code:"NO_HEALTH",message:"Health monitor not configured"});break;case "request_events":{let r=v.getEvents(),u=n.since,S=u!=null?r.filter(H=>H.id>u):r;t(e,{type:"event_batch",events:S});break}case "request_breakpoints":h?t(e,{type:"breakpoints",state:h()}):t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint provider not configured"});break;case "resume_breakpoint":if(p&&typeof n.breakpointId=="string"){let r=n.modifications?{input:n.modifications.input,skip:n.modifications.skip}:void 0;p(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint resume not configured"});break;case "cancel_breakpoint":if(b&&typeof n.breakpointId=="string"){let r=typeof n.reason=="string"?n.reason:void 0;b(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint cancel not configured"});break;case "export_session":t(e,{type:"event_batch",events:v.getEvents()});break;case "import_session":{if(typeof n.data!="string")t(e,{type:"error",code:"INVALID_DATA",message:"Missing data field for import"});else if(n.data.length>10485760)t(e,{type:"error",code:"IMPORT_TOO_LARGE",message:`Import data exceeds ${10485760/1024/1024} MB limit`});else try{v.import(n.data),t(e,{type:"event_batch",events:v.getEvents()});}catch(u){let S=u instanceof Error?u.message:String(u);t(e,{type:"error",code:"IMPORT_FAILED",message:S});}break}case "request_scratchpad":k?t(e,{type:"scratchpad_state",data:k()}):t(e,{type:"error",code:"NO_SCRATCHPAD",message:"Scratchpad provider not configured"});break;case "request_derived":T?t(e,{type:"derived_state",data:T()}):t(e,{type:"error",code:"NO_DERIVED",message:"Derived state provider not configured"});break;case "fork_from_snapshot":{if(g&&typeof n.eventId=="number")try{let r=g(n.eventId);t(e,{type:"fork_complete",eventId:n.eventId,newEventCount:r.newEventCount});}catch(r){let u=r instanceof Error?r.message:String(r);t(e,{type:"error",code:"FORK_FAILED",message:u});}else t(e,{type:"error",code:"NO_FORK",message:"Fork provider not configured"});break}default:t(e,{type:"error",code:"UNKNOWN_COMMAND",message:`Unknown message type: ${String(n.type).slice(0,100)}`});}}let I=new Map,P=50;return c.onConnection((e,a,n)=>{if(s.size+d.size>=w){try{let m={type:"error",code:"MAX_CLIENTS",message:"Connection limit reached"};e.send(JSON.stringify(m));}catch{}e.close();return}C?d.add(e):(s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})),a(m=>B(e,m)),n(()=>{s.delete(e),d.delete(e),I.delete(e);});}),{get clientCount(){return s.size},broadcast(e){l(e);},pushHealth(){i&&s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},pushBreakpoints(){h&&s.size>0&&l({type:"breakpoints",state:h()});},pushScratchpadUpdate(e,a){s.size>0&&l({type:"scratchpad_update",key:e,value:a});},pushDerivedUpdate(e,a){s.size>0&&l({type:"derived_update",id:e,value:a});},pushTokenStream(e,a,n){s.size>0&&l({type:"token_stream",agentId:e,tokens:a,tokenCount:n});},pushStreamDone(e,a){s.size>0&&l({type:"stream_done",agentId:e,totalTokens:a});},close(){N(),D&&(clearInterval(D),D=null),_&&(clearInterval(_),_=null),A();for(let e of s)try{e.close();}catch{}for(let e of d)try{e.close();}catch{}s.clear(),d.clear(),I.clear(),c.close();}}}async function z(o,c={}){if(!o.timeline)throw new Error("[Directive DevTools] Orchestrator must have debug: true to use DevTools");let v=await F({port:c.port??4040,host:c.host??"localhost"});return L({transport:v,timeline:o.timeline,healthMonitor:o.healthMonitor,healthPushIntervalMs:c.healthPushIntervalMs??5e3,batchSize:c.batchSize,authenticate:c.authenticate,getSnapshot:o.getAllAgentStates?()=>{let i=o.getAllAgentStates();return {timestamp:Date.now(),agents:i,eventCount:o.timeline.getEvents().length}}:void 0,getBreakpointState:o.getPendingBreakpoints?()=>({pending:o.getPendingBreakpoints(),resolved:[],cancelled:[]}):void 0,onResumeBreakpoint:o.resumeBreakpoint,onCancelBreakpoint:o.cancelBreakpoint,getScratchpadState:o.getScratchpadState,getDerivedState:o.getDerivedState,onForkFromSnapshot:o.timeline?.forkFrom?i=>(o.timeline.forkFrom(i),{newEventCount:o.timeline.getEvents().length}):void 0})}async function F(o={}){let c=o.port??4040,v=o.host??"localhost",{WebSocketServer:i}=await import('ws'),f=new i({port:c,host:v,maxPayload:o.maxPayloadBytes??1048576}),h=null;return f.on("connection",p=>{let b=null,k=null,T={send(g){p.readyState===p.OPEN&&p.send(g);},close(){p.close();}};p.on("message",g=>{b&&b(g.toString());}),p.on("close",()=>{k&&k();}),h?.(T,g=>{b=g;},g=>{k=g;});}),{onConnection(p){h=p;},close(){f.close();}}}exports.a=L;exports.b=z;exports.c=F;//# sourceMappingURL=chunk-7JTR4QBA.cjs.map
|
|
2
|
+
//# sourceMappingURL=chunk-7JTR4QBA.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools-server.ts"],"names":["createDevToolsServer","config","transport","timeline","healthMonitor","getSnapshot","getBreakpointState","onResumeBreakpoint","onCancelBreakpoint","getScratchpadState","getDerivedState","onForkFromSnapshot","batchSize","batchIntervalMs","healthPushIntervalMs","authenticate","maxClients","sessionId","clients","pendingAuthClients","batchBuffer","batchTimer","healthTimer","sendToClient","client","message","broadcastMessage","data","snapshot","flushBatch","unsubscribeTimeline","event","handleClientMessage","raw","msg","now","last","clientLastMessage","MIN_MESSAGE_INTERVAL_MS","result","handleResult","valid","events","since","filtered","e","mods","safeReason","err","errMsg","onMessage","onClose","key","value","id","agentId","tokens","tokenCount","totalTokens","connectDevTools","orchestrator","options","createWsTransport","agents","eventId","port","host","WebSocketServer","wss","connectionHandler","ws","messageHandler","closeHandler","handler"],"mappings":"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","file":"chunk-IR3IHBVQ.cjs","sourcesContent":["/**\n * DevTools Server — WebSocket-based bridge between orchestrators and DevTools UI.\n *\n * Streams debug timeline events, health metrics, breakpoint state, and system\n * snapshots in real-time to connected DevTools clients. Accepts commands from\n * clients to resume/cancel breakpoints and request snapshots.\n *\n * Transport-agnostic: works with any WebSocket implementation (ws, Bun, Deno)\n * via the {@link DevToolsTransport} interface.\n *\n * @module\n */\n\nimport type { DebugTimeline } from \"./debug-timeline.js\";\nimport type { AgentHealthMetrics, HealthMonitor } from \"./health-monitor.js\";\nimport type { BreakpointState, DebugEvent } from \"./types.js\";\n\n// ============================================================================\n// Transport Interface (WebSocket abstraction)\n// ============================================================================\n\n/** A connected DevTools client */\nexport interface DevToolsClient {\n /** Send a JSON-serializable message to this client */\n send(data: string): void;\n /** Close the connection */\n close(): void;\n}\n\n/**\n * Transport layer for the DevTools server.\n *\n * Implement this interface to bridge any WebSocket library (ws, Bun.serve, Deno.serve).\n *\n * @example Node.js with `ws`:\n * ```typescript\n * import { WebSocketServer } from \"ws\";\n *\n * function createWsTransport(port: number): DevToolsTransport {\n * const wss = new WebSocketServer({ port });\n * let onConnect: ((client: DevToolsClient) => void) | null = null;\n *\n * wss.on(\"connection\", (ws) => {\n * const client: DevToolsClient = {\n * send: (data) => { if (ws.readyState === ws.OPEN) ws.send(data); },\n * close: () => ws.close(),\n * };\n * ws.on(\"message\", (raw) => {\n * if (client._onMessage) client._onMessage(raw.toString());\n * });\n * ws.on(\"close\", () => {\n * if (client._onClose) client._onClose();\n * });\n * onConnect?.(client);\n * });\n *\n * return {\n * onConnection(handler) { onConnect = handler; },\n * close() { wss.close(); },\n * };\n * }\n * ```\n */\nexport interface DevToolsTransport {\n /** Register a handler for new client connections */\n onConnection(\n handler: (\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void,\n ): void;\n /** Shut down the transport */\n close(): void;\n}\n\n// ============================================================================\n// Protocol Messages\n// ============================================================================\n\n/** Messages sent FROM the server TO clients */\nexport type DevToolsServerMessage =\n | { type: \"welcome\"; version: number; sessionId: string; timestamp: number }\n | { type: \"event\"; event: DebugEvent }\n | { type: \"event_batch\"; events: DebugEvent[] }\n | { type: \"snapshot\"; data: DevToolsSnapshot }\n | { type: \"health\"; metrics: Record<string, AgentHealthMetrics> }\n | { type: \"breakpoints\"; state: BreakpointState }\n | { type: \"pong\"; timestamp: number }\n // Scratchpad & derived state\n | { type: \"scratchpad_state\"; data: Record<string, unknown> }\n | { type: \"scratchpad_update\"; key: string; value: unknown }\n | { type: \"derived_state\"; data: Record<string, unknown> }\n | { type: \"derived_update\"; id: string; value: unknown }\n // Fork\n | { type: \"fork_complete\"; eventId: number; newEventCount: number }\n // Token streaming\n | {\n type: \"token_stream\";\n agentId: string;\n tokens: string;\n tokenCount: number;\n }\n | { type: \"stream_done\"; agentId: string; totalTokens: number }\n | { type: \"error\"; code: string; message: string };\n\n/** Messages sent FROM clients TO the server */\nexport type DevToolsClientMessage =\n | { type: \"authenticate\"; token: string }\n | { type: \"request_snapshot\" }\n | { type: \"request_health\" }\n | { type: \"request_events\"; since?: number }\n | { type: \"request_breakpoints\" }\n | {\n type: \"resume_breakpoint\";\n breakpointId: string;\n modifications?: { input?: string; skip?: boolean };\n }\n | { type: \"cancel_breakpoint\"; breakpointId: string; reason?: string }\n | { type: \"export_session\" }\n | { type: \"import_session\"; data: string }\n // Scratchpad & derived requests\n | { type: \"request_scratchpad\" }\n | { type: \"request_derived\" }\n // Fork\n | { type: \"fork_from_snapshot\"; eventId: number }\n | { type: \"ping\" };\n\n/** System snapshot sent to clients on demand */\nexport interface DevToolsSnapshot {\n timestamp: number;\n agents: Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n coordinator?: { globalTokens: number; status: string };\n derived?: Record<string, unknown>;\n eventCount: number;\n}\n\n// ============================================================================\n// Server Configuration\n// ============================================================================\n\n/** Configuration for the DevTools server */\nexport interface DevToolsServerConfig {\n /** Transport to use for WebSocket connections */\n transport: DevToolsTransport;\n /** Debug timeline to subscribe to */\n timeline: DebugTimeline;\n /** Health monitor for metrics (optional) */\n healthMonitor?: HealthMonitor | null;\n /** Callback to get current agent states for snapshots */\n getSnapshot?: () => DevToolsSnapshot;\n /** Callback to get current breakpoint state */\n getBreakpointState?: () => BreakpointState;\n /** Callback to resume a breakpoint */\n onResumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n /** Callback to cancel a breakpoint */\n onCancelBreakpoint?: (id: string, reason?: string) => void;\n /** Callback to get current scratchpad state */\n getScratchpadState?: () => Record<string, unknown>;\n /** Callback to get current derived state */\n getDerivedState?: () => Record<string, unknown>;\n /** Callback to fork from a snapshot event */\n onForkFromSnapshot?: (eventId: number) => { newEventCount: number };\n /** Maximum events to batch before flushing. Default: 1 (no batching) */\n batchSize?: number;\n /** Flush interval for batched events (ms). Default: 50 */\n batchIntervalMs?: number;\n /** Health metrics push interval (ms). 0 = no auto-push. Default: 0 */\n healthPushIntervalMs?: number;\n /** Maximum connected clients. Default: 50 */\n maxClients?: number;\n /** Token authentication callback. When set, new connections must send an `authenticate` message before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n// ============================================================================\n// Server Instance\n// ============================================================================\n\n/** DevTools server instance */\nexport interface DevToolsServer {\n /** Number of connected clients */\n readonly clientCount: number;\n /** Broadcast a message to all connected clients */\n broadcast(message: DevToolsServerMessage): void;\n /** Push current health metrics to all clients */\n pushHealth(): void;\n /** Push current breakpoint state to all clients */\n pushBreakpoints(): void;\n /** Push a scratchpad key update to all clients */\n pushScratchpadUpdate(key: string, value: unknown): void;\n /** Push a derived value update to all clients */\n pushDerivedUpdate(id: string, value: unknown): void;\n /** Push streaming tokens to all clients */\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void;\n /** Signal stream completion to all clients */\n pushStreamDone(agentId: string, totalTokens: number): void;\n /** Shut down the server and disconnect all clients */\n close(): void;\n}\n\nconst PROTOCOL_VERSION = 1;\n\n/**\n * Create a DevTools server that bridges orchestrator state to DevTools UI clients.\n *\n * @example\n * ```typescript\n * const server = createDevToolsServer({\n * transport: createWsTransport(4040),\n * timeline: orchestrator.timeline!,\n * healthMonitor: orchestrator.healthMonitor,\n * getSnapshot: () => buildSnapshot(orchestrator),\n * getBreakpointState: () => orchestrator.getBreakpointState(),\n * onResumeBreakpoint: (id, mods) => orchestrator.resumeBreakpoint(id, mods),\n * onCancelBreakpoint: (id, reason) => orchestrator.cancelBreakpoint(id, reason),\n * });\n * ```\n */\nexport function createDevToolsServer(\n config: DevToolsServerConfig,\n): DevToolsServer {\n const {\n transport,\n timeline,\n healthMonitor,\n getSnapshot,\n getBreakpointState,\n onResumeBreakpoint,\n onCancelBreakpoint,\n getScratchpadState,\n getDerivedState,\n onForkFromSnapshot,\n batchSize = 1,\n batchIntervalMs = 50,\n healthPushIntervalMs = 0,\n authenticate,\n } = config;\n const maxClients = config.maxClients ?? 50;\n\n const sessionId = `devtools_${crypto.randomUUID()}`;\n const clients = new Set<DevToolsClient>();\n const pendingAuthClients = new Set<DevToolsClient>();\n let batchBuffer: DebugEvent[] = [];\n let batchTimer: ReturnType<typeof setInterval> | null = null;\n let healthTimer: ReturnType<typeof setInterval> | null = null;\n\n // ------------------------------------------------------------------\n // Helpers\n // ------------------------------------------------------------------\n\n function sendToClient(\n client: DevToolsClient,\n message: DevToolsServerMessage,\n ): void {\n try {\n client.send(JSON.stringify(message));\n } catch {\n // Client may have disconnected — remove silently\n clients.delete(client);\n }\n }\n\n function broadcastMessage(message: DevToolsServerMessage): void {\n const data = JSON.stringify(message);\n const snapshot = [...clients];\n for (const client of snapshot) {\n try {\n client.send(data);\n } catch {\n clients.delete(client);\n }\n }\n }\n\n function flushBatch(): void {\n if (batchBuffer.length === 0) {\n return;\n }\n\n if (batchBuffer.length === 1) {\n broadcastMessage({ type: \"event\", event: batchBuffer[0]! });\n } else {\n broadcastMessage({ type: \"event_batch\", events: batchBuffer });\n }\n\n batchBuffer = [];\n }\n\n // ------------------------------------------------------------------\n // Timeline subscription\n // ------------------------------------------------------------------\n\n const unsubscribeTimeline: () => void = timeline.subscribe(\n (event: DebugEvent) => {\n if (clients.size === 0) {\n return;\n }\n\n if (batchSize <= 1) {\n broadcastMessage({ type: \"event\", event });\n\n return;\n }\n\n batchBuffer.push(event);\n if (batchBuffer.length >= batchSize) {\n flushBatch();\n }\n },\n );\n\n // Start batch flush timer if batching enabled\n if (batchSize > 1 && batchIntervalMs > 0) {\n batchTimer = setInterval(flushBatch, batchIntervalMs);\n }\n\n // Start health push timer if configured\n if (healthPushIntervalMs > 0 && healthMonitor) {\n healthTimer = setInterval(() => {\n if (clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n }, healthPushIntervalMs);\n }\n\n // ------------------------------------------------------------------\n // Client message handler\n // ------------------------------------------------------------------\n\n function handleClientMessage(client: DevToolsClient, raw: string): void {\n let msg: DevToolsClientMessage;\n try {\n msg = JSON.parse(raw) as DevToolsClientMessage;\n } catch {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_JSON\",\n message: \"Could not parse message\",\n });\n\n return;\n }\n\n if (!msg || typeof msg !== \"object\" || typeof msg.type !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_MESSAGE\",\n message: \"Missing type field\",\n });\n\n return;\n }\n\n const now = Date.now();\n const last = clientLastMessage.get(client) ?? 0;\n if (now - last < MIN_MESSAGE_INTERVAL_MS) {\n sendToClient(client, {\n type: \"error\",\n code: \"RATE_LIMITED\",\n message: \"Too many requests\",\n });\n\n return;\n }\n clientLastMessage.set(client, now);\n\n // Handle authenticate message\n if (msg.type === \"authenticate\") {\n if (!authenticate) {\n // No auth configured — treat as unknown command\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: \"Authentication not configured on this server\",\n });\n\n return;\n }\n\n if (!pendingAuthClients.has(client)) {\n // Already authenticated\n sendToClient(client, {\n type: \"error\",\n code: \"ALREADY_AUTHENTICATED\",\n message: \"Already authenticated\",\n });\n\n return;\n }\n\n if (typeof msg.token !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Missing token\",\n });\n client.close();\n pendingAuthClients.delete(client);\n\n return;\n }\n\n const result = authenticate(msg.token);\n const handleResult = (valid: boolean) => {\n if (valid) {\n pendingAuthClients.delete(client);\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Invalid token\",\n });\n pendingAuthClients.delete(client);\n client.close();\n }\n };\n\n if (result instanceof Promise) {\n result.then(handleResult).catch(() => {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Authentication error\",\n });\n pendingAuthClients.delete(client);\n client.close();\n });\n } else {\n handleResult(result);\n }\n\n return;\n }\n\n // Reject commands from clients pending authentication\n if (pendingAuthClients.has(client)) {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_REQUIRED\",\n message: \"Authentication required\",\n });\n\n return;\n }\n\n switch (msg.type) {\n case \"ping\":\n sendToClient(client, { type: \"pong\", timestamp: Date.now() });\n break;\n\n case \"request_snapshot\":\n if (getSnapshot) {\n sendToClient(client, { type: \"snapshot\", data: getSnapshot() });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SNAPSHOT\",\n message: \"Snapshot provider not configured\",\n });\n }\n break;\n\n case \"request_health\":\n if (healthMonitor) {\n sendToClient(client, {\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_HEALTH\",\n message: \"Health monitor not configured\",\n });\n }\n break;\n\n case \"request_events\": {\n const events = timeline.getEvents();\n const since = msg.since;\n const filtered =\n since != null ? events.filter((e) => e.id > since) : events;\n sendToClient(client, { type: \"event_batch\", events: filtered });\n break;\n }\n\n case \"request_breakpoints\":\n if (getBreakpointState) {\n sendToClient(client, {\n type: \"breakpoints\",\n state: getBreakpointState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint provider not configured\",\n });\n }\n break;\n\n case \"resume_breakpoint\":\n if (onResumeBreakpoint && typeof msg.breakpointId === \"string\") {\n // Sanitize: only extract known fields to prevent prototype pollution\n const mods = msg.modifications\n ? { input: msg.modifications.input, skip: msg.modifications.skip }\n : undefined;\n onResumeBreakpoint(msg.breakpointId, mods);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint resume not configured\",\n });\n }\n break;\n\n case \"cancel_breakpoint\":\n if (onCancelBreakpoint && typeof msg.breakpointId === \"string\") {\n const safeReason =\n typeof msg.reason === \"string\" ? msg.reason : undefined;\n onCancelBreakpoint(msg.breakpointId, safeReason);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint cancel not configured\",\n });\n }\n break;\n\n case \"export_session\":\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n break;\n\n case \"import_session\": {\n const MAX_IMPORT_SIZE = 10 * 1024 * 1024; // ~10M characters (string .length check, not byte size)\n if (typeof msg.data !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_DATA\",\n message: \"Missing data field for import\",\n });\n } else if (msg.data.length > MAX_IMPORT_SIZE) {\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_TOO_LARGE\",\n message: `Import data exceeds ${MAX_IMPORT_SIZE / 1024 / 1024} MB limit`,\n });\n } else {\n try {\n timeline.import(msg.data);\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_FAILED\",\n message: errMsg,\n });\n }\n }\n break;\n }\n\n case \"request_scratchpad\":\n if (getScratchpadState) {\n sendToClient(client, {\n type: \"scratchpad_state\",\n data: getScratchpadState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SCRATCHPAD\",\n message: \"Scratchpad provider not configured\",\n });\n }\n break;\n\n case \"request_derived\":\n if (getDerivedState) {\n sendToClient(client, {\n type: \"derived_state\",\n data: getDerivedState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_DERIVED\",\n message: \"Derived state provider not configured\",\n });\n }\n break;\n\n case \"fork_from_snapshot\": {\n if (onForkFromSnapshot && typeof msg.eventId === \"number\") {\n try {\n const result = onForkFromSnapshot(msg.eventId);\n sendToClient(client, {\n type: \"fork_complete\",\n eventId: msg.eventId,\n newEventCount: result.newEventCount,\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"FORK_FAILED\",\n message: errMsg,\n });\n }\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_FORK\",\n message: \"Fork provider not configured\",\n });\n }\n break;\n }\n\n default:\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: `Unknown message type: ${String((msg as { type: string }).type).slice(0, 100)}`,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Rate limiting\n // ------------------------------------------------------------------\n\n const clientLastMessage = new Map<DevToolsClient, number>();\n const MIN_MESSAGE_INTERVAL_MS = 50;\n\n // ------------------------------------------------------------------\n // Connection handler\n // ------------------------------------------------------------------\n\n transport.onConnection((client, onMessage, onClose) => {\n if (clients.size + pendingAuthClients.size >= maxClients) {\n try {\n const msg: DevToolsServerMessage = {\n type: \"error\",\n code: \"MAX_CLIENTS\",\n message: \"Connection limit reached\",\n };\n client.send(JSON.stringify(msg));\n } catch {\n /* ignore */\n }\n client.close();\n\n return;\n }\n\n if (authenticate) {\n // Hold in pending state until client sends authenticate message\n pendingAuthClients.add(client);\n } else {\n // No auth — add directly and send welcome\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n }\n\n onMessage((data) => handleClientMessage(client, data));\n onClose(() => {\n clients.delete(client);\n pendingAuthClients.delete(client);\n clientLastMessage.delete(client);\n });\n });\n\n // ------------------------------------------------------------------\n // Public interface\n // ------------------------------------------------------------------\n\n return {\n get clientCount(): number {\n return clients.size;\n },\n\n broadcast(message: DevToolsServerMessage): void {\n broadcastMessage(message);\n },\n\n pushHealth(): void {\n if (healthMonitor && clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n },\n\n pushBreakpoints(): void {\n if (getBreakpointState && clients.size > 0) {\n broadcastMessage({ type: \"breakpoints\", state: getBreakpointState() });\n }\n },\n\n pushScratchpadUpdate(key: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"scratchpad_update\", key, value });\n }\n },\n\n pushDerivedUpdate(id: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"derived_update\", id, value });\n }\n },\n\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"token_stream\", agentId, tokens, tokenCount });\n }\n },\n\n pushStreamDone(agentId: string, totalTokens: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"stream_done\", agentId, totalTokens });\n }\n },\n\n close(): void {\n unsubscribeTimeline();\n\n if (batchTimer) {\n clearInterval(batchTimer);\n batchTimer = null;\n }\n\n if (healthTimer) {\n clearInterval(healthTimer);\n healthTimer = null;\n }\n\n flushBatch();\n\n for (const client of clients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n for (const client of pendingAuthClients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n clients.clear();\n pendingAuthClients.clear();\n clientLastMessage.clear();\n\n transport.close();\n },\n };\n}\n\n// ============================================================================\n// Orchestrator Connector\n// ============================================================================\n\n/** Options for connecting DevTools to an orchestrator */\nexport interface ConnectDevToolsOptions {\n /** Port for the WebSocket server. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Health metrics push interval (ms). Default: 5000 */\n healthPushIntervalMs?: number;\n /** Event batching size. Default: 1 (no batching) */\n batchSize?: number;\n /** Token authentication callback. When set, clients must authenticate before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n/** Minimal orchestrator interface for DevTools connection */\nexport interface DevToolsCompatibleOrchestrator {\n timeline: {\n subscribe: (listener: (event: DebugEvent) => void) => () => void;\n getEvents: () => DebugEvent[];\n import: (json: string) => void;\n export: () => string;\n forkFrom?: (eventId: number) => void;\n } | null;\n healthMonitor?: {\n getAllMetrics: () => Record<string, AgentHealthMetrics>;\n } | null;\n getPendingBreakpoints?: () => Array<{\n id: string;\n type: string;\n agentId: string;\n input: string;\n label?: string;\n requestedAt: number;\n }>;\n resumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n cancelBreakpoint?: (id: string, reason?: string) => void;\n getAllAgentStates?: () => Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n /** Get current scratchpad state (multi-agent only) */\n getScratchpadState?: () => Record<string, unknown>;\n /** Get current derived values (multi-agent only) */\n getDerivedState?: () => Record<string, unknown>;\n}\n\n/**\n * Connect DevTools to an orchestrator instance.\n *\n * Convenience function that creates a WebSocket transport and DevTools server,\n * automatically wiring up the orchestrator's timeline, health monitor, and breakpoint system.\n *\n * Requires the `ws` package: `npm install ws`\n *\n * **Security:** Binding to `0.0.0.0` exposes the server to all network interfaces.\n * Only do this behind a firewall or with proper authentication.\n *\n * @example\n * ```typescript\n * const orchestrator = createMultiAgentOrchestrator({ debug: true, ... });\n * const devtools = await connectDevTools(orchestrator, { port: 4040 });\n *\n * // Later, clean up:\n * devtools.close();\n * ```\n */\nexport async function connectDevTools(\n orchestrator: DevToolsCompatibleOrchestrator,\n options: ConnectDevToolsOptions = {},\n): Promise<DevToolsServer> {\n if (!orchestrator.timeline) {\n throw new Error(\n \"[Directive DevTools] Orchestrator must have debug: true to use DevTools\",\n );\n }\n\n const transport = await createWsTransport({\n port: options.port ?? 4040,\n host: options.host ?? \"localhost\",\n });\n\n return createDevToolsServer({\n transport,\n timeline: orchestrator.timeline as unknown as DebugTimeline,\n healthMonitor: orchestrator.healthMonitor as HealthMonitor | undefined,\n healthPushIntervalMs: options.healthPushIntervalMs ?? 5000,\n batchSize: options.batchSize,\n authenticate: options.authenticate,\n getSnapshot: orchestrator.getAllAgentStates\n ? () => {\n const agents = orchestrator.getAllAgentStates!();\n\n return {\n timestamp: Date.now(),\n agents,\n eventCount: orchestrator.timeline!.getEvents().length,\n };\n }\n : undefined,\n getBreakpointState: orchestrator.getPendingBreakpoints\n ? () => ({\n pending: orchestrator.getPendingBreakpoints!(),\n resolved: [],\n cancelled: [],\n })\n : undefined,\n onResumeBreakpoint: orchestrator.resumeBreakpoint,\n onCancelBreakpoint: orchestrator.cancelBreakpoint,\n getScratchpadState: orchestrator.getScratchpadState,\n getDerivedState: orchestrator.getDerivedState,\n onForkFromSnapshot: orchestrator.timeline?.forkFrom\n ? (eventId: number) => {\n orchestrator.timeline!.forkFrom!(eventId);\n const newEventCount = orchestrator.timeline!.getEvents().length;\n\n return { newEventCount };\n }\n : undefined,\n });\n}\n\n// ============================================================================\n// Node.js ws Transport Helper\n// ============================================================================\n\n/**\n * Configuration for the built-in Node.js `ws` transport.\n *\n * Requires the `ws` package to be installed: `npm install ws`\n */\nexport interface WsTransportConfig {\n /** Port to listen on. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Maximum incoming message size in bytes. Default: 1048576 (1MB) */\n maxPayloadBytes?: number;\n}\n\n/**\n * Create a DevTools transport using the Node.js `ws` WebSocket library.\n *\n * This is a convenience helper — you can implement {@link DevToolsTransport}\n * with any WebSocket library.\n *\n * @example\n * ```typescript\n * const transport = await createWsTransport({ port: 4040 });\n * const server = createDevToolsServer({ transport, timeline });\n * ```\n */\nexport async function createWsTransport(\n config: WsTransportConfig = {},\n): Promise<DevToolsTransport> {\n const port = config.port ?? 4040;\n const host = config.host ?? \"localhost\";\n\n // Dynamic import so ws is not a hard dependency\n const { WebSocketServer } = await import(\"ws\");\n // maxPayload is supported at runtime but missing from @types/ws ServerOptions\n const wss = new WebSocketServer({\n port,\n host,\n ...{ maxPayload: config.maxPayloadBytes ?? 1_048_576 },\n });\n\n let connectionHandler:\n | ((\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void)\n | null = null;\n\n // biome-ignore lint/suspicious/noExplicitAny: ws types resolved at runtime via dynamic import\n wss.on(\"connection\", (ws: any) => {\n let messageHandler: ((data: string) => void) | null = null;\n let closeHandler: (() => void) | null = null;\n\n const client: DevToolsClient = {\n send(data: string) {\n if (ws.readyState === ws.OPEN) {\n ws.send(data);\n }\n },\n close() {\n ws.close();\n },\n };\n\n ws.on(\"message\", (raw: any) => {\n if (messageHandler) {\n messageHandler(raw.toString());\n }\n });\n\n ws.on(\"close\", () => {\n if (closeHandler) {\n closeHandler();\n }\n });\n\n connectionHandler?.(\n client,\n (handler) => {\n messageHandler = handler;\n },\n (handler) => {\n closeHandler = handler;\n },\n );\n });\n\n return {\n onConnection(handler) {\n connectionHandler = handler;\n },\n close() {\n wss.close();\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/devtools-server.ts"],"names":["createDevToolsServer","config","transport","timeline","healthMonitor","getSnapshot","getBreakpointState","onResumeBreakpoint","onCancelBreakpoint","getScratchpadState","getDerivedState","onForkFromSnapshot","batchSize","batchIntervalMs","healthPushIntervalMs","authenticate","maxClients","sessionId","clients","pendingAuthClients","batchBuffer","batchTimer","healthTimer","sendToClient","client","message","broadcastMessage","data","snapshot","flushBatch","unsubscribeTimeline","event","handleClientMessage","raw","msg","now","last","clientLastMessage","MIN_MESSAGE_INTERVAL_MS","result","handleResult","valid","events","since","filtered","e","mods","safeReason","err","errMsg","onMessage","onClose","key","value","id","agentId","tokens","tokenCount","totalTokens","connectDevTools","orchestrator","options","createWsTransport","agents","eventId","port","host","WebSocketServer","wss","connectionHandler","ws","messageHandler","closeHandler","handler"],"mappings":"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","file":"chunk-7JTR4QBA.cjs","sourcesContent":["/**\n * DevTools Server — WebSocket-based bridge between orchestrators and DevTools UI.\n *\n * Streams debug timeline events, health metrics, breakpoint state, and system\n * snapshots in real-time to connected DevTools clients. Accepts commands from\n * clients to resume/cancel breakpoints and request snapshots.\n *\n * Transport-agnostic: works with any WebSocket implementation (ws, Bun, Deno)\n * via the {@link DevToolsTransport} interface.\n *\n * @module\n */\n\nimport type { DebugTimeline } from \"./debug-timeline.js\";\nimport type { AgentHealthMetrics, HealthMonitor } from \"./health-monitor.js\";\nimport type { BreakpointState, DebugEvent } from \"./types.js\";\n\n// ============================================================================\n// Transport Interface (WebSocket abstraction)\n// ============================================================================\n\n/** A connected DevTools client */\nexport interface DevToolsClient {\n /** Send a JSON-serializable message to this client */\n send(data: string): void;\n /** Close the connection */\n close(): void;\n}\n\n/**\n * Transport layer for the DevTools server.\n *\n * Implement this interface to bridge any WebSocket library (ws, Bun.serve, Deno.serve).\n *\n * @example Node.js with `ws`:\n * ```typescript\n * import { WebSocketServer } from \"ws\";\n *\n * function createWsTransport(port: number): DevToolsTransport {\n * const wss = new WebSocketServer({ port });\n * let onConnect: ((client: DevToolsClient) => void) | null = null;\n *\n * wss.on(\"connection\", (ws) => {\n * const client: DevToolsClient = {\n * send: (data) => { if (ws.readyState === ws.OPEN) ws.send(data); },\n * close: () => ws.close(),\n * };\n * ws.on(\"message\", (raw) => {\n * if (client._onMessage) client._onMessage(raw.toString());\n * });\n * ws.on(\"close\", () => {\n * if (client._onClose) client._onClose();\n * });\n * onConnect?.(client);\n * });\n *\n * return {\n * onConnection(handler) { onConnect = handler; },\n * close() { wss.close(); },\n * };\n * }\n * ```\n */\nexport interface DevToolsTransport {\n /** Register a handler for new client connections */\n onConnection(\n handler: (\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void,\n ): void;\n /** Shut down the transport */\n close(): void;\n}\n\n// ============================================================================\n// Protocol Messages\n// ============================================================================\n\n/** Messages sent FROM the server TO clients */\nexport type DevToolsServerMessage =\n | { type: \"welcome\"; version: number; sessionId: string; timestamp: number }\n | { type: \"event\"; event: DebugEvent }\n | { type: \"event_batch\"; events: DebugEvent[] }\n | { type: \"snapshot\"; data: DevToolsSnapshot }\n | { type: \"health\"; metrics: Record<string, AgentHealthMetrics> }\n | { type: \"breakpoints\"; state: BreakpointState }\n | { type: \"pong\"; timestamp: number }\n // Scratchpad & derived state\n | { type: \"scratchpad_state\"; data: Record<string, unknown> }\n | { type: \"scratchpad_update\"; key: string; value: unknown }\n | { type: \"derived_state\"; data: Record<string, unknown> }\n | { type: \"derived_update\"; id: string; value: unknown }\n // Fork\n | { type: \"fork_complete\"; eventId: number; newEventCount: number }\n // Token streaming\n | {\n type: \"token_stream\";\n agentId: string;\n tokens: string;\n tokenCount: number;\n }\n | { type: \"stream_done\"; agentId: string; totalTokens: number }\n | { type: \"error\"; code: string; message: string };\n\n/** Messages sent FROM clients TO the server */\nexport type DevToolsClientMessage =\n | { type: \"authenticate\"; token: string }\n | { type: \"request_snapshot\" }\n | { type: \"request_health\" }\n | { type: \"request_events\"; since?: number }\n | { type: \"request_breakpoints\" }\n | {\n type: \"resume_breakpoint\";\n breakpointId: string;\n modifications?: { input?: string; skip?: boolean };\n }\n | { type: \"cancel_breakpoint\"; breakpointId: string; reason?: string }\n | { type: \"export_session\" }\n | { type: \"import_session\"; data: string }\n // Scratchpad & derived requests\n | { type: \"request_scratchpad\" }\n | { type: \"request_derived\" }\n // Fork\n | { type: \"fork_from_snapshot\"; eventId: number }\n | { type: \"ping\" };\n\n/** System snapshot sent to clients on demand */\nexport interface DevToolsSnapshot {\n timestamp: number;\n agents: Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n coordinator?: { globalTokens: number; status: string };\n derived?: Record<string, unknown>;\n eventCount: number;\n}\n\n// ============================================================================\n// Server Configuration\n// ============================================================================\n\n/** Configuration for the DevTools server */\nexport interface DevToolsServerConfig {\n /** Transport to use for WebSocket connections */\n transport: DevToolsTransport;\n /** Debug timeline to subscribe to */\n timeline: DebugTimeline;\n /** Health monitor for metrics (optional) */\n healthMonitor?: HealthMonitor | null;\n /** Callback to get current agent states for snapshots */\n getSnapshot?: () => DevToolsSnapshot;\n /** Callback to get current breakpoint state */\n getBreakpointState?: () => BreakpointState;\n /** Callback to resume a breakpoint */\n onResumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n /** Callback to cancel a breakpoint */\n onCancelBreakpoint?: (id: string, reason?: string) => void;\n /** Callback to get current scratchpad state */\n getScratchpadState?: () => Record<string, unknown>;\n /** Callback to get current derived state */\n getDerivedState?: () => Record<string, unknown>;\n /** Callback to fork from a snapshot event */\n onForkFromSnapshot?: (eventId: number) => { newEventCount: number };\n /** Maximum events to batch before flushing. Default: 1 (no batching) */\n batchSize?: number;\n /** Flush interval for batched events (ms). Default: 50 */\n batchIntervalMs?: number;\n /** Health metrics push interval (ms). 0 = no auto-push. Default: 0 */\n healthPushIntervalMs?: number;\n /** Maximum connected clients. Default: 50 */\n maxClients?: number;\n /** Token authentication callback. When set, new connections must send an `authenticate` message before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n// ============================================================================\n// Server Instance\n// ============================================================================\n\n/** DevTools server instance */\nexport interface DevToolsServer {\n /** Number of connected clients */\n readonly clientCount: number;\n /** Broadcast a message to all connected clients */\n broadcast(message: DevToolsServerMessage): void;\n /** Push current health metrics to all clients */\n pushHealth(): void;\n /** Push current breakpoint state to all clients */\n pushBreakpoints(): void;\n /** Push a scratchpad key update to all clients */\n pushScratchpadUpdate(key: string, value: unknown): void;\n /** Push a derived value update to all clients */\n pushDerivedUpdate(id: string, value: unknown): void;\n /** Push streaming tokens to all clients */\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void;\n /** Signal stream completion to all clients */\n pushStreamDone(agentId: string, totalTokens: number): void;\n /** Shut down the server and disconnect all clients */\n close(): void;\n}\n\nconst PROTOCOL_VERSION = 1;\n\n/**\n * Create a DevTools server that bridges orchestrator state to DevTools UI clients.\n *\n * @example\n * ```typescript\n * const server = createDevToolsServer({\n * transport: createWsTransport(4040),\n * timeline: orchestrator.timeline!,\n * healthMonitor: orchestrator.healthMonitor,\n * getSnapshot: () => buildSnapshot(orchestrator),\n * getBreakpointState: () => orchestrator.getBreakpointState(),\n * onResumeBreakpoint: (id, mods) => orchestrator.resumeBreakpoint(id, mods),\n * onCancelBreakpoint: (id, reason) => orchestrator.cancelBreakpoint(id, reason),\n * });\n * ```\n */\nexport function createDevToolsServer(\n config: DevToolsServerConfig,\n): DevToolsServer {\n const {\n transport,\n timeline,\n healthMonitor,\n getSnapshot,\n getBreakpointState,\n onResumeBreakpoint,\n onCancelBreakpoint,\n getScratchpadState,\n getDerivedState,\n onForkFromSnapshot,\n batchSize = 1,\n batchIntervalMs = 50,\n healthPushIntervalMs = 0,\n authenticate,\n } = config;\n const maxClients = config.maxClients ?? 50;\n\n const sessionId = `devtools_${crypto.randomUUID()}`;\n const clients = new Set<DevToolsClient>();\n const pendingAuthClients = new Set<DevToolsClient>();\n let batchBuffer: DebugEvent[] = [];\n let batchTimer: ReturnType<typeof setInterval> | null = null;\n let healthTimer: ReturnType<typeof setInterval> | null = null;\n\n // ------------------------------------------------------------------\n // Helpers\n // ------------------------------------------------------------------\n\n function sendToClient(\n client: DevToolsClient,\n message: DevToolsServerMessage,\n ): void {\n try {\n client.send(JSON.stringify(message));\n } catch {\n // Client may have disconnected — remove silently\n clients.delete(client);\n }\n }\n\n function broadcastMessage(message: DevToolsServerMessage): void {\n const data = JSON.stringify(message);\n const snapshot = [...clients];\n for (const client of snapshot) {\n try {\n client.send(data);\n } catch {\n clients.delete(client);\n }\n }\n }\n\n function flushBatch(): void {\n if (batchBuffer.length === 0) {\n return;\n }\n\n if (batchBuffer.length === 1) {\n broadcastMessage({ type: \"event\", event: batchBuffer[0]! });\n } else {\n broadcastMessage({ type: \"event_batch\", events: batchBuffer });\n }\n\n batchBuffer = [];\n }\n\n // ------------------------------------------------------------------\n // Timeline subscription\n // ------------------------------------------------------------------\n\n const unsubscribeTimeline: () => void = timeline.subscribe(\n (event: DebugEvent) => {\n if (clients.size === 0) {\n return;\n }\n\n if (batchSize <= 1) {\n broadcastMessage({ type: \"event\", event });\n\n return;\n }\n\n batchBuffer.push(event);\n if (batchBuffer.length >= batchSize) {\n flushBatch();\n }\n },\n );\n\n // Start batch flush timer if batching enabled\n if (batchSize > 1 && batchIntervalMs > 0) {\n batchTimer = setInterval(flushBatch, batchIntervalMs);\n }\n\n // Start health push timer if configured\n if (healthPushIntervalMs > 0 && healthMonitor) {\n healthTimer = setInterval(() => {\n if (clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n }, healthPushIntervalMs);\n }\n\n // ------------------------------------------------------------------\n // Client message handler\n // ------------------------------------------------------------------\n\n function handleClientMessage(client: DevToolsClient, raw: string): void {\n let msg: DevToolsClientMessage;\n try {\n msg = JSON.parse(raw) as DevToolsClientMessage;\n } catch {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_JSON\",\n message: \"Could not parse message\",\n });\n\n return;\n }\n\n if (!msg || typeof msg !== \"object\" || typeof msg.type !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_MESSAGE\",\n message: \"Missing type field\",\n });\n\n return;\n }\n\n const now = Date.now();\n const last = clientLastMessage.get(client) ?? 0;\n if (now - last < MIN_MESSAGE_INTERVAL_MS) {\n sendToClient(client, {\n type: \"error\",\n code: \"RATE_LIMITED\",\n message: \"Too many requests\",\n });\n\n return;\n }\n clientLastMessage.set(client, now);\n\n // Handle authenticate message\n if (msg.type === \"authenticate\") {\n if (!authenticate) {\n // No auth configured — treat as unknown command\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: \"Authentication not configured on this server\",\n });\n\n return;\n }\n\n if (!pendingAuthClients.has(client)) {\n // Already authenticated\n sendToClient(client, {\n type: \"error\",\n code: \"ALREADY_AUTHENTICATED\",\n message: \"Already authenticated\",\n });\n\n return;\n }\n\n if (typeof msg.token !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Missing token\",\n });\n client.close();\n pendingAuthClients.delete(client);\n\n return;\n }\n\n const result = authenticate(msg.token);\n const handleResult = (valid: boolean) => {\n if (valid) {\n pendingAuthClients.delete(client);\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Invalid token\",\n });\n pendingAuthClients.delete(client);\n client.close();\n }\n };\n\n if (result instanceof Promise) {\n result.then(handleResult).catch(() => {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Authentication error\",\n });\n pendingAuthClients.delete(client);\n client.close();\n });\n } else {\n handleResult(result);\n }\n\n return;\n }\n\n // Reject commands from clients pending authentication\n if (pendingAuthClients.has(client)) {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_REQUIRED\",\n message: \"Authentication required\",\n });\n\n return;\n }\n\n switch (msg.type) {\n case \"ping\":\n sendToClient(client, { type: \"pong\", timestamp: Date.now() });\n break;\n\n case \"request_snapshot\":\n if (getSnapshot) {\n sendToClient(client, { type: \"snapshot\", data: getSnapshot() });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SNAPSHOT\",\n message: \"Snapshot provider not configured\",\n });\n }\n break;\n\n case \"request_health\":\n if (healthMonitor) {\n sendToClient(client, {\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_HEALTH\",\n message: \"Health monitor not configured\",\n });\n }\n break;\n\n case \"request_events\": {\n const events = timeline.getEvents();\n const since = msg.since;\n const filtered =\n since != null ? events.filter((e) => e.id > since) : events;\n sendToClient(client, { type: \"event_batch\", events: filtered });\n break;\n }\n\n case \"request_breakpoints\":\n if (getBreakpointState) {\n sendToClient(client, {\n type: \"breakpoints\",\n state: getBreakpointState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint provider not configured\",\n });\n }\n break;\n\n case \"resume_breakpoint\":\n if (onResumeBreakpoint && typeof msg.breakpointId === \"string\") {\n // Sanitize: only extract known fields to prevent prototype pollution\n const mods = msg.modifications\n ? { input: msg.modifications.input, skip: msg.modifications.skip }\n : undefined;\n onResumeBreakpoint(msg.breakpointId, mods);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint resume not configured\",\n });\n }\n break;\n\n case \"cancel_breakpoint\":\n if (onCancelBreakpoint && typeof msg.breakpointId === \"string\") {\n const safeReason =\n typeof msg.reason === \"string\" ? msg.reason : undefined;\n onCancelBreakpoint(msg.breakpointId, safeReason);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint cancel not configured\",\n });\n }\n break;\n\n case \"export_session\":\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n break;\n\n case \"import_session\": {\n const MAX_IMPORT_SIZE = 10 * 1024 * 1024; // ~10M characters (string .length check, not byte size)\n if (typeof msg.data !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_DATA\",\n message: \"Missing data field for import\",\n });\n } else if (msg.data.length > MAX_IMPORT_SIZE) {\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_TOO_LARGE\",\n message: `Import data exceeds ${MAX_IMPORT_SIZE / 1024 / 1024} MB limit`,\n });\n } else {\n try {\n timeline.import(msg.data);\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_FAILED\",\n message: errMsg,\n });\n }\n }\n break;\n }\n\n case \"request_scratchpad\":\n if (getScratchpadState) {\n sendToClient(client, {\n type: \"scratchpad_state\",\n data: getScratchpadState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SCRATCHPAD\",\n message: \"Scratchpad provider not configured\",\n });\n }\n break;\n\n case \"request_derived\":\n if (getDerivedState) {\n sendToClient(client, {\n type: \"derived_state\",\n data: getDerivedState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_DERIVED\",\n message: \"Derived state provider not configured\",\n });\n }\n break;\n\n case \"fork_from_snapshot\": {\n if (onForkFromSnapshot && typeof msg.eventId === \"number\") {\n try {\n const result = onForkFromSnapshot(msg.eventId);\n sendToClient(client, {\n type: \"fork_complete\",\n eventId: msg.eventId,\n newEventCount: result.newEventCount,\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"FORK_FAILED\",\n message: errMsg,\n });\n }\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_FORK\",\n message: \"Fork provider not configured\",\n });\n }\n break;\n }\n\n default:\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: `Unknown message type: ${String((msg as { type: string }).type).slice(0, 100)}`,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Rate limiting\n // ------------------------------------------------------------------\n\n const clientLastMessage = new Map<DevToolsClient, number>();\n const MIN_MESSAGE_INTERVAL_MS = 50;\n\n // ------------------------------------------------------------------\n // Connection handler\n // ------------------------------------------------------------------\n\n transport.onConnection((client, onMessage, onClose) => {\n if (clients.size + pendingAuthClients.size >= maxClients) {\n try {\n const msg: DevToolsServerMessage = {\n type: \"error\",\n code: \"MAX_CLIENTS\",\n message: \"Connection limit reached\",\n };\n client.send(JSON.stringify(msg));\n } catch {\n /* ignore */\n }\n client.close();\n\n return;\n }\n\n if (authenticate) {\n // Hold in pending state until client sends authenticate message\n pendingAuthClients.add(client);\n } else {\n // No auth — add directly and send welcome\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n }\n\n onMessage((data) => handleClientMessage(client, data));\n onClose(() => {\n clients.delete(client);\n pendingAuthClients.delete(client);\n clientLastMessage.delete(client);\n });\n });\n\n // ------------------------------------------------------------------\n // Public interface\n // ------------------------------------------------------------------\n\n return {\n get clientCount(): number {\n return clients.size;\n },\n\n broadcast(message: DevToolsServerMessage): void {\n broadcastMessage(message);\n },\n\n pushHealth(): void {\n if (healthMonitor && clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n },\n\n pushBreakpoints(): void {\n if (getBreakpointState && clients.size > 0) {\n broadcastMessage({ type: \"breakpoints\", state: getBreakpointState() });\n }\n },\n\n pushScratchpadUpdate(key: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"scratchpad_update\", key, value });\n }\n },\n\n pushDerivedUpdate(id: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"derived_update\", id, value });\n }\n },\n\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"token_stream\", agentId, tokens, tokenCount });\n }\n },\n\n pushStreamDone(agentId: string, totalTokens: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"stream_done\", agentId, totalTokens });\n }\n },\n\n close(): void {\n unsubscribeTimeline();\n\n if (batchTimer) {\n clearInterval(batchTimer);\n batchTimer = null;\n }\n\n if (healthTimer) {\n clearInterval(healthTimer);\n healthTimer = null;\n }\n\n flushBatch();\n\n for (const client of clients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n for (const client of pendingAuthClients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n clients.clear();\n pendingAuthClients.clear();\n clientLastMessage.clear();\n\n transport.close();\n },\n };\n}\n\n// ============================================================================\n// Orchestrator Connector\n// ============================================================================\n\n/** Options for connecting DevTools to an orchestrator */\nexport interface ConnectDevToolsOptions {\n /** Port for the WebSocket server. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Health metrics push interval (ms). Default: 5000 */\n healthPushIntervalMs?: number;\n /** Event batching size. Default: 1 (no batching) */\n batchSize?: number;\n /** Token authentication callback. When set, clients must authenticate before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n/** Minimal orchestrator interface for DevTools connection */\nexport interface DevToolsCompatibleOrchestrator {\n timeline: {\n subscribe: (listener: (event: DebugEvent) => void) => () => void;\n getEvents: () => DebugEvent[];\n import: (json: string) => void;\n export: () => string;\n forkFrom?: (eventId: number) => void;\n } | null;\n healthMonitor?: {\n getAllMetrics: () => Record<string, AgentHealthMetrics>;\n } | null;\n getPendingBreakpoints?: () => Array<{\n id: string;\n type: string;\n agentId: string;\n input: string;\n label?: string;\n requestedAt: number;\n }>;\n resumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n cancelBreakpoint?: (id: string, reason?: string) => void;\n getAllAgentStates?: () => Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n /** Get current scratchpad state (multi-agent only) */\n getScratchpadState?: () => Record<string, unknown>;\n /** Get current derived values (multi-agent only) */\n getDerivedState?: () => Record<string, unknown>;\n}\n\n/**\n * Connect DevTools to an orchestrator instance.\n *\n * Convenience function that creates a WebSocket transport and DevTools server,\n * automatically wiring up the orchestrator's timeline, health monitor, and breakpoint system.\n *\n * Requires the `ws` package: `npm install ws`\n *\n * **Security:** Binding to `0.0.0.0` exposes the server to all network interfaces.\n * Only do this behind a firewall or with proper authentication.\n *\n * @example\n * ```typescript\n * const orchestrator = createMultiAgentOrchestrator({ debug: true, ... });\n * const devtools = await connectDevTools(orchestrator, { port: 4040 });\n *\n * // Later, clean up:\n * devtools.close();\n * ```\n */\nexport async function connectDevTools(\n orchestrator: DevToolsCompatibleOrchestrator,\n options: ConnectDevToolsOptions = {},\n): Promise<DevToolsServer> {\n if (!orchestrator.timeline) {\n throw new Error(\n \"[Directive DevTools] Orchestrator must have debug: true to use DevTools\",\n );\n }\n\n const transport = await createWsTransport({\n port: options.port ?? 4040,\n host: options.host ?? \"localhost\",\n });\n\n return createDevToolsServer({\n transport,\n timeline: orchestrator.timeline as unknown as DebugTimeline,\n healthMonitor: orchestrator.healthMonitor as HealthMonitor | undefined,\n healthPushIntervalMs: options.healthPushIntervalMs ?? 5000,\n batchSize: options.batchSize,\n authenticate: options.authenticate,\n getSnapshot: orchestrator.getAllAgentStates\n ? () => {\n const agents = orchestrator.getAllAgentStates!();\n\n return {\n timestamp: Date.now(),\n agents,\n eventCount: orchestrator.timeline!.getEvents().length,\n };\n }\n : undefined,\n getBreakpointState: orchestrator.getPendingBreakpoints\n ? () => ({\n pending: orchestrator.getPendingBreakpoints!(),\n resolved: [],\n cancelled: [],\n })\n : undefined,\n onResumeBreakpoint: orchestrator.resumeBreakpoint,\n onCancelBreakpoint: orchestrator.cancelBreakpoint,\n getScratchpadState: orchestrator.getScratchpadState,\n getDerivedState: orchestrator.getDerivedState,\n onForkFromSnapshot: orchestrator.timeline?.forkFrom\n ? (eventId: number) => {\n orchestrator.timeline!.forkFrom!(eventId);\n const newEventCount = orchestrator.timeline!.getEvents().length;\n\n return { newEventCount };\n }\n : undefined,\n });\n}\n\n// ============================================================================\n// Node.js ws Transport Helper\n// ============================================================================\n\n/**\n * Configuration for the built-in Node.js `ws` transport.\n *\n * Requires the `ws` package to be installed: `npm install ws`\n */\nexport interface WsTransportConfig {\n /** Port to listen on. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Maximum incoming message size in bytes. Default: 1048576 (1MB) */\n maxPayloadBytes?: number;\n}\n\n/**\n * Create a DevTools transport using the Node.js `ws` WebSocket library.\n *\n * This is a convenience helper — you can implement {@link DevToolsTransport}\n * with any WebSocket library.\n *\n * @example\n * ```typescript\n * const transport = await createWsTransport({ port: 4040 });\n * const server = createDevToolsServer({ transport, timeline });\n * ```\n */\nexport async function createWsTransport(\n config: WsTransportConfig = {},\n): Promise<DevToolsTransport> {\n const port = config.port ?? 4040;\n const host = config.host ?? \"localhost\";\n\n // Dynamic import so ws is not a hard dependency\n const { WebSocketServer } = await import(\"ws\");\n // maxPayload is supported at runtime but missing from @types/ws ServerOptions\n const wss = new WebSocketServer({\n port,\n host,\n ...{ maxPayload: config.maxPayloadBytes ?? 1_048_576 },\n });\n\n let connectionHandler:\n | ((\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void)\n | null = null;\n\n wss.on(\"connection\", (ws: any) => {\n let messageHandler: ((data: string) => void) | null = null;\n let closeHandler: (() => void) | null = null;\n\n const client: DevToolsClient = {\n send(data: string) {\n if (ws.readyState === ws.OPEN) {\n ws.send(data);\n }\n },\n close() {\n ws.close();\n },\n };\n\n ws.on(\"message\", (raw: any) => {\n if (messageHandler) {\n messageHandler(raw.toString());\n }\n });\n\n ws.on(\"close\", () => {\n if (closeHandler) {\n closeHandler();\n }\n });\n\n connectionHandler?.(\n client,\n (handler) => {\n messageHandler = handler;\n },\n (handler) => {\n closeHandler = handler;\n },\n );\n });\n\n return {\n onConnection(handler) {\n connectionHandler = handler;\n },\n close() {\n wss.close();\n },\n };\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function L(o){let{transport:c,timeline:v,healthMonitor:i,getSnapshot:f,getBreakpointState:h,onResumeBreakpoint:p,onCancelBreakpoint:b,getScratchpadState:k,getDerivedState:T,onForkFromSnapshot:g,batchSize:M=1,batchIntervalMs:E=50,healthPushIntervalMs:O=0,authenticate:C}=o,w=o.maxClients??50,R=`devtools_${crypto.randomUUID()}`,s=new Set,d=new Set,y=[],D=null,_=null;function t(e,a){try{e.send(JSON.stringify(a));}catch{s.delete(e);}}function l(e){let a=JSON.stringify(e),n=[...s];for(let m of n)try{m.send(a);}catch{s.delete(m);}}function A(){y.length!==0&&(y.length===1?l({type:"event",event:y[0]}):l({type:"event_batch",events:y}),y=[]);}let N=v.subscribe(e=>{if(s.size!==0){if(M<=1){l({type:"event",event:e});return}y.push(e),y.length>=M&&A();}});M>1&&E>0&&(D=setInterval(A,E)),O>0&&i&&(_=setInterval(()=>{s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},O));function B(e,a){let n;try{n=JSON.parse(a);}catch{t(e,{type:"error",code:"INVALID_JSON",message:"Could not parse message"});return}if(!n||typeof n!="object"||typeof n.type!="string"){t(e,{type:"error",code:"INVALID_MESSAGE",message:"Missing type field"});return}let m=Date.now(),x=I.get(e)??0;if(m-x<P){t(e,{type:"error",code:"RATE_LIMITED",message:"Too many requests"});return}if(I.set(e,m),n.type==="authenticate"){if(!C){t(e,{type:"error",code:"UNKNOWN_COMMAND",message:"Authentication not configured on this server"});return}if(!d.has(e)){t(e,{type:"error",code:"ALREADY_AUTHENTICATED",message:"Already authenticated"});return}if(typeof n.token!="string"){t(e,{type:"error",code:"AUTH_FAILED",message:"Missing token"}),e.close(),d.delete(e);return}let r=C(n.token),u=S=>{S?(d.delete(e),s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})):(t(e,{type:"error",code:"AUTH_FAILED",message:"Invalid token"}),d.delete(e),e.close());};r instanceof Promise?r.then(u).catch(()=>{t(e,{type:"error",code:"AUTH_FAILED",message:"Authentication error"}),d.delete(e),e.close();}):u(r);return}if(d.has(e)){t(e,{type:"error",code:"AUTH_REQUIRED",message:"Authentication required"});return}switch(n.type){case "ping":t(e,{type:"pong",timestamp:Date.now()});break;case "request_snapshot":f?t(e,{type:"snapshot",data:f()}):t(e,{type:"error",code:"NO_SNAPSHOT",message:"Snapshot provider not configured"});break;case "request_health":i?t(e,{type:"health",metrics:i.getAllMetrics()}):t(e,{type:"error",code:"NO_HEALTH",message:"Health monitor not configured"});break;case "request_events":{let r=v.getEvents(),u=n.since,S=u!=null?r.filter(H=>H.id>u):r;t(e,{type:"event_batch",events:S});break}case "request_breakpoints":h?t(e,{type:"breakpoints",state:h()}):t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint provider not configured"});break;case "resume_breakpoint":if(p&&typeof n.breakpointId=="string"){let r=n.modifications?{input:n.modifications.input,skip:n.modifications.skip}:void 0;p(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint resume not configured"});break;case "cancel_breakpoint":if(b&&typeof n.breakpointId=="string"){let r=typeof n.reason=="string"?n.reason:void 0;b(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint cancel not configured"});break;case "export_session":t(e,{type:"event_batch",events:v.getEvents()});break;case "import_session":{if(typeof n.data!="string")t(e,{type:"error",code:"INVALID_DATA",message:"Missing data field for import"});else if(n.data.length>10485760)t(e,{type:"error",code:"IMPORT_TOO_LARGE",message:`Import data exceeds ${10485760/1024/1024} MB limit`});else try{v.import(n.data),t(e,{type:"event_batch",events:v.getEvents()});}catch(u){let S=u instanceof Error?u.message:String(u);t(e,{type:"error",code:"IMPORT_FAILED",message:S});}break}case "request_scratchpad":k?t(e,{type:"scratchpad_state",data:k()}):t(e,{type:"error",code:"NO_SCRATCHPAD",message:"Scratchpad provider not configured"});break;case "request_derived":T?t(e,{type:"derived_state",data:T()}):t(e,{type:"error",code:"NO_DERIVED",message:"Derived state provider not configured"});break;case "fork_from_snapshot":{if(g&&typeof n.eventId=="number")try{let r=g(n.eventId);t(e,{type:"fork_complete",eventId:n.eventId,newEventCount:r.newEventCount});}catch(r){let u=r instanceof Error?r.message:String(r);t(e,{type:"error",code:"FORK_FAILED",message:u});}else t(e,{type:"error",code:"NO_FORK",message:"Fork provider not configured"});break}default:t(e,{type:"error",code:"UNKNOWN_COMMAND",message:`Unknown message type: ${String(n.type).slice(0,100)}`});}}let I=new Map,P=50;return c.onConnection((e,a,n)=>{if(s.size+d.size>=w){try{let m={type:"error",code:"MAX_CLIENTS",message:"Connection limit reached"};e.send(JSON.stringify(m));}catch{}e.close();return}C?d.add(e):(s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})),a(m=>B(e,m)),n(()=>{s.delete(e),d.delete(e),I.delete(e);});}),{get clientCount(){return s.size},broadcast(e){l(e);},pushHealth(){i&&s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},pushBreakpoints(){h&&s.size>0&&l({type:"breakpoints",state:h()});},pushScratchpadUpdate(e,a){s.size>0&&l({type:"scratchpad_update",key:e,value:a});},pushDerivedUpdate(e,a){s.size>0&&l({type:"derived_update",id:e,value:a});},pushTokenStream(e,a,n){s.size>0&&l({type:"token_stream",agentId:e,tokens:a,tokenCount:n});},pushStreamDone(e,a){s.size>0&&l({type:"stream_done",agentId:e,totalTokens:a});},close(){N(),D&&(clearInterval(D),D=null),_&&(clearInterval(_),_=null),A();for(let e of s)try{e.close();}catch{}for(let e of d)try{e.close();}catch{}s.clear(),d.clear(),I.clear(),c.close();}}}async function z(o,c={}){if(!o.timeline)throw new Error("[Directive DevTools] Orchestrator must have debug: true to use DevTools");let v=await F({port:c.port??4040,host:c.host??"localhost"});return L({transport:v,timeline:o.timeline,healthMonitor:o.healthMonitor,healthPushIntervalMs:c.healthPushIntervalMs??5e3,batchSize:c.batchSize,authenticate:c.authenticate,getSnapshot:o.getAllAgentStates?()=>{let i=o.getAllAgentStates();return {timestamp:Date.now(),agents:i,eventCount:o.timeline.getEvents().length}}:void 0,getBreakpointState:o.getPendingBreakpoints?()=>({pending:o.getPendingBreakpoints(),resolved:[],cancelled:[]}):void 0,onResumeBreakpoint:o.resumeBreakpoint,onCancelBreakpoint:o.cancelBreakpoint,getScratchpadState:o.getScratchpadState,getDerivedState:o.getDerivedState,onForkFromSnapshot:o.timeline?.forkFrom?i=>(o.timeline.forkFrom(i),{newEventCount:o.timeline.getEvents().length}):void 0})}async function F(o={}){let c=o.port??4040,v=o.host??"localhost",{WebSocketServer:i}=await import('ws'),f=new i({port:c,host:v,maxPayload:o.maxPayloadBytes??1048576}),h=null;return f.on("connection",p=>{let b=null,k=null,T={send(g){p.readyState===p.OPEN&&p.send(g);},close(){p.close();}};p.on("message",g=>{b&&b(g.toString());}),p.on("close",()=>{k&&k();}),h?.(T,g=>{b=g;},g=>{k=g;});}),{onConnection(p){h=p;},close(){f.close();}}}export{L as a,z as b,F as c};//# sourceMappingURL=chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
function L(o){let{transport:c,timeline:v,healthMonitor:i,getSnapshot:f,getBreakpointState:h,onResumeBreakpoint:p,onCancelBreakpoint:b,getScratchpadState:k,getDerivedState:T,onForkFromSnapshot:g,batchSize:M=1,batchIntervalMs:E=50,healthPushIntervalMs:O=0,authenticate:C}=o,w=o.maxClients??50,R=`devtools_${crypto.randomUUID()}`,s=new Set,d=new Set,y=[],D=null,_=null;function t(e,a){try{e.send(JSON.stringify(a));}catch{s.delete(e);}}function l(e){let a=JSON.stringify(e),n=[...s];for(let m of n)try{m.send(a);}catch{s.delete(m);}}function A(){y.length!==0&&(y.length===1?l({type:"event",event:y[0]}):l({type:"event_batch",events:y}),y=[]);}let N=v.subscribe(e=>{if(s.size!==0){if(M<=1){l({type:"event",event:e});return}y.push(e),y.length>=M&&A();}});M>1&&E>0&&(D=setInterval(A,E)),O>0&&i&&(_=setInterval(()=>{s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},O));function B(e,a){let n;try{n=JSON.parse(a);}catch{t(e,{type:"error",code:"INVALID_JSON",message:"Could not parse message"});return}if(!n||typeof n!="object"||typeof n.type!="string"){t(e,{type:"error",code:"INVALID_MESSAGE",message:"Missing type field"});return}let m=Date.now(),x=I.get(e)??0;if(m-x<P){t(e,{type:"error",code:"RATE_LIMITED",message:"Too many requests"});return}if(I.set(e,m),n.type==="authenticate"){if(!C){t(e,{type:"error",code:"UNKNOWN_COMMAND",message:"Authentication not configured on this server"});return}if(!d.has(e)){t(e,{type:"error",code:"ALREADY_AUTHENTICATED",message:"Already authenticated"});return}if(typeof n.token!="string"){t(e,{type:"error",code:"AUTH_FAILED",message:"Missing token"}),e.close(),d.delete(e);return}let r=C(n.token),u=S=>{S?(d.delete(e),s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})):(t(e,{type:"error",code:"AUTH_FAILED",message:"Invalid token"}),d.delete(e),e.close());};r instanceof Promise?r.then(u).catch(()=>{t(e,{type:"error",code:"AUTH_FAILED",message:"Authentication error"}),d.delete(e),e.close();}):u(r);return}if(d.has(e)){t(e,{type:"error",code:"AUTH_REQUIRED",message:"Authentication required"});return}switch(n.type){case "ping":t(e,{type:"pong",timestamp:Date.now()});break;case "request_snapshot":f?t(e,{type:"snapshot",data:f()}):t(e,{type:"error",code:"NO_SNAPSHOT",message:"Snapshot provider not configured"});break;case "request_health":i?t(e,{type:"health",metrics:i.getAllMetrics()}):t(e,{type:"error",code:"NO_HEALTH",message:"Health monitor not configured"});break;case "request_events":{let r=v.getEvents(),u=n.since,S=u!=null?r.filter(H=>H.id>u):r;t(e,{type:"event_batch",events:S});break}case "request_breakpoints":h?t(e,{type:"breakpoints",state:h()}):t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint provider not configured"});break;case "resume_breakpoint":if(p&&typeof n.breakpointId=="string"){let r=n.modifications?{input:n.modifications.input,skip:n.modifications.skip}:void 0;p(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint resume not configured"});break;case "cancel_breakpoint":if(b&&typeof n.breakpointId=="string"){let r=typeof n.reason=="string"?n.reason:void 0;b(n.breakpointId,r);}else t(e,{type:"error",code:"NO_BREAKPOINTS",message:"Breakpoint cancel not configured"});break;case "export_session":t(e,{type:"event_batch",events:v.getEvents()});break;case "import_session":{if(typeof n.data!="string")t(e,{type:"error",code:"INVALID_DATA",message:"Missing data field for import"});else if(n.data.length>10485760)t(e,{type:"error",code:"IMPORT_TOO_LARGE",message:`Import data exceeds ${10485760/1024/1024} MB limit`});else try{v.import(n.data),t(e,{type:"event_batch",events:v.getEvents()});}catch(u){let S=u instanceof Error?u.message:String(u);t(e,{type:"error",code:"IMPORT_FAILED",message:S});}break}case "request_scratchpad":k?t(e,{type:"scratchpad_state",data:k()}):t(e,{type:"error",code:"NO_SCRATCHPAD",message:"Scratchpad provider not configured"});break;case "request_derived":T?t(e,{type:"derived_state",data:T()}):t(e,{type:"error",code:"NO_DERIVED",message:"Derived state provider not configured"});break;case "fork_from_snapshot":{if(g&&typeof n.eventId=="number")try{let r=g(n.eventId);t(e,{type:"fork_complete",eventId:n.eventId,newEventCount:r.newEventCount});}catch(r){let u=r instanceof Error?r.message:String(r);t(e,{type:"error",code:"FORK_FAILED",message:u});}else t(e,{type:"error",code:"NO_FORK",message:"Fork provider not configured"});break}default:t(e,{type:"error",code:"UNKNOWN_COMMAND",message:`Unknown message type: ${String(n.type).slice(0,100)}`});}}let I=new Map,P=50;return c.onConnection((e,a,n)=>{if(s.size+d.size>=w){try{let m={type:"error",code:"MAX_CLIENTS",message:"Connection limit reached"};e.send(JSON.stringify(m));}catch{}e.close();return}C?d.add(e):(s.add(e),t(e,{type:"welcome",version:1,sessionId:R,timestamp:Date.now()})),a(m=>B(e,m)),n(()=>{s.delete(e),d.delete(e),I.delete(e);});}),{get clientCount(){return s.size},broadcast(e){l(e);},pushHealth(){i&&s.size>0&&l({type:"health",metrics:i.getAllMetrics()});},pushBreakpoints(){h&&s.size>0&&l({type:"breakpoints",state:h()});},pushScratchpadUpdate(e,a){s.size>0&&l({type:"scratchpad_update",key:e,value:a});},pushDerivedUpdate(e,a){s.size>0&&l({type:"derived_update",id:e,value:a});},pushTokenStream(e,a,n){s.size>0&&l({type:"token_stream",agentId:e,tokens:a,tokenCount:n});},pushStreamDone(e,a){s.size>0&&l({type:"stream_done",agentId:e,totalTokens:a});},close(){N(),D&&(clearInterval(D),D=null),_&&(clearInterval(_),_=null),A();for(let e of s)try{e.close();}catch{}for(let e of d)try{e.close();}catch{}s.clear(),d.clear(),I.clear(),c.close();}}}async function z(o,c={}){if(!o.timeline)throw new Error("[Directive DevTools] Orchestrator must have debug: true to use DevTools");let v=await F({port:c.port??4040,host:c.host??"localhost"});return L({transport:v,timeline:o.timeline,healthMonitor:o.healthMonitor,healthPushIntervalMs:c.healthPushIntervalMs??5e3,batchSize:c.batchSize,authenticate:c.authenticate,getSnapshot:o.getAllAgentStates?()=>{let i=o.getAllAgentStates();return {timestamp:Date.now(),agents:i,eventCount:o.timeline.getEvents().length}}:void 0,getBreakpointState:o.getPendingBreakpoints?()=>({pending:o.getPendingBreakpoints(),resolved:[],cancelled:[]}):void 0,onResumeBreakpoint:o.resumeBreakpoint,onCancelBreakpoint:o.cancelBreakpoint,getScratchpadState:o.getScratchpadState,getDerivedState:o.getDerivedState,onForkFromSnapshot:o.timeline?.forkFrom?i=>(o.timeline.forkFrom(i),{newEventCount:o.timeline.getEvents().length}):void 0})}async function F(o={}){let c=o.port??4040,v=o.host??"localhost",{WebSocketServer:i}=await import('ws'),f=new i({port:c,host:v,maxPayload:o.maxPayloadBytes??1048576}),h=null;return f.on("connection",p=>{let b=null,k=null,T={send(g){p.readyState===p.OPEN&&p.send(g);},close(){p.close();}};p.on("message",g=>{b&&b(g.toString());}),p.on("close",()=>{k&&k();}),h?.(T,g=>{b=g;},g=>{k=g;});}),{onConnection(p){h=p;},close(){f.close();}}}export{L as a,z as b,F as c};//# sourceMappingURL=chunk-BZB3RDI2.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-BZB3RDI2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools-server.ts"],"names":["createDevToolsServer","config","transport","timeline","healthMonitor","getSnapshot","getBreakpointState","onResumeBreakpoint","onCancelBreakpoint","getScratchpadState","getDerivedState","onForkFromSnapshot","batchSize","batchIntervalMs","healthPushIntervalMs","authenticate","maxClients","sessionId","clients","pendingAuthClients","batchBuffer","batchTimer","healthTimer","sendToClient","client","message","broadcastMessage","data","snapshot","flushBatch","unsubscribeTimeline","event","handleClientMessage","raw","msg","now","last","clientLastMessage","MIN_MESSAGE_INTERVAL_MS","result","handleResult","valid","events","since","filtered","e","mods","safeReason","err","errMsg","onMessage","onClose","key","value","id","agentId","tokens","tokenCount","totalTokens","connectDevTools","orchestrator","options","createWsTransport","agents","eventId","port","host","WebSocketServer","wss","connectionHandler","ws","messageHandler","closeHandler","handler"],"mappings":"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","file":"chunk-5JQ2A3JK.js","sourcesContent":["/**\n * DevTools Server — WebSocket-based bridge between orchestrators and DevTools UI.\n *\n * Streams debug timeline events, health metrics, breakpoint state, and system\n * snapshots in real-time to connected DevTools clients. Accepts commands from\n * clients to resume/cancel breakpoints and request snapshots.\n *\n * Transport-agnostic: works with any WebSocket implementation (ws, Bun, Deno)\n * via the {@link DevToolsTransport} interface.\n *\n * @module\n */\n\nimport type { DebugTimeline } from \"./debug-timeline.js\";\nimport type { AgentHealthMetrics, HealthMonitor } from \"./health-monitor.js\";\nimport type { BreakpointState, DebugEvent } from \"./types.js\";\n\n// ============================================================================\n// Transport Interface (WebSocket abstraction)\n// ============================================================================\n\n/** A connected DevTools client */\nexport interface DevToolsClient {\n /** Send a JSON-serializable message to this client */\n send(data: string): void;\n /** Close the connection */\n close(): void;\n}\n\n/**\n * Transport layer for the DevTools server.\n *\n * Implement this interface to bridge any WebSocket library (ws, Bun.serve, Deno.serve).\n *\n * @example Node.js with `ws`:\n * ```typescript\n * import { WebSocketServer } from \"ws\";\n *\n * function createWsTransport(port: number): DevToolsTransport {\n * const wss = new WebSocketServer({ port });\n * let onConnect: ((client: DevToolsClient) => void) | null = null;\n *\n * wss.on(\"connection\", (ws) => {\n * const client: DevToolsClient = {\n * send: (data) => { if (ws.readyState === ws.OPEN) ws.send(data); },\n * close: () => ws.close(),\n * };\n * ws.on(\"message\", (raw) => {\n * if (client._onMessage) client._onMessage(raw.toString());\n * });\n * ws.on(\"close\", () => {\n * if (client._onClose) client._onClose();\n * });\n * onConnect?.(client);\n * });\n *\n * return {\n * onConnection(handler) { onConnect = handler; },\n * close() { wss.close(); },\n * };\n * }\n * ```\n */\nexport interface DevToolsTransport {\n /** Register a handler for new client connections */\n onConnection(\n handler: (\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void,\n ): void;\n /** Shut down the transport */\n close(): void;\n}\n\n// ============================================================================\n// Protocol Messages\n// ============================================================================\n\n/** Messages sent FROM the server TO clients */\nexport type DevToolsServerMessage =\n | { type: \"welcome\"; version: number; sessionId: string; timestamp: number }\n | { type: \"event\"; event: DebugEvent }\n | { type: \"event_batch\"; events: DebugEvent[] }\n | { type: \"snapshot\"; data: DevToolsSnapshot }\n | { type: \"health\"; metrics: Record<string, AgentHealthMetrics> }\n | { type: \"breakpoints\"; state: BreakpointState }\n | { type: \"pong\"; timestamp: number }\n // Scratchpad & derived state\n | { type: \"scratchpad_state\"; data: Record<string, unknown> }\n | { type: \"scratchpad_update\"; key: string; value: unknown }\n | { type: \"derived_state\"; data: Record<string, unknown> }\n | { type: \"derived_update\"; id: string; value: unknown }\n // Fork\n | { type: \"fork_complete\"; eventId: number; newEventCount: number }\n // Token streaming\n | {\n type: \"token_stream\";\n agentId: string;\n tokens: string;\n tokenCount: number;\n }\n | { type: \"stream_done\"; agentId: string; totalTokens: number }\n | { type: \"error\"; code: string; message: string };\n\n/** Messages sent FROM clients TO the server */\nexport type DevToolsClientMessage =\n | { type: \"authenticate\"; token: string }\n | { type: \"request_snapshot\" }\n | { type: \"request_health\" }\n | { type: \"request_events\"; since?: number }\n | { type: \"request_breakpoints\" }\n | {\n type: \"resume_breakpoint\";\n breakpointId: string;\n modifications?: { input?: string; skip?: boolean };\n }\n | { type: \"cancel_breakpoint\"; breakpointId: string; reason?: string }\n | { type: \"export_session\" }\n | { type: \"import_session\"; data: string }\n // Scratchpad & derived requests\n | { type: \"request_scratchpad\" }\n | { type: \"request_derived\" }\n // Fork\n | { type: \"fork_from_snapshot\"; eventId: number }\n | { type: \"ping\" };\n\n/** System snapshot sent to clients on demand */\nexport interface DevToolsSnapshot {\n timestamp: number;\n agents: Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n coordinator?: { globalTokens: number; status: string };\n derived?: Record<string, unknown>;\n eventCount: number;\n}\n\n// ============================================================================\n// Server Configuration\n// ============================================================================\n\n/** Configuration for the DevTools server */\nexport interface DevToolsServerConfig {\n /** Transport to use for WebSocket connections */\n transport: DevToolsTransport;\n /** Debug timeline to subscribe to */\n timeline: DebugTimeline;\n /** Health monitor for metrics (optional) */\n healthMonitor?: HealthMonitor | null;\n /** Callback to get current agent states for snapshots */\n getSnapshot?: () => DevToolsSnapshot;\n /** Callback to get current breakpoint state */\n getBreakpointState?: () => BreakpointState;\n /** Callback to resume a breakpoint */\n onResumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n /** Callback to cancel a breakpoint */\n onCancelBreakpoint?: (id: string, reason?: string) => void;\n /** Callback to get current scratchpad state */\n getScratchpadState?: () => Record<string, unknown>;\n /** Callback to get current derived state */\n getDerivedState?: () => Record<string, unknown>;\n /** Callback to fork from a snapshot event */\n onForkFromSnapshot?: (eventId: number) => { newEventCount: number };\n /** Maximum events to batch before flushing. Default: 1 (no batching) */\n batchSize?: number;\n /** Flush interval for batched events (ms). Default: 50 */\n batchIntervalMs?: number;\n /** Health metrics push interval (ms). 0 = no auto-push. Default: 0 */\n healthPushIntervalMs?: number;\n /** Maximum connected clients. Default: 50 */\n maxClients?: number;\n /** Token authentication callback. When set, new connections must send an `authenticate` message before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n// ============================================================================\n// Server Instance\n// ============================================================================\n\n/** DevTools server instance */\nexport interface DevToolsServer {\n /** Number of connected clients */\n readonly clientCount: number;\n /** Broadcast a message to all connected clients */\n broadcast(message: DevToolsServerMessage): void;\n /** Push current health metrics to all clients */\n pushHealth(): void;\n /** Push current breakpoint state to all clients */\n pushBreakpoints(): void;\n /** Push a scratchpad key update to all clients */\n pushScratchpadUpdate(key: string, value: unknown): void;\n /** Push a derived value update to all clients */\n pushDerivedUpdate(id: string, value: unknown): void;\n /** Push streaming tokens to all clients */\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void;\n /** Signal stream completion to all clients */\n pushStreamDone(agentId: string, totalTokens: number): void;\n /** Shut down the server and disconnect all clients */\n close(): void;\n}\n\nconst PROTOCOL_VERSION = 1;\n\n/**\n * Create a DevTools server that bridges orchestrator state to DevTools UI clients.\n *\n * @example\n * ```typescript\n * const server = createDevToolsServer({\n * transport: createWsTransport(4040),\n * timeline: orchestrator.timeline!,\n * healthMonitor: orchestrator.healthMonitor,\n * getSnapshot: () => buildSnapshot(orchestrator),\n * getBreakpointState: () => orchestrator.getBreakpointState(),\n * onResumeBreakpoint: (id, mods) => orchestrator.resumeBreakpoint(id, mods),\n * onCancelBreakpoint: (id, reason) => orchestrator.cancelBreakpoint(id, reason),\n * });\n * ```\n */\nexport function createDevToolsServer(\n config: DevToolsServerConfig,\n): DevToolsServer {\n const {\n transport,\n timeline,\n healthMonitor,\n getSnapshot,\n getBreakpointState,\n onResumeBreakpoint,\n onCancelBreakpoint,\n getScratchpadState,\n getDerivedState,\n onForkFromSnapshot,\n batchSize = 1,\n batchIntervalMs = 50,\n healthPushIntervalMs = 0,\n authenticate,\n } = config;\n const maxClients = config.maxClients ?? 50;\n\n const sessionId = `devtools_${crypto.randomUUID()}`;\n const clients = new Set<DevToolsClient>();\n const pendingAuthClients = new Set<DevToolsClient>();\n let batchBuffer: DebugEvent[] = [];\n let batchTimer: ReturnType<typeof setInterval> | null = null;\n let healthTimer: ReturnType<typeof setInterval> | null = null;\n\n // ------------------------------------------------------------------\n // Helpers\n // ------------------------------------------------------------------\n\n function sendToClient(\n client: DevToolsClient,\n message: DevToolsServerMessage,\n ): void {\n try {\n client.send(JSON.stringify(message));\n } catch {\n // Client may have disconnected — remove silently\n clients.delete(client);\n }\n }\n\n function broadcastMessage(message: DevToolsServerMessage): void {\n const data = JSON.stringify(message);\n const snapshot = [...clients];\n for (const client of snapshot) {\n try {\n client.send(data);\n } catch {\n clients.delete(client);\n }\n }\n }\n\n function flushBatch(): void {\n if (batchBuffer.length === 0) {\n return;\n }\n\n if (batchBuffer.length === 1) {\n broadcastMessage({ type: \"event\", event: batchBuffer[0]! });\n } else {\n broadcastMessage({ type: \"event_batch\", events: batchBuffer });\n }\n\n batchBuffer = [];\n }\n\n // ------------------------------------------------------------------\n // Timeline subscription\n // ------------------------------------------------------------------\n\n const unsubscribeTimeline: () => void = timeline.subscribe(\n (event: DebugEvent) => {\n if (clients.size === 0) {\n return;\n }\n\n if (batchSize <= 1) {\n broadcastMessage({ type: \"event\", event });\n\n return;\n }\n\n batchBuffer.push(event);\n if (batchBuffer.length >= batchSize) {\n flushBatch();\n }\n },\n );\n\n // Start batch flush timer if batching enabled\n if (batchSize > 1 && batchIntervalMs > 0) {\n batchTimer = setInterval(flushBatch, batchIntervalMs);\n }\n\n // Start health push timer if configured\n if (healthPushIntervalMs > 0 && healthMonitor) {\n healthTimer = setInterval(() => {\n if (clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n }, healthPushIntervalMs);\n }\n\n // ------------------------------------------------------------------\n // Client message handler\n // ------------------------------------------------------------------\n\n function handleClientMessage(client: DevToolsClient, raw: string): void {\n let msg: DevToolsClientMessage;\n try {\n msg = JSON.parse(raw) as DevToolsClientMessage;\n } catch {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_JSON\",\n message: \"Could not parse message\",\n });\n\n return;\n }\n\n if (!msg || typeof msg !== \"object\" || typeof msg.type !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_MESSAGE\",\n message: \"Missing type field\",\n });\n\n return;\n }\n\n const now = Date.now();\n const last = clientLastMessage.get(client) ?? 0;\n if (now - last < MIN_MESSAGE_INTERVAL_MS) {\n sendToClient(client, {\n type: \"error\",\n code: \"RATE_LIMITED\",\n message: \"Too many requests\",\n });\n\n return;\n }\n clientLastMessage.set(client, now);\n\n // Handle authenticate message\n if (msg.type === \"authenticate\") {\n if (!authenticate) {\n // No auth configured — treat as unknown command\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: \"Authentication not configured on this server\",\n });\n\n return;\n }\n\n if (!pendingAuthClients.has(client)) {\n // Already authenticated\n sendToClient(client, {\n type: \"error\",\n code: \"ALREADY_AUTHENTICATED\",\n message: \"Already authenticated\",\n });\n\n return;\n }\n\n if (typeof msg.token !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Missing token\",\n });\n client.close();\n pendingAuthClients.delete(client);\n\n return;\n }\n\n const result = authenticate(msg.token);\n const handleResult = (valid: boolean) => {\n if (valid) {\n pendingAuthClients.delete(client);\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Invalid token\",\n });\n pendingAuthClients.delete(client);\n client.close();\n }\n };\n\n if (result instanceof Promise) {\n result.then(handleResult).catch(() => {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Authentication error\",\n });\n pendingAuthClients.delete(client);\n client.close();\n });\n } else {\n handleResult(result);\n }\n\n return;\n }\n\n // Reject commands from clients pending authentication\n if (pendingAuthClients.has(client)) {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_REQUIRED\",\n message: \"Authentication required\",\n });\n\n return;\n }\n\n switch (msg.type) {\n case \"ping\":\n sendToClient(client, { type: \"pong\", timestamp: Date.now() });\n break;\n\n case \"request_snapshot\":\n if (getSnapshot) {\n sendToClient(client, { type: \"snapshot\", data: getSnapshot() });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SNAPSHOT\",\n message: \"Snapshot provider not configured\",\n });\n }\n break;\n\n case \"request_health\":\n if (healthMonitor) {\n sendToClient(client, {\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_HEALTH\",\n message: \"Health monitor not configured\",\n });\n }\n break;\n\n case \"request_events\": {\n const events = timeline.getEvents();\n const since = msg.since;\n const filtered =\n since != null ? events.filter((e) => e.id > since) : events;\n sendToClient(client, { type: \"event_batch\", events: filtered });\n break;\n }\n\n case \"request_breakpoints\":\n if (getBreakpointState) {\n sendToClient(client, {\n type: \"breakpoints\",\n state: getBreakpointState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint provider not configured\",\n });\n }\n break;\n\n case \"resume_breakpoint\":\n if (onResumeBreakpoint && typeof msg.breakpointId === \"string\") {\n // Sanitize: only extract known fields to prevent prototype pollution\n const mods = msg.modifications\n ? { input: msg.modifications.input, skip: msg.modifications.skip }\n : undefined;\n onResumeBreakpoint(msg.breakpointId, mods);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint resume not configured\",\n });\n }\n break;\n\n case \"cancel_breakpoint\":\n if (onCancelBreakpoint && typeof msg.breakpointId === \"string\") {\n const safeReason =\n typeof msg.reason === \"string\" ? msg.reason : undefined;\n onCancelBreakpoint(msg.breakpointId, safeReason);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint cancel not configured\",\n });\n }\n break;\n\n case \"export_session\":\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n break;\n\n case \"import_session\": {\n const MAX_IMPORT_SIZE = 10 * 1024 * 1024; // ~10M characters (string .length check, not byte size)\n if (typeof msg.data !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_DATA\",\n message: \"Missing data field for import\",\n });\n } else if (msg.data.length > MAX_IMPORT_SIZE) {\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_TOO_LARGE\",\n message: `Import data exceeds ${MAX_IMPORT_SIZE / 1024 / 1024} MB limit`,\n });\n } else {\n try {\n timeline.import(msg.data);\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_FAILED\",\n message: errMsg,\n });\n }\n }\n break;\n }\n\n case \"request_scratchpad\":\n if (getScratchpadState) {\n sendToClient(client, {\n type: \"scratchpad_state\",\n data: getScratchpadState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SCRATCHPAD\",\n message: \"Scratchpad provider not configured\",\n });\n }\n break;\n\n case \"request_derived\":\n if (getDerivedState) {\n sendToClient(client, {\n type: \"derived_state\",\n data: getDerivedState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_DERIVED\",\n message: \"Derived state provider not configured\",\n });\n }\n break;\n\n case \"fork_from_snapshot\": {\n if (onForkFromSnapshot && typeof msg.eventId === \"number\") {\n try {\n const result = onForkFromSnapshot(msg.eventId);\n sendToClient(client, {\n type: \"fork_complete\",\n eventId: msg.eventId,\n newEventCount: result.newEventCount,\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"FORK_FAILED\",\n message: errMsg,\n });\n }\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_FORK\",\n message: \"Fork provider not configured\",\n });\n }\n break;\n }\n\n default:\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: `Unknown message type: ${String((msg as { type: string }).type).slice(0, 100)}`,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Rate limiting\n // ------------------------------------------------------------------\n\n const clientLastMessage = new Map<DevToolsClient, number>();\n const MIN_MESSAGE_INTERVAL_MS = 50;\n\n // ------------------------------------------------------------------\n // Connection handler\n // ------------------------------------------------------------------\n\n transport.onConnection((client, onMessage, onClose) => {\n if (clients.size + pendingAuthClients.size >= maxClients) {\n try {\n const msg: DevToolsServerMessage = {\n type: \"error\",\n code: \"MAX_CLIENTS\",\n message: \"Connection limit reached\",\n };\n client.send(JSON.stringify(msg));\n } catch {\n /* ignore */\n }\n client.close();\n\n return;\n }\n\n if (authenticate) {\n // Hold in pending state until client sends authenticate message\n pendingAuthClients.add(client);\n } else {\n // No auth — add directly and send welcome\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n }\n\n onMessage((data) => handleClientMessage(client, data));\n onClose(() => {\n clients.delete(client);\n pendingAuthClients.delete(client);\n clientLastMessage.delete(client);\n });\n });\n\n // ------------------------------------------------------------------\n // Public interface\n // ------------------------------------------------------------------\n\n return {\n get clientCount(): number {\n return clients.size;\n },\n\n broadcast(message: DevToolsServerMessage): void {\n broadcastMessage(message);\n },\n\n pushHealth(): void {\n if (healthMonitor && clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n },\n\n pushBreakpoints(): void {\n if (getBreakpointState && clients.size > 0) {\n broadcastMessage({ type: \"breakpoints\", state: getBreakpointState() });\n }\n },\n\n pushScratchpadUpdate(key: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"scratchpad_update\", key, value });\n }\n },\n\n pushDerivedUpdate(id: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"derived_update\", id, value });\n }\n },\n\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"token_stream\", agentId, tokens, tokenCount });\n }\n },\n\n pushStreamDone(agentId: string, totalTokens: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"stream_done\", agentId, totalTokens });\n }\n },\n\n close(): void {\n unsubscribeTimeline();\n\n if (batchTimer) {\n clearInterval(batchTimer);\n batchTimer = null;\n }\n\n if (healthTimer) {\n clearInterval(healthTimer);\n healthTimer = null;\n }\n\n flushBatch();\n\n for (const client of clients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n for (const client of pendingAuthClients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n clients.clear();\n pendingAuthClients.clear();\n clientLastMessage.clear();\n\n transport.close();\n },\n };\n}\n\n// ============================================================================\n// Orchestrator Connector\n// ============================================================================\n\n/** Options for connecting DevTools to an orchestrator */\nexport interface ConnectDevToolsOptions {\n /** Port for the WebSocket server. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Health metrics push interval (ms). Default: 5000 */\n healthPushIntervalMs?: number;\n /** Event batching size. Default: 1 (no batching) */\n batchSize?: number;\n /** Token authentication callback. When set, clients must authenticate before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n/** Minimal orchestrator interface for DevTools connection */\nexport interface DevToolsCompatibleOrchestrator {\n timeline: {\n subscribe: (listener: (event: DebugEvent) => void) => () => void;\n getEvents: () => DebugEvent[];\n import: (json: string) => void;\n export: () => string;\n forkFrom?: (eventId: number) => void;\n } | null;\n healthMonitor?: {\n getAllMetrics: () => Record<string, AgentHealthMetrics>;\n } | null;\n getPendingBreakpoints?: () => Array<{\n id: string;\n type: string;\n agentId: string;\n input: string;\n label?: string;\n requestedAt: number;\n }>;\n resumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n cancelBreakpoint?: (id: string, reason?: string) => void;\n getAllAgentStates?: () => Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n /** Get current scratchpad state (multi-agent only) */\n getScratchpadState?: () => Record<string, unknown>;\n /** Get current derived values (multi-agent only) */\n getDerivedState?: () => Record<string, unknown>;\n}\n\n/**\n * Connect DevTools to an orchestrator instance.\n *\n * Convenience function that creates a WebSocket transport and DevTools server,\n * automatically wiring up the orchestrator's timeline, health monitor, and breakpoint system.\n *\n * Requires the `ws` package: `npm install ws`\n *\n * **Security:** Binding to `0.0.0.0` exposes the server to all network interfaces.\n * Only do this behind a firewall or with proper authentication.\n *\n * @example\n * ```typescript\n * const orchestrator = createMultiAgentOrchestrator({ debug: true, ... });\n * const devtools = await connectDevTools(orchestrator, { port: 4040 });\n *\n * // Later, clean up:\n * devtools.close();\n * ```\n */\nexport async function connectDevTools(\n orchestrator: DevToolsCompatibleOrchestrator,\n options: ConnectDevToolsOptions = {},\n): Promise<DevToolsServer> {\n if (!orchestrator.timeline) {\n throw new Error(\n \"[Directive DevTools] Orchestrator must have debug: true to use DevTools\",\n );\n }\n\n const transport = await createWsTransport({\n port: options.port ?? 4040,\n host: options.host ?? \"localhost\",\n });\n\n return createDevToolsServer({\n transport,\n timeline: orchestrator.timeline as unknown as DebugTimeline,\n healthMonitor: orchestrator.healthMonitor as HealthMonitor | undefined,\n healthPushIntervalMs: options.healthPushIntervalMs ?? 5000,\n batchSize: options.batchSize,\n authenticate: options.authenticate,\n getSnapshot: orchestrator.getAllAgentStates\n ? () => {\n const agents = orchestrator.getAllAgentStates!();\n\n return {\n timestamp: Date.now(),\n agents,\n eventCount: orchestrator.timeline!.getEvents().length,\n };\n }\n : undefined,\n getBreakpointState: orchestrator.getPendingBreakpoints\n ? () => ({\n pending: orchestrator.getPendingBreakpoints!(),\n resolved: [],\n cancelled: [],\n })\n : undefined,\n onResumeBreakpoint: orchestrator.resumeBreakpoint,\n onCancelBreakpoint: orchestrator.cancelBreakpoint,\n getScratchpadState: orchestrator.getScratchpadState,\n getDerivedState: orchestrator.getDerivedState,\n onForkFromSnapshot: orchestrator.timeline?.forkFrom\n ? (eventId: number) => {\n orchestrator.timeline!.forkFrom!(eventId);\n const newEventCount = orchestrator.timeline!.getEvents().length;\n\n return { newEventCount };\n }\n : undefined,\n });\n}\n\n// ============================================================================\n// Node.js ws Transport Helper\n// ============================================================================\n\n/**\n * Configuration for the built-in Node.js `ws` transport.\n *\n * Requires the `ws` package to be installed: `npm install ws`\n */\nexport interface WsTransportConfig {\n /** Port to listen on. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Maximum incoming message size in bytes. Default: 1048576 (1MB) */\n maxPayloadBytes?: number;\n}\n\n/**\n * Create a DevTools transport using the Node.js `ws` WebSocket library.\n *\n * This is a convenience helper — you can implement {@link DevToolsTransport}\n * with any WebSocket library.\n *\n * @example\n * ```typescript\n * const transport = await createWsTransport({ port: 4040 });\n * const server = createDevToolsServer({ transport, timeline });\n * ```\n */\nexport async function createWsTransport(\n config: WsTransportConfig = {},\n): Promise<DevToolsTransport> {\n const port = config.port ?? 4040;\n const host = config.host ?? \"localhost\";\n\n // Dynamic import so ws is not a hard dependency\n const { WebSocketServer } = await import(\"ws\");\n // maxPayload is supported at runtime but missing from @types/ws ServerOptions\n const wss = new WebSocketServer({\n port,\n host,\n ...{ maxPayload: config.maxPayloadBytes ?? 1_048_576 },\n });\n\n let connectionHandler:\n | ((\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void)\n | null = null;\n\n // biome-ignore lint/suspicious/noExplicitAny: ws types resolved at runtime via dynamic import\n wss.on(\"connection\", (ws: any) => {\n let messageHandler: ((data: string) => void) | null = null;\n let closeHandler: (() => void) | null = null;\n\n const client: DevToolsClient = {\n send(data: string) {\n if (ws.readyState === ws.OPEN) {\n ws.send(data);\n }\n },\n close() {\n ws.close();\n },\n };\n\n ws.on(\"message\", (raw: any) => {\n if (messageHandler) {\n messageHandler(raw.toString());\n }\n });\n\n ws.on(\"close\", () => {\n if (closeHandler) {\n closeHandler();\n }\n });\n\n connectionHandler?.(\n client,\n (handler) => {\n messageHandler = handler;\n },\n (handler) => {\n closeHandler = handler;\n },\n );\n });\n\n return {\n onConnection(handler) {\n connectionHandler = handler;\n },\n close() {\n wss.close();\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/devtools-server.ts"],"names":["createDevToolsServer","config","transport","timeline","healthMonitor","getSnapshot","getBreakpointState","onResumeBreakpoint","onCancelBreakpoint","getScratchpadState","getDerivedState","onForkFromSnapshot","batchSize","batchIntervalMs","healthPushIntervalMs","authenticate","maxClients","sessionId","clients","pendingAuthClients","batchBuffer","batchTimer","healthTimer","sendToClient","client","message","broadcastMessage","data","snapshot","flushBatch","unsubscribeTimeline","event","handleClientMessage","raw","msg","now","last","clientLastMessage","MIN_MESSAGE_INTERVAL_MS","result","handleResult","valid","events","since","filtered","e","mods","safeReason","err","errMsg","onMessage","onClose","key","value","id","agentId","tokens","tokenCount","totalTokens","connectDevTools","orchestrator","options","createWsTransport","agents","eventId","port","host","WebSocketServer","wss","connectionHandler","ws","messageHandler","closeHandler","handler"],"mappings":"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","file":"chunk-BZB3RDI2.js","sourcesContent":["/**\n * DevTools Server — WebSocket-based bridge between orchestrators and DevTools UI.\n *\n * Streams debug timeline events, health metrics, breakpoint state, and system\n * snapshots in real-time to connected DevTools clients. Accepts commands from\n * clients to resume/cancel breakpoints and request snapshots.\n *\n * Transport-agnostic: works with any WebSocket implementation (ws, Bun, Deno)\n * via the {@link DevToolsTransport} interface.\n *\n * @module\n */\n\nimport type { DebugTimeline } from \"./debug-timeline.js\";\nimport type { AgentHealthMetrics, HealthMonitor } from \"./health-monitor.js\";\nimport type { BreakpointState, DebugEvent } from \"./types.js\";\n\n// ============================================================================\n// Transport Interface (WebSocket abstraction)\n// ============================================================================\n\n/** A connected DevTools client */\nexport interface DevToolsClient {\n /** Send a JSON-serializable message to this client */\n send(data: string): void;\n /** Close the connection */\n close(): void;\n}\n\n/**\n * Transport layer for the DevTools server.\n *\n * Implement this interface to bridge any WebSocket library (ws, Bun.serve, Deno.serve).\n *\n * @example Node.js with `ws`:\n * ```typescript\n * import { WebSocketServer } from \"ws\";\n *\n * function createWsTransport(port: number): DevToolsTransport {\n * const wss = new WebSocketServer({ port });\n * let onConnect: ((client: DevToolsClient) => void) | null = null;\n *\n * wss.on(\"connection\", (ws) => {\n * const client: DevToolsClient = {\n * send: (data) => { if (ws.readyState === ws.OPEN) ws.send(data); },\n * close: () => ws.close(),\n * };\n * ws.on(\"message\", (raw) => {\n * if (client._onMessage) client._onMessage(raw.toString());\n * });\n * ws.on(\"close\", () => {\n * if (client._onClose) client._onClose();\n * });\n * onConnect?.(client);\n * });\n *\n * return {\n * onConnection(handler) { onConnect = handler; },\n * close() { wss.close(); },\n * };\n * }\n * ```\n */\nexport interface DevToolsTransport {\n /** Register a handler for new client connections */\n onConnection(\n handler: (\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void,\n ): void;\n /** Shut down the transport */\n close(): void;\n}\n\n// ============================================================================\n// Protocol Messages\n// ============================================================================\n\n/** Messages sent FROM the server TO clients */\nexport type DevToolsServerMessage =\n | { type: \"welcome\"; version: number; sessionId: string; timestamp: number }\n | { type: \"event\"; event: DebugEvent }\n | { type: \"event_batch\"; events: DebugEvent[] }\n | { type: \"snapshot\"; data: DevToolsSnapshot }\n | { type: \"health\"; metrics: Record<string, AgentHealthMetrics> }\n | { type: \"breakpoints\"; state: BreakpointState }\n | { type: \"pong\"; timestamp: number }\n // Scratchpad & derived state\n | { type: \"scratchpad_state\"; data: Record<string, unknown> }\n | { type: \"scratchpad_update\"; key: string; value: unknown }\n | { type: \"derived_state\"; data: Record<string, unknown> }\n | { type: \"derived_update\"; id: string; value: unknown }\n // Fork\n | { type: \"fork_complete\"; eventId: number; newEventCount: number }\n // Token streaming\n | {\n type: \"token_stream\";\n agentId: string;\n tokens: string;\n tokenCount: number;\n }\n | { type: \"stream_done\"; agentId: string; totalTokens: number }\n | { type: \"error\"; code: string; message: string };\n\n/** Messages sent FROM clients TO the server */\nexport type DevToolsClientMessage =\n | { type: \"authenticate\"; token: string }\n | { type: \"request_snapshot\" }\n | { type: \"request_health\" }\n | { type: \"request_events\"; since?: number }\n | { type: \"request_breakpoints\" }\n | {\n type: \"resume_breakpoint\";\n breakpointId: string;\n modifications?: { input?: string; skip?: boolean };\n }\n | { type: \"cancel_breakpoint\"; breakpointId: string; reason?: string }\n | { type: \"export_session\" }\n | { type: \"import_session\"; data: string }\n // Scratchpad & derived requests\n | { type: \"request_scratchpad\" }\n | { type: \"request_derived\" }\n // Fork\n | { type: \"fork_from_snapshot\"; eventId: number }\n | { type: \"ping\" };\n\n/** System snapshot sent to clients on demand */\nexport interface DevToolsSnapshot {\n timestamp: number;\n agents: Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n coordinator?: { globalTokens: number; status: string };\n derived?: Record<string, unknown>;\n eventCount: number;\n}\n\n// ============================================================================\n// Server Configuration\n// ============================================================================\n\n/** Configuration for the DevTools server */\nexport interface DevToolsServerConfig {\n /** Transport to use for WebSocket connections */\n transport: DevToolsTransport;\n /** Debug timeline to subscribe to */\n timeline: DebugTimeline;\n /** Health monitor for metrics (optional) */\n healthMonitor?: HealthMonitor | null;\n /** Callback to get current agent states for snapshots */\n getSnapshot?: () => DevToolsSnapshot;\n /** Callback to get current breakpoint state */\n getBreakpointState?: () => BreakpointState;\n /** Callback to resume a breakpoint */\n onResumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n /** Callback to cancel a breakpoint */\n onCancelBreakpoint?: (id: string, reason?: string) => void;\n /** Callback to get current scratchpad state */\n getScratchpadState?: () => Record<string, unknown>;\n /** Callback to get current derived state */\n getDerivedState?: () => Record<string, unknown>;\n /** Callback to fork from a snapshot event */\n onForkFromSnapshot?: (eventId: number) => { newEventCount: number };\n /** Maximum events to batch before flushing. Default: 1 (no batching) */\n batchSize?: number;\n /** Flush interval for batched events (ms). Default: 50 */\n batchIntervalMs?: number;\n /** Health metrics push interval (ms). 0 = no auto-push. Default: 0 */\n healthPushIntervalMs?: number;\n /** Maximum connected clients. Default: 50 */\n maxClients?: number;\n /** Token authentication callback. When set, new connections must send an `authenticate` message before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n// ============================================================================\n// Server Instance\n// ============================================================================\n\n/** DevTools server instance */\nexport interface DevToolsServer {\n /** Number of connected clients */\n readonly clientCount: number;\n /** Broadcast a message to all connected clients */\n broadcast(message: DevToolsServerMessage): void;\n /** Push current health metrics to all clients */\n pushHealth(): void;\n /** Push current breakpoint state to all clients */\n pushBreakpoints(): void;\n /** Push a scratchpad key update to all clients */\n pushScratchpadUpdate(key: string, value: unknown): void;\n /** Push a derived value update to all clients */\n pushDerivedUpdate(id: string, value: unknown): void;\n /** Push streaming tokens to all clients */\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void;\n /** Signal stream completion to all clients */\n pushStreamDone(agentId: string, totalTokens: number): void;\n /** Shut down the server and disconnect all clients */\n close(): void;\n}\n\nconst PROTOCOL_VERSION = 1;\n\n/**\n * Create a DevTools server that bridges orchestrator state to DevTools UI clients.\n *\n * @example\n * ```typescript\n * const server = createDevToolsServer({\n * transport: createWsTransport(4040),\n * timeline: orchestrator.timeline!,\n * healthMonitor: orchestrator.healthMonitor,\n * getSnapshot: () => buildSnapshot(orchestrator),\n * getBreakpointState: () => orchestrator.getBreakpointState(),\n * onResumeBreakpoint: (id, mods) => orchestrator.resumeBreakpoint(id, mods),\n * onCancelBreakpoint: (id, reason) => orchestrator.cancelBreakpoint(id, reason),\n * });\n * ```\n */\nexport function createDevToolsServer(\n config: DevToolsServerConfig,\n): DevToolsServer {\n const {\n transport,\n timeline,\n healthMonitor,\n getSnapshot,\n getBreakpointState,\n onResumeBreakpoint,\n onCancelBreakpoint,\n getScratchpadState,\n getDerivedState,\n onForkFromSnapshot,\n batchSize = 1,\n batchIntervalMs = 50,\n healthPushIntervalMs = 0,\n authenticate,\n } = config;\n const maxClients = config.maxClients ?? 50;\n\n const sessionId = `devtools_${crypto.randomUUID()}`;\n const clients = new Set<DevToolsClient>();\n const pendingAuthClients = new Set<DevToolsClient>();\n let batchBuffer: DebugEvent[] = [];\n let batchTimer: ReturnType<typeof setInterval> | null = null;\n let healthTimer: ReturnType<typeof setInterval> | null = null;\n\n // ------------------------------------------------------------------\n // Helpers\n // ------------------------------------------------------------------\n\n function sendToClient(\n client: DevToolsClient,\n message: DevToolsServerMessage,\n ): void {\n try {\n client.send(JSON.stringify(message));\n } catch {\n // Client may have disconnected — remove silently\n clients.delete(client);\n }\n }\n\n function broadcastMessage(message: DevToolsServerMessage): void {\n const data = JSON.stringify(message);\n const snapshot = [...clients];\n for (const client of snapshot) {\n try {\n client.send(data);\n } catch {\n clients.delete(client);\n }\n }\n }\n\n function flushBatch(): void {\n if (batchBuffer.length === 0) {\n return;\n }\n\n if (batchBuffer.length === 1) {\n broadcastMessage({ type: \"event\", event: batchBuffer[0]! });\n } else {\n broadcastMessage({ type: \"event_batch\", events: batchBuffer });\n }\n\n batchBuffer = [];\n }\n\n // ------------------------------------------------------------------\n // Timeline subscription\n // ------------------------------------------------------------------\n\n const unsubscribeTimeline: () => void = timeline.subscribe(\n (event: DebugEvent) => {\n if (clients.size === 0) {\n return;\n }\n\n if (batchSize <= 1) {\n broadcastMessage({ type: \"event\", event });\n\n return;\n }\n\n batchBuffer.push(event);\n if (batchBuffer.length >= batchSize) {\n flushBatch();\n }\n },\n );\n\n // Start batch flush timer if batching enabled\n if (batchSize > 1 && batchIntervalMs > 0) {\n batchTimer = setInterval(flushBatch, batchIntervalMs);\n }\n\n // Start health push timer if configured\n if (healthPushIntervalMs > 0 && healthMonitor) {\n healthTimer = setInterval(() => {\n if (clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n }, healthPushIntervalMs);\n }\n\n // ------------------------------------------------------------------\n // Client message handler\n // ------------------------------------------------------------------\n\n function handleClientMessage(client: DevToolsClient, raw: string): void {\n let msg: DevToolsClientMessage;\n try {\n msg = JSON.parse(raw) as DevToolsClientMessage;\n } catch {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_JSON\",\n message: \"Could not parse message\",\n });\n\n return;\n }\n\n if (!msg || typeof msg !== \"object\" || typeof msg.type !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_MESSAGE\",\n message: \"Missing type field\",\n });\n\n return;\n }\n\n const now = Date.now();\n const last = clientLastMessage.get(client) ?? 0;\n if (now - last < MIN_MESSAGE_INTERVAL_MS) {\n sendToClient(client, {\n type: \"error\",\n code: \"RATE_LIMITED\",\n message: \"Too many requests\",\n });\n\n return;\n }\n clientLastMessage.set(client, now);\n\n // Handle authenticate message\n if (msg.type === \"authenticate\") {\n if (!authenticate) {\n // No auth configured — treat as unknown command\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: \"Authentication not configured on this server\",\n });\n\n return;\n }\n\n if (!pendingAuthClients.has(client)) {\n // Already authenticated\n sendToClient(client, {\n type: \"error\",\n code: \"ALREADY_AUTHENTICATED\",\n message: \"Already authenticated\",\n });\n\n return;\n }\n\n if (typeof msg.token !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Missing token\",\n });\n client.close();\n pendingAuthClients.delete(client);\n\n return;\n }\n\n const result = authenticate(msg.token);\n const handleResult = (valid: boolean) => {\n if (valid) {\n pendingAuthClients.delete(client);\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Invalid token\",\n });\n pendingAuthClients.delete(client);\n client.close();\n }\n };\n\n if (result instanceof Promise) {\n result.then(handleResult).catch(() => {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_FAILED\",\n message: \"Authentication error\",\n });\n pendingAuthClients.delete(client);\n client.close();\n });\n } else {\n handleResult(result);\n }\n\n return;\n }\n\n // Reject commands from clients pending authentication\n if (pendingAuthClients.has(client)) {\n sendToClient(client, {\n type: \"error\",\n code: \"AUTH_REQUIRED\",\n message: \"Authentication required\",\n });\n\n return;\n }\n\n switch (msg.type) {\n case \"ping\":\n sendToClient(client, { type: \"pong\", timestamp: Date.now() });\n break;\n\n case \"request_snapshot\":\n if (getSnapshot) {\n sendToClient(client, { type: \"snapshot\", data: getSnapshot() });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SNAPSHOT\",\n message: \"Snapshot provider not configured\",\n });\n }\n break;\n\n case \"request_health\":\n if (healthMonitor) {\n sendToClient(client, {\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_HEALTH\",\n message: \"Health monitor not configured\",\n });\n }\n break;\n\n case \"request_events\": {\n const events = timeline.getEvents();\n const since = msg.since;\n const filtered =\n since != null ? events.filter((e) => e.id > since) : events;\n sendToClient(client, { type: \"event_batch\", events: filtered });\n break;\n }\n\n case \"request_breakpoints\":\n if (getBreakpointState) {\n sendToClient(client, {\n type: \"breakpoints\",\n state: getBreakpointState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint provider not configured\",\n });\n }\n break;\n\n case \"resume_breakpoint\":\n if (onResumeBreakpoint && typeof msg.breakpointId === \"string\") {\n // Sanitize: only extract known fields to prevent prototype pollution\n const mods = msg.modifications\n ? { input: msg.modifications.input, skip: msg.modifications.skip }\n : undefined;\n onResumeBreakpoint(msg.breakpointId, mods);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint resume not configured\",\n });\n }\n break;\n\n case \"cancel_breakpoint\":\n if (onCancelBreakpoint && typeof msg.breakpointId === \"string\") {\n const safeReason =\n typeof msg.reason === \"string\" ? msg.reason : undefined;\n onCancelBreakpoint(msg.breakpointId, safeReason);\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_BREAKPOINTS\",\n message: \"Breakpoint cancel not configured\",\n });\n }\n break;\n\n case \"export_session\":\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n break;\n\n case \"import_session\": {\n const MAX_IMPORT_SIZE = 10 * 1024 * 1024; // ~10M characters (string .length check, not byte size)\n if (typeof msg.data !== \"string\") {\n sendToClient(client, {\n type: \"error\",\n code: \"INVALID_DATA\",\n message: \"Missing data field for import\",\n });\n } else if (msg.data.length > MAX_IMPORT_SIZE) {\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_TOO_LARGE\",\n message: `Import data exceeds ${MAX_IMPORT_SIZE / 1024 / 1024} MB limit`,\n });\n } else {\n try {\n timeline.import(msg.data);\n sendToClient(client, {\n type: \"event_batch\",\n events: timeline.getEvents(),\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"IMPORT_FAILED\",\n message: errMsg,\n });\n }\n }\n break;\n }\n\n case \"request_scratchpad\":\n if (getScratchpadState) {\n sendToClient(client, {\n type: \"scratchpad_state\",\n data: getScratchpadState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_SCRATCHPAD\",\n message: \"Scratchpad provider not configured\",\n });\n }\n break;\n\n case \"request_derived\":\n if (getDerivedState) {\n sendToClient(client, {\n type: \"derived_state\",\n data: getDerivedState(),\n });\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_DERIVED\",\n message: \"Derived state provider not configured\",\n });\n }\n break;\n\n case \"fork_from_snapshot\": {\n if (onForkFromSnapshot && typeof msg.eventId === \"number\") {\n try {\n const result = onForkFromSnapshot(msg.eventId);\n sendToClient(client, {\n type: \"fork_complete\",\n eventId: msg.eventId,\n newEventCount: result.newEventCount,\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n sendToClient(client, {\n type: \"error\",\n code: \"FORK_FAILED\",\n message: errMsg,\n });\n }\n } else {\n sendToClient(client, {\n type: \"error\",\n code: \"NO_FORK\",\n message: \"Fork provider not configured\",\n });\n }\n break;\n }\n\n default:\n sendToClient(client, {\n type: \"error\",\n code: \"UNKNOWN_COMMAND\",\n message: `Unknown message type: ${String((msg as { type: string }).type).slice(0, 100)}`,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Rate limiting\n // ------------------------------------------------------------------\n\n const clientLastMessage = new Map<DevToolsClient, number>();\n const MIN_MESSAGE_INTERVAL_MS = 50;\n\n // ------------------------------------------------------------------\n // Connection handler\n // ------------------------------------------------------------------\n\n transport.onConnection((client, onMessage, onClose) => {\n if (clients.size + pendingAuthClients.size >= maxClients) {\n try {\n const msg: DevToolsServerMessage = {\n type: \"error\",\n code: \"MAX_CLIENTS\",\n message: \"Connection limit reached\",\n };\n client.send(JSON.stringify(msg));\n } catch {\n /* ignore */\n }\n client.close();\n\n return;\n }\n\n if (authenticate) {\n // Hold in pending state until client sends authenticate message\n pendingAuthClients.add(client);\n } else {\n // No auth — add directly and send welcome\n clients.add(client);\n sendToClient(client, {\n type: \"welcome\",\n version: PROTOCOL_VERSION,\n sessionId,\n timestamp: Date.now(),\n });\n }\n\n onMessage((data) => handleClientMessage(client, data));\n onClose(() => {\n clients.delete(client);\n pendingAuthClients.delete(client);\n clientLastMessage.delete(client);\n });\n });\n\n // ------------------------------------------------------------------\n // Public interface\n // ------------------------------------------------------------------\n\n return {\n get clientCount(): number {\n return clients.size;\n },\n\n broadcast(message: DevToolsServerMessage): void {\n broadcastMessage(message);\n },\n\n pushHealth(): void {\n if (healthMonitor && clients.size > 0) {\n broadcastMessage({\n type: \"health\",\n metrics: healthMonitor.getAllMetrics(),\n });\n }\n },\n\n pushBreakpoints(): void {\n if (getBreakpointState && clients.size > 0) {\n broadcastMessage({ type: \"breakpoints\", state: getBreakpointState() });\n }\n },\n\n pushScratchpadUpdate(key: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"scratchpad_update\", key, value });\n }\n },\n\n pushDerivedUpdate(id: string, value: unknown): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"derived_update\", id, value });\n }\n },\n\n pushTokenStream(agentId: string, tokens: string, tokenCount: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"token_stream\", agentId, tokens, tokenCount });\n }\n },\n\n pushStreamDone(agentId: string, totalTokens: number): void {\n if (clients.size > 0) {\n broadcastMessage({ type: \"stream_done\", agentId, totalTokens });\n }\n },\n\n close(): void {\n unsubscribeTimeline();\n\n if (batchTimer) {\n clearInterval(batchTimer);\n batchTimer = null;\n }\n\n if (healthTimer) {\n clearInterval(healthTimer);\n healthTimer = null;\n }\n\n flushBatch();\n\n for (const client of clients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n for (const client of pendingAuthClients) {\n try {\n client.close();\n } catch {\n // Ignore close errors\n }\n }\n clients.clear();\n pendingAuthClients.clear();\n clientLastMessage.clear();\n\n transport.close();\n },\n };\n}\n\n// ============================================================================\n// Orchestrator Connector\n// ============================================================================\n\n/** Options for connecting DevTools to an orchestrator */\nexport interface ConnectDevToolsOptions {\n /** Port for the WebSocket server. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Health metrics push interval (ms). Default: 5000 */\n healthPushIntervalMs?: number;\n /** Event batching size. Default: 1 (no batching) */\n batchSize?: number;\n /** Token authentication callback. When set, clients must authenticate before receiving data. */\n authenticate?: (token: string) => boolean | Promise<boolean>;\n}\n\n/** Minimal orchestrator interface for DevTools connection */\nexport interface DevToolsCompatibleOrchestrator {\n timeline: {\n subscribe: (listener: (event: DebugEvent) => void) => () => void;\n getEvents: () => DebugEvent[];\n import: (json: string) => void;\n export: () => string;\n forkFrom?: (eventId: number) => void;\n } | null;\n healthMonitor?: {\n getAllMetrics: () => Record<string, AgentHealthMetrics>;\n } | null;\n getPendingBreakpoints?: () => Array<{\n id: string;\n type: string;\n agentId: string;\n input: string;\n label?: string;\n requestedAt: number;\n }>;\n resumeBreakpoint?: (\n id: string,\n modifications?: { input?: string; skip?: boolean },\n ) => void;\n cancelBreakpoint?: (id: string, reason?: string) => void;\n getAllAgentStates?: () => Record<\n string,\n {\n status: string;\n lastInput?: string;\n lastOutput?: unknown;\n totalTokens: number;\n runCount: number;\n }\n >;\n /** Get current scratchpad state (multi-agent only) */\n getScratchpadState?: () => Record<string, unknown>;\n /** Get current derived values (multi-agent only) */\n getDerivedState?: () => Record<string, unknown>;\n}\n\n/**\n * Connect DevTools to an orchestrator instance.\n *\n * Convenience function that creates a WebSocket transport and DevTools server,\n * automatically wiring up the orchestrator's timeline, health monitor, and breakpoint system.\n *\n * Requires the `ws` package: `npm install ws`\n *\n * **Security:** Binding to `0.0.0.0` exposes the server to all network interfaces.\n * Only do this behind a firewall or with proper authentication.\n *\n * @example\n * ```typescript\n * const orchestrator = createMultiAgentOrchestrator({ debug: true, ... });\n * const devtools = await connectDevTools(orchestrator, { port: 4040 });\n *\n * // Later, clean up:\n * devtools.close();\n * ```\n */\nexport async function connectDevTools(\n orchestrator: DevToolsCompatibleOrchestrator,\n options: ConnectDevToolsOptions = {},\n): Promise<DevToolsServer> {\n if (!orchestrator.timeline) {\n throw new Error(\n \"[Directive DevTools] Orchestrator must have debug: true to use DevTools\",\n );\n }\n\n const transport = await createWsTransport({\n port: options.port ?? 4040,\n host: options.host ?? \"localhost\",\n });\n\n return createDevToolsServer({\n transport,\n timeline: orchestrator.timeline as unknown as DebugTimeline,\n healthMonitor: orchestrator.healthMonitor as HealthMonitor | undefined,\n healthPushIntervalMs: options.healthPushIntervalMs ?? 5000,\n batchSize: options.batchSize,\n authenticate: options.authenticate,\n getSnapshot: orchestrator.getAllAgentStates\n ? () => {\n const agents = orchestrator.getAllAgentStates!();\n\n return {\n timestamp: Date.now(),\n agents,\n eventCount: orchestrator.timeline!.getEvents().length,\n };\n }\n : undefined,\n getBreakpointState: orchestrator.getPendingBreakpoints\n ? () => ({\n pending: orchestrator.getPendingBreakpoints!(),\n resolved: [],\n cancelled: [],\n })\n : undefined,\n onResumeBreakpoint: orchestrator.resumeBreakpoint,\n onCancelBreakpoint: orchestrator.cancelBreakpoint,\n getScratchpadState: orchestrator.getScratchpadState,\n getDerivedState: orchestrator.getDerivedState,\n onForkFromSnapshot: orchestrator.timeline?.forkFrom\n ? (eventId: number) => {\n orchestrator.timeline!.forkFrom!(eventId);\n const newEventCount = orchestrator.timeline!.getEvents().length;\n\n return { newEventCount };\n }\n : undefined,\n });\n}\n\n// ============================================================================\n// Node.js ws Transport Helper\n// ============================================================================\n\n/**\n * Configuration for the built-in Node.js `ws` transport.\n *\n * Requires the `ws` package to be installed: `npm install ws`\n */\nexport interface WsTransportConfig {\n /** Port to listen on. Default: 4040 */\n port?: number;\n /** Host to bind to. Default: \"localhost\" */\n host?: string;\n /** Maximum incoming message size in bytes. Default: 1048576 (1MB) */\n maxPayloadBytes?: number;\n}\n\n/**\n * Create a DevTools transport using the Node.js `ws` WebSocket library.\n *\n * This is a convenience helper — you can implement {@link DevToolsTransport}\n * with any WebSocket library.\n *\n * @example\n * ```typescript\n * const transport = await createWsTransport({ port: 4040 });\n * const server = createDevToolsServer({ transport, timeline });\n * ```\n */\nexport async function createWsTransport(\n config: WsTransportConfig = {},\n): Promise<DevToolsTransport> {\n const port = config.port ?? 4040;\n const host = config.host ?? \"localhost\";\n\n // Dynamic import so ws is not a hard dependency\n const { WebSocketServer } = await import(\"ws\");\n // maxPayload is supported at runtime but missing from @types/ws ServerOptions\n const wss = new WebSocketServer({\n port,\n host,\n ...{ maxPayload: config.maxPayloadBytes ?? 1_048_576 },\n });\n\n let connectionHandler:\n | ((\n client: DevToolsClient,\n onMessage: (handler: (data: string) => void) => void,\n onClose: (handler: () => void) => void,\n ) => void)\n | null = null;\n\n wss.on(\"connection\", (ws: any) => {\n let messageHandler: ((data: string) => void) | null = null;\n let closeHandler: (() => void) | null = null;\n\n const client: DevToolsClient = {\n send(data: string) {\n if (ws.readyState === ws.OPEN) {\n ws.send(data);\n }\n },\n close() {\n ws.close();\n },\n };\n\n ws.on(\"message\", (raw: any) => {\n if (messageHandler) {\n messageHandler(raw.toString());\n }\n });\n\n ws.on(\"close\", () => {\n if (closeHandler) {\n closeHandler();\n }\n });\n\n connectionHandler?.(\n client,\n (handler) => {\n messageHandler = handler;\n },\n (handler) => {\n closeHandler = handler;\n },\n );\n });\n\n return {\n onConnection(handler) {\n connectionHandler = handler;\n },\n close() {\n wss.close();\n },\n };\n}\n"]}
|