@north-light/crouter 0.3.327 → 0.3.329

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.
@@ -19,10 +19,18 @@ export declare class NodeEventRing {
19
19
  };
20
20
  get empty(): boolean;
21
21
  }
22
- /** Translate only the application-safe subset of broker frames. The map retains
23
- * tool argument summaries between start/end; raw arguments and tool output never
24
- * cross this boundary. */
25
- export declare function translateBrokerFrame(nodeId: string, frame: BrokerToClient, toolSummaries?: Map<string, string>): StreamEventPayload[];
22
+ /** Per-node state retained while broker frames become public stream events. */
23
+ export declare class NodeEventTranslationState {
24
+ readonly toolSummaries: Map<string, string>;
25
+ private emittedAssistantText;
26
+ resetAssistantText(): void;
27
+ emitAssistantTextDelta(message: unknown): string;
28
+ seedAssistantText(message: unknown): string;
29
+ }
30
+ /** Translate only the application-safe subset of broker frames. Tool argument
31
+ * summaries and emitted assistant text stay per node hub; raw arguments and
32
+ * tool output never cross this boundary. */
33
+ export declare function translateBrokerFrame(nodeId: string, frame: BrokerToClient, state?: NodeEventTranslationState): StreamEventPayload[];
26
34
  declare class NodeEventStreams {
27
35
  private readonly hubs;
28
36
  subscribe(nodeId: string, after: number | undefined, subscriber: Subscriber): {
@@ -1,6 +1,6 @@
1
- var q=Object.defineProperty;var o=(n,e)=>q(n,"name",{value:e,configurable:!0});import{randomUUID as T}from"node:crypto";import{ApiError as E}from"../../../api/errors.js";import{BrokerClient as C}from"../../../core/broker-client/client.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{isPidAlive as A}from"../../../core/canvas/pid.js";import{BROKER_VIEW_SOCKET_WAIT_MS as M}from"../../../core/runtime/view-socket.js";import{toNodeOutcomeDTO as B}from"../map.js";import{reportsForNode as k}from"./reports.js";const L=15e3,$=6e4,w=250,P=512,R=256*1024,j=1e3,D=32*1024*1024;class G{static{o(this,"NodeEventRing")}events=[];bytes=0;nextSequence=1;earliestAvailable=1;append(e){const t={...e,sequence_number:this.nextSequence++},s=Buffer.byteLength(JSON.stringify(t),"utf8");if(s>R)return this.events=[],this.bytes=0,this.earliestAvailable=this.nextSequence,t;for(this.events.push(t),this.bytes+=s;this.events.length>P||this.bytes>R;){const r=this.events.shift();if(r===void 0)break;this.bytes-=Buffer.byteLength(JSON.stringify(r),"utf8"),this.earliestAvailable=r.sequence_number+1}return t}replay(e){if(e===void 0)return{gap:null,events:this.events};const t=e<this.earliestAvailable-1||e>=this.nextSequence?N(this.earliestAvailable):null;return{gap:t,events:t===null?this.events.filter(s=>s.sequence_number>e):this.events}}get empty(){return this.events.length===0}}function N(n){return{type:"error",error:{code:"stream_gap",message:"the requested event cursor is older than this daemon can resume",details:{earliest_sequence:n}}}}o(N,"streamGap");function V(n){return n===null?"arguments: null":Array.isArray(n)?`arguments: array (${n.length} items)`:typeof n=="object"?`arguments: object (${Object.keys(n).length} fields)`:`arguments: ${typeof n}`}o(V,"toolSummary");function I(n){if(typeof n!="object"||n===null)return"";const e=n.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(t=>typeof t=="object"&&t!==null).filter(t=>t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(""):""}o(I,"assistantText");function H(n,e,t=new Map){switch(e.type){case"message_update":return e.message.role==="assistant"&&e.assistantMessageEvent.type==="text_delta"?[{type:"node.output_text.delta",node_id:n,delta:e.assistantMessageEvent.delta}]:[];case"message_end":return e.message.role==="assistant"?[{type:"node.output_text.done",node_id:n,text:I(e.message)}]:[];case"tool_execution_start":{const s=V(e.args);return t.set(e.toolCallId,s),[{type:"node.tool_call.started",node_id:n,tool_call_id:e.toolCallId,tool:e.toolName,summary:s}]}case"tool_execution_end":{const s=t.get(e.toolCallId)??"[arguments unavailable]";return t.delete(e.toolCallId),[{type:"node.tool_call.completed",node_id:n,tool_call_id:e.toolCallId,tool:e.toolName,status:e.isError?"error":"ok",summary:s}]}case"turn_start":return[{type:"node.turn.started",node_id:n}];case"turn_end":return[{type:"node.turn.completed",node_id:n}];default:return[]}}o(H,"translateBrokerFrame");class z{static{o(this,"NodeEventHub")}nodeId;remove;ring=new G;subscribers=new Set;observer;observerErrorAt;poll;reconnect;idleClose;status;settledRevision;settledOutcome;settledSequence;snapshotSeeded=!1;reportsSeeded=!1;toolSummaries=new Map;fresh=!0;constructor(e,t){this.nodeId=e,this.remove=t}subscribe(e,t){const s=this.fresh&&e!==void 0;this.fresh=!1,this.start();const r=this.settledOutcome!==void 0,d=s?{gap:N(1),events:this.ring.replay(void 0).events}:this.ring.replay(e);r||(this.subscribers.add(t),this.status!=="dormant"&&this.openObserver());let h=!1;return queueMicrotask(()=>{if(!h){d.gap!==null&&t(d.gap);for(const l of d.events)t(l)}}),r&&this.scheduleIdleClose(),{unsubscribe:o(()=>{h=!0,r||this.unsubscribe(t)},"unsubscribe"),terminal:r}}report(e){this.settledRevision===void 0&&this.publish({type:"node.report.pushed",node_id:this.nodeId,report:e})}start(){this.idleClose!==void 0&&(clearTimeout(this.idleClose),this.idleClose=void 0),this.poll===void 0&&(this.check(),this.settledRevision===void 0&&(this.seedReports(),this.poll=setInterval(()=>this.check(),w)))}seedReports(){if(!this.reportsSeeded){this.reportsSeeded=!0;for(const e of k(this.nodeId).reverse())this.report(e)}}check(){const e=b(this.nodeId);if(e===null){this.fail("stream_error",`node ${this.nodeId} no longer exists`);return}const t=B(e);if(t!==null){this.settledRevision!==t.revision&&(this.settledRevision=t.revision,this.settledOutcome=t,this.settledSequence=this.publish({type:"node.settled",node_id:this.nodeId,outcome:t}).sequence_number,this.stopObserver(),this.stopPoll());return}const s=e.pi_pid===null?"dormant":e.status;if(s==="dormant"){this.status!=="dormant"&&(this.status=s,this.publish({type:"node.status.changed",node_id:this.nodeId,status:s}));return}this.status===void 0?this.status=s:this.status!=="dormant"&&this.status!==s&&(this.status=s,this.publish({type:"node.status.changed",node_id:this.nodeId,status:s})),this.openObserver()}openObserver(){if(this.observer!==void 0||this.subscribers.size===0)return;const e=new C(this.nodeId);this.observer=e,e.on("connect",()=>{this.observerErrorAt=void 0;const t=b(this.nodeId);this.status==="dormant"&&t!==null&&t.pi_pid!==null&&(this.status=t.status,this.publish({type:"node.status.changed",node_id:this.nodeId,status:t.status})),e.send({type:"hello",role:"observer",client_id:T(),attends:!1})}),e.on("frame",t=>{try{t.type==="welcome"&&this.seedSnapshot(t.snapshot);for(const s of H(this.nodeId,t,this.toolSummaries))this.publish(s)}catch(s){this.fail("stream_error",s instanceof Error?s.message:String(s))}}),e.on("error",()=>{const t=b(this.nodeId),s=Date.now();t!==null&&t.pi_pid!==null&&A(t.pi_pid)&&(this.observerErrorAt??=s,s-this.observerErrorAt<M)||this.fail("stream_error","observer connection failed")}),e.on("close",()=>{this.observer===e&&(this.observer=void 0,!(this.subscribers.size===0||this.settledRevision!==void 0)&&(this.status!=="dormant"&&(this.publish({type:"node.status.changed",node_id:this.nodeId,status:"dormant"}),this.status="dormant"),this.scheduleReconnect()))}),e.connect()}seedSnapshot(e){if(this.snapshotSeeded)return;this.snapshotSeeded=!0;const t=e.messages.filter(r=>r.role==="assistant"),s=e.state.isStreaming?t.pop():void 0;for(const r of t)this.publish({type:"node.output_text.done",node_id:this.nodeId,text:I(r)});s!==void 0&&this.publish({type:"node.output_text.delta",node_id:this.nodeId,delta:I(s)})}scheduleReconnect(){this.reconnect===void 0&&(this.reconnect=setTimeout(()=>{this.reconnect=void 0,this.check()},w))}publish(e){const t=this.ring.append(e);for(const s of[...this.subscribers])s(t);return t}fail(e,t){const s={type:"error",error:{code:e,message:t}};for(const r of[...this.subscribers])r(s);this.stopObserver(),this.stopPoll()}unsubscribe(e){this.subscribers.delete(e),this.subscribers.size===0&&this.scheduleIdleClose()}scheduleIdleClose(){this.idleClose===void 0&&(this.idleClose=setTimeout(()=>{this.stopObserver(),this.stopPoll(),this.remove()},$))}stopObserver(){this.reconnect!==void 0&&(clearTimeout(this.reconnect),this.reconnect=void 0);const e=this.observer;this.observer=void 0,e?.close()}stopPoll(){this.poll!==void 0&&(clearInterval(this.poll),this.poll=void 0)}}class J{static{o(this,"NodeEventStreams")}hubs=new Map;subscribe(e,t,s){let r=this.hubs.get(e);return r===void 0&&(r=new z(e,()=>this.hubs.delete(e)),this.hubs.set(e,r)),r.subscribe(t,s)}report(e,t){this.hubs.get(e)?.report(t)}}const F=new J;function K(n){const e=n.get("after");if(e===null||e==="")return{};if(!/^(?:0|[1-9]\d*)$/.test(e))throw new E(400,"invalid_request","`after` must be a non-negative integer");const t=Number(e);if(!Number.isSafeInteger(t))throw new E(400,"invalid_request","`after` must be a safe integer");return{after:t}}o(K,"parseQuery");function S(n){const{type:e,...t}=n;return`event: ${e}
1
+ var O=Object.defineProperty;var o=(n,e)=>O(n,"name",{value:e,configurable:!0});import{randomUUID as q}from"node:crypto";import{ApiError as E}from"../../../api/errors.js";import{BrokerClient as C}from"../../../core/broker-client/client.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{isPidAlive as B}from"../../../core/canvas/pid.js";import{BROKER_VIEW_SOCKET_WAIT_MS as k}from"../../../core/runtime/view-socket.js";import{toNodeOutcomeDTO as M}from"../map.js";import{reportsForNode as L}from"./reports.js";const D=15e3,$=6e4,x=250,P=512,T=256*1024,j=1e3,G=32*1024*1024;class V{static{o(this,"NodeEventRing")}events=[];bytes=0;nextSequence=1;earliestAvailable=1;append(e){const t={...e,sequence_number:this.nextSequence++},s=Buffer.byteLength(JSON.stringify(t),"utf8");if(s>T)return this.events=[],this.bytes=0,this.earliestAvailable=this.nextSequence,t;for(this.events.push(t),this.bytes+=s;this.events.length>P||this.bytes>T;){const r=this.events.shift();if(r===void 0)break;this.bytes-=Buffer.byteLength(JSON.stringify(r),"utf8"),this.earliestAvailable=r.sequence_number+1}return t}replay(e){if(e===void 0)return{gap:null,events:this.events};const t=e<this.earliestAvailable-1||e>=this.nextSequence?A(this.earliestAvailable):null;return{gap:t,events:t===null?this.events.filter(s=>s.sequence_number>e):this.events}}get empty(){return this.events.length===0}}function A(n){return{type:"error",error:{code:"stream_gap",message:"the requested event cursor is older than this daemon can resume",details:{earliest_sequence:n}}}}o(A,"streamGap");function H(n){return n===null?"arguments: null":Array.isArray(n)?`arguments: array (${n.length} items)`:typeof n=="object"?`arguments: object (${Object.keys(n).length} fields)`:`arguments: ${typeof n}`}o(H,"toolSummary");function m(n){if(typeof n!="object"||n===null)return"";const e=n.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(t=>typeof t=="object"&&t!==null).filter(t=>t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(""):""}o(m,"assistantText");class w{static{o(this,"NodeEventTranslationState")}toolSummaries=new Map;emittedAssistantText="";resetAssistantText(){this.emittedAssistantText=""}emitAssistantTextDelta(e){const t=m(e),s=t.startsWith(this.emittedAssistantText)?t.slice(this.emittedAssistantText.length):t;return this.emittedAssistantText=t,s}seedAssistantText(e){const t=m(e);return this.emittedAssistantText=t,t}}function z(n,e,t=new w){switch(e.type){case"message_start":return e.message.role==="assistant"&&t.resetAssistantText(),[];case"message_update":{if(e.message.role!=="assistant")return[];const s=t.emitAssistantTextDelta(e.message);return s===""?[]:[{type:"node.output_text.delta",node_id:n,delta:s}]}case"message_end":{if(e.message.role!=="assistant")return[];const s=m(e.message);return t.resetAssistantText(),[{type:"node.output_text.done",node_id:n,text:s}]}case"tool_execution_start":{const s=H(e.args);return t.toolSummaries.set(e.toolCallId,s),[{type:"node.tool_call.started",node_id:n,tool_call_id:e.toolCallId,tool:e.toolName,summary:s}]}case"tool_execution_end":{const s=t.toolSummaries.get(e.toolCallId)??"[arguments unavailable]";return t.toolSummaries.delete(e.toolCallId),[{type:"node.tool_call.completed",node_id:n,tool_call_id:e.toolCallId,tool:e.toolName,status:e.isError?"error":"ok",summary:s}]}case"turn_start":return[{type:"node.turn.started",node_id:n}];case"turn_end":return[{type:"node.turn.completed",node_id:n}];default:return[]}}o(z,"translateBrokerFrame");class J{static{o(this,"NodeEventHub")}nodeId;remove;ring=new V;subscribers=new Set;observer;observerErrorAt;poll;reconnect;idleClose;status;settledRevision;settledOutcome;settledSequence;snapshotSeeded=!1;reportsSeeded=!1;translationState=new w;fresh=!0;constructor(e,t){this.nodeId=e,this.remove=t}subscribe(e,t){const s=this.fresh&&e!==void 0;this.fresh=!1,this.start();const r=this.settledOutcome!==void 0,d=s?{gap:A(1),events:this.ring.replay(void 0).events}:this.ring.replay(e);r||(this.subscribers.add(t),this.status!=="dormant"&&this.openObserver());let h=!1;return queueMicrotask(()=>{if(!h){d.gap!==null&&t(d.gap);for(const l of d.events)t(l)}}),r&&this.scheduleIdleClose(),{unsubscribe:o(()=>{h=!0,r||this.unsubscribe(t)},"unsubscribe"),terminal:r}}report(e){this.settledRevision===void 0&&this.publish({type:"node.report.pushed",node_id:this.nodeId,report:e})}start(){this.idleClose!==void 0&&(clearTimeout(this.idleClose),this.idleClose=void 0),this.poll===void 0&&(this.check(),this.settledRevision===void 0&&(this.seedReports(),this.poll=setInterval(()=>this.check(),x)))}seedReports(){if(!this.reportsSeeded){this.reportsSeeded=!0;for(const e of L(this.nodeId).reverse())this.report(e)}}check(){const e=b(this.nodeId);if(e===null){this.fail("stream_error",`node ${this.nodeId} no longer exists`);return}const t=M(e);if(t!==null){this.settledRevision!==t.revision&&(this.settledRevision=t.revision,this.settledOutcome=t,this.settledSequence=this.publish({type:"node.settled",node_id:this.nodeId,outcome:t}).sequence_number,this.stopObserver(),this.stopPoll());return}const s=e.pi_pid===null?"dormant":e.status;if(s==="dormant"){this.status!=="dormant"&&(this.status=s,this.publish({type:"node.status.changed",node_id:this.nodeId,status:s}));return}this.status===void 0?this.status=s:this.status!=="dormant"&&this.status!==s&&(this.status=s,this.publish({type:"node.status.changed",node_id:this.nodeId,status:s})),this.openObserver()}openObserver(){if(this.observer!==void 0||this.subscribers.size===0)return;const e=new C(this.nodeId);this.observer=e,e.on("connect",()=>{this.observerErrorAt=void 0;const t=b(this.nodeId);this.status==="dormant"&&t!==null&&t.pi_pid!==null&&(this.status=t.status,this.publish({type:"node.status.changed",node_id:this.nodeId,status:t.status})),e.send({type:"hello",role:"observer",client_id:q(),attends:!1})}),e.on("frame",t=>{try{t.type==="welcome"&&this.seedSnapshot(t.snapshot);for(const s of z(this.nodeId,t,this.translationState))this.publish(s)}catch(s){this.fail("stream_error",s instanceof Error?s.message:String(s))}}),e.on("error",()=>{const t=b(this.nodeId),s=Date.now();t!==null&&t.pi_pid!==null&&B(t.pi_pid)&&(this.observerErrorAt??=s,s-this.observerErrorAt<k)||this.fail("stream_error","observer connection failed")}),e.on("close",()=>{this.observer===e&&(this.observer=void 0,!(this.subscribers.size===0||this.settledRevision!==void 0)&&(this.status!=="dormant"&&(this.publish({type:"node.status.changed",node_id:this.nodeId,status:"dormant"}),this.status="dormant"),this.scheduleReconnect()))}),e.connect()}seedSnapshot(e){if(this.snapshotSeeded)return;this.snapshotSeeded=!0;const t=e.messages.filter(r=>r.role==="assistant"),s=e.state.isStreaming?t.pop():void 0;for(const r of t)this.publish({type:"node.output_text.done",node_id:this.nodeId,text:m(r)});s!==void 0&&this.publish({type:"node.output_text.delta",node_id:this.nodeId,delta:this.translationState.seedAssistantText(s)})}scheduleReconnect(){this.reconnect===void 0&&(this.reconnect=setTimeout(()=>{this.reconnect=void 0,this.check()},x))}publish(e){const t=this.ring.append(e);for(const s of[...this.subscribers])s(t);return t}fail(e,t){const s={type:"error",error:{code:e,message:t}};for(const r of[...this.subscribers])r(s);this.stopObserver(),this.stopPoll()}unsubscribe(e){this.subscribers.delete(e),this.subscribers.size===0&&this.scheduleIdleClose()}scheduleIdleClose(){this.idleClose===void 0&&(this.idleClose=setTimeout(()=>{this.stopObserver(),this.stopPoll(),this.remove()},$))}stopObserver(){this.reconnect!==void 0&&(clearTimeout(this.reconnect),this.reconnect=void 0);const e=this.observer;this.observer=void 0,e?.close()}stopPoll(){this.poll!==void 0&&(clearInterval(this.poll),this.poll=void 0)}}class W{static{o(this,"NodeEventStreams")}hubs=new Map;subscribe(e,t,s){let r=this.hubs.get(e);return r===void 0&&(r=new J(e,()=>this.hubs.delete(e)),this.hubs.set(e,r)),r.subscribe(t,s)}report(e,t){this.hubs.get(e)?.report(t)}}const F=new W;function K(n){const e=n.get("after");if(e===null||e==="")return{};if(!/^(?:0|[1-9]\d*)$/.test(e))throw new E(400,"invalid_request","`after` must be a non-negative integer");const t=Number(e);if(!Number.isSafeInteger(t))throw new E(400,"invalid_request","`after` must be a safe integer");return{after:t}}o(K,"parseQuery");function I(n){const{type:e,...t}=n;return`event: ${e}
2
2
  data: ${JSON.stringify(t)}
3
3
 
4
- `}o(S,"sseRecord");async function U(n){const e=n.params.id??"";if(b(e)===null)throw new E(404,"node_not_found",`no node ${e}`);const{after:t}=K(n.query),{req:s,res:r}=n;r.writeHead(200,{"content-type":"text/event-stream; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});let d=!1,h=!1,l=!1,c=0;const u=[];let m,f;const v=o(()=>{r.writableEnded||r.end()},"finish"),p=o(()=>{if(!d){if(d=!0,f!==void 0&&clearInterval(f),m?.(),s.destroyed||r.destroyed){u.length=0,c=0,v();return}if(l||u.length>0){h=!0;return}v()}},"close"),_=o(()=>{for(l=!1;u.length>0;){const i=u.shift();if(c-=Buffer.byteLength(i,"utf8"),!r.write(i)){l=!0,r.once("drain",_);return}}h&&v()},"flush"),O=o(()=>{if(d)return;u.length=0,c=0;const i=S({type:"error",error:{code:"stream_dropped",message:"stream reader is too slow"}});u.push(i),c=Buffer.byteLength(i,"utf8"),d=!0,h=!0,f!==void 0&&clearInterval(f),m?.(),l||_()},"dropSlowReader"),y=o(i=>{if(d)return!1;if(l||u.length>0){const a=Buffer.byteLength(i,"utf8");return u.length>=j||c+a>D?(O(),!1):(u.push(i),c+=a,!0)}return r.write(i)||(l=!0,r.once("drain",_)),!0},"write"),g=o((i,a)=>{d||y(S({type:"error",error:{code:i,message:a}})),p()},"fail"),x=o(i=>{try{if(!y(S(i)))return;(i.type==="node.settled"||i.type==="error"&&i.error.code!=="stream_gap")&&p()}catch(a){g("stream_error",a instanceof Error?a.message:String(a))}},"onEvent");f=setInterval(()=>{try{d||y(`: keepalive
4
+ `}o(I,"sseRecord");async function U(n){const e=n.params.id??"";if(b(e)===null)throw new E(404,"node_not_found",`no node ${e}`);const{after:t}=K(n.query),{req:s,res:r}=n;r.writeHead(200,{"content-type":"text/event-stream; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});let d=!1,h=!1,l=!1,c=0;const u=[];let v,f;const _=o(()=>{r.writableEnded||r.end()},"finish"),p=o(()=>{if(!d){if(d=!0,f!==void 0&&clearInterval(f),v?.(),s.destroyed||r.destroyed){u.length=0,c=0,_();return}if(l||u.length>0){h=!0;return}_()}},"close"),g=o(()=>{for(l=!1;u.length>0;){const i=u.shift();if(c-=Buffer.byteLength(i,"utf8"),!r.write(i)){l=!0,r.once("drain",g);return}}h&&_()},"flush"),N=o(()=>{if(d)return;u.length=0,c=0;const i=I({type:"error",error:{code:"stream_dropped",message:"stream reader is too slow"}});u.push(i),c=Buffer.byteLength(i,"utf8"),d=!0,h=!0,f!==void 0&&clearInterval(f),v?.(),l||g()},"dropSlowReader"),y=o(i=>{if(d)return!1;if(l||u.length>0){const a=Buffer.byteLength(i,"utf8");return u.length>=j||c+a>G?(N(),!1):(u.push(i),c+=a,!0)}return r.write(i)||(l=!0,r.once("drain",g)),!0},"write"),S=o((i,a)=>{d||y(I({type:"error",error:{code:i,message:a}})),p()},"fail"),R=o(i=>{try{if(!y(I(i)))return;(i.type==="node.settled"||i.type==="error"&&i.error.code!=="stream_gap")&&p()}catch(a){S("stream_error",a instanceof Error?a.message:String(a))}},"onEvent");f=setInterval(()=>{try{d||y(`: keepalive
5
5
 
6
- `)}catch(i){g("stream_error",i instanceof Error?i.message:String(i))}},L),s.once("close",p);try{const i=F.subscribe(e,t,x);m=i.unsubscribe,i.terminal&&queueMicrotask(p)}catch(i){g("stream_error",i instanceof Error?i.message:String(i))}return{status:200}}o(U,"handleEvents");const re=[{method:"GET",pattern:"/v1/nodes/:id/events",handler:U}];export{G as NodeEventRing,re as nodeEventRoutes,F as nodeEventStreams,H as translateBrokerFrame};
6
+ `)}catch(i){S("stream_error",i instanceof Error?i.message:String(i))}},D),s.once("close",p);try{const i=F.subscribe(e,t,R);v=i.unsubscribe,i.terminal&&queueMicrotask(p)}catch(i){S("stream_error",i instanceof Error?i.message:String(i))}return{status:200}}o(U,"handleEvents");const ie=[{method:"GET",pattern:"/v1/nodes/:id/events",handler:U}];export{V as NodeEventRing,w as NodeEventTranslationState,ie as nodeEventRoutes,F as nodeEventStreams,z as translateBrokerFrame};
@@ -14,7 +14,7 @@ Set `baseUrl` only when `request.url` is not the public URL, such as a proxy tha
14
14
 
