@north-light/crouter 0.3.322 → 0.3.324

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/bin/progress-painter.mjs +89 -0
  2. package/bin/runtime-selector.mjs +79 -9
  3. package/dist/api/client.d.ts +6 -2
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/broker-ops.d.ts +9 -0
  6. package/dist/api/dto/canvas.d.ts +23 -1
  7. package/dist/api/dto/nodes.d.ts +8 -0
  8. package/dist/api/node-transport.js +1 -1
  9. package/dist/api/routes.d.ts +2 -0
  10. package/dist/api/routes.js +1 -1
  11. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  12. package/dist/clients/attach/overlays/graph.d.ts +6 -5
  13. package/dist/clients/attach/overlays/graph.js +1 -1
  14. package/dist/clients/attach/viewer.js +536 -536
  15. package/dist/commands/node/create.js +3 -3
  16. package/dist/commands/sys/panels/plugins-panel.js +1 -1
  17. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  18. package/dist/commands/sys/panels/provider-panel.js +1 -1
  19. package/dist/commands/sys/setup-core.js +7 -4
  20. package/dist/commands/sys/setup-wizard.d.ts +1 -1
  21. package/dist/commands/sys/setup-wizard.js +1 -1
  22. package/dist/core/canvas/canvas.d.ts +24 -0
  23. package/dist/core/canvas/canvas.js +29 -15
  24. package/dist/core/canvas/migrations.js +35 -32
  25. package/dist/core/canvas/nav-model.d.ts +1 -1
  26. package/dist/core/canvas/nav-model.js +1 -1
  27. package/dist/core/canvas/nav-render.d.ts +31 -25
  28. package/dist/core/canvas/nav-render.js +1 -1
  29. package/dist/core/canvas/render-source.d.ts +6 -16
  30. package/dist/core/canvas/render-source.js +9 -9
  31. package/dist/core/canvas/types.d.ts +16 -0
  32. package/dist/core/provider-credential.d.ts +6 -0
  33. package/dist/core/provider-credential.js +1 -0
  34. package/dist/core/runtime/boot-root.d.ts +2 -0
  35. package/dist/core/runtime/boot-root.js +5 -1
  36. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -1
  37. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  38. package/dist/core/runtime/front-door-login.d.ts +2 -0
  39. package/dist/core/runtime/front-door-login.js +1 -0
  40. package/dist/core/runtime/front-door.js +7 -5
  41. package/dist/core/runtime/nerd-font.d.ts +19 -1
  42. package/dist/core/runtime/nerd-font.js +2 -2
  43. package/dist/core/runtime/progress-bar.d.ts +13 -0
  44. package/dist/core/runtime/progress-bar.js +2 -0
  45. package/dist/core/runtime/provider-credential-gate.d.ts +4 -0
  46. package/dist/core/runtime/provider-credential-gate.js +2 -0
  47. package/dist/core/runtime/spawn-env.d.ts +7 -0
  48. package/dist/core/runtime/spawn-env.js +1 -1
  49. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  50. package/dist/daemon/api/handlers/canvas.js +4 -4
  51. package/dist/daemon/api/map.d.ts +15 -1
  52. package/dist/daemon/api/map.js +2 -2
  53. package/dist/daemon/fleet.js +1 -1
  54. package/dist/pi-extensions/canvas-stophook.js +1 -1
  55. package/package.json +1 -1
  56. package/runtime.lock.json +5 -5
  57. package/scripts/install-runtime.mjs +7 -3
@@ -1,10 +1,10 @@
1
- var W=Object.defineProperty;var u=(t,e)=>W(t,"name",{value:e,configurable:!0});import{existsSync as $,readFileSync as g,readdirSync as H,statSync as C,openSync as Z,readSync as q,closeSync as K}from"node:fs";import{join as S}from"node:path";import{RemoteCanvasSource as y}from"./remote-canvas-source.js";import{fullName as N}from"./labels.js";import{jobDir as A,contextDir as Q,reportsDir as j}from"./paths.js";import{readNodeRecap as X}from"./node-recap.js";import{parseFrontmatterGeneric as I}from"../frontmatter.js";import{isFrozenRow as P,resolveNodeVisual as L,faultSummary as M}from"./status-glyph.js";import{parseCard as z}from"../../shared/generated-context.js";function b(t){const e=S(A(t),"telemetry.json");if(!$(e))return{};try{return JSON.parse(g(e,"utf8"))}catch{return{}}}u(b,"readNodeTelemetry");function w(t){return t===void 0||t===0?"0k":`${Math.floor(t/1e3)}k`}u(w,"fmtCtx");function tt(t,e,n,r,a,f){if(t===void 0)return`${n}${r}? <missing meta: ${e}>`;const i=t.fault??null,s=L(t.status,{hanging:i,frozen:P(t)}).glyph,o=a?"0k":w(b(e).tokens_in),c=f[e]??0,d=c>0?` \u2691${c}`:"",p=i!==null?` \xB7 ${M(i)}`:"";return`${n}${r}${s} ${N(t)} [${t.kind}/${t.mode}] ctx ${o}${d}${p}`}u(tt,"nodeLineFromSource");async function E(t,e,n,r,a,f,i,s,o){if(f.has(n))return;f.add(n);const c=a?"\u2514\u2500 ":"\u251C\u2500 ";i.push(tt(e.get(n),n,r,c,s,o));const d=r+(a?" ":"\u2502 ");let p;try{p=await t.subscriptionsOf(n)}catch(l){i.push(`${d}\u26A0 children unavailable: ${l instanceof Error?l.message:String(l)}`);return}for(let l=0;l<p.length;l++){const h=p[l],k=l===p.length-1;if(f.has(h.node_id)){const O=k?"\u2514\u2500 ":"\u251C\u2500 ";i.push(`${d}${O}\u21BA <cycle: ${h.node_id}>`);continue}await E(t,e,h.node_id,d,k,f,i,s,o)}}u(E,"walkTreeFromSource");async function et(t,e,n,r,a){const f=t instanceof y,i=new Map((n??await t.listNodes()).map(m=>[m.node_id,m])),s=i.get(e);if(s===void 0)return`? <missing node: ${e}>`;let o=r,c=a??null;if(o===void 0)try{o=await t.ticketCountsForView(e)}catch(m){o={},c=m instanceof Error?m.message:String(m)}const d=f?"0k":w(b(e).tokens_in),p=o[e]??0,l=p>0?` \u2691${p}`:"",h=s.fault??null,k=L(s.status,{hanging:h,frozen:P(s)}).glyph,O=h!==null?` \xB7 ${M(h)}`:"",_=[];_.push(`${k} ${N(s)} [${s.kind}/${s.mode}] ctx ${d}${l}${O}`);const U=new Set([e]);let x;try{x=await t.subscriptionsOf(e)}catch(m){_.push(`\u26A0 children unavailable: ${m instanceof Error?m.message:String(m)}`),x=[]}for(let m=0;m<x.length;m++){const Y=x[m],B=m===x.length-1;await E(t,i,Y.node_id,"",B,U,_,f,o)}return c!==null&&_.push(`Tickets: unavailable (${c}).`),_.join(`
2
- `)}u(et,"renderTreeFromSource");async function bt(t,e,n,r){const a=e??await t.listNodes();if(a.length===0)return"(canvas is empty)";const f=a.filter(s=>s.parent===null&&(s.status==="active"||s.status==="idle"));if(f.length===0)return"(no live roots)";const i=[];for(const s of f)i.push(await et(t,s.node_id,a,n,r));return i.join(`
1
+ var Y=Object.defineProperty;var f=(t,e)=>Y(t,"name",{value:e,configurable:!0});import{existsSync as b,readFileSync as _,readdirSync as B,statSync as U,openSync as W,readSync as H,closeSync as Z}from"node:fs";import{join as T}from"node:path";import{RemoteCanvasSource as x}from"./remote-canvas-source.js";import{fullName as $}from"./labels.js";import{jobDir as q,contextDir as K,reportsDir as R}from"./paths.js";import{readNodeRecap as Q}from"./node-recap.js";import{parseFrontmatterGeneric as X}from"../frontmatter.js";import{isFrozenRow as v,resolveNodeVisual as C,faultSummary as P}from"./status-glyph.js";import{parseCard as L}from"../../shared/generated-context.js";function j(t){return t===void 0||t===0?"0k":`${Math.floor(t/1e3)}k`}f(j,"fmtCtx");function I(t,e,n,i,c,a){if(t===void 0)return`${n}${i}? <missing meta: ${e}>`;const s=t.fault??null,r=C(t.status,{hanging:s,frozen:v(t)}).glyph,o=c?"0k":j(t.telemetry_tokens_in??void 0),u=a[e]??0,m=u>0?` \u2691${u}`:"",d=s!==null?` \xB7 ${P(s)}`:"";return`${n}${i}${r} ${$(t)} [${t.kind}/${t.mode}] ctx ${o}${m}${d}`}f(I,"nodeLineFromSource");async function z(t,e,n,i,c,a,s,r,o){if(a.has(n))return;a.add(n);const u=c?"\u2514\u2500 ":"\u251C\u2500 ";s.push(I(e.get(n),n,i,u,r,o));const m=i+(c?" ":"\u2502 ");let d;try{d=await t.subscriptionsOf(n)}catch(l){s.push(`${m}\u26A0 children unavailable: ${l instanceof Error?l.message:String(l)}`);return}for(let l=0;l<d.length;l++){const h=d[l],S=l===d.length-1;if(a.has(h.node_id)){const N=S?"\u2514\u2500 ":"\u251C\u2500 ";s.push(`${m}${N}\u21BA <cycle: ${h.node_id}>`);continue}await z(t,e,h.node_id,m,S,a,s,r,o)}}f(z,"walkTreeFromSource");async function tt(t,e,n,i,c){const a=t instanceof x,s=new Map((n??await t.listNodes()).map(p=>[p.node_id,p])),r=s.get(e);if(r===void 0)return`? <missing node: ${e}>`;let o=i,u=c??null;if(o===void 0)try{o=await t.ticketCountsForView(e)}catch(p){o={},u=p instanceof Error?p.message:String(p)}const m=a?"0k":j(r.telemetry_tokens_in??void 0),d=o[e]??0,l=d>0?` \u2691${d}`:"",h=r.fault??null,S=C(r.status,{hanging:h,frozen:v(r)}).glyph,N=h!==null?` \xB7 ${P(h)}`:"",g=[];g.push(`${S} ${$(r)} [${r.kind}/${r.mode}] ctx ${m}${l}${N}`);const V=new Set([e]);let y;try{y=await t.subscriptionsOf(e)}catch(p){g.push(`\u26A0 children unavailable: ${p instanceof Error?p.message:String(p)}`),y=[]}for(let p=0;p<y.length;p++){const G=y[p],J=p===y.length-1;await z(t,s,G.node_id,"",J,V,g,a,o)}return u!==null&&g.push(`Tickets: unavailable (${u}).`),g.join(`
2
+ `)}f(tt,"renderTreeFromSource");async function Nt(t,e,n,i){const c=e??await t.listNodes();if(c.length===0)return"(canvas is empty)";const a=c.filter(r=>r.parent===null&&(r.status==="active"||r.status==="idle"));if(a.length===0)return"(no live roots)";const s=[];for(const r of a)s.push(await tt(t,r.node_id,c,n,i));return s.join(`
3
3
 
4
- `)}u(bt,"renderForestFromSource");const D=4096;function nt(t){try{const e=S(Q(t),"initial-prompt.md");if(!$(e))return;const n=g(e,"utf8").trim();return n===""?void 0:n.length>D?n.slice(0,D):n}catch{return}}u(nt,"readGoalText");const F=1024;function rt(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})?$/);if(e!==null)return`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}.${e[7]??"000"}Z`}u(rt,"reportStampToIso");function it(t){let e;try{for(const l of H(j(t)))l.endsWith(".md")&&(e===void 0||l>e)&&(e=l)}catch{return}if(e===void 0)return;let n;try{n=g(S(j(t),e),"utf8")}catch{return}const{data:r,body:a}=I(n),f=e.replace(/\.md$/,""),i=typeof r?.kind=="string"?r.kind:f.split("-").pop()??"report",s=typeof r?.ts=="string"?r.ts:rt(f.split("-")[0]??"")??"",o=a.split(`
5
- `);let c="",d=a;for(let l=0;l<o.length;l++){const h=(o[l]??"").trim();if(h!==""){c=h.startsWith("#")?h.replace(/^#+\s*/,"").trim():h,d=o.slice(l+1).join(`
6
- `);break}}const p=d.replace(/\s+/g," ").trim();return{kind:i,ts:s,heading:c,body:p.length>F?p.slice(0,F):p}}u(it,"readNewestReport");const st=1<<20,ot=1<<20,at=4<<20;function J(t,e,n){if(t==null||t==="")return null;try{if(!$(t))return null;const r=C(t).size;if(r<=e+n){const f=g(t,"utf8").split(`
7
- `);return{head:f,tail:f}}const a=Z(t,"r");try{const f=u((o,c)=>{if(c<=0)return[];const d=Buffer.allocUnsafe(c),p=q(a,d,0,c,o);return d.subarray(0,p).toString("utf8").split(`
8
- `)},"slice"),i=f(0,e),s=f(r-n,n);return i.length>0&&i.pop(),s.length>0&&s.shift(),{head:i,tail:s}}finally{K(a)}}catch{return null}}u(J,"readSessionWindow");const R=8192,T=2048;function ct(t){const e=J(t,st,ot);if(e===null)return{};const n=[];let r=0;for(const i of e.head){if(i===""||i.indexOf('"role":"user"')===-1&&i.indexOf('"role": "user"')===-1)continue;let s;try{s=JSON.parse(i)}catch{continue}if(s.type!=="message"||s.message?.role!=="user")continue;const o=v(s.message.content);if(o===""||z({role:"user",content:o})!==null)continue;const c=o.length>T?o.slice(0,T):o;if(n.push(c),r+=c.length+1,r>=R)break}let a;if(n.length>0){const i=n.join(`
9
- `);a=i.length>R?i.slice(0,R):i}let f;for(let i=e.tail.length-1;i>=0;i--){const s=e.tail[i];if(s===""||s.indexOf('"role":"assistant"')===-1&&s.indexOf('"role": "assistant"')===-1)continue;let o;try{o=JSON.parse(s)}catch{continue}if(o.type!=="message"||o.message?.role!=="assistant")continue;const c=v(o.message.content);if(c!==""){f=c.length>T?c.slice(0,T):c;break}}return{prompts:a,lastAssistant:f}}u(ct,"readSessionParts");const V=120,G=4096;function ft(t){const e=J(t,0,at);if(e===null)return[];const n=[];for(const r of e.tail){if(r==="")continue;const a=r.indexOf('"role":"user"')!==-1||r.indexOf('"role": "user"')!==-1,f=!a&&(r.indexOf('"role":"assistant"')!==-1||r.indexOf('"role": "assistant"')!==-1);if(!a&&!f)continue;let i;try{i=JSON.parse(r)}catch{continue}if(i.type!=="message")continue;const s=i.message?.role;if(s!=="user"&&s!=="assistant")continue;const o=v(i.message?.content);o!==""&&z({role:s,content:o})===null&&n.push({role:s,text:o.length>G?o.slice(0,G):o})}return n.length>V?n.slice(n.length-V):n}u(ft,"readTranscript");function Tt(t){if(t==null||t==="")return!1;let e;try{if(!$(t))return!1;e=g(t,"utf8").split(`
10
- `)}catch{return!1}for(const n of e){if(n===""||n.indexOf('"role":"assistant"')===-1&&n.indexOf('"role": "assistant"')===-1)continue;let r;try{r=JSON.parse(n)}catch{continue}if(!(r.type!=="message"||r.message?.role!=="assistant")&&ut(r.message.content))return!0}return!1}u(Tt,"nodeHasAssistantMessage");function ut(t){if(typeof t=="string")return t.trim()!=="";if(!Array.isArray(t))return!1;for(const e of t){if(e===null||typeof e!="object")continue;const n=e,r=(n.type??"").toLowerCase();if(r==="text"){if(typeof n.text=="string"&&n.text.trim()!=="")return!0}else if(r==="thinking"){if(typeof n.thinking=="string"&&n.thinking.trim()!=="")return!0}else return!0}return!1}u(ut,"assistantContentIsSubstantive");function v(t){if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";const e=[];for(const n of t)if(n!==null&&typeof n=="object"){const r=n;r.type==="text"&&typeof r.text=="string"&&e.push(r.text)}return e.join(" ").trim()}u(v,"extractUserText");function lt(t,e,n=!1){if(!n)try{const a=C(S(A(t),"telemetry.json"),{throwIfNoEntry:!1});if(a!==void 0)return a.mtimeMs}catch{}const r=Date.parse(e);return Number.isNaN(r)?0:r}u(lt,"sessionMtime");function dt(t){if(t.status!=="active")return!1;try{const e=JSON.parse(g(S(A(t.node_id),"attach.json"),"utf8"));return typeof e.viewers=="number"&&e.viewers>0}catch{return!1}}u(dt,"hasLiveBrokerViewer");function pt(t,e,n){const r=t.status==="active"||t.status==="idle",a=t.fault??null;return{node_id:t.node_id,name:N(t),handle:t.name,description:t.description,status:t.status,frozen_at:t.frozen_at??null,terminal_reason:t.terminal_reason??null,kind:t.kind,mode:t.mode,ctx_tokens:0,asks:0,cwd:t.cwd,profile_id:t.profile_id,created:t.created,lifecycle:t.lifecycle,finalized:t.final_report!=null,mtimeMs:lt(t.node_id,t.created,n),streaming:a===null&&r&&t.streaming===!0,hanging:a,viewed:n?!1:e.has(t.node_id)||dt(t),srcRow:t}}u(pt,"dashboardRowFromNodeRow");async function Ot(t,e,n,r){const a=t instanceof y,f=r??await t.ticketCountsForView(e).catch(()=>({})),i=new Map((n??await t.listNodes()).map(o=>[o.node_id,o]));return[e,...await t.view(e)].flatMap(o=>{const c=i.get(o);if(c===void 0)return[];const d=a?{}:b(o);return[{node_id:o,name:N(c),handle:c.name,description:c.description,status:c.status,frozen_at:c.frozen_at??null,terminal_reason:c.terminal_reason??null,kind:c.kind,mode:c.mode,ctx_tokens:d.tokens_in??0,asks:f[o]??0,cwd:c.cwd,profile_id:c.profile_id,created:c.created}]})}u(Ot,"dashboardRowsFromSource");async function At(t,e=new Set,n=!1,r){const a=t instanceof y,f=a?new Set:e;return(r??await t.listNodes(n?{status:["active","idle"]}:void 0)).map(s=>pt(s,f,a))}u(At,"dashboardRowsAllFromSource");async function Rt(t,e,n){const r=e.filter(i=>i.enriched!==!0);if(r.length===0)return;const a=t instanceof y,f=n??{};for(const i of r)i.ctx_tokens=a?0:b(i.node_id).tokens_in??0,i.asks=f[i.node_id]??0,i.enriched=!0}u(Rt,"enrichRowsFromSource");async function vt(t,e){if(e.previewLoaded===!0)return e;const n=t instanceof y;if(e.goal=n?void 0:nt(e.node_id),!n){const r=await t.getNode(e.node_id),{prompts:a,lastAssistant:f}=ct(r?.pi_session_file);e.prompts=a,e.lastAssistant=f,e.recap=X(e.node_id),e.report=it(e.node_id)}return e.previewLoaded=!0,e}u(vt,"loadPreviewFromSource");async function Ct(t,e){if(e.transcriptLoaded===!0)return e;if(t instanceof y)return e.transcript=[],e.transcriptLoaded=!0,e;const n=await t.getNode(e.node_id);return e.transcript=ft(n?.pi_session_file),e.transcriptLoaded=!0,e}u(Ct,"loadTranscriptFromSource");export{pt as dashboardRowFromNodeRow,At as dashboardRowsAllFromSource,Ot as dashboardRowsFromSource,Rt as enrichRowsFromSource,w as fmtCtx,vt as loadPreviewFromSource,Ct as loadTranscriptFromSource,Tt as nodeHasAssistantMessage,nt as readGoalText,it as readNewestReport,b as readNodeTelemetry,ct as readSessionParts,ft as readTranscript,bt as renderForestFromSource,et as renderTreeFromSource,lt as sessionMtime};
4
+ `)}f(Nt,"renderForestFromSource");const M=4096;function et(t){try{const e=T(K(t),"initial-prompt.md");if(!b(e))return;const n=_(e,"utf8").trim();return n===""?void 0:n.length>M?n.slice(0,M):n}catch{return}}f(et,"readGoalText");const E=1024;function nt(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})?$/);if(e!==null)return`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}.${e[7]??"000"}Z`}f(nt,"reportStampToIso");function it(t){let e;try{for(const l of B(R(t)))l.endsWith(".md")&&(e===void 0||l>e)&&(e=l)}catch{return}if(e===void 0)return;let n;try{n=_(T(R(t),e),"utf8")}catch{return}const{data:i,body:c}=X(n),a=e.replace(/\.md$/,""),s=typeof i?.kind=="string"?i.kind:a.split("-").pop()??"report",r=typeof i?.ts=="string"?i.ts:nt(a.split("-")[0]??"")??"",o=c.split(`
5
+ `);let u="",m=c;for(let l=0;l<o.length;l++){const h=(o[l]??"").trim();if(h!==""){u=h.startsWith("#")?h.replace(/^#+\s*/,"").trim():h,m=o.slice(l+1).join(`
6
+ `);break}}const d=m.replace(/\s+/g," ").trim();return{kind:s,ts:r,heading:u,body:d.length>E?d.slice(0,E):d}}f(it,"readNewestReport");const rt=1<<20,st=1<<20,ot=4<<20;function w(t,e,n){if(t==null||t==="")return null;try{if(!b(t))return null;const i=U(t).size;if(i<=e+n){const a=_(t,"utf8").split(`
7
+ `);return{head:a,tail:a}}const c=W(t,"r");try{const a=f((o,u)=>{if(u<=0)return[];const m=Buffer.allocUnsafe(u),d=H(c,m,0,u,o);return m.subarray(0,d).toString("utf8").split(`
8
+ `)},"slice"),s=a(0,e),r=a(i-n,n);return s.length>0&&s.pop(),r.length>0&&r.shift(),{head:s,tail:r}}finally{Z(c)}}catch{return null}}f(w,"readSessionWindow");const O=8192,k=2048;function at(t){const e=w(t,rt,st);if(e===null)return{};const n=[];let i=0;for(const s of e.head){if(s===""||s.indexOf('"role":"user"')===-1&&s.indexOf('"role": "user"')===-1)continue;let r;try{r=JSON.parse(s)}catch{continue}if(r.type!=="message"||r.message?.role!=="user")continue;const o=A(r.message.content);if(o===""||L({role:"user",content:o})!==null)continue;const u=o.length>k?o.slice(0,k):o;if(n.push(u),i+=u.length+1,i>=O)break}let c;if(n.length>0){const s=n.join(`
9
+ `);c=s.length>O?s.slice(0,O):s}let a;for(let s=e.tail.length-1;s>=0;s--){const r=e.tail[s];if(r===""||r.indexOf('"role":"assistant"')===-1&&r.indexOf('"role": "assistant"')===-1)continue;let o;try{o=JSON.parse(r)}catch{continue}if(o.type!=="message"||o.message?.role!=="assistant")continue;const u=A(o.message.content);if(u!==""){a=u.length>k?u.slice(0,k):u;break}}return{prompts:c,lastAssistant:a}}f(at,"readSessionParts");const D=120,F=4096;function ct(t){const e=w(t,0,ot);if(e===null)return[];const n=[];for(const i of e.tail){if(i==="")continue;const c=i.indexOf('"role":"user"')!==-1||i.indexOf('"role": "user"')!==-1,a=!c&&(i.indexOf('"role":"assistant"')!==-1||i.indexOf('"role": "assistant"')!==-1);if(!c&&!a)continue;let s;try{s=JSON.parse(i)}catch{continue}if(s.type!=="message")continue;const r=s.message?.role;if(r!=="user"&&r!=="assistant")continue;const o=A(s.message?.content);o!==""&&L({role:r,content:o})===null&&n.push({role:r,text:o.length>F?o.slice(0,F):o})}return n.length>D?n.slice(n.length-D):n}f(ct,"readTranscript");function bt(t){if(t==null||t==="")return!1;let e;try{if(!b(t))return!1;e=_(t,"utf8").split(`
10
+ `)}catch{return!1}for(const n of e){if(n===""||n.indexOf('"role":"assistant"')===-1&&n.indexOf('"role": "assistant"')===-1)continue;let i;try{i=JSON.parse(n)}catch{continue}if(!(i.type!=="message"||i.message?.role!=="assistant")&&ut(i.message.content))return!0}return!1}f(bt,"nodeHasAssistantMessage");function ut(t){if(typeof t=="string")return t.trim()!=="";if(!Array.isArray(t))return!1;for(const e of t){if(e===null||typeof e!="object")continue;const n=e,i=(n.type??"").toLowerCase();if(i==="text"){if(typeof n.text=="string"&&n.text.trim()!=="")return!0}else if(i==="thinking"){if(typeof n.thinking=="string"&&n.thinking.trim()!=="")return!0}else return!0}return!1}f(ut,"assistantContentIsSubstantive");function A(t){if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";const e=[];for(const n of t)if(n!==null&&typeof n=="object"){const i=n;i.type==="text"&&typeof i.text=="string"&&e.push(i.text)}return e.join(" ").trim()}f(A,"extractUserText");function ft(t,e,n=!1){if(!n&&e!==null&&e!==void 0){const c=Date.parse(e);if(!Number.isNaN(c))return c}const i=Date.parse(t);return Number.isNaN(i)?0:i}f(ft,"sessionMtime");function lt(t){if(t.status!=="active")return!1;try{const e=JSON.parse(_(T(q(t.node_id),"attach.json"),"utf8"));return typeof e.viewers=="number"&&e.viewers>0}catch{return!1}}f(lt,"hasLiveBrokerViewer");function dt(t,e,n){const i=t.status==="active"||t.status==="idle",c=t.fault??null;return{node_id:t.node_id,name:$(t),handle:t.name,description:t.description,status:t.status,frozen_at:t.frozen_at??null,terminal_reason:t.terminal_reason??null,kind:t.kind,mode:t.mode,ctx_tokens:n?0:t.telemetry_tokens_in??0,asks:0,cwd:t.cwd,profile_id:t.profile_id,created:t.created,lifecycle:t.lifecycle,finalized:t.final_report!=null,mtimeMs:ft(t.created,t.telemetry_updated_at,n),streaming:c===null&&i&&t.streaming===!0,hanging:c,viewed:n?!1:e.has(t.node_id)||lt(t),srcRow:t}}f(dt,"dashboardRowFromNodeRow");async function Tt(t,e,n,i){const c=t instanceof x,a=i??await t.ticketCountsForView(e).catch(()=>({})),s=new Map((n??await t.listNodes()).map(o=>[o.node_id,o]));return[e,...await t.view(e)].flatMap(o=>{const u=s.get(o);return u===void 0?[]:[{node_id:o,name:$(u),handle:u.name,description:u.description,status:u.status,frozen_at:u.frozen_at??null,terminal_reason:u.terminal_reason??null,kind:u.kind,mode:u.mode,ctx_tokens:c?0:u.telemetry_tokens_in??0,asks:a[o]??0,cwd:u.cwd,profile_id:u.profile_id,created:u.created}]})}f(Tt,"dashboardRowsFromSource");async function Ot(t,e=new Set,n=!1,i){const c=t instanceof x,a=c?new Set:e;return(i??await t.listNodes(n?{status:["active","idle"]}:void 0)).map(r=>dt(r,a,c))}f(Ot,"dashboardRowsAllFromSource");async function At(t,e,n){const i=e.filter(a=>a.enriched!==!0);if(i.length===0)return;const c=n??{};for(const a of i)a.asks=c[a.node_id]??0,a.enriched=!0}f(At,"enrichRowsFromSource");async function Rt(t,e){if(e.previewLoaded===!0)return e;const n=t instanceof x;if(e.goal=n?void 0:et(e.node_id),!n){const i=await t.getNode(e.node_id),{prompts:c,lastAssistant:a}=at(i?.pi_session_file);e.prompts=c,e.lastAssistant=a,e.recap=Q(e.node_id),e.report=it(e.node_id)}return e.previewLoaded=!0,e}f(Rt,"loadPreviewFromSource");async function vt(t,e){if(e.transcriptLoaded===!0)return e;if(t instanceof x)return e.transcript=[],e.transcriptLoaded=!0,e;const n=await t.getNode(e.node_id);return e.transcript=ct(n?.pi_session_file),e.transcriptLoaded=!0,e}f(vt,"loadTranscriptFromSource");export{dt as dashboardRowFromNodeRow,Ot as dashboardRowsAllFromSource,Tt as dashboardRowsFromSource,At as enrichRowsFromSource,j as fmtCtx,Rt as loadPreviewFromSource,vt as loadTranscriptFromSource,bt as nodeHasAssistantMessage,et as readGoalText,it as readNewestReport,at as readSessionParts,ct as readTranscript,Nt as renderForestFromSource,tt as renderTreeFromSource,ft as sessionMtime};
@@ -294,6 +294,14 @@ export interface NodeRuntime {
294
294
  outcome_detail_json?: string | null;
295
295
  /** Absolute wall-clock spawn deadline, or null when unbounded. */
296
296
  deadline_at?: string | null;
297
+ /** Cumulative input tokens reported by the broker telemetry producer. */
298
+ telemetry_tokens_in?: number | null;
299
+ /** Latest live context-window token gauge reported by the broker. */
300
+ telemetry_context_tokens?: number | null;
301
+ /** Latest tool summary reported by the broker. */
302
+ telemetry_last_activity?: string | null;
303
+ /** Timestamp of the latest broker telemetry update. */
304
+ telemetry_updated_at?: string | null;
297
305
  /** OS pid of the live broker process, recorded on boot (stophook session_start).
298
306
  * The daemon's authoritative liveness signal — every node is a detached broker,
299
307
  * so `isPidAlive(pi_pid)` is the sole liveness check. Cleared to null by
@@ -381,6 +389,14 @@ export interface NodeRow {
381
389
  outcome_revision?: number;
382
390
  outcome_detail_json?: string | null;
383
391
  deadline_at?: string | null;
392
+ /** Cumulative input tokens reported by the broker telemetry producer. */
393
+ telemetry_tokens_in?: number | null;
394
+ /** Latest live context-window token gauge reported by the broker. */
395
+ telemetry_context_tokens?: number | null;
396
+ /** Latest tool summary reported by the broker. */
397
+ telemetry_last_activity?: string | null;
398
+ /** Timestamp of the latest broker telemetry update. */
399
+ telemetry_updated_at?: string | null;
384
400
  pi_pid: number | null;
385
401
  /** See `NodeRuntime.pi_pid_identity`. */
386
402
  pi_pid_identity: string | null;
@@ -0,0 +1,6 @@
1
+ import type { ModelRegistry, ModelRuntime } from '@earendil-works/pi-coding-agent';
2
+ /** Whether the provider has a credential crouter can use. This is the same
3
+ * configured predicate shown by the setup Providers panel. */
4
+ export declare function isProviderCredentialConfigured(providerId: string, registry: ModelRegistry): boolean;
5
+ /** Whether any provider in the setup catalog has a usable configured credential. */
6
+ export declare function hasProviderCredential(runtime: ModelRuntime, registry: ModelRegistry): boolean;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var t=(e,r)=>i(e,"name",{value:r,configurable:!0});import{isManagedProvider as n,readSubscriptionPool as d}from"./subscription-state.js";function a(e,r){return r.getProviderAuthStatus(e).configured||n(e)&&d(e).length>0}t(a,"isProviderCredentialConfigured");function g(e,r){return[...new Set([...e.getProviders().map(o=>o.id),...r.getAll().map(o=>o.provider)])].some(o=>a(o,r))}t(g,"hasProviderCredential");export{g as hasProviderCredential,a as isProviderCredentialConfigured};
@@ -11,6 +11,8 @@ export interface BootRootOpts {
11
11
  * spawner to inherit from, so this is the front door's only source of profile
12
12
  * identity. */
13
13
  profile?: string | null;
14
+ /** Profile already selected by the front door before its credential gate. */
15
+ selectedProfileId?: string;
14
16
  /** `crtr --pick-profile`: force the startup profile chooser to open even when
15
17
  * a per-cwd default is pinned, so the user can re-pin or unpin it. Without
16
18
  * this a pinned default auto-picks silently (that is what "default" means). */
@@ -1 +1,5 @@
1
- var l=Object.defineProperty;var c=(e,o)=>l(e,"name",{value:o,configurable:!0});import{spawn as p}from"node:child_process";import{inTmux as u,currentTmux as _,viewerSplitEnv as T}from"./placement-tmux.js";import{selectProfileForCwd as h}from"../profiles/select.js";import{cliClient as s}from"../../commands/api-client.js";import{mark as t}from"../timing.js";async function k(e){if(!u())throw new Error("crtr must be started from inside a tmux session \u2014 start tmux first (e.g. `tmux new -s work`), then run `crtr` there.");const o=e.kind;t("boot_root.start");const m=await h(e.cwd,e.profile,e.pickProfile??!1);t("boot_root.profile_resolved");const n=(await s().createNode({...o!==void 0?{kind:o}:{},mode:"base",prompt:e.prompt,profile:m,cwd:e.cwd,...e.name!==void 0?{name:e.name}:o!==void 0?{name:o}:{},root:!0,prefer_warm:!0})).node_id;t("boot_root.node_created",{node:n});const r=_();if(r!==null)try{await s().registerFocus({node_id:n,pane:r.pane,session:r.session,window:r.window})}catch{}const i={...process.env,...T(),CRTR_ATTACH_WAIT_MS:"30000",...e.prompt!==void 0&&e.prompt!==""?{CRTR_ATTACH_INITIAL_WHIP:"1"}:{}};r!==null&&(i.CRTR_ATTACH_BORROWED_PANE=r.pane),t("boot_root.viewer_spawn");const a=p("crtr",["surface","attach","to",n],{stdio:"inherit",env:i}),f=await new Promise(d=>{a.once("exit",w=>d(w??0)),a.once("error",()=>d(1))});process.exit(f)}c(k,"bootRoot");export{k as bootRoot};
1
+ var l=Object.defineProperty;var s=(e,r)=>l(e,"name",{value:r,configurable:!0});import{spawn as p}from"node:child_process";import{inTmux as u,currentTmux as _,viewerSplitEnv as T}from"./placement-tmux.js";import{selectProfileForCwd as x}from"../profiles/select.js";import{cliClient as m}from"../../commands/api-client.js";import{mark as i}from"../timing.js";async function P(e){if(!u()){const t=process.stderr.isTTY?n=>`\x1B[1;33m${n}\x1B[0m`:n=>n;process.stderr.write(`
2
+ ${t("crtr must be started from inside a tmux session.")}
3
+ ${t("Start tmux first, e.g. tmux new -s work \u2014 then run crtr there.")}
4
+
5
+ `),process.exit(1)}const r=e.kind;i("boot_root.start");const f=e.selectedProfileId??await x(e.cwd,e.profile,e.pickProfile??!1);i("boot_root.profile_resolved");const d=(await m().createNode({...r!==void 0?{kind:r}:{},mode:"base",prompt:e.prompt,profile:f,cwd:e.cwd,...e.name!==void 0?{name:e.name}:r!==void 0?{name:r}:{},root:!0,prefer_warm:!0})).node_id;i("boot_root.node_created",{node:d});const o=_();if(o!==null)try{await m().registerFocus({node_id:d,pane:o.pane,session:o.session,window:o.window})}catch{}const a={...process.env,...T(),CRTR_ATTACH_WAIT_MS:"30000",...e.prompt!==void 0&&e.prompt!==""?{CRTR_ATTACH_INITIAL_WHIP:"1"}:{}};o!==null&&(a.CRTR_ATTACH_BORROWED_PANE=o.pane),i("boot_root.viewer_spawn");const c=p("crtr",["surface","attach","to",d],{stdio:"inherit",env:a}),w=await new Promise(t=>{c.once("exit",n=>t(n??0)),c.once("error",()=>t(1))});process.exit(w)}s(P,"bootRoot");export{P as bootRoot};
@@ -1,4 +1,4 @@
1
- import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from '../../../api/dto/broker-ops.js';
1
+ import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerParkActivityResultDTO, BrokerParkCompleteRequest, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest, BrokerTelemetryRequest } from '../../../api/dto/broker-ops.js';
2
2
  import type { AcknowledgeMailResultDTO, ClaimMailResultDTO, MailReceiptDTO } from '../../../api/dto/mail.js';
3
3
  import type { BrokerFaultInputDTO, BrokerFaultRequest, BrokerFaultResultDTO, BrokerProviderRetryRequest, BrokerProviderRetryResultDTO, BrokerTurnRequest, BrokerTurnResultDTO, RecoveryStateDTO } from '../../../api/dto/recovery.js';
4
4
  import type { RelaunchRootResultDTO } from '../../../api/dto/lifecycle.js';
@@ -9,6 +9,7 @@ type BrokerInput<T> = T extends unknown ? Omit<T, 'expected_execution_id'> : nev
9
9
  export declare function settleBroker(nodeId: string, request: BrokerInput<BrokerSettleRequest>): Promise<BrokerSettleDirective>;
10
10
  export declare function completeBrokerPark(nodeId: string, request: BrokerInput<BrokerParkCompleteRequest>): Promise<BrokerSettleDirective>;
11
11
  export declare function recordBrokerParkActivity(nodeId: string): Promise<BrokerParkActivityResultDTO>;
12
+ export declare function recordBrokerTelemetry(nodeId: string, request: Omit<BrokerTelemetryRequest, 'expected_execution_id'>): Promise<void>;
12
13
  export declare function claimBrokerMail(nodeId: string, channel: 'wake' | 'passive'): Promise<ClaimMailResultDTO>;
13
14
  export declare function acknowledgeBrokerMail(nodeId: string, deliveries: MailReceiptDTO[]): Promise<AcknowledgeMailResultDTO>;
14
15
  export declare function recordBrokerTurn(nodeId: string, request: Omit<BrokerTurnRequest, 'expected_execution_id'>): Promise<BrokerTurnResultDTO>;
@@ -1 +1 @@
1
- var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{localClient as u}from"../../../api/node-transport.js";import{ApiError as d}from"../../../api/errors.js";import{envExecutionId as a}from"../../../shared/env.js";function t(){return u({autostart:!1})}o(t,"daemonClient");function n(){const e=a();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}o(n,"brokerExecutionId");function f(e,r){return t().bindBrokerSession(e,{...r,executionId:n()})}o(f,"bindBrokerSession");function m(e,r){return t().settleBroker(e,{...r,expected_execution_id:n()})}o(m,"settleBroker");function B(e,r){return t().completeBrokerPark(e,{...r,expected_execution_id:n()})}o(B,"completeBrokerPark");function _(e){return t().recordBrokerParkActivity(e,{expected_execution_id:n()})}o(_,"recordBrokerParkActivity");function s(e,r){return t().claimNodeMail(e,{execution_id:n(),channel:r})}o(s,"claimBrokerMail");function v(e,r){return t().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}o(v,"acknowledgeBrokerMail");function E(e,r){return t().recordBrokerTurn(e,{...r,expected_execution_id:n()})}o(E,"recordBrokerTurn");function R(e,r){return t().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}o(R,"mutateBrokerProviderRetry");function h(e,r){return t().mutateBrokerFault(e,{...r,expected_execution_id:n()})}o(h,"mutateBrokerFault");function y(e){return t().getBrokerRecovery(e,n())}o(y,"brokerRecovery");function N(e,r){return t().recordNodeFault(e,r)}o(N,"recordNodeFault");function b(e,r={}){return t().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}o(b,"clearNodeFault");function P(e,r){return t().commitBrokerModel(e,{...r,expected_execution_id:n()})}o(P,"commitBrokerModel");function w(e){return t().brokerExtensionState(e)}o(w,"brokerExtensionState");function F(e,r){return t().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}o(F,"commitBrokerGeneratedName");function M(e,r){return t().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}o(M,"commitBrokerPersonaAck");async function A(e,r){try{await t().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof d&&i.code==="already_finalized")return;throw i}}o(A,"publishBrokerReport");function I(e){return t().relaunchRoot(e)}o(I,"relaunchBrokerRoot");export{v as acknowledgeBrokerMail,f as bindBrokerSession,n as brokerExecutionId,w as brokerExtensionState,y as brokerRecovery,s as claimBrokerMail,b as clearNodeFault,F as commitBrokerGeneratedName,P as commitBrokerModel,M as commitBrokerPersonaAck,B as completeBrokerPark,h as mutateBrokerFault,R as mutateBrokerProviderRetry,A as publishBrokerReport,_ as recordBrokerParkActivity,E as recordBrokerTurn,N as recordNodeFault,I as relaunchBrokerRoot,m as settleBroker};
1
+ var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{localClient as u}from"../../../api/node-transport.js";import{ApiError as d}from"../../../api/errors.js";import{envExecutionId as a}from"../../../shared/env.js";function t(){return u({autostart:!1})}o(t,"daemonClient");function n(){const e=a();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}o(n,"brokerExecutionId");function f(e,r){return t().bindBrokerSession(e,{...r,executionId:n()})}o(f,"bindBrokerSession");function m(e,r){return t().settleBroker(e,{...r,expected_execution_id:n()})}o(m,"settleBroker");function B(e,r){return t().completeBrokerPark(e,{...r,expected_execution_id:n()})}o(B,"completeBrokerPark");function _(e){return t().recordBrokerParkActivity(e,{expected_execution_id:n()})}o(_,"recordBrokerParkActivity");function s(e,r){return t().recordBrokerTelemetry(e,{...r,expected_execution_id:n()})}o(s,"recordBrokerTelemetry");function y(e,r){return t().claimNodeMail(e,{execution_id:n(),channel:r})}o(y,"claimBrokerMail");function v(e,r){return t().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}o(v,"acknowledgeBrokerMail");function E(e,r){return t().recordBrokerTurn(e,{...r,expected_execution_id:n()})}o(E,"recordBrokerTurn");function R(e,r){return t().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}o(R,"mutateBrokerProviderRetry");function h(e,r){return t().mutateBrokerFault(e,{...r,expected_execution_id:n()})}o(h,"mutateBrokerFault");function N(e){return t().getBrokerRecovery(e,n())}o(N,"brokerRecovery");function b(e,r){return t().recordNodeFault(e,r)}o(b,"recordNodeFault");function P(e,r={}){return t().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}o(P,"clearNodeFault");function w(e,r){return t().commitBrokerModel(e,{...r,expected_execution_id:n()})}o(w,"commitBrokerModel");function F(e){return t().brokerExtensionState(e)}o(F,"brokerExtensionState");function M(e,r){return t().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}o(M,"commitBrokerGeneratedName");function T(e,r){return t().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}o(T,"commitBrokerPersonaAck");async function A(e,r){try{await t().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof d&&i.code==="already_finalized")return;throw i}}o(A,"publishBrokerReport");function I(e){return t().relaunchRoot(e)}o(I,"relaunchBrokerRoot");export{v as acknowledgeBrokerMail,f as bindBrokerSession,n as brokerExecutionId,F as brokerExtensionState,N as brokerRecovery,y as claimBrokerMail,P as clearNodeFault,M as commitBrokerGeneratedName,w as commitBrokerModel,T as commitBrokerPersonaAck,B as completeBrokerPark,h as mutateBrokerFault,R as mutateBrokerProviderRetry,A as publishBrokerReport,_ as recordBrokerParkActivity,s as recordBrokerTelemetry,E as recordBrokerTurn,b as recordNodeFault,I as relaunchBrokerRoot,m as settleBroker};
@@ -0,0 +1,2 @@
1
+ /** Open pi's provider picker and LoginDialogComponent before a root broker starts. */
2
+ export declare function runFrontDoorLogin(): Promise<boolean>;
@@ -0,0 +1 @@
1
+ var m=Object.defineProperty;var r=(a,t)=>m(a,"name",{value:t,configurable:!0});import{CredentialSynchronizationError as d,LoginDialogComponent as l,OAuthSelectorComponent as p}from"@earendil-works/pi-coding-agent";import{execFile as f}from"node:child_process";import{join as g}from"node:path";import{setAuthCredential as w}from"../auth-file.js";import{dialogAuthInteraction as y}from"../auth-interaction.js";import{commitManagedLogin as I,isManagedProvider as L,readSubscriptionPool as b}from"../subscription-state.js";import{runSetupSettingsProcess as A}from"../../commands/sys/setup-settings-runner.js";import{buildProviderCatalog as P}from"../../commands/sys/panels/provider-panel.js";function x(a){const t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",i=process.platform==="win32"?["/c","start","",a]:[a];f(t,i,{timeout:5e3},()=>{})}r(x,"openBrowser");class C{static{r(this,"FrontDoorLogin")}tui;runtime;agentDir;finish;component;dialog;settled=!1;constructor(t,i,s,o,c){this.tui=t,this.runtime=i,this.agentDir=s,this.finish=c,this.component=new p("login",o,n=>this.startLogin(o.find(u=>u.id===n)),()=>this.complete(!1))}get focused(){return this.component.focused}set focused(t){this.component.focused=t}handleInput(t){this.component.handleInput?.(t)}invalidate(){this.tui.requestRender()}render(t){return this.component.render(t)}dispose(){this.settled||this.dialog?.handleInput("\x1B")}complete(t){this.settled||(this.settled=!0,this.finish(t))}startLogin(t){if(!t){this.complete(!1);return}const i=new l(this.tui,t.id,e=>this.complete(e),t.name);this.dialog=i,this.component=i,this.tui.setFocus(this),this.tui.requestRender();const s=y(i,{openBrowser:x,onChange:r(()=>this.tui.requestRender(),"onChange"),isActive:r(()=>!this.settled&&!i.signal.aborted,"isActive")}),o=r(()=>{i.signal.aborted||this.complete(!1)},"fail");if(t.authType==="api_key"){i.showPrompt(`Enter API key for ${t.name}:`,"sk-...").then(async e=>{if(!e.trim()||this.settled){this.complete(!1);return}await w(t.id,{type:"api_key",key:e.trim()},g(this.agentDir,"auth.json")),this.complete(!0)}).catch(o);return}const c=this.runtime.getProvider(t.id)?.auth.oauth;if(!c){this.complete(!1);return}const n=t.id;if(!L(n)){this.runtime.login(n,"oauth",s).then(()=>this.complete(!0)).catch(e=>{if(e instanceof d){this.complete(!0);return}o()});return}const u=Math.max(0,...b(n).map(e=>e.lastRateLimitedAt));c.login(s).then(async e=>{if(this.settled||i.signal.aborted)return;const h=typeof e.accountId=="string"&&e.accountId.trim()?e.accountId.trim():void 0;await I(n,void 0,{access:e.access,refresh:e.refresh,expires:e.expires,...h?{accountId:h}:{},lastRateLimitedAt:u,autoLabel:!0}),this.complete(!0)}).catch(o)}}async function E(){return await A(({tui:t,agentDir:i,runtime:s,registry:o},c)=>new C(t,s,i,P(s,o).map(({providerId:n,name:u,authType:e})=>({id:n,name:u,authType:e})),c.submit))===!0}r(E,"runFrontDoorLogin");export{E as runFrontDoorLogin};
@@ -1,7 +1,9 @@
1
- var w=Object.defineProperty;var u=(r,n)=>w(r,"name",{value:n,configurable:!0});import{existsSync as R,statSync as g}from"node:fs";import{resolve as m}from"node:path";import{SUBTREE_NAMES as O}from"../../build-root.js";import{FRONT_DOOR_ENV as D}from"./front-door-env.js";function p(r){try{return R(r)&&g(r).isDirectory()}catch{return!1}}u(p,"isDir");const y=new Set(["--name","--kind","--profile","--pick-profile","--continue","-c","--resume","-r"]);function _(r){let n=process.cwd(),t,c,f,a=!1,l;const o=[];for(let i=0;i<r.length;i++){const e=r[i];e==="--name"?t=r[++i]:e==="--kind"?c=r[++i]:e==="--profile"?f=r[++i]:e==="--pick-profile"?a=!0:e==="--continue"||e==="-c"?l="continue":e==="--resume"||e==="-r"?l="pick":e.startsWith("--")||o.push(e)}o.length>0&&p(m(o[0]))&&(n=m(o.shift()));const s=o.length>0?o.join(" "):void 0;return{cwd:n,prompt:s,name:t,kind:c,profile:f,pickProfile:a,resume:l}}u(_,"parseRootArgs");import{FRONT_DOOR_ENV as L}from"./front-door-env.js";async function P(r){const n=r.slice(2),t=n[0];if(process.env[D]||t==="-h"||t==="--help"||t==="--version"||t==="-v"||t!==void 0&&O.includes(t))return!1;if(t!==void 0){const i=/\s/.test(t),e=!t.startsWith("-")&&p(m(t)),d=y.has(t);if(!i&&!e&&!d)return!1;if(e){const{buildRoot:h}=await import("../../build-root.js");if((await h()).subtrees.some(k=>k.name===t))return!1}}const[{bootRoot:c},{resumeRoot:f},{rendererWarning:a,missingPackageWarning:l,piAgentDir:o}]=await Promise.all([import("./boot-root.js"),import("./resume-root.js"),import("./package-health.js")]),s=_(n);try{const i=l(o());i!==null&&process.stderr.write(`
2
- ${i}
1
+ var E=Object.defineProperty;var p=(r,i)=>E(r,"name",{value:i,configurable:!0});import{existsSync as w,statSync as F}from"node:fs";import{homedir as v}from"node:os";import{join as I,resolve as m}from"node:path";import{SUBTREE_NAMES as _}from"../../build-root.js";import{FRONT_DOOR_ENV as N}from"./front-door-env.js";function g(r){try{return w(r)&&F(r).isDirectory()}catch{return!1}}p(g,"isDir");const A=new Set(["--name","--kind","--profile","--pick-profile","--continue","-c","--resume","-r"]),h=I(v(),".crouter","setup-completed.json");async function C(){let r=!1;const i=p(()=>{r=!0},"onSigint");process.once("SIGINT",i);try{const{runSetup:e}=await import("../../commands/sys/setup-wizard.js"),t=await e();if(r){const c=new Error("Interrupted");throw c.name="AbortError",c}const[{atomicWriteJson:a},{crtrVersion:f}]=await Promise.all([import("../fs-utils.js"),import("../../shared/crtr-version.js")]);a(h,{packageVersion:f(),completedAt:new Date().toISOString(),outcome:t})}finally{process.removeListener("SIGINT",i)}}p(C,"runFirstSetup");function L(r){let i=process.cwd(),e,t,a,f=!1,c;const l=[];for(let n=0;n<r.length;n++){const o=r[n];o==="--name"?e=r[++n]:o==="--kind"?t=r[++n]:o==="--profile"?a=r[++n]:o==="--pick-profile"?f=!0:o==="--continue"||o==="-c"?c="continue":o==="--resume"||o==="-r"?c="pick":o.startsWith("--")||l.push(o)}l.length>0&&g(m(l[0]))&&(i=m(l.shift()));const d=l.length>0?l.join(" "):void 0;return{cwd:i,prompt:d,name:e,kind:t,profile:a,pickProfile:f,resume:c}}p(L,"parseRootArgs");import{FRONT_DOOR_ENV as Y}from"./front-door-env.js";async function B(r){const i=r.slice(2),e=i[0];if(process.env[N]||e==="-h"||e==="--help"||e==="--version"||e==="-v"||e!==void 0&&_.includes(e))return!1;if(e!==void 0){const s=/\s/.test(e),u=!e.startsWith("-")&&g(m(e)),T=A.has(e);if(!s&&!u&&!T)return!1;if(u){const{buildRoot:y}=await import("../../build-root.js");if((await y()).subtrees.some(D=>D.name===e))return!1}}const t=L(i);if(t.profile!==void 0){const{resolveProfileOperand:s}=await import("../profiles/manifest.js");t.profile=s(t.profile).profileId}const a=process.stdin.isTTY&&process.stdout.isTTY;let f=!1;a&&!w(h)&&(await C(),f=!0);const{selectProfileForCwd:c,selectProfileForCwdReadOnly:l}=await import("../profiles/select.js");f&&t.profile===void 0&&process.stdout.write(`
2
+ Choose a profile
3
+ `);const d=t.profile??(a?await c(t.cwd,void 0,t.pickProfile):l(t.cwd)),{exitForMissingProviderCredential:n,hasConfiguredProviderCredential:o}=await import("./provider-credential-gate.js");if(!await o(d)){a||n();const{runFrontDoorLogin:s}=await import("./front-door-login.js");await s()||n()}const[{bootRoot:R},{resumeRoot:P},{rendererWarning:k,missingPackageWarning:S,piAgentDir:O}]=await Promise.all([import("./boot-root.js"),import("./resume-root.js"),import("./package-health.js")]);try{const s=S(O());s!==null&&process.stderr.write(`
4
+ ${s}
3
5
 
4
- `);const e=a();e!==null&&process.stderr.write(`
5
- ${e}
6
+ `);const u=k();u!==null&&process.stderr.write(`
7
+ ${u}
6
8
 
7
- `)}catch{}return s.resume!==void 0&&await f(s.cwd,s.resume==="pick")==="aborted"||await c({...s}),!0}u(P,"maybeBootRoot");export{L as FRONT_DOOR_ENV,P as maybeBootRoot};
9
+ `)}catch{}return t.resume!==void 0&&await P(t.cwd,t.resume==="pick")==="aborted"||await R({...t,selectedProfileId:d}),!0}p(B,"maybeBootRoot");export{Y as FRONT_DOOR_ENV,B as maybeBootRoot};
@@ -10,8 +10,26 @@ export declare function detectNerdFont(platform?: NodeJS.Platform, home?: string
10
10
  /** Download the upstream symbols-only patch into the user's font dir. Works on
11
11
  * every Linux regardless of package manager — Debian/Ubuntu and Fedora ship no
12
12
  * Nerd Font package, so there is nothing native to install there. Needs no
13
- * sudo: it writes to `~/.local/share/fonts`. */
13
+ * sudo: it writes to `~/.local/share/fonts`.
14
+ *
15
+ * curl runs with its progress meter on (no `-s`) because this is the one
16
+ * install step with a real download percentage: setup captures that stderr
17
+ * and drives the step's progress bar from it (`parseCurlPercent`). */
14
18
  export declare const NERD_FONT_MANUAL_LINUX_COMMAND: string;
19
+ /** Reads percent complete out of curl's default progress meter as its stderr
20
+ * arrives. Rows are separated by `\r` and look like
21
+ * `100 1234k 100 1234k 0 0 987k 0 --:--:-- …`; the leading
22
+ * column is the percentage of the whole transfer, and the header rows
23
+ * (` % Total % Received …`) start with `%` so they never match.
24
+ *
25
+ * Stateful because curl's writes split rows anywhere: the tail of a chunk is
26
+ * held back until its row is terminated. Reading a half-row instead lands on
27
+ * a different column and reports a number that was never true — in practice
28
+ * the completed download's own summary row parsed as 0%.
29
+ *
30
+ * Returns the percentage of the last complete row in this chunk, or null when
31
+ * the chunk completed no row. */
32
+ export declare function createCurlPercentReader(): (chunk: string) => number | null;
15
33
  export interface NerdFontInstallCommand {
16
34
  command: string | null;
17
35
  hint: string;
@@ -1,2 +1,2 @@
1
- var u=Object.defineProperty;var e=(t,n)=>u(t,"name",{value:n,configurable:!0});import{spawnSync as i}from"node:child_process";import{readdirSync as c}from"node:fs";import{homedir as d}from"node:os";import{join as s}from"node:path";const f=/nerd[ _-]?font|symbolsnerdfont|symbols-only/i;function m(t,n){return t==="darwin"?[s(n,"Library","Fonts"),"/Library/Fonts","/System/Library/Fonts"]:[s(n,".local","share","fonts"),s(n,".fonts"),"/usr/local/share/fonts","/usr/share/fonts"]}e(m,"fontDirs");function a(t,n){if(n<0)return null;let o;try{o=c(t,{withFileTypes:!0})}catch{return null}for(const r of o){if(r.isDirectory()){const l=a(s(t,r.name),n-1);if(l!==null)return l;continue}if(/\.(ttf|otf|ttc)$/i.test(r.name)&&f.test(r.name))return r.name}return null}e(a,"scanForNerdFont");function y(){if(i("sh",["-lc","command -v fc-list >/dev/null 2>&1"],{stdio:"ignore"}).status!==0)return null;const n=i("fc-list",[":","family"],{encoding:"utf8",timeout:5e3});if(n.status!==0||typeof n.stdout!="string")return null;for(const o of n.stdout.split(`
2
- `))if(f.test(o))return o.split(",")[0].trim();return""}e(y,"queryFontconfig");function S(t=process.platform,n=d()){if(t!=="darwin"){const o=y();if(o!==null&&o!=="")return{installed:!0,evidence:o,source:"fc-list"}}for(const o of m(t,n)){const r=a(o,3);if(r!==null)return{installed:!0,evidence:r,source:"font-dir"}}return{installed:!1,evidence:null,source:null}}e(S,"detectNerdFont");const p="mkdir -p ~/.local/share/fonts && curl -fsSL -o /tmp/NerdFontsSymbolsOnly.zip https://github.com/ryanoasis/nerd-fonts/releases/latest/download/NerdFontsSymbolsOnly.zip && unzip -oq /tmp/NerdFontsSymbolsOnly.zip -d ~/.local/share/fonts && fc-cache -f";function _(t,n=process.platform){const o=n!=="darwin"||t==="apt-get"||t==="dnf"||t==="pacman";return t==="brew"?{command:"brew install --cask font-symbols-only-nerd-font",hint:"Homebrew cask",autoInstall:!0}:t==="pacman"?{command:"sudo pacman -S --noconfirm ttf-nerd-fonts-symbols",hint:"pacman install",autoInstall:!0}:o?{command:p,hint:"download symbols-only patch to ~/.local/share/fonts (needs curl + unzip)",autoInstall:!0}:{command:null,hint:"install Homebrew, or download a Nerd Font from https://nerdfonts.com and add it in Font Book",autoInstall:!1}}e(_,"nerdFontInstallCommand");const I=`then set your terminal profile's font to a Nerd Font (e.g. add "Symbols Nerd Font Mono" as the non-ASCII/fallback font) \u2014 installing it does not select it`;export{p as NERD_FONT_MANUAL_LINUX_COMMAND,I as NERD_FONT_SELECT_HINT,S as detectNerdFont,_ as nerdFontInstallCommand};
1
+ var d=Object.defineProperty;var e=(n,t)=>d(n,"name",{value:t,configurable:!0});import{spawnSync as u}from"node:child_process";import{readdirSync as m}from"node:fs";import{homedir as p}from"node:os";import{join as l}from"node:path";const c=/nerd[ _-]?font|symbolsnerdfont|symbols-only/i;function y(n,t){return n==="darwin"?[l(t,"Library","Fonts"),"/Library/Fonts","/System/Library/Fonts"]:[l(t,".local","share","fonts"),l(t,".fonts"),"/usr/local/share/fonts","/usr/share/fonts"]}e(y,"fontDirs");function a(n,t){if(t<0)return null;let o;try{o=m(n,{withFileTypes:!0})}catch{return null}for(const r of o){if(r.isDirectory()){const s=a(l(n,r.name),t-1);if(s!==null)return s;continue}if(/\.(ttf|otf|ttc)$/i.test(r.name)&&c.test(r.name))return r.name}return null}e(a,"scanForNerdFont");function b(){if(u("sh",["-lc","command -v fc-list >/dev/null 2>&1"],{stdio:"ignore"}).status!==0)return null;const t=u("fc-list",[":","family"],{encoding:"utf8",timeout:5e3});if(t.status!==0||typeof t.stdout!="string")return null;for(const o of t.stdout.split(`
2
+ `))if(c.test(o))return o.split(",")[0].trim();return""}e(b,"queryFontconfig");function I(n=process.platform,t=p()){if(n!=="darwin"){const o=b();if(o!==null&&o!=="")return{installed:!0,evidence:o,source:"fc-list"}}for(const o of y(n,t)){const r=a(o,3);if(r!==null)return{installed:!0,evidence:r,source:"font-dir"}}return{installed:!1,evidence:null,source:null}}e(I,"detectNerdFont");const N="mkdir -p ~/.local/share/fonts && curl -fL -o /tmp/NerdFontsSymbolsOnly.zip https://github.com/ryanoasis/nerd-fonts/releases/latest/download/NerdFontsSymbolsOnly.zip && unzip -oq /tmp/NerdFontsSymbolsOnly.zip -d ~/.local/share/fonts && fc-cache -f";function L(){let n="";return t=>{n+=t;const o=n.split(/[\r\n]/);n=o.pop()??"";let r=null;for(const s of o){const i=/^\s*(\d{1,3})\s+\S+\s+\d{1,3}\s/.exec(s);if(i===null)continue;const f=Number(i[1]);f<=100&&(r=f)}return r}}e(L,"createCurlPercentReader");function T(n,t=process.platform){const o=t!=="darwin"||n==="apt-get"||n==="dnf"||n==="pacman";return n==="brew"?{command:"brew install --cask font-symbols-only-nerd-font",hint:"Homebrew cask",autoInstall:!0}:n==="pacman"?{command:"sudo pacman -S --noconfirm ttf-nerd-fonts-symbols",hint:"pacman install",autoInstall:!0}:o?{command:N,hint:"download symbols-only patch to ~/.local/share/fonts (needs curl + unzip)",autoInstall:!0}:{command:null,hint:"install Homebrew, or download a Nerd Font from https://nerdfonts.com and add it in Font Book",autoInstall:!1}}e(T,"nerdFontInstallCommand");const x=`then set your terminal profile's font to a Nerd Font (e.g. add "Symbols Nerd Font Mono" as the non-ASCII/fallback font) \u2014 installing it does not select it`;export{N as NERD_FONT_MANUAL_LINUX_COMMAND,x as NERD_FONT_SELECT_HINT,L as createCurlPercentReader,I as detectNerdFont,T as nerdFontInstallCommand};
@@ -0,0 +1,13 @@
1
+ /** A running progress bar line. `setFraction` fills it from a real count;
2
+ * leaving it unset keeps the indeterminate slider. `stop` erases the line and
3
+ * resolves once the painter has released the terminal, so the caller can
4
+ * write its own outcome line without interleaving. */
5
+ export interface ProgressBar {
6
+ setFraction(fraction: number): void;
7
+ stop(): Promise<void>;
8
+ }
9
+ /** Start an animated bar on `stream`, drawn by a child process so it keeps
10
+ * moving while this process blocks inside the step it describes. */
11
+ export declare function startProgressBar(label: string, stream?: NodeJS.WriteStream & {
12
+ fd: number;
13
+ }): ProgressBar;
@@ -0,0 +1,2 @@
1
+ var p=Object.defineProperty;var n=(o,e)=>p(o,"name",{value:e,configurable:!0});import{spawn as f}from"node:child_process";import{dirname as m,join as d}from"node:path";import{assetRoot as u}from"../asset-root.js";const s={setFraction(){},stop:n(async()=>{},"stop")};function l(){return d(m(u()),"bin","progress-painter.mjs")}n(l,"painterPath");function b(o,e=process.stdout){if(!e.isTTY)return s;let t;try{t=f(process.execPath,[l(),o],{stdio:["pipe",e.fd,"ignore"]})}catch{return s}let i=!0;t.stdin?.on("error",()=>{i=!1});const a=new Promise(r=>{t.once("exit",()=>{i=!1,r()}),t.once("error",()=>{i=!1,r()})});return{setFraction(r){i&&t.stdin?.write(`${Math.min(1,Math.max(0,r))}
2
+ `)},async stop(){i&&t.stdin?.end();const r=new Promise(c=>setTimeout(()=>{t.kill("SIGKILL"),c()},1e3).unref());await Promise.race([a,r]),e.write("\r\x1B[2K\x1B[?25h")}}}n(b,"startProgressBar");export{b as startProgressBar};
@@ -0,0 +1,4 @@
1
+ export declare const NO_PROVIDER_CREDENTIAL_MESSAGE = "crtr: no provider credential; run `crtr sys setup` to log in.";
2
+ /** Check the setup catalog before a path creates a broker-backed node. */
3
+ export declare function hasConfiguredProviderCredential(profileId?: string | null): Promise<boolean>;
4
+ export declare function exitForMissingProviderCredential(): never;
@@ -0,0 +1,2 @@
1
+ var m=Object.defineProperty;var o=(r,e)=>m(r,"name",{value:e,configurable:!0});import{ModelRegistry as a,ModelRuntime as d}from"@earendil-works/pi-coding-agent";import{join as s}from"node:path";import{PoolCredentialStore as l}from"../pool-credential-store.js";import{readProfileEnvVars as p}from"../profiles/env-store.js";import{hasProviderCredential as c}from"../provider-credential.js";import{piAgentDir as f}from"./package-health.js";import{PROVIDER_ENV_KEYS as u}from"./spawn-env.js";const E="crtr: no provider credential; run `crtr sys setup` to log in.";async function h(r=null){const e=p(r);if(Object.values(u).some(n=>(e[n]??process.env[n])?.trim()))return!0;const t=f(),i=await d.create({credentials:new l(s(t,"auth.json")),modelsPath:s(t,"models.json")});return c(i,new a(i))}o(h,"hasConfiguredProviderCredential");function j(){process.stderr.write(`${E}
2
+ `),process.exit(1)}o(j,"exitForMissingProviderCredential");export{E as NO_PROVIDER_CREDENTIAL_MESSAGE,j as exitForMissingProviderCredential,h as hasConfiguredProviderCredential};
@@ -1,4 +1,5 @@
1
1
  import type { PiInvocation } from './invocation.js';
2
+ import type { ModelProvider } from '../../types.js';
2
3
  /** The unshimmed PATH admitted from the host. Broker and cron shells resolve
3
4
  * crouter-owned executables from this value, while commands those shells run
4
5
  * still receive the shim-prepended PATH. */
@@ -7,6 +8,12 @@ export declare const ADMITTED_HOST_PATH_ENV = "CRTR_ADMITTED_HOST_PATH";
7
8
  * The result is absolute, or null when no PATH entry supplies the command. */
8
9
  export declare function resolvePathExecutable(name: string, env: NodeJS.ProcessEnv, cwd: string): string | null;
9
10
  export declare function resolveAdmittedHostCommand(name: string, env: NodeJS.ProcessEnv, cwd: string): string;
11
+ /** B — the exact env-var name of each crtr-configured model provider's API
12
+ * key. Deliberately an explicit provider→env-key mapping, NOT inferred from
13
+ * `MODEL_PROVIDER_KEYS` in launch.ts (that constant is a provider-ID list —
14
+ * `['anthropic', 'openai']` — not env-var names; conflating the two would
15
+ * silently admit the wrong names the moment either list changes). */
16
+ export declare const PROVIDER_ENV_KEYS: Record<ModelProvider, string>;
10
17
  /** Sources A–C: the operational base shared by the broker boundary (this
11
18
  * module's `buildBrokerEnv`) and cron executor — the single shared definition
12
19
  * of "non-secret host state the runtime exposes to any spawned shell." Does not include
@@ -1 +1 @@
1
- var u=Object.defineProperty;var a=(e,t)=>u(e,"name",{value:t,configurable:!0});import{statSync as d}from"node:fs";import{delimiter as P,resolve as E}from"node:path";import{readMergedLaunchConfig as T}from"../config.js";import{readProfileEnvVars as _}from"../profiles/env-store.js";import{metadataEnvName as p,readProfileMetadata as m}from"../profiles/manifest.js";import{binShimDirFor as A}from"./bin-contributions.js";import{FRONT_DOOR_ENV as O}from"./front-door-env.js";const R=new Set(["HOME","PATH","SHELL","USER","LOGNAME","PWD","TMPDIR","TERM","TERMINFO","COLORTERM","LANG","LANGUAGE","TZ","NO_PROXY","no_proxy","SSH_AUTH_SOCK","CRTR_BASH_VALVE_MS"]),h=["LC_","XDG_","PI_"],f="CRTR_ADMITTED_HOST_PATH";function H(e,t,o){const n=t.PATH;if(n===void 0||n==="")return null;for(const s of n.split(P)){const c=E(o,s===""?".":s,e);try{const r=d(c);if(r.isFile()&&(r.mode&73)!==0)return c}catch{}}return null}a(H,"resolvePathExecutable");function $(e,t,o){const n=t[f]??t.PATH;if(n===void 0||n==="")throw new Error(`cannot resolve crouter-owned ${e}: the admitted host PATH is empty`);const s=H(e,{PATH:n},o);if(s!==null)return s;throw new Error(`cannot resolve crouter-owned ${e} from the admitted host PATH`)}a($,"resolveAdmittedHostCommand");const v=["HTTP_PROXY","HTTPS_PROXY","http_proxy","https_proxy"],I={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY"};function w(e){let t;try{t=new URL(e)}catch{return!1}return!(t.protocol!=="http:"&&t.protocol!=="https:"||t.hostname===""||t.username!==""||t.password!=="")}a(w,"isCredentialFreeProxyValue");function N(e,t){if(!t.includes("*"))return e===t;const o=t.split("*").map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${o}$`).test(e)}a(N,"matchesAllowPattern");function S(e){const t=e.host??process.env,o={};for(const[r,i]of Object.entries(t))i!==void 0&&(R.has(r)||h.some(l=>r.startsWith(l)))&&(o[r]=i);for(const r of v){const i=t[r];i!==void 0&&w(i)&&(o[r]=i)}for(const r of Object.values(I)){const i=t[r];i!==void 0&&(o[r]=i)}const n=T(e.targetCwd,e.targetProfileId).spawnEnv.allow;if(n.length>0)for(const[r,i]of Object.entries(t))i!==void 0&&n.some(l=>N(r,l))&&(o[r]=i);const s=t[f]??o.PATH;s!==void 0&&s!==""&&(o[f]=s);const c=A(e.targetCwd,e.targetProfileId);if(c!==null){const r=o.PATH;o.PATH=r===void 0||r===""?c:`${c}:${r}`}return o}a(S,"buildOperationalEnvBase");function C(e){const t={};for(const[o,n]of Object.entries(m(e)))t[p(o)]=n;return t}a(C,"profileMetadataEnv");function F(e){const t=e.env.CRTR_NODE_CWD??process.cwd(),o=e.env.CRTR_PROFILE_ID||null,n=S({targetCwd:t,targetProfileId:o});return{...n,...C(o),..._(o),...e.env,[f]:n[f],[O]:"1"}}a(F,"buildBrokerEnv");export{f as ADMITTED_HOST_PATH_ENV,F as buildBrokerEnv,S as buildOperationalEnvBase,C as profileMetadataEnv,$ as resolveAdmittedHostCommand,H as resolvePathExecutable};
1
+ var u=Object.defineProperty;var a=(e,t)=>u(e,"name",{value:t,configurable:!0});import{statSync as d}from"node:fs";import{delimiter as P,resolve as E}from"node:path";import{readMergedLaunchConfig as p}from"../config.js";import{readProfileEnvVars as T}from"../profiles/env-store.js";import{metadataEnvName as _,readProfileMetadata as m}from"../profiles/manifest.js";import{binShimDirFor as A}from"./bin-contributions.js";import{FRONT_DOOR_ENV as O}from"./front-door-env.js";const R=new Set(["HOME","PATH","SHELL","USER","LOGNAME","PWD","TMPDIR","TERM","TERMINFO","COLORTERM","LANG","LANGUAGE","TZ","NO_PROXY","no_proxy","SSH_AUTH_SOCK","CRTR_BASH_VALVE_MS"]),h=["LC_","XDG_","PI_"],f="CRTR_ADMITTED_HOST_PATH";function H(e,t,o){const n=t.PATH;if(n===void 0||n==="")return null;for(const s of n.split(P)){const c=E(o,s===""?".":s,e);try{const r=d(c);if(r.isFile()&&(r.mode&73)!==0)return c}catch{}}return null}a(H,"resolvePathExecutable");function $(e,t,o){const n=t[f]??t.PATH;if(n===void 0||n==="")throw new Error(`cannot resolve crouter-owned ${e}: the admitted host PATH is empty`);const s=H(e,{PATH:n},o);if(s!==null)return s;throw new Error(`cannot resolve crouter-owned ${e} from the admitted host PATH`)}a($,"resolveAdmittedHostCommand");const v=["HTTP_PROXY","HTTPS_PROXY","http_proxy","https_proxy"],I={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY"};function w(e){let t;try{t=new URL(e)}catch{return!1}return!(t.protocol!=="http:"&&t.protocol!=="https:"||t.hostname===""||t.username!==""||t.password!=="")}a(w,"isCredentialFreeProxyValue");function N(e,t){if(!t.includes("*"))return e===t;const o=t.split("*").map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${o}$`).test(e)}a(N,"matchesAllowPattern");function S(e){const t=e.host??process.env,o={};for(const[r,i]of Object.entries(t))i!==void 0&&(R.has(r)||h.some(l=>r.startsWith(l)))&&(o[r]=i);for(const r of v){const i=t[r];i!==void 0&&w(i)&&(o[r]=i)}for(const r of Object.values(I)){const i=t[r];i!==void 0&&(o[r]=i)}const n=p(e.targetCwd,e.targetProfileId).spawnEnv.allow;if(n.length>0)for(const[r,i]of Object.entries(t))i!==void 0&&n.some(l=>N(r,l))&&(o[r]=i);const s=t[f]??o.PATH;s!==void 0&&s!==""&&(o[f]=s);const c=A(e.targetCwd,e.targetProfileId);if(c!==null){const r=o.PATH;o.PATH=r===void 0||r===""?c:`${c}:${r}`}return o}a(S,"buildOperationalEnvBase");function C(e){const t={};for(const[o,n]of Object.entries(m(e)))t[_(o)]=n;return t}a(C,"profileMetadataEnv");function F(e){const t=e.env.CRTR_NODE_CWD??process.cwd(),o=e.env.CRTR_PROFILE_ID||null,n=S({targetCwd:t,targetProfileId:o});return{...n,...C(o),...T(o),...e.env,[f]:n[f],[O]:"1"}}a(F,"buildBrokerEnv");export{f as ADMITTED_HOST_PATH_ENV,I as PROVIDER_ENV_KEYS,F as buildBrokerEnv,S as buildOperationalEnvBase,C as profileMetadataEnv,$ as resolveAdmittedHostCommand,H as resolvePathExecutable};
@@ -1 +1 @@
1
- var A=Object.defineProperty;var r=(e,t)=>A(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as N,findNodeBySessionFile as P,getNode as k,isWarmSpare as R,listNodeIdentities as T,recordSettledTurn as $,setPresence as _,subscriptionsOf as C,updateNode as g}from"../../../core/canvas/canvas.js";import{recordExecutionPid as I}from"../../../core/canvas/executions.js";import{bindSession as j,readLiveSession as q,transferSession as E}from"../../../core/canvas/sessions.js";import{isSafeNodeId as M}from"../../../core/canvas/paths.js";import{isPidAlive as L}from"../../../core/canvas/pid.js";import{editorLabel as B}from"../../../core/canvas/labels.js";import{assembleNodeSubject as G}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as a}from"../../../core/errors.js";import{hasUnseenWakeMail as O}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as J}from"../../../core/runtime/kickoff.js";import{transition as b}from"../../../core/runtime/lifecycle.js";import{focusOf as w,tearDownNode as S}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../../../core/runtime/broker/client-registry.js";import{evaluateStop as D}from"../../../core/runtime/stop-guard.js";import{clearFault as f,recordFault as U}from"../../../core/canvas/recovery.js";import{updateModelRecipe as V}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as Y}from"../../review/finish.js";import{emitEvent as z}from"../../../core/events/emit.js";import{consumePendingPark as H,recordPendingParkActivity as K}from"../../park-pending.js";import{shouldParkAfterSummary as Q}from"../../park-activity.js";import{requireCurrentExecution as m}from"./broker-recovery.js";function p(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw a(`${t} requires a JSON body`);return e}r(p,"objectBody");function X(e){const t=p(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw a("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw a("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw a("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw a("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw a("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw a("reviewBoundaryIds must be an array of strings");return t}r(X,"parseSessionBoundBody");function Z(e){const t=p(e,"broker settle");if(typeof t.stopReason!="string")throw a("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof t[n]!="boolean")throw a(`${n} must be a boolean`);return t}r(Z,"parseSettleBody");function ee(e){const t=p(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw a("outcome must be completed or failed");return t}r(ee,"parseParkCompleteBody");function te(e){const t=p(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw a("spec must be a non-empty string");if(t.pinnedOverride!==void 0&&typeof t.pinnedOverride!="boolean")throw a("pinnedOverride must be a boolean when present");if(typeof t.userSelected!="boolean")throw a("userSelected must be a boolean");return t}r(te,"parseModelCommitBody");function h(e){const t=k(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}r(h,"requireNode");function y(e){return{node_id:e.node_id,name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}r(y,"extensionNode");function ne(e){const t=h(e),n=[],o=new Set([e]);let i=t.parent??null;for(;i!==null&&i!==""&&!o.has(i);){o.add(i);const c=k(i);if(c===null)break;n.unshift(y(c)),i=c.parent??null}const s=C(e).map(c=>k(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,x)=>c.status===x.status?0:c.status==="active"?-1:x.status==="active"?1:0).map(y),u=typeof t.fork_source_file=="string"?P(t.fork_source_file):null,d=G(e);if(d===null)throw v(`unknown node: ${e}`,{received:e});return{node:y(t),warm_spare:R(e),ancestors:n,children:s,fork_source:u===null?null:y(u),subject:d,report_nodes:T()}}r(ne,"extensionState");function F(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}r(F,"samePersona");function ie(e){const t=p(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw a("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw a("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(o=>typeof n[o]!="string"))throw a("recap expected must contain name, description, title, icon, and kind strings");return t}r(ie,"parseGeneratedNameBody");function oe(e){const t=p(e,"broker persona-ack"),n=r(o=>{const i=t[o];if(typeof i!="object"||i===null||Array.isArray(i)||typeof i.kind!="string"||i.mode!=="base"&&i.mode!=="orchestrator"||i.lifecycle!=="terminal"&&i.lifecycle!=="resident")throw a(`${o} must be a persona state`);return i},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}r(oe,"parsePersonaAckBody");function re(e){const t=e.params.id,n=X(e.body),o=n.sessionFile===null?null:N(n.sessionFile);return{status:200,body:l(()=>{const s=h(t);if(I(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const u=s.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))return{action:"shutdown"};if(n.reason==="new"&&s.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&s.fork_from!=null&&s.pi_session_id==null&&o===null)return{action:"shutdown"};const d=o===null?null:P(o);if(d!==null&&d.node_id!==t){if(L(d.pi_pid))return U(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${o}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const c=q(d.node_id);if(c===null||E({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})!=="transferred")return{action:"shutdown"}}else if(j(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(J(t),s.intent==="refresh"&&b(t,"revive")),{action:"none"}})}}r(re,"handleSessionBound");function se(e,t){const n=k(e);if(n===null){if(t.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${e}`,{received:e})}if($(e,new Date().toISOString()),t.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(b(e,"finish"),f(e),w(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(t.stopReason!=="stop"&&t.stopReason!=="length")return f(e,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const o={pushedFinal:t.pushedFinal};if(o.pushedFinal||n.status==="done")return f(e),w(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return f(e),{action:"shutdown"};const i=D(e,o,t.backgroundJobsRunning);return f(e),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?O(e)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:w(e)!==null||W(e)||O(e)?{action:"stay_dormant"}:(b(e,"release"),{action:"shutdown"})}r(se,"settleBroker");function ae(e){const t=e.params.id,n=Z(e.body);m(t,n.expected_execution_id);const o=l(()=>se(t,n));return o.action!=="reprompt"&&Y(t),{status:200,body:o}}r(ae,"handleSettle");function de(e){const t=e.params.id,n=ee(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=H(t);if(i===void 0)return{action:"stay_dormant"};const s=h(t);return Q(t,s,i)?(f(t),b(t,"park"),w(t)!==null&&S(t),_(t,{pane:null,tmux_session:null,window:null}),z({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...M(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}r(de,"handleParkComplete");function ue(e){const t=e.params.id;return m(t,p(e.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:K(t)?"recorded":"none"}))}}r(ue,"handleParkActivity");function ce(e){const t=e.params.id,n=te(e.body);return m(t,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>V(h(t),n.spec,n.pinnedOverride,n.userSelected)).model_override}}}r(ce,"handleModelCommit");function le(e){return{status:200,body:ne(e.params.id)}}r(le,"handleExtensionState");function pe(e){const t=e.params.id,n=ie(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:B(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const s=n.expected;if(i.name!==s.name||(i.description??"")!==s.description||(i.title??"")!==s.title||(i.icon??"")!==s.icon||i.kind!==s.kind)return{applied:!1};const u=g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:B(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}r(pe,"handleGeneratedName");function fe(e){const t=e.params.id,n=oe(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t),s={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},u=i.persona_ack,d=u===void 0?s:{kind:u.kind??i.kind,mode:u.mode,lifecycle:u.lifecycle};return!F(s,n.to)||!F(d,n.from)?{applied:!1}:(g(t,{persona_ack:n.to}),{applied:!0})})}}r(fe,"handlePersonaAck");const qe=[{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:re},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:ae},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:de},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:ue},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:ce},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:le},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:fe}];export{qe as brokerOperationRoutes};
1
+ var F=Object.defineProperty;var r=(t,e)=>F(t,"name",{value:e,configurable:!0});import{canonicalSessionFile as A,findNodeBySessionFile as P,getNode as k,isWarmSpare as T,listNodeIdentities as I,recordSettledTurn as R,setPresence as w,subscriptionsOf as $,updateNode as g,updateNodeTelemetry as q}from"../../../core/canvas/canvas.js";import{recordExecutionPid as C}from"../../../core/canvas/executions.js";import{bindSession as j,readLiveSession as E,transferSession as M}from"../../../core/canvas/sessions.js";import{isSafeNodeId as D}from"../../../core/canvas/paths.js";import{isPidAlive as L}from"../../../core/canvas/pid.js";import{editorLabel as N}from"../../../core/canvas/labels.js";import{assembleNodeSubject as G}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as s}from"../../../core/errors.js";import{hasUnseenWakeMail as O}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as J}from"../../../core/runtime/kickoff.js";import{transition as h}from"../../../core/runtime/lifecycle.js";import{focusOf as b,tearDownNode as x}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../../../core/runtime/broker/client-registry.js";import{evaluateStop as U}from"../../../core/runtime/stop-guard.js";import{clearFault as m,recordFault as V}from"../../../core/canvas/recovery.js";import{updateModelRecipe as Y}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as z}from"../../review/finish.js";import{emitEvent as H}from"../../../core/events/emit.js";import{consumePendingPark as K,recordPendingParkActivity as Q}from"../../park-pending.js";import{shouldParkAfterSummary as X}from"../../park-activity.js";import{requireCurrentExecution as f}from"./broker-recovery.js";function p(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw s(`${e} requires a JSON body`);return t}r(p,"objectBody");function Z(t){const e=p(t,"broker session-bound");if(typeof e.executionId!="string"||e.executionId==="")throw s("executionId must be a non-empty string");if(typeof e.piSessionId!="string"||e.piSessionId==="")throw s("piSessionId must be a non-empty string");if(e.sessionFile!==null&&typeof e.sessionFile!="string")throw s("sessionFile must be a string or null");if(!Number.isSafeInteger(e.pid)||e.pid<=0)throw s("pid must be a positive safe integer");if(e.reason!==null&&typeof e.reason!="string")throw s("reason must be a string or null");if(!Array.isArray(e.reviewBoundaryIds)||!e.reviewBoundaryIds.every(n=>typeof n=="string"))throw s("reviewBoundaryIds must be an array of strings");return e}r(Z,"parseSessionBoundBody");function ee(t){const e=p(t,"broker settle");if(typeof e.stopReason!="string")throw s("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof e[n]!="boolean")throw s(`${n} must be a boolean`);return e}r(ee,"parseSettleBody");function te(t){const e=p(t,"broker park-complete");if(e.outcome!=="completed"&&e.outcome!=="failed")throw s("outcome must be completed or failed");return e}r(te,"parseParkCompleteBody");function ne(t){const e=p(t,"broker telemetry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw s("expected_execution_id must be a non-empty string");if(typeof e.tokens_in!="number"||!Number.isFinite(e.tokens_in)||e.tokens_in<0)throw s("tokens_in must be a non-negative finite number");if(e.context_tokens!==null&&(typeof e.context_tokens!="number"||!Number.isFinite(e.context_tokens)||e.context_tokens<0))throw s("context_tokens must be a non-negative finite number or null");if(e.last_activity!==null&&typeof e.last_activity!="string")throw s("last_activity must be a string or null");if(typeof e.updated_at!="string"||Number.isNaN(Date.parse(e.updated_at)))throw s("updated_at must be an ISO timestamp");return{...e,updated_at:new Date(e.updated_at).toISOString()}}r(ne,"parseTelemetryBody");function ie(t){const e=p(t,"broker model");if(typeof e.spec!="string"||e.spec.trim()==="")throw s("spec must be a non-empty string");if(e.pinnedOverride!==void 0&&typeof e.pinnedOverride!="boolean")throw s("pinnedOverride must be a boolean when present");if(typeof e.userSelected!="boolean")throw s("userSelected must be a boolean");return e}r(ie,"parseModelCommitBody");function _(t){const e=k(t);if(e===null)throw v(`unknown node: ${t}`,{received:t});return e}r(_,"requireNode");function y(t){return{node_id:t.node_id,name:t.name,...t.description===void 0?{}:{description:t.description},...t.title===void 0?{}:{title:t.title},...t.icon===void 0?{}:{icon:t.icon},kind:t.kind,mode:t.mode,lifecycle:t.lifecycle,status:t.status,cwd:t.cwd,parent:t.parent??null,fork_from:t.fork_from??null,profile_id:t.profile_id??null,...t.managed_worktree===void 0?{}:{managed_worktree:t.managed_worktree===null?null:{state:t.managed_worktree.state,...t.managed_worktree.cleanup===void 0?{}:{cleanup:t.managed_worktree.cleanup},path:t.managed_worktree.path,branch:t.managed_worktree.branch,base_ref:t.managed_worktree.base_ref,base_sha:t.managed_worktree.base_sha}},...t.review_binding===void 0?{}:{review_binding:t.review_binding??null},intent:t.intent??null,...t.persona_ack===void 0?{}:{persona_ack:t.persona_ack},created:t.created}}r(y,"extensionNode");function oe(t){const e=_(t),n=[],o=new Set([t]);let i=e.parent??null;for(;i!==null&&i!==""&&!o.has(i);){o.add(i);const c=k(i);if(c===null)break;n.unshift(y(c)),i=c.parent??null}const a=$(t).map(c=>k(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,S)=>c.status===S.status?0:c.status==="active"?-1:S.status==="active"?1:0).map(y),u=typeof e.fork_source_file=="string"?P(e.fork_source_file):null,d=G(t);if(d===null)throw v(`unknown node: ${t}`,{received:t});return{node:y(e),warm_spare:T(t),ancestors:n,children:a,fork_source:u===null?null:y(u),subject:d,report_nodes:I()}}r(oe,"extensionState");function B(t,e){return t?.kind===e.kind&&t?.mode===e.mode&&t?.lifecycle===e.lifecycle}r(B,"samePersona");function re(t){const e=p(t,"broker generated-name");if(e.kind!=="initial"&&e.kind!=="recap")throw s("kind must be initial or recap");if(typeof e.description!="string"||typeof e.title!="string"||typeof e.icon!="string")throw s("description, title, and icon must be strings");if(e.kind==="initial")return e;const n=e.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(o=>typeof n[o]!="string"))throw s("recap expected must contain name, description, title, icon, and kind strings");return e}r(re,"parseGeneratedNameBody");function se(t){const e=p(t,"broker persona-ack"),n=r(o=>{const i=e[o];if(typeof i!="object"||i===null||Array.isArray(i)||typeof i.kind!="string"||i.mode!=="base"&&i.mode!=="orchestrator"||i.lifecycle!=="terminal"&&i.lifecycle!=="resident")throw s(`${o} must be a persona state`);return i},"parse");return{expected_execution_id:e.expected_execution_id,from:n("from"),to:n("to")}}r(se,"parsePersonaAckBody");function ae(t){const e=t.params.id,n=Z(t.body),o=n.sessionFile===null?null:A(n.sessionFile);return{status:200,body:l(()=>{const a=_(e);if(C(n.executionId,e,n.pid)==="shutdown")return{action:"shutdown"};const u=a.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))return{action:"shutdown"};if(n.reason==="new"&&a.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&a.fork_from!=null&&a.pi_session_id==null&&o===null)return{action:"shutdown"};const d=o===null?null:P(o);if(d!==null&&d.node_id!==e){if(L(d.pi_pid))return V(e,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${o}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const c=E(d.node_id);if(c===null||M({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:e,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})!=="transferred")return{action:"shutdown"}}else if(j(e,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(J(e),a.intent==="refresh"&&h(e,"revive")),{action:"none"}})}}r(ae,"handleSessionBound");function de(t,e){const n=k(t);if(n===null){if(e.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${t}`,{received:t})}if(R(t,new Date().toISOString()),e.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(h(t,"finish"),m(t),b(t)!==null&&x(t),w(t,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(e.stopReason!=="stop"&&e.stopReason!=="length")return m(t,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const o={pushedFinal:e.pushedFinal};if(o.pushedFinal||n.status==="done")return m(t),b(t)!==null&&x(t),w(t,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return m(t),{action:"shutdown"};const i=U(t,o,e.backgroundJobsRunning);return m(t),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?O(t)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:b(t)!==null||W(t)||O(t)?{action:"stay_dormant"}:(h(t,"release"),{action:"shutdown"})}r(de,"settleBroker");function ue(t){const e=t.params.id,n=ee(t.body);f(e,n.expected_execution_id);const o=l(()=>de(e,n));return o.action!=="reprompt"&&z(e),{status:200,body:o}}r(ue,"handleSettle");function ce(t){const e=t.params.id,n=te(t.body);return f(e,n.expected_execution_id),{status:200,body:l(()=>{const i=K(e);if(i===void 0)return{action:"stay_dormant"};const a=_(e);return X(e,a,i)?(m(e),h(e,"park"),b(e)!==null&&x(e),w(e,{pane:null,tmux_session:null,window:null}),H({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...D(e)?{node_id:e}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}r(ce,"handleParkComplete");function le(t){const e=t.params.id;return f(e,p(t.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:Q(e)?"recorded":"none"}))}}r(le,"handleParkActivity");function pe(t){const e=t.params.id,n=ne(t.body);return f(e,n.expected_execution_id),l(()=>{q(e,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at})}),{status:204}}r(pe,"handleTelemetry");function fe(t){const e=t.params.id,n=ie(t.body);return f(e,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>Y(_(e),n.spec,n.pinnedOverride,n.userSelected)).model_override}}}r(fe,"handleModelCommit");function me(t){return{status:200,body:oe(t.params.id)}}r(me,"handleExtensionState");function _e(t){const e=t.params.id,n=re(t.body);return f(e,n.expected_execution_id),{status:200,body:l(()=>{const i=_(e);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=g(e,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:N(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const a=n.expected;if(i.name!==a.name||(i.description??"")!==a.description||(i.title??"")!==a.title||(i.icon??"")!==a.icon||i.kind!==a.kind)return{applied:!1};const u=g(e,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:N(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}r(_e,"handleGeneratedName");function ke(t){const e=t.params.id,n=se(t.body);return f(e,n.expected_execution_id),{status:200,body:l(()=>{const i=_(e),a={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},u=i.persona_ack,d=u===void 0?a:{kind:u.kind??i.kind,mode:u.mode,lifecycle:u.lifecycle};return!B(a,n.to)||!B(d,n.from)?{applied:!1}:(g(e,{persona_ack:n.to}),{applied:!0})})}}r(ke,"handlePersonaAck");const De=[{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:ae},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:ue},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:ce},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:le},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:fe},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:me},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:ke}];export{De as brokerOperationRoutes};
@@ -1,6 +1,6 @@
1
- var E=Object.defineProperty;var u=(t,e)=>E(t,"name",{value:e,configurable:!0});import{pruneNodes as I,pruneToLimit as K,rosterEdges as $,rosterNodes as A}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as G}from"../../../core/bash-jobs.js";import{contextDir as D}from"../../../core/canvas/paths.js";import{nowIso as M}from"../../../core/fs-utils.js";import{isPidPresent as q}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as H,enrichRowsFromSource as J}from"../../../core/canvas/render-source.js";import{localCanvasSource as N}from"../../../core/canvas/source.js";import{listFocuses as z}from"../../../core/canvas/focuses.js";import{ticketCountsForNodes as j,ticketsAcrossCanvas as Q}from"../../../core/canvas/attention.js";import{buildCorpus as U,groupCorpus as Y,resolveRef as V}from"../../../core/canvas/history.js";import{reapEmptyNodes as W}from"../../../core/runtime/placement.js";import{notFound as X,usage as p}from"../../../core/errors.js";function Z(){return{status:200,body:{items:Q().map(e=>({node_id:e.node_id,name:e.name,cwd:e.cwd,count:e.count,subjects:e.subjects}))}}}u(Z,"handleAttention");function ee(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw p("attention count request requires node_ids: string[]");const n=e.node_ids;if(!n.every(s=>typeof s=="string"))throw p("attention count request node_ids must contain only strings");return{status:200,body:{counts:j(n)}}}u(ee,"handleAttentionCounts");function R(t){return Buffer.from(String(t),"utf8").toString("base64")}u(R,"encodeCursor");function B(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw p(`invalid cursor: ${t}`);return e}u(B,"decodeCursor");function te(t,e,n){const s=t.loadBody().split(`
2
- `);if(e.length>0){const i=s.findIndex(d=>{const o=d.toLowerCase();return e.some(c=>o.includes(c))});if(i!==-1)return s.slice(i,i+n).map(d=>d.trim()).filter(d=>d!=="").join(" \u23CE ")}const a=s.map(i=>i.trim()).filter(i=>i!=="").slice(0,n).join(" \u23CE ");return a!==""?a:t.title}u(te,"snippet");function ne(t,e,n){const r=[...t];return e==="relevance"&&n!==void 0?r.sort((s,a)=>(n.get(a.ref)??0)-(n.get(s.ref)??0)||a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)):e==="oldest"?r.sort((s,a)=>s.tsMs-a.tsMs||s.ref.localeCompare(a.ref)):r.sort((s,a)=>a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)),r}u(ne,"sortArtifacts");function oe(t){if(t==null)return{};if(typeof t!="object")throw p("history search body must be a JSON object");return t}u(oe,"parseSearchBody");function re(t){if(t===null||typeof t!="object")throw p("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw p("history grep body requires a non-empty pattern");return e}u(re,"parseGrepBody");function C(t){const e={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},n={types:t.types,reportKind:t.report_kind,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from};return U(e,n)}u(C,"buildCorpusFromQuery");function se(t){if(t==null)return{};if(typeof t!="object")throw p("history stats body must be a JSON object");return t}u(se,"parseStatsBody");const x=["origin","node","kind","day","type","role"];function ie(t){const e=se(t.body),n=e.group_by??"type";if(!x.includes(n))throw p(`--group-by must be one of: ${x.join(", ")}; received: ${String(e.group_by)}`);const r=C(e),s=Y(r,n);return{status:200,body:{group_by:n,groups:s,total:s.reduce((i,d)=>i+d.count,0),scanned:r.length}}}u(ie,"handleHistoryStats");function de(t){const e=re(t.body),n=Math.min(100,Math.max(1,e.limit??20)),r=C(e),s=e.cursor!==void 0?B(e.cursor):0;let a;try{a=new RegExp(e.pattern,"i")}catch{throw p(`invalid regex pattern: ${e.pattern}`)}const i=[];for(const f of r)f.loadBody().split(`
3
- `).forEach((y,_)=>{a.test(y)&&i.push({ref:f.ref,node:`${f.nodeName} (${f.nodeId})`,ts:f.ts,line:_+1,text:y.trim()})});i.sort((f,m)=>f.ref.localeCompare(m.ref)||f.line-m.line);const d=i.slice(s,s+n),o=s+n<i.length?R(s+n):null;return{status:200,body:{hits:d,next_cursor:o,total:i.length}}}u(de,"handleHistoryGrep");function ae(t){const e=oe(t.body),n=(e.query??"").trim(),r=e.weigh_body===!0,s=e.full===!0,a=Math.max(1,e.snippet_lines??1),i=Math.min(100,Math.max(1,e.limit??20)),d=C(e),o=e.cursor!==void 0?B(e.cursor):0,c=n.toLowerCase().split(/\s+/).filter(l=>l.length>0);let f=d,m;const y=e.sort??(c.length>0?"relevance":"recency");if(c.length>0&&y==="relevance"){m=new Map;const l=[];for(const h of d){const S=h.title.toLowerCase(),F=h.nodeName.toLowerCase(),P=h.nodeDesc.toLowerCase(),k=r?h.loadBody().toLowerCase():null;let b=0;for(const v of c)S.includes(v)&&(b+=10),F.includes(v)&&(b+=5),P.includes(v)&&(b+=3),k!==null&&k.includes(v)&&(b+=1);b>0&&(m.set(h.ref,b),l.push(h))}f=l}else c.length>0&&(f=d.filter(l=>{const h=`${l.title}
1
+ var P=Object.defineProperty;var u=(t,e)=>P(t,"name",{value:e,configurable:!0});import{graphNodes as I,pruneNodes as K,pruneToLimit as A,rosterEdges as C,rosterNodes as D}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as q}from"../../../core/bash-jobs.js";import{contextDir as H}from"../../../core/canvas/paths.js";import{nowIso as k}from"../../../core/fs-utils.js";import{isPidPresent as J}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as z,enrichRowsFromSource as Q}from"../../../core/canvas/render-source.js";import{localCanvasSource as M}from"../../../core/canvas/source.js";import{ticketCountsForNodes as j,ticketsAcrossCanvas as U}from"../../../core/canvas/attention.js";import{buildCorpus as Y,groupCorpus as V,resolveRef as W}from"../../../core/canvas/history.js";import{listFocuses as R,reapEmptyNodes as X}from"../../../core/runtime/placement.js";import{notFound as Z,usage as p}from"../../../core/errors.js";import{toGraphNodeDTO as ee}from"../map.js";function te(){return{status:200,body:{items:U().map(e=>({node_id:e.node_id,name:e.name,cwd:e.cwd,count:e.count,subjects:e.subjects}))}}}u(te,"handleAttention");function ne(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw p("attention count request requires node_ids: string[]");const n=e.node_ids;if(!n.every(s=>typeof s=="string"))throw p("attention count request node_ids must contain only strings");return{status:200,body:{counts:j(n)}}}u(ne,"handleAttentionCounts");function B(t){return Buffer.from(String(t),"utf8").toString("base64")}u(B,"encodeCursor");function x(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw p(`invalid cursor: ${t}`);return e}u(x,"decodeCursor");function oe(t,e,n){const s=t.loadBody().split(`
2
+ `);if(e.length>0){const i=s.findIndex(d=>{const o=d.toLowerCase();return e.some(c=>o.includes(c))});if(i!==-1)return s.slice(i,i+n).map(d=>d.trim()).filter(d=>d!=="").join(" \u23CE ")}const a=s.map(i=>i.trim()).filter(i=>i!=="").slice(0,n).join(" \u23CE ");return a!==""?a:t.title}u(oe,"snippet");function re(t,e,n){const r=[...t];return e==="relevance"&&n!==void 0?r.sort((s,a)=>(n.get(a.ref)??0)-(n.get(s.ref)??0)||a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)):e==="oldest"?r.sort((s,a)=>s.tsMs-a.tsMs||s.ref.localeCompare(a.ref)):r.sort((s,a)=>a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)),r}u(re,"sortArtifacts");function se(t){if(t==null)return{};if(typeof t!="object")throw p("history search body must be a JSON object");return t}u(se,"parseSearchBody");function ie(t){if(t===null||typeof t!="object")throw p("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw p("history grep body requires a non-empty pattern");return e}u(ie,"parseGrepBody");function $(t){const e={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},n={types:t.types,reportKind:t.report_kind,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from};return Y(e,n)}u($,"buildCorpusFromQuery");function de(t){if(t==null)return{};if(typeof t!="object")throw p("history stats body must be a JSON object");return t}u(de,"parseStatsBody");const L=["origin","node","kind","day","type","role"];function ae(t){const e=de(t.body),n=e.group_by??"type";if(!L.includes(n))throw p(`--group-by must be one of: ${L.join(", ")}; received: ${String(e.group_by)}`);const r=$(e),s=V(r,n);return{status:200,body:{group_by:n,groups:s,total:s.reduce((i,d)=>i+d.count,0),scanned:r.length}}}u(ae,"handleHistoryStats");function ce(t){const e=ie(t.body),n=Math.min(100,Math.max(1,e.limit??20)),r=$(e),s=e.cursor!==void 0?x(e.cursor):0;let a;try{a=new RegExp(e.pattern,"i")}catch{throw p(`invalid regex pattern: ${e.pattern}`)}const i=[];for(const f of r)f.loadBody().split(`
3
+ `).forEach((y,b)=>{a.test(y)&&i.push({ref:f.ref,node:`${f.nodeName} (${f.nodeId})`,ts:f.ts,line:b+1,text:y.trim()})});i.sort((f,m)=>f.ref.localeCompare(m.ref)||f.line-m.line);const d=i.slice(s,s+n),o=s+n<i.length?B(s+n):null;return{status:200,body:{hits:d,next_cursor:o,total:i.length}}}u(ce,"handleHistoryGrep");function ue(t){const e=se(t.body),n=(e.query??"").trim(),r=e.weigh_body===!0,s=e.full===!0,a=Math.max(1,e.snippet_lines??1),i=Math.min(100,Math.max(1,e.limit??20)),d=$(e),o=e.cursor!==void 0?x(e.cursor):0,c=n.toLowerCase().split(/\s+/).filter(l=>l.length>0);let f=d,m;const y=e.sort??(c.length>0?"relevance":"recency");if(c.length>0&&y==="relevance"){m=new Map;const l=[];for(const h of d){const S=h.title.toLowerCase(),F=h.nodeName.toLowerCase(),G=h.nodeDesc.toLowerCase(),N=r?h.loadBody().toLowerCase():null;let _=0;for(const v of c)S.includes(v)&&(_+=10),F.includes(v)&&(_+=5),G.includes(v)&&(_+=3),N!==null&&N.includes(v)&&(_+=1);_>0&&(m.set(h.ref,_),l.push(h))}f=l}else c.length>0&&(f=d.filter(l=>{const h=`${l.title}
4
4
  ${l.nodeName}
5
5
  ${l.nodeDesc}${r?`
6
- `+l.loadBody():""}`.toLowerCase();return c.some(S=>h.includes(S))}));const _=ne(f,y,m),O=_.slice(o,o+i),T=o+i<_.length?R(o+i):null;return{status:200,body:{hits:O.map(l=>{const h={ref:l.ref,node:`${l.nodeName} (${l.nodeId})`,kind:l.nodeKind,source:l.source==="report"&&l.reportKind?`report:${l.reportKind}`:l.source,ts:l.ts};return y==="relevance"&&m!==void 0&&(h.score=m.get(l.ref)??0),s?h.body=l.loadBody():h.snippet=te(l,c,a),h}),next_cursor:T,total:_.length}}}u(ae,"handleHistorySearch");function ce(t){const e=(t.query.get("ref")??"").trim(),n=t.query.get("frontmatter")==="true";if(!e.includes(":"))throw p(`ref must be <node-id>:<relpath>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search` or `crtr node inspect artifacts <node-id>`."});let r;try{r=V(e)}catch(o){throw p(`ref rejected: ${o.message}`,{received:e,next:"Refs come verbatim from `crtr canvas history search`; do not hand-construct relpaths."})}if(r===null)throw X(`no artifact for ref: ${e}`,{ref:e,next:"The node or file may not exist. Re-run `crtr canvas history search` for a current ref, or `crtr node inspect artifacts <node-id>` to list a node's artifacts."});const s=r.source==="report"&&r.reportKind?`report:${r.reportKind}`:r.source,i=(t.query.get("format")==="raw"||n)&&r.raw!==null?r.raw:r.body;return{status:200,body:{ref:e,node:`${r.nodeName} (${r.nodeId})`,source:s,ts:r.ts,content:i}}}u(ce,"handleHistoryRead");function ue(t){for(const[r]of t.query)if(r!=="live")throw p(`unknown snapshot query parameter: ${r}`);const e=t.query.getAll("live");if(e.length>1)throw p("live must appear at most once");const n=e[0];if(n===void 0||n==="false"||n==="0")return!1;if(n==="true"||n==="1")return!0;throw p("live must be true or false")}u(ue,"snapshotLiveOnly");async function le(t){const e=new Set(z().map(o=>o.node_id)),n=await H(N,e,ue(t)),r=j(n.map(o=>o.node_id));await J(N,n,r);const s=n.map(o=>{const c=o.srcRow,f=c?.host_kind??"tmux";return{node_id:o.node_id,name:o.name,title:o.handle??o.name,description:o.description??null,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle??c?.lifecycle,status:o.status,cwd:o.cwd,profile_id:o.profile_id??null,parent:c?.parent??null,created:o.created,host_kind:f,enterable:f==="broker",attention_count:o.asks,...c?.cycles!=null?{cycles:c.cycles}:{},...o.mtimeMs!==void 0?{last_activity:new Date(o.mtimeMs).toISOString()}:{},ctx_tokens:o.ctx_tokens,streaming:o.streaming??!1,jobs_active:c!==void 0&&q(c.pi_pid)?G(D(o.node_id)).length:0,waiting_for:c?.waiting_for??null,hanging:o.hanging??null,viewed:o.viewed??!1,final_report:c?.final_report??null,finalized_at:c?.finalized_at??null}}),a=new Map;for(const o of $()){const c=a.get(o.from_id);c===void 0?a.set(o.from_id,[o.to_id]):c.push(o.to_id)}const i=Object.fromEntries(n.map(o=>[o.node_id,a.get(o.node_id)??[]]));return{status:200,body:{generated_at:M(),nodes:s,subscriptions:i}}}u(le,"handleSnapshot");function L(){const t=A().map(n=>{const r=n.host_kind??"tmux";return{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:r,enterable:r==="broker",parent:n.parent,created:n.created}}),e=$().map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created}));return{generated_at:M(),nodes:t,edges:e}}u(L,"buildRoster");let g=null,w=null;function fe(){return g===null?(g=Promise.resolve().then(()=>L()).finally(()=>{g=null}),g):(w===null&&(w=g.then(()=>L()).finally(()=>{w=null})),w)}u(fe,"rosterCoalesced");async function me(){return{status:200,body:await fe()}}u(me,"handleRoster");function pe(t){if(t==null)return{};if(typeof t!="object")throw p("prune body must be a JSON object");const e=t,n=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="number"||!Number.isFinite(m))throw p(`${f} must be a number`);return m}},"num"),r=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="boolean")throw p(`${f} must be a boolean`);return m}},"bool"),s={},a=n("limit");a!==void 0&&(s.limit=a);const i=n("ttl_days");i!==void 0&&(s.ttl_days=i);const d=r("include_stale");d!==void 0&&(s.include_stale=d);const o=r("empty");o!==void 0&&(s.empty=o);const c=r("dry_run");return c!==void 0&&(s.dry_run=c),s}u(pe,"parsePruneBody");function he(t){const e=pe(t.body),n=e.ttl_days??14,r=e.dry_run??!1;let s;return e.limit!==void 0?s=K({maxNodes:e.limit,dryRun:r}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})):e.empty===!0?s=W({dryRun:r}).map(d=>({node_id:d,status:"empty",created:""})):s=I({ttlDays:n,dryRun:r,includeStale:e.include_stale??!1}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})),{status:200,body:{pruned:s,dry_run:r,ttl_days:n}}}u(he,"handlePrune");const xe=[{method:"GET",pattern:"/v1/canvas/attention",handler:Z},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:ee},{method:"POST",pattern:"/v1/canvas/history/search",handler:ae},{method:"POST",pattern:"/v1/canvas/history/grep",handler:de},{method:"GET",pattern:"/v1/canvas/history/read",handler:ce},{method:"POST",pattern:"/v1/canvas/history/stats",handler:ie},{method:"GET",pattern:"/v1/canvas/snapshot",handler:le},{method:"GET",pattern:"/v1/canvas/roster",handler:me},{method:"POST",pattern:"/v1/canvas/prune",handler:he}];export{xe as canvasRoutes};
6
+ `+l.loadBody():""}`.toLowerCase();return c.some(S=>h.includes(S))}));const b=re(f,y,m),T=b.slice(o,o+i),E=o+i<b.length?B(o+i):null;return{status:200,body:{hits:T.map(l=>{const h={ref:l.ref,node:`${l.nodeName} (${l.nodeId})`,kind:l.nodeKind,source:l.source==="report"&&l.reportKind?`report:${l.reportKind}`:l.source,ts:l.ts};return y==="relevance"&&m!==void 0&&(h.score=m.get(l.ref)??0),s?h.body=l.loadBody():h.snippet=oe(l,c,a),h}),next_cursor:E,total:b.length}}}u(ue,"handleHistorySearch");function le(t){const e=(t.query.get("ref")??"").trim(),n=t.query.get("frontmatter")==="true";if(!e.includes(":"))throw p(`ref must be <node-id>:<relpath>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search` or `crtr node inspect artifacts <node-id>`."});let r;try{r=W(e)}catch(o){throw p(`ref rejected: ${o.message}`,{received:e,next:"Refs come verbatim from `crtr canvas history search`; do not hand-construct relpaths."})}if(r===null)throw Z(`no artifact for ref: ${e}`,{ref:e,next:"The node or file may not exist. Re-run `crtr canvas history search` for a current ref, or `crtr node inspect artifacts <node-id>` to list a node's artifacts."});const s=r.source==="report"&&r.reportKind?`report:${r.reportKind}`:r.source,i=(t.query.get("format")==="raw"||n)&&r.raw!==null?r.raw:r.body;return{status:200,body:{ref:e,node:`${r.nodeName} (${r.nodeId})`,source:s,ts:r.ts,content:i}}}u(le,"handleHistoryRead");function fe(t){for(const[r]of t.query)if(r!=="live")throw p(`unknown snapshot query parameter: ${r}`);const e=t.query.getAll("live");if(e.length>1)throw p("live must appear at most once");const n=e[0];if(n===void 0||n==="false"||n==="0")return!1;if(n==="true"||n==="1")return!0;throw p("live must be true or false")}u(fe,"snapshotLiveOnly");async function me(t){const e=new Set(R().map(o=>o.node_id)),n=await z(M,e,fe(t)),r=j(n.map(o=>o.node_id));await Q(M,n,r);const s=n.map(o=>{const c=o.srcRow,f=c?.host_kind??"tmux";return{node_id:o.node_id,name:o.name,title:o.handle??o.name,description:o.description??null,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle??c?.lifecycle,status:o.status,cwd:o.cwd,profile_id:o.profile_id??null,parent:c?.parent??null,created:o.created,host_kind:f,enterable:f==="broker",attention_count:o.asks,...c?.cycles!=null?{cycles:c.cycles}:{},...o.mtimeMs!==void 0?{last_activity:new Date(o.mtimeMs).toISOString()}:{},ctx_tokens:o.ctx_tokens,streaming:o.streaming??!1,jobs_active:c!==void 0&&J(c.pi_pid)?q(H(o.node_id)).length:0,waiting_for:c?.waiting_for??null,hanging:o.hanging??null,viewed:o.viewed??!1,final_report:c?.final_report??null,finalized_at:c?.finalized_at??null}}),a=new Map;for(const o of C()){const c=a.get(o.from_id);c===void 0?a.set(o.from_id,[o.to_id]):c.push(o.to_id)}const i=Object.fromEntries(n.map(o=>[o.node_id,a.get(o.node_id)??[]]));return{status:200,body:{generated_at:k(),nodes:s,subscriptions:i}}}u(me,"handleSnapshot");function O(){const t=D().map(n=>{const r=n.host_kind??"tmux";return{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:r,enterable:r==="broker",parent:n.parent,created:n.created}}),e=C().map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created}));return{generated_at:k(),nodes:t,edges:e}}u(O,"buildRoster");let g=null,w=null;function pe(){return g===null?(g=Promise.resolve().then(()=>O()).finally(()=>{g=null}),g):(w===null&&(w=g.then(()=>O()).finally(()=>{w=null})),w)}u(pe,"rosterCoalesced");async function he(){return{status:200,body:await pe()}}u(he,"handleRoster");function ye(){return{status:200,body:{generated_at:k(),nodes:I().map(ee),edges:C().map(e=>({from_id:e.from_id,to_id:e.to_id,active:e.active,created:e.created})),focused_node_ids:R().map(e=>e.node_id)}}}u(ye,"handleGraph");function _e(t){if(t==null)return{};if(typeof t!="object")throw p("prune body must be a JSON object");const e=t,n=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="number"||!Number.isFinite(m))throw p(`${f} must be a number`);return m}},"num"),r=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="boolean")throw p(`${f} must be a boolean`);return m}},"bool"),s={},a=n("limit");a!==void 0&&(s.limit=a);const i=n("ttl_days");i!==void 0&&(s.ttl_days=i);const d=r("include_stale");d!==void 0&&(s.include_stale=d);const o=r("empty");o!==void 0&&(s.empty=o);const c=r("dry_run");return c!==void 0&&(s.dry_run=c),s}u(_e,"parsePruneBody");function be(t){const e=_e(t.body),n=e.ttl_days??14,r=e.dry_run??!1;let s;return e.limit!==void 0?s=A({maxNodes:e.limit,dryRun:r}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})):e.empty===!0?s=X({dryRun:r}).map(d=>({node_id:d,status:"empty",created:""})):s=K({ttlDays:n,dryRun:r,includeStale:e.include_stale??!1}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})),{status:200,body:{pruned:s,dry_run:r,ttl_days:n}}}u(be,"handlePrune");const Te=[{method:"GET",pattern:"/v1/canvas/attention",handler:te},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:ne},{method:"POST",pattern:"/v1/canvas/history/search",handler:ue},{method:"POST",pattern:"/v1/canvas/history/grep",handler:ce},{method:"GET",pattern:"/v1/canvas/history/read",handler:le},{method:"POST",pattern:"/v1/canvas/history/stats",handler:ae},{method:"GET",pattern:"/v1/canvas/snapshot",handler:me},{method:"GET",pattern:"/v1/canvas/roster",handler:he},{method:"GET",pattern:"/v1/canvas/graph",handler:ye},{method:"POST",pattern:"/v1/canvas/prune",handler:be}];export{Te as canvasRoutes};
@@ -7,7 +7,7 @@ import type { CloseNodeResult } from '../../core/runtime/close.js';
7
7
  import { type PushResult } from '../../core/feed/feed.js';
8
8
  import type { PageFeedback, PageFeedbackComment } from '../../core/human/feedback.js';
9
9
  import type { OnDiskMigrationRunResult } from '../../migrations/runner.js';
10
- import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodeOutcomeSummaryDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
10
+ import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodeOutcomeSummaryDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, GraphNodeDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
11
11
  export declare function toMigrateStateDTO(result: OnDiskMigrationRunResult, options: {
12
12
  resumed: boolean;
13
13
  resumeError?: string;
@@ -37,6 +37,20 @@ export interface OutcomeDeliveryDTOInput {
37
37
  /** Project a durable delivery row without exposing its execution coordinates or stderr tail. */
38
38
  export declare function toOutcomeDeliveryDTO(row: OutcomeDeliveryDTOInput): OutcomeDeliveryDTO;
39
39
  /** Project the queryable row (what `listNodes` yields) into a summary DTO. */
40
+ export declare function toGraphNodeDTO(row: {
41
+ node_id: string;
42
+ name: string;
43
+ description: string | null;
44
+ cycles: number | null;
45
+ kind: string;
46
+ status: NodeStatusDTO;
47
+ frozen_at: string | null;
48
+ pi_pid: number | null;
49
+ telemetry_context_tokens: number | null;
50
+ telemetry_last_activity: string | null;
51
+ fault: NodeRow['fault'];
52
+ streaming: boolean;
53
+ }): GraphNodeDTO;
40
54
  export declare function toNodeSummaryDTO(row: NodeRow): NodeSummaryDTO;
41
55
  /** The subscription/child edges a detail projection needs. The handler gathers
42
56
  * these from `subscriptionsOf`/`subscribersOf` + a children query and passes