15
15
  ## Authentication
16
16
 
17
- Pass `token` to require `Authorization: Bearer <token>` on archive and command requests. `--auth-env NAME` tells crtr which environment variable on the calling machine holds that value. It does not configure the server. Omitting `token` serves without authentication and logs a warning when the handler is created.
17
+ Pass `token` to require `Authorization: Bearer <token>` on archive and command requests. `--auth-env NAME` tells crtr which environment variable of the calling process holds that value. It does not configure the server. For a command an agent runs, the calling process is its broker, which reads the profile env store (`crtr profile env set <profile> --name NAME`) rather than your shell's exports. Omitting `token` serves without authentication and logs a warning when the handler is created.
18
18
 
19
19
  ## Archive response
20
20
 
@@ -9,6 +9,8 @@ crtr pkg plugin install --endpoint https://acme.example.com/crtr --name acme --a
9
9
  crtr acme app create my-app --region eu-west
10
10
  ```
11
11
 
12
+ `export` covers commands you type yourself. An agent's `crtr acme …` runs inside its broker, whose env comes from the profile env store, not from your shell — so for agents, store the token there too: `echo -n "$ACME_CRTR_TOKEN" | crtr profile env set <profile> --name ACME_CRTR_TOKEN`. Nodes launched under that profile from then on carry it.
13
+
12
14
  The endpoint receives `GET` to provide the install archive and `POST` to run a command. A successful non-streaming command response is the bare JSON object returned by the handler, for example `{ "appId": "app_my-app", "url": "https://my-app.eu-west.acme.example.com" }`. It is not an exec-style protocol envelope.
13
15
 
14
16
  Run `crtr pkg plugin show acme` after installation to inspect the installed command tree, and `crtr sys doctor` to check the installed package. A plugin name collision with crtr or another installed plugin is determined during installation and cannot be predicted from an application repository alone.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.327",
3
+ "version": "0.3.329",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.327",
3
+ "version": "0.3.329",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.327",
9
+ "version": "0.3.329",
10
10
  "hasInstallScript": true,
11
11
  "license": "GPL-3.0-only",
12
12
  "workspaces": [
@@ -4795,25 +4795,25 @@
4795
4795
  },
4796
4796
  "packages/crouter-api": {
4797
4797
  "name": "@north-light/crouter-api",
4798
- "version": "0.3.327",
4798
+ "version": "0.3.329",
4799
4799
  "license": "GPL-3.0-only"
4800
4800
  },
4801
4801
  "packages/crouter-env-docker": {
4802
4802
  "name": "@north-light/crouter-env-docker",
4803
- "version": "0.3.327",
4803
+ "version": "0.3.329",
4804
4804
  "license": "GPL-3.0-only"
4805
4805
  },
4806
4806
  "packages/crouter-plugin": {
4807
4807
  "name": "@north-light/crouter-plugin",
4808
- "version": "0.3.327",
4808
+ "version": "0.3.329",
4809
4809
  "license": "GPL-3.0-only",
4810
4810
  "dependencies": {
4811
- "@north-light/crouter-api": "^0.3.327"
4811
+ "@north-light/crouter-api": "^0.3.329"
4812
4812
  }
4813
4813
  },
4814
4814
  "packages/crouter-sdk": {
4815
4815
  "name": "@north-light/crouter-sdk",
4816
- "version": "0.3.327",
4816
+ "version": "0.3.329",
4817
4817
  "license": "GPL-3.0-only",
4818
4818
  "dependencies": {
4819
4819
  "@north-light/crouter-api": "^0.3.322"