@north-light/cli 0.3.506 → 0.3.507

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.
@@ -1739,7 +1739,7 @@ ${u}`,"1").then(l=>{let d=a.options[Number.parseInt(l,10)-1]?.id;if(d===void 0)t
1739
1739
  ) SELECT o.* FROM chain c CROSS JOIN objects o WHERE o.rowid = c.rowid ORDER BY c.depth`).all(e.rowid)}function Ovn(t,e){let n=Age(t,e),r=n.length?n[n.length-1]:e,i=Mvn[r.type];if(!i)throw new Error(`${e.type} ${e.id} has no space: its owner chain ends at ${r.type} ${r.id}`);let o=n.length?[...n.slice(0,-1).reverse(),e]:[];return{space:r,path:o,impl:i}}function bgi(t,e){return e.type!=="document"?!1:ae(t,"SELECT source_path FROM documents WHERE object = ?").get(e.rowid)?.source_path!=null}function Nvn(t,e){return ae(t,`SELECT a.* FROM objects a WHERE a.type = 'app' AND a.deleted_at IS NULL AND EXISTS (
1740
1740
  SELECT 1 FROM objects o JOIN documents d ON d.object = o.rowid
1741
1741
  WHERE o.owner = a.rowid AND o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL)
1742
- ORDER BY a.name = 'crtr', a.name`).all().filter(r=>EXe(t,e,r))}function EXe(t,e,n){return n.type==="app"}function _gi(t,e,n){let r=`${fp(t,n).external_id.replace(/^app:/,"")}:`;return e.some(i=>i.startsWith(r)&&!i.slice(r.length).includes(":"))}function Pvn(t,e,n){return e.class==="person"?!0:e.class==="object"?e.owner.rowid===n.rowid:e.class==="app"?e.app.rowid===n.rowid||n.type==="profile"&&n.owner===e.app.rowid:e.app.rowid===n.rowid||n.type==="profile"&&e.profile?.rowid===n.rowid||n.type==="repo"&&yge(t,e,n,"rw")}function Lvn(t,e,n){if(e.class!=="node"&&!(e.class==="app"&&e.place!==void 0))return!0;let r=e.class==="app"?e.place:nb(e.node.id,t);if(r===null)return!0;let i=uge(n.rowid,t);return i===null?!r.isolated:lge(r,i)}function vgi(t,{space:e,path:n},r,i){let o=[];if(e.type==="person")o.push("user");else if(e.type==="app"&&n.length>0){let s=n[0];if(s.type==="profile")n.length>1&&o.push(`profile:${fp(t,s).external_id}`);else if(s.type==="node"||_Xe(s)){let a=fp(t,e).external_id;a!==i&&o.push(a)}}return r.type==="node"&&o.push("node"),o}function vXe(t,e,n,r,i){if(e.class==="person"||e.scopes===null)return!1;let o=e.scopes;if(o.length===0||r.space.type==="app"&&e.app.rowid===r.space.rowid)return!1;let s=fp(t,e.app).external_id;return vgi(t,r,i,s).some(a=>{let c=`crtr:objects:${n}:${a}`;return o.some(u=>la(u,c))})}function Sgi(t,e,n,r){return e.class==="person"||e.scopes===null?!1:vXe(t,e,n,Ovn(t,r),r)}function Bvn(t,e,n,r,i){let o=r.owner===null?null:t.prepare("SELECT * FROM objects WHERE rowid = ?").get(r.owner)??null;if(o===null)return!1;let s={class:"app",app:e,scopes:n??[]};return Pvn(t,s,o)?n===null||Sgi(t,s,"link",i):!1}function nl(t,e,n){return SXe(t,n)(e)}function SXe(t,e){let n=null,r=null;return i=>{if(i.class==="person")return!0;if(n??=Ovn(t,e),n.space.type==="app"&&n.path.length>0){if(r??=bgi(t,e),r&&EXe(t,i,n.space))return!0;if(_Xe(e)){if(i.app.rowid===n.space.rowid&&!Lvn(t,i,e))return!1;if(i.app.rowid!==n.space.rowid&&i.scopes!==null&&EXe(t,i,n.space)&&(e.privacy==="public"||Egi(i)&&_gi(t,i.scopes,n.space)))return!0}}return vXe(t,i,"read",n,e)||i.class==="object"&&_Xe(i.object)&&vXe(t,i,"watch",n,e)?!0:n.impl.canRead(t,i,n.space,n.path,e)}}var Egi,_Xe,lh=h(()=>{"use strict";Qt();B0();j6();fge();q6();bXe();Egi=t=>t.class!=="app"||t.place!==void 0;_Xe=t=>t.type.includes(".")});function G6(t){let e=t.match(Cgi);if(!e)return{data:null,body:t,raw:""};let n=e[1],r=t.slice(e[0].length);return{data:Igi(n),body:r,raw:n}}function Igi(t){return Tgi((0,$vn.parse)(t))}function Tgi(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{}}var $vn,Cgi,wge=h(()=>{"use strict";$vn=Kt(S4e(),1),Cgi=/^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n?/});import{closeSync as I9s,existsSync as T9s,fsyncSync as k9s,mkdirSync as R9s,openSync as D9s,readFileSync as Fvn,renameSync as M9s,writeSync as O9s}from"node:fs";import{join as kgi}from"node:path";function Rgi(t){if(!/^[0-9a-f]{64}$/.test(t))throw new Error(`invalid body hash: ${t}`);return kgi(Xo(),"bodies",t.slice(0,2),t)}function xge(t){try{return Fvn(Rgi(t),"utf8")}catch(e){throw e.code==="ENOENT"?Of(`no body ${t}`):e}}function OS(t,e){return e===null?xge(t):G6(Fvn(e,"utf8")).body}var NS=h(()=>{"use strict";Co();Rr();wge()});function fU(t,e){let n=ae(t,"SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),r=Nvn(t,e),i=e.class==="node"?[e.node,...e.repos,...e.projectRepos,e.profile,e.app]:e.class==="app"?[e.app]:e.class==="object"?[e.owner,...e.repos,e.app]:[],o=new Set;return[...i,n,...r].filter(s=>!!s&&!o.has(s.rowid)&&!!o.add(s.rowid))}function z6(t,e,n,r){return t.prepare(`SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS NULL
1742
+ ORDER BY a.name = 'crtr', a.name`).all().filter(r=>EXe(t,e,r))}function EXe(t,e,n){return n.type==="app"}function _gi(t,e,n){let r=`${fp(t,n).external_id.replace(/^app:/,"")}:`;return e.some(i=>i.startsWith(r)&&!i.slice(r.length).includes(":"))}function Pvn(t,e,n){return e.class==="person"?!0:e.class==="object"?e.owner.rowid===n.rowid:e.class==="app"?e.app.rowid===n.rowid||n.type==="profile"&&n.owner===e.app.rowid:e.app.rowid===n.rowid||n.type==="profile"&&e.profile?.rowid===n.rowid||n.type==="repo"&&yge(t,e,n,"rw")}function Lvn(t,e,n){if(e.class!=="node"&&!(e.class==="app"&&e.place!==void 0))return!0;let r=e.class==="app"?e.place:nb(e.node.id,t);if(r===null)return!0;let i=uge(n.rowid,t);return i===null?!r.isolated:lge(r,i)}function vgi(t,{space:e,path:n},r,i){let o=[];if(e.type==="person")o.push("user");else if(e.type==="app"&&n.length>0){let s=n[0];if(s.type==="profile")n.length>1&&o.push(`profile:${fp(t,s).external_id}`);else if(s.type==="node"||_Xe(s)){let a=fp(t,e).external_id;a!==i&&o.push(a)}}return r.type==="node"&&o.push("node"),o}function vXe(t,e,n,r,i){if(e.class==="person"||e.scopes===null)return!1;let o=e.scopes;if(o.length===0||r.space.type==="app"&&e.app.rowid===r.space.rowid)return!1;let s=fp(t,e.app).external_id;return vgi(t,r,i,s).some(a=>{let c=`crtr:objects:${n}:${a}`;return o.some(u=>la(u,c))})}function Sgi(t,e,n,r){return e.class==="person"||e.scopes===null?!1:vXe(t,e,n,Ovn(t,r),r)}function Bvn(t,e,n,r,i){let o=r.owner===null?null:t.prepare("SELECT * FROM objects WHERE rowid = ?").get(r.owner)??null;if(o===null)return!1;let s={class:"app",app:e,scopes:n??[]};return Pvn(t,s,o)?n===null||Sgi(t,s,"link",i):!1}function nl(t,e,n){return SXe(t,n)(e)}function SXe(t,e){let n=null,r=null;return i=>{if(i.class==="person")return!0;if(n??=Ovn(t,e),n.space.type==="app"&&n.path.length>0){if(r??=bgi(t,e),r&&EXe(t,i,n.space))return!0;if(_Xe(e)){if(i.app.rowid===n.space.rowid&&!Lvn(t,i,e))return!1;if(i.app.rowid!==n.space.rowid&&i.scopes!==null&&EXe(t,i,n.space)&&(e.privacy==="public"||Egi(i)&&_gi(t,i.scopes,n.space)))return!0}}return vXe(t,i,"read",n,e)||i.class==="object"&&_Xe(i.object)&&vXe(t,i,"watch",n,e)?!0:n.impl.canRead(t,i,n.space,n.path,e)}}var Egi,_Xe,lh=h(()=>{"use strict";Qt();B0();j6();fge();q6();bXe();Egi=t=>t.class!=="app"||t.place!==void 0;_Xe=t=>t.type.includes(".")});function G6(t){let e=t.match(Cgi);if(!e)return{data:null,body:t,raw:""};let n=e[1],r=t.slice(e[0].length);return{data:Igi(n),body:r,raw:n}}function Igi(t){return Tgi((0,$vn.parse)(t))}function Tgi(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{}}var $vn,Cgi,wge=h(()=>{"use strict";$vn=Kt(S4e(),1),Cgi=/^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n?/});import{closeSync as I9s,existsSync as T9s,fsyncSync as k9s,mkdirSync as R9s,openSync as D9s,readFileSync as Fvn,renameSync as M9s,writeSync as O9s}from"node:fs";import{join as kgi}from"node:path";function Rgi(t){if(!/^[0-9a-f]{64}$/.test(t))throw new Error(`invalid body hash: ${t}`);return kgi(Xo(),"bodies",t.slice(0,2),t)}function xge(t){try{return Fvn(Rgi(t),"utf8")}catch(e){throw e.code==="ENOENT"?Of(`no body ${t}`):e}}function OS(t,e){return e===null?xge(t):G6(Fvn(e,"utf8")).body}var NS=h(()=>{"use strict";Co();Rr();wge()});function fU(t,e){let n=ae(t,"SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),r=Nvn(t,e),i=e.class==="node"?[e.node,...e.repos,...e.projectRepos,e.profile,e.app]:e.class==="app"?[e.app]:e.class==="object"?[e.owner,...e.repos,e.app]:[],o=new Set;return[...i,n,...r].filter(s=>!!s&&!o.has(s.rowid)&&!!o.add(s.rowid))}function z6(t,e,n,r,i=!1){return t.prepare(`SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS ${i?"NOT NULL":"NULL"}
1743
1743
  AND deleted_at IS ${r?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(e.rowid,n)}function Dgi(t,e,n){return n==="node"?ae(t,"SELECT * FROM objects WHERE type = 'node' AND id = ?").all(e):n?ae(t,"SELECT * FROM objects WHERE type = ? AND (name = ? OR id = ?) AND home_machine IS NULL").all(n,e,e):ae(t,`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
1744
1744
  OR (type IN ('person','app','repo','profile') AND (name = ? OR id = ?) AND home_machine IS NULL)`).all(e,e,e)}function bge(t,e,n,r){let i=n.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),o=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(i);o&&!Uvn.test(i)&&(i=`${o[1]}/reports/${o[2]}`);let s=r?.readable??(d=>nl(t,e,d)),a=rl(t,i);if(a&&s(a))return a.deleted_at?{deleted:a}:{object:a};let c=r?.view??fU(t,e);for(let d of c){let p=z6(t,d,i,!1).find(s);if(p)return{object:p}}let u=Uvn.exec(i),l=i.indexOf("/");if(u||l>0){let d=u?u[2]:i.slice(0,l),p=u?u[3]:i.slice(l+1),f=Dgi(t,d,u?.[1]),m=x=>{let E=c.findIndex(_=>_.rowid===x.rowid);return E<0?1/0:E},g=f.filter(x=>m(x)<1/0).sort((x,E)=>m(x)-m(E));for(let x of g){let E=z6(t,x,p,!1).find(s);if(E)return{object:E}}let y=f.flatMap(x=>z6(t,x,p,!1)).filter(s);if(y.length===1)return{object:y[0]};if(y.length>1)return{ambiguous:y};let w=f.flatMap(x=>z6(t,x,p,!0)).find(s);return w?{deleted:w}:!u&&f.length===0&&SC(d)?{remote:i}:{missing:!0}}for(let d of c){let p=z6(t,d,i,!0).find(s);if(p)return{deleted:p}}return{missing:!0}}var Uvn,V6=h(()=>{"use strict";Qt();Rr();lh();fs();Uvn=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/});function Qvn(t){return{rowid:t.rowid,object:t.object,owner:t.owner,position:t.position,on:t.on_event,deliver:t.deliver,...t.match_json!==null?{match:JSON.parse(t.match_json)}:{},...t.match_frontmatter_json!==null?{matchFrontmatter:JSON.parse(t.match_frontmatter_json)}:{},...t.if_json!==null?{if:JSON.parse(t.if_json)}:{}}}function mU(t,e){return ae(t,"SELECT * FROM rules WHERE object = ? ORDER BY position").all(e.rowid).map(Qvn)}function Wvn(t,e,n){if(e.length===0||n.length===0)return[];let r=`SELECT * FROM rules WHERE on_event IN (${e.map(()=>"?").join(",")})
1745
1745
  AND owner IN (${n.map(()=>"?").join(",")}) ORDER BY object, position`;return t.prepare(r).all(...e,...n).map(Qvn)}var Ege=h(()=>{"use strict";Qt()});var Hvn=h(()=>{"use strict"});function CXe(t){return t==="orchestrator"?"\uF0E8":"\uF007"}function _ge(t){let e=(t.description??"").trim(),r=[t.name&&t.name!==t.kind?t.name:"",e].filter(i=>i!=="").join(" ");return r!==""?r:t.name}function jvn(t){return`${CXe(t.mode)} ${t.kind}`}var K6=h(()=>{"use strict"});var vge=h(()=>{"use strict";Qt();fi();Vx()});var IXe=h(()=>{"use strict";Qt();fi();DD();Jo();vge()});var Gvn=h(()=>{"use strict";Qt();fi();rw();Vx();IXe()});function MD(t){if(typeof t=="string")return JSON.parse(t)}function zvn(t){if(t===void 0)return null;let e=MD(t.sweep_observed_json),n=t.attempts,r=e===void 0?void 0:{reason:t.sweep_reason,...t.sweep_detail===null?{}:{detail:t.sweep_detail},observed:e,attempts:n,last_attempt:t.sweep_last_at,next_attempt:t.next_attempt_at,...t.quarantined===1?{quarantined:!0}:{}};return{state:t.state,...t.cleanup_state===null?{}:{cleanup:t.cleanup_state},path:t.path,branch:t.branch,repo_root:t.repo_root,base_ref:t.base_ref,base_sha:t.base_sha,created:t.created_at,...t.closed_at===null?{}:{closed:t.closed_at},...MD(t.abandoned_json)===void 0?{}:{abandoned:MD(t.abandoned_json)},...MD(t.land_intent_json)===void 0?{}:{land_intent:MD(t.land_intent_json)},...r===void 0?{}:{sweep:r},...MD(t.disposal_json)===void 0?{}:{disposal:MD(t.disposal_json)}}}function Vvn(t){return zvn(ae(ir(),"SELECT * FROM worktrees WHERE node_id = ?").get(t))}var Sge=h(()=>{"use strict";Qt();fi()});function Ogi(){let t=new Map;for(let e of Jvn()){let n=e.requester_node_id,r=t.get(n);r===void 0?t.set(n,[e.title]):r.push(e.title)}return t}function Kvn(t){let e=Ogi();return Object.fromEntries(t.map(n=>[n,e.get(n)?.length??0]))}var Yvn=h(()=>{"use strict";J6();v0()});var TXe,DKs,Xvn=h(()=>{"use strict";v0();Yvn();Jo();Sme();u6();_o();Co();TXe=class{async getNode(e){return td(e)}async getRow(e){return OD(e)}async listNodes(e){return Cge(e)}async subscriptionsOf(e){return Ige(e)}async subscribersOf(e){return kXe(e)}async view(e){return Y6(e)}async ticketCountsForNodes(e){return Kvn([...e])}async ticketCountsForView(e){return this.ticketCountsForNodes([e,...Y6(e)])}async hasActiveLiveSubscription(e){return RXe(e)}},DKs=new TXe});var Tge=h(()=>{"use strict";Qt();lh();fs()});function ND(t){return Array.isArray(t)?t:t===void 0?[]:[t]}function rb(t,e){return t===e?!0:(typeof t=="number"||typeof t=="string")&&(typeof e=="number"||typeof e=="string")?String(t)===String(e):!1}function Zvn(t,e){if(t&&typeof t=="object"&&e in t)return t[e];if(!e.includes("."))return;let n=t;for(let r of e.split(".")){if(n==null||typeof n!="object")return;n=n[r]}return n}function Ngi(t,e){if(typeof t!="string")return null;try{return new RegExp(t,e)}catch{return null}}function DXe(t,e,n){let r=ND(e);switch(t){case"eq":return Array.isArray(e)?e.some(i=>rb(i,n)):rb(e,n);case"ne":return!DXe("eq",e,n);case"in":return ND(n).some(i=>r.some(o=>rb(o,i)));case"nin":return!DXe("in",e,n);case"exists":return e!==void 0==(n!==!1);case"contains":return r.some(i=>rb(i,n));case"containsAll":return ND(n).every(i=>r.some(o=>rb(o,i)));case"containsAny":return ND(n).some(i=>r.some(o=>rb(o,i)));case"matches":case"imatches":{let i=Ngi(n,t==="imatches"?"i":"");return i?r.some(o=>typeof o=="string"||typeof o=="number"?i.test(String(o)):!1):!1}case"gt":case"gte":case"lt":case"lte":{let i=Number(e),o=Number(n);return Number.isNaN(i)||Number.isNaN(o)?!1:t==="gt"?i>o:t==="gte"?i>=o:t==="lt"?i<o:i<=o}default:return!1}}function eSn(t,e){if(e===null||["string","number","boolean"].includes(typeof e))return Array.isArray(t)?t.some(n=>rb(n,e)):rb(t,e);if(Array.isArray(e)){let n=ND(t);return e.some(r=>n.some(i=>rb(i,r)))}return e&&typeof e=="object"?Object.entries(e).every(([n,r])=>DXe(n,t,r)):!1}function ib(t,e){if(t==null)return!1;if(Array.isArray(t))return t.every(o=>ib(o,e));if(typeof t!="object")return!1;let n=t;if("all"in n||"any"in n||"not"in n){let o=!0;"all"in n&&(o=o&&ND(n.all).every(s=>ib(s,e))),"any"in n&&(o=o&&ND(n.any).some(s=>ib(s,e))),"not"in n&&(o=o&&!ib(n.not,e));for(let s of Object.keys(n))s==="all"||s==="any"||s==="not"||(o=o&&eSn(Zvn(e,s),n[s]));return o}let i=Object.keys(n);return i.length===0?!1:i.every(o=>eSn(Zvn(e,o),n[o]))}var MXe=h(()=>{"use strict"});var OXe=h(()=>{"use strict";Vi();Bme();Vx();vge()});var NXe=h(()=>{"use strict";_o();DD();Vi();gge();gge()});var tSn=h(()=>{"use strict";Vi();Rr();vge();NXe()});var PXe=h(()=>{"use strict"});var nSn=h(()=>{"use strict";Vi()});async function rSn(t,e="SIGKILL",n){if(!("ok"in await Lme({operation:"stop",pid:t,signal:e,...n===void 0?{}:{nodeId:n}})))throw new Error("launcher did not stop process")}var LXe=h(()=>{"use strict";sge();v0();Rr();Vi();DD();Jo();Pf();OXe();tSn();PXe();nSn();Bme();Vx()});function Bgi(t){if(typeof t!="string")return null;try{let e=JSON.parse(t);return Array.isArray(e)?e.filter(n=>typeof n=="string"):null}catch{return null}}function $gi(t){return{cron_id:t.cron_id,name:t.name,created_by:t.created_by??null,grantee:t.grantee,sub:t.sub??"user:local",grant_id:t.grant_id??null,scopes:Bgi(t.scopes_json),origin_run_id:t.origin_run_id??null,run_execution_id:t.run_execution_id??null,isolated:Number(t.isolated)!==0,command:t.command,fire_at:t.fire_at,recur:t.recur??null,tz:t.tz??null,expires_at:t.expires_at??null,anchor_node:t.anchor_node??null,cancel_on_wake:Number(t.cancel_on_wake)!==0,cwd:t.cwd,env_json:t.env_json??null,profile:t.profile??null,scope:t.scope,run_timeout_s:Number(t.run_timeout_s),overlap:t.overlap,on_output:t.on_output,sink:t.sink,tier:t.tier,last_output_hash:t.last_output_hash??null,held:Number(t.held)!==0,last_poke_at:t.last_poke_at??null,state:t.state,run_state:t.run_state,run_pid:t.run_pid??null,run_pid_identity:t.run_pid_identity??null,run_started_at:t.run_started_at??null,run_lease_owner:t.run_lease_owner??null,run_out_of_band:Number(t.run_out_of_band)!==0,created:t.created,updated:t.updated}}async function Fgi(t,e="SIGTERM"){if(!BXe(t))return!1;if(process.platform!=="linux")return hlt(t.run_pid,e),!0;try{return await rSn(t.run_pid,e,t.anchor_node??void 0),!0}catch(n){if(!BXe(t))return!1;throw n}}function Ugi(t,e="SIGTERM"){return BXe(t)?(Fgi(t,e).catch(n=>{za({level:"error",event:"cron.run.stop_failed",error:n,fields:{cron_id:t.cron_id,pid:t.run_pid}})}),!0):!1}function BXe(t){let e=t.run_pid;if(e==null||t.run_pid_identity==null)return!1;let n=$be([e]);if(n===null)return!1;let r=n.get(e);return r===void 0?!1:Pbe(r,t.run_pid_identity)}function $Xe(t){return Fa(e=>{let n=ae(e,"SELECT * FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1").all(t).map($gi);for(let r of n)r.run_state==="running"&&Ugi(r),ae(e,"DELETE FROM crons WHERE cron_id = ?").run(r.cron_id);return n.map(r=>r.cron_id)})}var kge=h(()=>{"use strict";Qt();fi();rw();Su();LXe();Pf()});function FXe(t,e,n,r=ir()){if(e===null)return!1;let i=ae(r,"SELECT wait_id, generation FROM waits WHERE node_id = ? AND kind = 'controller' AND target_id = ? AND satisfied_at IS NULL").get(t,e);return i===void 0?!1:Number(ae(r,"UPDATE waits SET satisfied_at = ? WHERE wait_id = ? AND generation = ? AND satisfied_at IS NULL").run(n,i.wait_id,i.generation).changes)===1}var UXe=h(()=>{"use strict";Qt();fi()});import{existsSync as Qgi,mkdirSync as Wgi,renameSync as Hgi,writeFileSync as jgi}from"node:fs";import{randomBytes as qgi,randomUUID as Ggi}from"node:crypto";import{join as zgi}from"node:path";function QXe(){let t;do t=qgi(16).toString("hex");while(t==="00000000000000000000000000000000");return t}function Vgi(t,e){let n=JSON.stringify(t);if(n===void 0)throw new TypeError(`${e} must be JSON-serializable`);return n}function iSn(t,e){return e!=="normal"&&e!=="deferred"?e:OD(t)?.lifecycle==="terminal"?"urgent":e}function Kgi(t,e,n){let r=Nat(t);Qgi(r)||Wgi(r,{recursive:!0});let i=e.replace(/[^0-9]/g,""),o=zgi(r,`${i}-${Ggi().slice(0,6)}.md`),s=`${o}.tmp`;return jgi(s,n,"utf8"),ZM(s),Hgi(s,o),hy(r),o}function Ygi(t){if(typeof t!="object"||t===null)return"";let e=t.body;return typeof e=="string"?e.trim():""}function WXe(t,e){let n=e.messageId??QXe(),r=Number(ae(t,"UPDATE message_sequence SET seq = seq + 1 WHERE id = 1 RETURNING seq").get().seq);return ae(t,`INSERT INTO messages
@@ -1,2 +1,2 @@
1
- var Q=Object.defineProperty;var d=(s,f)=>Q(s,"name",{value:f,configurable:!0});import{mkdtempSync as V,readFileSync as q,rmSync as E,existsSync as Y}from"node:fs";import{tmpdir as Z}from"node:os";import{join as F}from"node:path";import{cliClient as ee}from"../../commands/api-client.js";import{loadPins as re,savePins as ne}from"../../core/canvas/browse/pins.js";import{detectColorCaps as oe}from"../../core/tui/draw.js";import{getTerminalSize as ie,parseKeypress as te,restoreTerminal as se,setupTerminal as de}from"../../core/tui/terminal.js";import{getPaneOption as le,runShellInBackground as ce,setPaneOption as C,shellQuote as h}from"../../core/runtime/placement-tmux.js";import{matchesTerminalInput as ae,resolveUserKeybindings as fe}from"../../core/keybindings/index.js";import{VIEWER_OWNER_OPTION as S}from"../attach/session/pane-tag.js";import{buildLines as ue,nearestSelectable as M,placements as pe,rootOf as b,stepSelectable as D}from"./model.js";import{listHeight as me,renderDashboard as he}from"./render.js";const ge=2e3,we=250,be=6e3;function P(s){return s.kind==="heading"?null:s.kind==="root"?`root:${s.id}`:`child:${s.rootId}:${s.id}`}d(P,"lineKey");async function Oe(s){const f=process.env.TMUX_PANE;if(f===void 0||f==="")throw new Error("the dashboard runs in a tmux pane (TMUX_PANE is unset)");const m=ee(),R=fe(),j=oe(),c=d((r,n)=>ae(R,r,n),"matches"),k=String(process.pid);C(f,S,k);for(const r of["@crtr_node","@crtr_attach","@crtr_viewer_at"])C(f,r,"");const K=V(F(Z(),"crtr-dashboard-"));let I=!1;const L=d(()=>{if(!I){I=!0;try{se()}catch{}le(f,S)===k&&C(f,S,"");try{E(K,{recursive:!0,force:!0})}catch{}}},"cleanup");process.once("exit",L);for(const r of["SIGTERM","SIGHUP"])process.once(r,()=>{L(),process.exit(0)});const e={rows:[],placed:new Map,pinned:re(),expanded:new Set,lines:[],cursorKey:null,cursor:0,scroll:0,scope:s.profileId===void 0?"all":"profile",profileLabel:s.profileId??"",loaded:!1,help:!1,inputFocused:!1,inputText:"",dirs:[s.cwd],dirIndex:0,dirsLoaded:!1,rename:null,renameTarget:null,confirmClose:null,notice:null,opening:null},x=new Set;let $;const u=d(r=>{e.notice=r,$!==void 0&&clearTimeout($),$=setTimeout(()=>{e.notice=null,l()},be)},"notify"),g=d(()=>{const r=e.rows.filter(t=>!x.has(t.node_id));e.lines=ue(r,e.placed,e.pinned,e.expanded);const n=e.cursorKey===null?-1:e.lines.findIndex(t=>P(t)===e.cursorKey);e.cursor=n>=0?n:M(e.lines,e.cursor),e.cursor<0&&(e.cursor=0);const o=e.lines[e.cursor];e.cursorKey=o===void 0?null:P(o)},"rebuild"),l=d(()=>{if(I)return;const r=ie(),n=me(r.rows)-1;e.cursor<e.scroll&&(e.scroll=e.cursor),e.cursor>=e.scroll+n&&(e.scroll=e.cursor-n+1),e.scroll<0&&(e.scroll=0),process.stdout.write(he({lines:e.lines,cursor:e.cursor,scroll:e.scroll,pinned:e.pinned,scope:e.scope,profileLabel:e.profileLabel,rename:e.rename,inputText:e.inputText,inputFocused:e.inputFocused,chipDir:e.dirs[e.dirIndex]??s.cwd,confirmName:e.confirmClose===null?null:e.rows.find(o=>o.node_id===e.confirmClose)?.name??e.confirmClose,notice:e.notice,opening:e.opening!==null,help:e.help,loaded:e.loaded},r,j))},"paint");let v=!1,y=!1;const p=d(async()=>{if(v){y=!0;return}v=!0;try{const r=await m.liveRoots(e.scope==="profile"&&s.profileId!==void 0?{profile:s.profileId}:{});e.rows=r.rows,e.placed=pe(r.rows,e.placed),e.loaded=!0,g()}catch(r){u(`refresh failed: ${r.message}`)}finally{v=!1}l(),y&&(y=!1,p())},"poll");s.profileId!==void 0&&m.getProfile(s.profileId).then(r=>{e.profileLabel=r.name,l()}).catch(()=>{});const U=d(()=>e.lines[e.cursor],"current"),z=d(r=>{if(e.opening!==null||r.kind==="heading")return;const o=(r.kind==="root"?r.row:e.rows.find(_=>_.node_id===r.rootId)?.children.find(_=>_.node_id===r.id))?.name??r.id,t=r.kind==="root"&&r.row.asks>0?r.row.first_ask_ticket_id:null,i=F(K,`open-${Date.now()}`),T=`${["crtr","surface","node","focus",r.id,"--pane",f,"--in-place","--keep-other-viewers",...t===null?[]:["--open-ticket",t],"--json"].map(h).join(" ")} >${h(`${i}.out`)} 2>${h(`${i}.err`)}; echo $? >${h(`${i}.code`)}; mv ${h(`${i}.code`)} ${h(i)}`;if(!ce(T)){u(`could not open ${o}`),l();return}e.opening={file:i,name:o},l()},"open"),A=d(()=>{const r=e.opening;if(r===null||!Y(r.file))return;const n=d(a=>{try{return q(a,"utf8").trim()}catch{return""}},"read"),o=n(r.file),t=n(`${r.file}.out`),i=n(`${r.file}.err`);for(const a of[r.file,`${r.file}.out`,`${r.file}.err`])E(a,{force:!0});if(e.opening=null,o!=="0")u(i===""?`could not open ${r.name}`:i.split(`
2
- `)[0]);else{let a=!1;try{a=JSON.parse(t).focused===!0}catch{a=!1}a||u(`could not open ${r.name}`)}l(),p()},"finishOpen"),G=d(async()=>{const r=e.inputText.trim();if(r!==""){try{await m.createNode({root:!0,prompt:r,cwd:e.dirs[e.dirIndex]??s.cwd,...s.profileId===void 0?{}:{profile:s.profileId}}),e.inputText="",e.inputFocused=!1,p()}catch(n){u(`could not start: ${n.message}`)}l()}},"startConversation"),H=d(()=>{e.dirsLoaded||s.profileId===void 0||(e.dirsLoaded=!0,m.getProfile(s.profileId).then(r=>{e.dirs=[s.cwd,...r.projects.map(n=>n.path).filter(n=>n!==s.cwd)],l()}).catch(r=>{u(`could not list directories: ${r.message}`),l()}))},"loadDirs"),O=d(async r=>{e.confirmClose=null,x.add(r),g(),l();try{await m.closeNode(r,{finish:!0})}catch(n){u(`could not close: ${n.message}`)}finally{x.delete(r)}p(),l()},"doClose"),W=d(async()=>{const r=e.renameTarget,n=(e.rename??"").trim();if(e.rename=null,e.renameTarget=null,r!==null&&n!==""){try{await m.patchConfig(r,{name:n})}catch(o){u(`could not rename: ${o.message}`)}p()}l()},"commitRename"),X=d(r=>{e.pinned.has(r)?e.pinned.delete(r):e.pinned.add(r),ne(e.pinned),g()},"togglePin"),w=d(r=>{const n=M(e.lines,r);n<0||(e.cursor=n,e.cursorKey=P(e.lines[n]))},"moveTo"),B=d(r=>[...r].filter(n=>n>=" "&&n!=="\x7F").join(""),"printable"),N=d((r,n,o,t)=>{if(n.backspace)return t(o().slice(0,-1)),!0;if(n.ctrl||n.meta)return!0;const i=B(r);return i!==""&&t(o()+i),!0},"onText"),J=d((r,n)=>{const o={input:r,...n};if(e.help){e.help=!1,l();return}if(e.rename!==null){if(n.escape)e.rename=null,e.renameTarget=null;else if(n.return){W();return}else N(r,n,()=>e.rename??"",i=>{e.rename=i});l();return}if(e.inputFocused){if(c("crtr.dashboard.input-cancel",o))e.inputFocused=!1;else if(c("crtr.dashboard.input-submit",o)){G();return}else c("crtr.dashboard.directory-next",o)?e.dirIndex=(e.dirIndex+1)%e.dirs.length:c("crtr.dashboard.directory-previous",o)?e.dirIndex=(e.dirIndex-1+e.dirs.length)%e.dirs.length:N(r,n,()=>e.inputText,i=>{e.inputText=i});l();return}if(e.confirmClose!==null){const i=e.confirmClose;if(c("crtr.dashboard.confirm-close",o)){O(i);return}c("crtr.dashboard.cancel-close",o)&&(e.confirmClose=null,l());return}const t=U();if(c("crtr.dashboard.down",o))w(D(e.lines,e.cursor,1));else if(c("crtr.dashboard.up",o))w(D(e.lines,e.cursor,-1));else if(c("crtr.dashboard.first",o))w(0);else if(c("crtr.dashboard.last",o))w(e.lines.length-1);else if(c("crtr.dashboard.expand",o))t?.kind==="root"&&t.row.children.length>0&&(e.expanded.add(t.id),g());else if(c("crtr.dashboard.collapse",o)){if(t!==void 0&&t.kind!=="heading"){const i=b(t);e.expanded.delete(i),e.cursorKey=`root:${i}`,g()}}else if(c("crtr.dashboard.open",o)){t!==void 0&&z(t);return}else if(c("crtr.dashboard.pin",o)){const i=t===void 0?null:b(t);i!==null&&X(i)}else if(c("crtr.dashboard.rename",o)){const i=t===void 0?null:b(t);i!==null&&(e.renameTarget=i,e.rename=e.rows.find(a=>a.node_id===i)?.name??"")}else if(c("crtr.dashboard.close",o)){const i=t===void 0?null:b(t),a=i===null?void 0:e.rows.find(T=>T.node_id===i);if(a!==void 0)if(a.running_count>0)e.confirmClose=a.node_id;else{O(a.node_id);return}}else c("crtr.dashboard.profile",o)?s.profileId!==void 0&&(e.scope=e.scope==="profile"?"all":"profile",p()):c("crtr.dashboard.input",o)?(e.inputFocused=!0,H()):c("crtr.dashboard.help",o)&&(e.help=!0);l()},"onKey");de(),l(),p(),setInterval(()=>{p()},ge),setInterval(A,we),process.stdout.on("resize",l),await new Promise(()=>{process.stdin.on("data",r=>{try{const{input:n,key:o}=te(r);J(n,o)}catch(n){u(`internal error: ${n.message}`),l()}})})}d(Oe,"runDashboard");export{Oe as runDashboard};
1
+ var Q=Object.defineProperty;var d=(s,f)=>Q(s,"name",{value:f,configurable:!0});import{mkdtempSync as V,readFileSync as q,rmSync as E,existsSync as Y}from"node:fs";import{tmpdir as Z}from"node:os";import{join as F}from"node:path";import{cliClient as ee}from"../../commands/api-client.js";import{loadPins as re,savePins as ne}from"../../core/canvas/browse/pins.js";import{detectColorCaps as oe}from"../../core/tui/draw.js";import{getTerminalSize as ie,parseKeypress as te,restoreTerminal as se,setupTerminal as de}from"../../core/tui/terminal.js";import{getPaneOption as le,runShellInBackground as ce,setPaneOption as C,shellQuote as h}from"../../core/runtime/placement-tmux.js";import{matchesTerminalInput as ae,resolveUserKeybindings as fe}from"../../core/keybindings/index.js";import{VIEWER_OWNER_OPTION as S}from"../attach/session/pane-tag.js";import{buildLines as ue,nearestSelectable as M,placements as pe,rootOf as b,stepSelectable as D}from"./model.js";import{listHeight as me,renderDashboard as he}from"./render.js";const ge=2e3,we=250,be=6e3;function P(s){return s.kind==="heading"?null:s.kind==="root"?`root:${s.id}`:`child:${s.rootId}:${s.id}`}d(P,"lineKey");async function Oe(s){const f=process.env.TMUX_PANE;if(f===void 0||f==="")throw new Error("the dashboard runs in a tmux pane (TMUX_PANE is unset)");const m=ee(),R=fe(),j=oe(),c=d((r,n)=>ae(R,r,n),"matches"),k=String(process.pid);C(f,S,k);for(const r of["@crtr_node","@crtr_attach","@crtr_viewer_at"])C(f,r,"");const K=V(F(Z(),"crtr-dashboard-"));let x=!1;const L=d(()=>{if(!x){x=!0;try{se()}catch{}le(f,S)===k&&C(f,S,"");try{E(K,{recursive:!0,force:!0})}catch{}}},"cleanup");process.once("exit",L);for(const r of["SIGTERM","SIGHUP"])process.once(r,()=>{L(),process.exit(0)});const e={rows:[],placed:new Map,pinned:re(),expanded:new Set,lines:[],cursorKey:null,cursor:0,scroll:0,scope:s.profileId===void 0?"all":"profile",profileLabel:s.profileId??"",loaded:!1,help:!1,inputFocused:!1,inputText:"",dirs:[s.cwd],dirIndex:0,dirsLoaded:!1,rename:null,renameTarget:null,confirmClose:null,notice:null,opening:null},I=new Set;let v;const u=d(r=>{e.notice=r,v!==void 0&&clearTimeout(v),v=setTimeout(()=>{e.notice=null,l()},be)},"notify"),g=d(()=>{const r=e.rows.filter(t=>!I.has(t.node_id));e.lines=ue(r,e.placed,e.pinned,e.expanded);const n=e.cursorKey===null?-1:e.lines.findIndex(t=>P(t)===e.cursorKey);e.cursor=n>=0?n:M(e.lines,e.cursor),e.cursor<0&&(e.cursor=0);const o=e.lines[e.cursor];e.cursorKey=o===void 0?null:P(o)},"rebuild"),l=d(()=>{if(x)return;const r=ie(),n=me(r.rows)-1;e.cursor<e.scroll&&(e.scroll=e.cursor),e.cursor>=e.scroll+n&&(e.scroll=e.cursor-n+1),e.scroll<0&&(e.scroll=0),process.stdout.write(he({lines:e.lines,cursor:e.cursor,scroll:e.scroll,pinned:e.pinned,scope:e.scope,profileLabel:e.profileLabel,rename:e.rename,inputText:e.inputText,inputFocused:e.inputFocused,chipDir:e.dirs[e.dirIndex]??s.cwd,confirmName:e.confirmClose===null?null:e.rows.find(o=>o.node_id===e.confirmClose)?.name??e.confirmClose,notice:e.notice,opening:e.opening!==null,help:e.help,loaded:e.loaded},r,j))},"paint");let $=!1,y=!1;const p=d(async()=>{if($){y=!0;return}$=!0;try{const r=await m.liveRoots(e.scope==="profile"&&s.profileId!==void 0?{profile:s.profileId}:{});e.rows=r.rows,e.placed=pe(r.rows,e.placed),e.loaded=!0,g()}catch(r){u(`refresh failed: ${r.message}`)}finally{$=!1}l(),y&&(y=!1,p())},"poll");s.profileId!==void 0&&m.getProfile(s.profileId).then(r=>{e.profileLabel=r.name,l()}).catch(()=>{});const U=d(()=>e.lines[e.cursor],"current"),z=d(r=>{if(e.opening!==null||r.kind==="heading")return;const o=(r.kind==="root"?r.row:e.rows.find(_=>_.node_id===r.rootId)?.children.find(_=>_.node_id===r.id))?.name??r.id,t=r.kind==="root"&&r.row.asks>0?r.row.first_ask_ticket_id:null,i=F(K,`open-${Date.now()}`),T=`{ ${["crtr","surface","node","focus",r.id,"--pane",f,"--in-place","--keep-other-viewers",...t===null?[]:["--open-ticket",t],"--json"].map(h).join(" ")} >${h(`${i}.out`)} 2>${h(`${i}.err`)}; echo $? >${h(`${i}.code`)} && mv ${h(`${i}.code`)} ${h(i)}; } 2>/dev/null; exit 0`;if(!ce(T)){u(`could not open ${o}`),l();return}e.opening={file:i,name:o},l()},"open"),A=d(()=>{const r=e.opening;if(r===null||!Y(r.file))return;const n=d(a=>{try{return q(a,"utf8").trim()}catch{return""}},"read"),o=n(r.file),t=n(`${r.file}.out`),i=n(`${r.file}.err`);for(const a of[r.file,`${r.file}.out`,`${r.file}.err`])E(a,{force:!0});if(e.opening=null,o!=="0")u(i===""?`could not open ${r.name}`:i.split(`
2
+ `)[0]);else{let a=!1;try{a=JSON.parse(t).focused===!0}catch{a=!1}a||u(`could not open ${r.name}`)}l(),p()},"finishOpen"),G=d(async()=>{const r=e.inputText.trim();if(r!==""){try{await m.createNode({root:!0,prompt:r,cwd:e.dirs[e.dirIndex]??s.cwd,...s.profileId===void 0?{}:{profile:s.profileId}}),e.inputText="",e.inputFocused=!1,p()}catch(n){u(`could not start: ${n.message}`)}l()}},"startConversation"),H=d(()=>{e.dirsLoaded||s.profileId===void 0||(e.dirsLoaded=!0,m.getProfile(s.profileId).then(r=>{e.dirs=[s.cwd,...r.projects.map(n=>n.path).filter(n=>n!==s.cwd)],l()}).catch(r=>{u(`could not list directories: ${r.message}`),l()}))},"loadDirs"),O=d(async r=>{e.confirmClose=null,I.add(r),g(),l();try{await m.closeNode(r,{finish:!0})}catch(n){u(`could not close: ${n.message}`)}finally{I.delete(r)}p(),l()},"doClose"),W=d(async()=>{const r=e.renameTarget,n=(e.rename??"").trim();if(e.rename=null,e.renameTarget=null,r!==null&&n!==""){try{await m.patchConfig(r,{name:n})}catch(o){u(`could not rename: ${o.message}`)}p()}l()},"commitRename"),X=d(r=>{e.pinned.has(r)?e.pinned.delete(r):e.pinned.add(r),ne(e.pinned),g()},"togglePin"),w=d(r=>{const n=M(e.lines,r);n<0||(e.cursor=n,e.cursorKey=P(e.lines[n]))},"moveTo"),B=d(r=>[...r].filter(n=>n>=" "&&n!=="\x7F").join(""),"printable"),N=d((r,n,o,t)=>{if(n.backspace)return t(o().slice(0,-1)),!0;if(n.ctrl||n.meta)return!0;const i=B(r);return i!==""&&t(o()+i),!0},"onText"),J=d((r,n)=>{const o={input:r,...n};if(e.help){e.help=!1,l();return}if(e.rename!==null){if(n.escape)e.rename=null,e.renameTarget=null;else if(n.return){W();return}else N(r,n,()=>e.rename??"",i=>{e.rename=i});l();return}if(e.inputFocused){if(c("crtr.dashboard.input-cancel",o))e.inputFocused=!1;else if(c("crtr.dashboard.input-submit",o)){G();return}else c("crtr.dashboard.directory-next",o)?e.dirIndex=(e.dirIndex+1)%e.dirs.length:c("crtr.dashboard.directory-previous",o)?e.dirIndex=(e.dirIndex-1+e.dirs.length)%e.dirs.length:N(r,n,()=>e.inputText,i=>{e.inputText=i});l();return}if(e.confirmClose!==null){const i=e.confirmClose;if(c("crtr.dashboard.confirm-close",o)){O(i);return}c("crtr.dashboard.cancel-close",o)&&(e.confirmClose=null,l());return}const t=U();if(c("crtr.dashboard.down",o))w(D(e.lines,e.cursor,1));else if(c("crtr.dashboard.up",o))w(D(e.lines,e.cursor,-1));else if(c("crtr.dashboard.first",o))w(0);else if(c("crtr.dashboard.last",o))w(e.lines.length-1);else if(c("crtr.dashboard.expand",o))t?.kind==="root"&&t.row.children.length>0&&(e.expanded.add(t.id),g());else if(c("crtr.dashboard.collapse",o)){if(t!==void 0&&t.kind!=="heading"){const i=b(t);e.expanded.delete(i),e.cursorKey=`root:${i}`,g()}}else if(c("crtr.dashboard.open",o)){t!==void 0&&z(t);return}else if(c("crtr.dashboard.pin",o)){const i=t===void 0?null:b(t);i!==null&&X(i)}else if(c("crtr.dashboard.rename",o)){const i=t===void 0?null:b(t);i!==null&&(e.renameTarget=i,e.rename=e.rows.find(a=>a.node_id===i)?.name??"")}else if(c("crtr.dashboard.close",o)){const i=t===void 0?null:b(t),a=i===null?void 0:e.rows.find(T=>T.node_id===i);if(a!==void 0)if(a.running_count>0)e.confirmClose=a.node_id;else{O(a.node_id);return}}else c("crtr.dashboard.profile",o)?s.profileId!==void 0&&(e.scope=e.scope==="profile"?"all":"profile",p()):c("crtr.dashboard.input",o)?(e.inputFocused=!0,H()):c("crtr.dashboard.help",o)&&(e.help=!0);l()},"onKey");de(),l(),p(),setInterval(()=>{p()},ge),setInterval(A,we),process.stdout.on("resize",l),await new Promise(()=>{process.stdin.on("data",r=>{try{const{input:n,key:o}=te(r);J(n,o)}catch(n){u(`internal error: ${n.message}`),l()}})})}d(Oe,"runDashboard");export{Oe as runDashboard};
@@ -1,3 +1,3 @@
1
- var E=Object.defineProperty;var s=(t,a)=>E(t,"name",{value:a,configurable:!0});import{defineLeaf as _}from"../core/command.js";import{envProfileId as p}from"../shared/env.js";import{getDefaultProfileId as f}from"../core/profiles/default-binding.js";import{SECTION_ORDER as k,SECTION_TITLE as x,sectionOf as R}from"../clients/dashboard/model.js";import{closeWindow as I,currentTmux as T,displayMessage as v,getPaneOption as P,openNodeWindow as N,paneCurrentCommand as C,paneCurrentPath as D,paneLocation as O,paneStartCommand as U,renameWindow as W,respawnPaneSync as L,shellQuote as S,swapPanes as A,viewerSplitEnv as M,windowOfPane as X}from"../core/runtime/placement-tmux.js";import{cliClient as $}from"./api-client.js";const h="CRTR_DASHBOARD_RUN";async function j(t,a,e){if(t!==void 0&&t!=="")return t;const o=a===void 0?void 0:P(a,"@crtr_node");if(o!==void 0&&o!=="")try{const r=(await $().getNode(o)).profile_id;if(r!=null)return r}catch{}return p()??f(e)??void 0}s(j,"profileFor");async function q(t){const a=await $().liveRoots(t===void 0?{}:{profile:t}),e=[];for(const o of k){const r=a.rows.filter(n=>R(n)===o);if(r.length!==0){e.push(`${x[o]} (${r.length})`);for(const n of r){const i=[n.running_count>0?`\u27F3 ${n.running_count}`:"",n.asks>0?`? ${n.asks}`:"",n.fault!==null?"\u26A0":""].filter(d=>d!=="").join(" ");e.push(` ${n.name} ${n.state_line??n.goal??""}${i===""?"":` ${i}`}`)}}}process.stdout.write(`${e.length===0?"no live conversations":e.join(`
1
+ var R=Object.defineProperty;var i=(r,s)=>R(r,"name",{value:s,configurable:!0});import{defineLeaf as N}from"../core/command.js";import{envProfileId as f}from"../shared/env.js";import{getDefaultProfileId as l}from"../core/profiles/default-binding.js";import{SECTION_ORDER as O,SECTION_TITLE as P,sectionOf as T}from"../clients/dashboard/model.js";import{closeWindow as I,currentTmux as C,displayMessage as w,getPaneOption as m,openNodeWindow as D,paneCurrentCommand as U,paneCurrentPath as W,paneLocation as A,paneStartCommand as L,renameWindow as S,respawnPaneSync as M,setPaneOption as X,shellQuote as j,swapPanes as q,viewerSplitEnv as F,windowOfPane as V}from"../core/runtime/placement-tmux.js";import{cliClient as g}from"./api-client.js";const b="CRTR_DASHBOARD_RUN",x="@crtr_dashboard_return";async function B(r,s,e){if(r!==void 0&&r!=="")return r;const n=s===void 0?void 0:m(s,"@crtr_node");if(n!==void 0&&n!=="")try{const a=(await g().getNode(n)).profile_id;if(a!=null)return a}catch{}return f()??l(e)??void 0}i(B,"profileFor");async function H(r){const s=await g().liveRoots(r===void 0?{}:{profile:r}),e=[];for(const n of O){const a=s.rows.filter(o=>T(o)===n);if(a.length!==0){e.push(`${P[n]} (${a.length})`);for(const o of a){const d=[o.running_count>0?`\u27F3 ${o.running_count}`:"",o.asks>0?`? ${o.asks}`:"",o.fault!==null?"\u26A0":""].filter(c=>c!=="").join(" ");e.push(` ${o.name} ${o.state_line??o.goal??""}${d===""?"":` ${d}`}`)}}}process.stdout.write(`${e.length===0?"no live conversations":e.join(`
2
2
  `)}
3
- `)}s(q,"printListing");const G=_({name:"dashboard",description:"show the profile\u2019s live root conversations in a tmux pane \u2014 which need the person, which run, which are idle",whenToUse:"the person asks to see all their running conversations in one place, or you are wiring a key to it. It is a screen for the person, not a read: use `canvas dashboard` for a one-shot tree you can pipe",help:{name:"surface dashboard",summary:"put the dashboard in a tmux pane: live root conversations in Waiting for you / Running / Idle, Enter opens one in that pane, n starts a new background conversation. Outside tmux it prints the same listing as text",params:[{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane that shows the dashboard. Default: $TMUX_PANE. A pane running a crouter viewer or a dashboard is respawned; any other pane (a shell, an editor) is swapped for a new window that runs the dashboard, and its program keeps running in the background window."},{kind:"flag",name:"profile-id",type:"string",required:!1,constraint:"Exact profile id to list. Default: the profile of the conversation shown in the pane, then $CRTR_PROFILE_ID, then the pane directory\u2019s pinned default profile; absent means all profiles."}],output:[],outputKind:"object",effects:["Respawns the target pane onto the dashboard (a crouter viewer\u2019s engine keeps running), or opens a new tmux window with the dashboard and swaps it into the pane\u2019s place.","Never kills a pane that is not running a crouter viewer or dashboard.","Inside the dashboard, Enter runs `surface node focus` for the chosen conversation, `n` creates a root conversation, `x` finishes one."]},run:s(async t=>{const a=t.profileId;if(process.env[h]==="1"){delete process.env[h];const{runDashboard:c}=await import("../clients/dashboard/app.js"),y=a??p()??f(process.cwd())??void 0;await c({profileId:y,cwd:process.cwd()});return}if(process.env.TMUX===void 0||process.env.TMUX===""){await q(a??p()??f(process.cwd())??void 0);return}const e=t.pane??process.env.TMUX_PANE??T()?.pane;if(e===void 0||e==="")throw v("crtr: no pane to show the dashboard in"),new Error("no tmux pane to show the dashboard in \u2014 pass --pane <id>");const o=s(c=>{throw v(`crtr: ${c}`,e),new Error(c)},"fail"),r=U(e)?.replace(/^"|"$/g,"");if(r===void 0)return o(`pane ${e} is not reachable`);if(r.startsWith("crtr surface dashboard"))return;const n=D(e)??process.cwd(),i=await j(a,e,n),d=`crtr surface dashboard${i===void 0?"":` --profile-id ${S(i)}`}`,l={...M(),[h]:"1"};if(r.startsWith("crtr surface attach to ")){L({pane:e,cwd:n,env:l,command:d})||o(`tmux could not respawn pane ${e}`);return}const w=O(e);if(w===null)return o(`pane ${e} is not in a tmux window`);const u=N({session:w.session,name:"dashboard",cwd:n,env:l,command:d});if(u===null)return o("tmux could not open a window for the dashboard");const m=C(e),g=A(u.pane,e);if(g!==null)return I(u.window),o(`could not show the dashboard: ${g}`);const b=X(e);b!==null&&m!==void 0&&W(b,m)},"run"),render:s(()=>"","render")});export{G as surfaceDashboardLeaf};
3
+ `)}i(H,"printListing");const ne=N({name:"dashboard",description:"show the profile\u2019s live root conversations in a tmux pane \u2014 which need the person, which run, which are idle",whenToUse:"the person asks to see all their running conversations in one place, or you are wiring a key to it. It is a screen for the person, not a read: use `canvas dashboard` for a one-shot tree you can pipe",help:{name:"surface dashboard",summary:"put the dashboard in a tmux pane: live root conversations in Waiting for you / Running / Idle, Enter opens one in that pane, n starts a new background conversation. Outside tmux it prints the same listing as text",params:[{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane that shows the dashboard. Default: $TMUX_PANE. A pane running a crouter viewer is respawned; any other pane (a shell, an editor) is swapped for a new window that runs the dashboard, and its program keeps running in the background window. A pane already showing the dashboard returns to the conversation it showed before."},{kind:"flag",name:"profile-id",type:"string",required:!1,constraint:"Exact profile id to list. Default: the profile of the conversation shown in the pane, then $CRTR_PROFILE_ID, then the pane directory\u2019s pinned default profile; absent means all profiles."}],output:[],outputKind:"object",effects:["Respawns the target pane onto the dashboard (a crouter viewer\u2019s engine keeps running), or opens a new tmux window with the dashboard and swaps it into the pane\u2019s place.","On a pane already showing the dashboard: opens the conversation that pane showed before the dashboard, in that pane; with none recorded, shows a tmux message and changes nothing.","Never kills a pane that is not running a crouter viewer or dashboard.","Inside the dashboard, Enter runs `surface node focus` for the chosen conversation, `n` creates a root conversation, `x` finishes one."]},run:i(async r=>{const s=r.profileId;if(process.env[b]==="1"){delete process.env[b];const{runDashboard:t}=await import("../clients/dashboard/app.js"),u=s??f()??l(process.cwd())??void 0;await t({profileId:u,cwd:process.cwd()});return}if(process.env.TMUX===void 0||process.env.TMUX===""){await H(s??f()??l(process.cwd())??void 0);return}const e=r.pane??process.env.TMUX_PANE??C()?.pane;if(e===void 0||e==="")throw w("crtr: no pane to show the dashboard in"),new Error("no tmux pane to show the dashboard in \u2014 pass --pane <id>");const n=i(t=>{throw w(`crtr: ${t}`,e),new Error(t)},"fail"),a=L(e)?.replace(/^"|"$/g,"");if(a===void 0)return n(`pane ${e} is not reachable`);if(a.startsWith("crtr surface dashboard")){const t=m(e,x);if(t===void 0||t===""){w("crtr: no conversation to return to from this dashboard",e);return}const u=g(),p=await u.getNode(t).catch(()=>null);if(p===null)return n("the conversation this pane showed before no longer exists");const{focusNode:E}=await import("../core/runtime/focus-viewer.js");(await E(u,p,{pane:e,inPlace:!0,keepOtherViewers:!0})).focused||n(`could not return to ${p.name}`);return}const o=W(e)??process.cwd(),d=await B(s,e,o),c=`crtr surface dashboard${d===void 0?"":` --profile-id ${j(d)}`}`,v={...F(),[b]:"1"};if(a.startsWith("crtr surface attach to ")){const t=m(e,"@crtr_node");t!==void 0&&t!==""&&X(e,x,t),M({pane:e,cwd:o,env:v,command:c})||n(`tmux could not respawn pane ${e}`);return}const $=A(e);if($===null)return n(`pane ${e} is not in a tmux window`);const h=D({session:$.session,name:"dashboard",cwd:o,env:v,command:c});if(h===null)return n("tmux could not open a window for the dashboard");const _=U(e),y=q(h.pane,e);if(y!==null)return I(h.window),n(`could not show the dashboard: ${y}`);const k=V(e);k!==null&&_!==void 0&&S(k,_)},"run"),render:i(()=>"","render")});export{ne as surfaceDashboardLeaf};
@@ -33,3 +33,7 @@ export interface ResolveContext {
33
33
  readable: (o: ObjectRow) => boolean;
34
34
  }
35
35
  export declare function resolveName(db: DatabaseSync, reader: Reader, raw: string, context?: ResolveContext): Resolution;
36
+ /** The stub of another machine's object that `raw` (`<owner handle>/<name>`, `<type>:<owner handle>/<name>` or a bare name) names, or null.
37
+ * `resolveName` never answers a stub, so a stub cannot shadow a local object; this is the lookup a forwarding handler makes only after
38
+ * `resolveName` found no local object, to learn that the name belongs to an object another machine homes. */
39
+ export declare function stubsNamed(db: DatabaseSync, reader: Reader, raw: string): ObjectRow[];
@@ -1,3 +1,3 @@
1
- var j=Object.defineProperty;var m=(t,e)=>j(t,"name",{value:e,configurable:!0});import{prepared as R}from"../sqlite-statements.js";import{isSafeNodeId as I}from"../canvas/paths.js";import{canRead as y,toolApps as g}from"./access.js";import{getById as T}from"./objects.js";function _(t,e){const s=R(t,"SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),l=g(t,e),o=e.class==="node"?[e.node,...e.repos,...e.projectRepos,e.profile,e.app]:e.class==="app"?[e.app]:e.class==="object"?[e.owner,...e.repos,e.app]:[],a=new Set;return[...o,s,...l].filter(r=>!!r&&!a.has(r.rowid)&&!!a.add(r.rowid))}m(_,"viewOf");function E(t,e,s,l){return t.prepare(`SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS NULL
2
- AND deleted_at IS ${l?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(e.rowid,s)}m(E,"namedObjects");const F=["person","app","repo","profile"],h=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/;function x(t,e,s){return s==="node"?R(t,"SELECT * FROM objects WHERE type = 'node' AND id = ?").all(e):s?R(t,"SELECT * FROM objects WHERE type = ? AND (name = ? OR id = ?) AND home_machine IS NULL").all(s,e,e):R(t,`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
3
- OR (type IN ('person','app','repo','profile') AND (name = ? OR id = ?) AND home_machine IS NULL)`).all(e,e,e)}m(x,"ownersByHandle");function W(t,e,s,l){let o=s.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim();const a=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(o);a&&!h.test(o)&&(o=`${a[1]}/reports/${a[2]}`);const r=l?.readable??(c=>y(t,e,c)),u=T(t,o);if(u&&r(u))return u.deleted_at?{deleted:u}:{object:u};const L=l?.view??_(t,e);for(const c of L){const i=E(t,c,o,!1).find(r);if(i)return{object:i}}const p=h.exec(o),w=o.indexOf("/");if(p||w>0){const c=p?p[2]:o.slice(0,w),i=p?p[3]:o.slice(w+1),d=x(t,c,p?.[1]),D=m(n=>{const f=L.findIndex(O=>O.rowid===n.rowid);return f<0?1/0:f},"rank"),A=d.filter(n=>D(n)<1/0).sort((n,f)=>D(n)-D(f));for(const n of A){const f=E(t,n,i,!1).find(r);if(f)return{object:f}}const N=d.flatMap(n=>E(t,n,i,!1)).filter(r);if(N.length===1)return{object:N[0]};if(N.length>1)return{ambiguous:N};const S=d.flatMap(n=>E(t,n,i,!0)).find(r);return S?{deleted:S}:!p&&d.length===0&&I(c)?{remote:o}:{missing:!0}}for(const c of L){const i=E(t,c,o,!0).find(r);if(i)return{deleted:i}}return{missing:!0}}m(W,"resolveName");export{F as HANDLE_TYPES,x as ownersByHandle,W as resolveName,_ as viewOf};
1
+ var g=Object.defineProperty;var m=(t,e)=>g(t,"name",{value:e,configurable:!0});import{prepared as R}from"../sqlite-statements.js";import{isSafeNodeId as x}from"../canvas/paths.js";import{canRead as S,toolApps as $}from"./access.js";import{getById as T}from"./objects.js";function A(t,e){const i=R(t,"SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),s=$(t,e),o=e.class==="node"?[e.node,...e.repos,...e.projectRepos,e.profile,e.app]:e.class==="app"?[e.app]:e.class==="object"?[e.owner,...e.repos,e.app]:[],p=new Set;return[...o,i,...s].filter(r=>!!r&&!p.has(r.rowid)&&!!p.add(r.rowid))}m(A,"viewOf");function E(t,e,i,s,o=!1){return t.prepare(`SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS ${o?"NOT NULL":"NULL"}
2
+ AND deleted_at IS ${s?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(e.rowid,i)}m(E,"namedObjects");const v=["person","app","repo","profile"],D=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/;function j(t,e,i){return i==="node"?R(t,"SELECT * FROM objects WHERE type = 'node' AND id = ?").all(e):i?R(t,"SELECT * FROM objects WHERE type = ? AND (name = ? OR id = ?) AND home_machine IS NULL").all(i,e,e):R(t,`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
3
+ OR (type IN ('person','app','repo','profile') AND (name = ? OR id = ?) AND home_machine IS NULL)`).all(e,e,e)}m(j,"ownersByHandle");function F(t,e,i,s){let o=i.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim();const p=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(o);p&&!D.test(o)&&(o=`${p[1]}/reports/${p[2]}`);const r=s?.readable??(f=>S(t,e,f)),a=T(t,o);if(a&&r(a))return a.deleted_at?{deleted:a}:{object:a};const N=s?.view??A(t,e);for(const f of N){const n=E(t,f,o,!1).find(r);if(n)return{object:n}}const l=D.exec(o),d=o.indexOf("/");if(l||d>0){const f=l?l[2]:o.slice(0,d),n=l?l[3]:o.slice(d+1),w=j(t,f,l?.[1]),h=m(c=>{const u=N.findIndex(I=>I.rowid===c.rowid);return u<0?1/0:u},"rank"),y=w.filter(c=>h(c)<1/0).sort((c,u)=>h(c)-h(u));for(const c of y){const u=E(t,c,n,!1).find(r);if(u)return{object:u}}const L=w.flatMap(c=>E(t,c,n,!1)).filter(r);if(L.length===1)return{object:L[0]};if(L.length>1)return{ambiguous:L};const O=w.flatMap(c=>E(t,c,n,!0)).find(r);return O?{deleted:O}:!l&&w.length===0&&x(f)?{remote:o}:{missing:!0}}for(const f of N){const n=E(t,f,o,!0).find(r);if(n)return{deleted:n}}return{missing:!0}}m(F,"resolveName");function W(t,e,i){const s=i.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),o=D.exec(s),p=s.indexOf("/"),r=A(t,e),a=m((d,f)=>d.flatMap(n=>E(t,n,f,!1,!0)).filter(n=>S(t,e,n)),"found"),N=a(r,s);if(N.length)return N;if(!o&&p<=0)return[];const l=j(t,o?o[2]:s.slice(0,p),o?.[1]);return a(l,o?o[3]:s.slice(p+1))}m(W,"stubsNamed");export{v as HANDLE_TYPES,j as ownersByHandle,F as resolveName,W as stubsNamed,A as viewOf};
@@ -1,6 +1,6 @@
1
- var Y=Object.defineProperty;var l=(t,e)=>Y(t,"name",{value:e,configurable:!0});import{gzipSync as V}from"node:zlib";import{browseNodes as F,graphNodes as X,listNodes as G,pruneNodes as Z,pruneToLimit as ee,rosterEdges as w,rosterNodes as te}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as ne}from"../../../core/bash-jobs.js";import{contextDir as se}from"../../../core/canvas/node-agent-paths.js";import{nowIso as $}from"../../../core/fs-utils.js";import{isPidPresent as oe}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as re,enrichRowsFromSource as ie}from"../../../core/canvas/render-source.js";import{localCanvasSource as P}from"../../../core/canvas/source.js";import{ticketCountsForNodes as q,ticketsAcrossCanvas as ae}from"../../../core/canvas/attention.js";import{buildCorpus as de,groupCorpus as le,resolveRef as ce}from"../../../core/canvas/history.js";import{listFocuses as D,reapEmptyNodes as ue}from"../../../core/runtime/placement.js";import{boundFleet as fe}from"../../../core/runtime/fleet.js";import{retentionHold as pe}from"../../reconcilers/live-obligation.js";import{notFound as me,usage as _}from"../../../core/errors.js";import{openDb as he}from"../../../core/canvas/db.js";import{prepared as _e}from"../../../core/sqlite-statements.js";import{view as ye}from"../../../core/canvas/tree.js";import{isFinishedWork as ge,isLiveStatus as be}from"../../../core/canvas/node-order.js";import{readNodeRecap as ve}from"../../../core/canvas/node-recap.js";import{readGoal as ke}from"../../../core/runtime/kickoff.js";import{faultSummary as Se}from"../../../core/canvas/status-glyph.js";import{listPendingAsks as we}from"../../../core/human/requests.js";import{toGraphNodeDTO as Ne}from"../map.js";import{actsAsPerson as Re,canReadNode as O,canReadRun as Ce}from"../router.js";import{ApiError as T}from"../../../api/errors.js";function N(t){return t.principal.class==="person"?null:new Set(G().filter(e=>O(t.principal,e.grantee??"app:terminal",e.node_id)).map(e=>e.node_id))}l(N,"visibleNodes");function H(t){return t.principal.class==="person"?null:new Set(G().filter(e=>e.run_id?Ce(t.principal,e.grantee??"app:terminal",e.node_id):O(t.principal,e.grantee??"app:terminal",e.node_id)).map(e=>e.node_id))}l(H,"visibleHistoryNodes");function Me(t){const e=N(t);return{status:200,body:{items:ae().filter(s=>e===null||e.has(s.node_id)).map(s=>({node_id:s.node_id,name:s.name,cwd:s.cwd,count:s.count,subjects:s.subjects}))}}}l(Me,"handleAttention");function Le(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw _("attention count request requires node_ids: string[]");const n=e.node_ids;if(!n.every(o=>typeof o=="string"))throw _("attention count request node_ids must contain only strings");const s=N(t);return{status:200,body:{counts:q(n.filter(o=>s===null||s.has(o)))}}}l(Le,"handleAttentionCounts");function z(t){return Buffer.from(String(t),"utf8").toString("base64")}l(z,"encodeCursor");function x(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw _(`invalid cursor: ${t}`);return e}l(x,"decodeCursor");function $e(t,e,n){const a=t.loadBody().split(`
2
- `);if(e.length>0){const c=a.findIndex(u=>{const f=u.toLowerCase();return e.some(i=>f.includes(i))});if(c!==-1)return a.slice(c,c+n).map(u=>u.trim()).filter(u=>u!=="").join(" \u23CE ")}const o=a.map(c=>c.trim()).filter(c=>c!=="").slice(0,n).join(" \u23CE ");return o!==""?o:t.title}l($e,"snippet");function Be(t,e,n){const s=[...t];return e==="relevance"&&n!==void 0?s.sort((a,o)=>(n.get(o.ref)??0)-(n.get(a.ref)??0)||o.tsMs-a.tsMs||a.ref.localeCompare(o.ref)):e==="oldest"?s.sort((a,o)=>a.tsMs-o.tsMs||a.ref.localeCompare(o.ref)):s.sort((a,o)=>o.tsMs-a.tsMs||a.ref.localeCompare(o.ref)),s}l(Be,"sortArtifacts");function Ee(t){if(t==null)return{};if(typeof t!="object")throw _("history search body must be a JSON object");return t}l(Ee,"parseSearchBody");function Ie(t){if(t===null||typeof t!="object")throw _("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw _("history grep body requires a non-empty pattern");return e}l(Ie,"parseGrepBody");function j(t,e){const n={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},s={types:t.types,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from},a=H(e);return de(n,s).filter(o=>a===null||a.has(o.nodeId))}l(j,"buildCorpusFromQuery");function Oe(t){if(t==null)return{};if(typeof t!="object")throw _("history stats body must be a JSON object");return t}l(Oe,"parseStatsBody");const J=["origin","node","kind","day","type","role"];function Te(t){const e=Oe(t.body),n=e.group_by??"type";if(!J.includes(n))throw _(`--group-by must be one of: ${J.join(", ")}; received: ${String(e.group_by)}`);const s=j(e,t),a=le(s,n);return{status:200,body:{group_by:n,groups:a,total:a.reduce((c,u)=>c+u.count,0),scanned:s.length}}}l(Te,"handleHistoryStats");function je(t){const e=Ie(t.body),n=Math.min(100,Math.max(1,e.limit??20)),s=j(e,t),a=e.cursor!==void 0?x(e.cursor):0;let o;try{o=new RegExp(e.pattern,"i")}catch{throw _(`invalid regex pattern: ${e.pattern}`)}const c=[];for(const r of s)r.loadBody().split(`
3
- `).forEach((y,b)=>{o.test(y)&&c.push({ref:r.ref,node:`${r.nodeName} (${r.nodeId})`,ts:r.ts,line:b+1,text:y.trim()})});c.sort((r,d)=>r.ref.localeCompare(d.ref)||r.line-d.line);const u=c.slice(a,a+n),f=a+n<c.length?z(a+n):null;return{status:200,body:{hits:u,next_cursor:f,total:c.length}}}l(je,"handleHistoryGrep");function Ae(t){const e=Ee(t.body),n=(e.query??"").trim(),s=e.weigh_body===!0,a=e.full===!0,o=Math.max(1,e.snippet_lines??1),c=Math.min(100,Math.max(1,e.limit??20)),u=e.per_node===!0;if(u&&(e.nodes===void 0||e.nodes.length===0))throw new T(400,"invalid_request","`per_node` requires a non-empty `nodes` list",{param:"nodes"});const f=j(e,t),i=e.cursor!==void 0?x(e.cursor):0,r=n.toLowerCase().split(/\s+/).filter(p=>p.length>0);let d=f,y;const b=e.sort??(r.length>0?"relevance":"recency");if(r.length>0&&b==="relevance"){y=new Map;const p=[];for(const h of f){const I=h.title.toLowerCase(),W=h.nodeName.toLowerCase(),Q=h.nodeDesc.toLowerCase(),A=s?h.loadBody().toLowerCase():null;let S=0;for(const L of r)I.includes(L)&&(S+=10),W.includes(L)&&(S+=5),Q.includes(L)&&(S+=3),A!==null&&A.includes(L)&&(S+=1);S>0&&(y.set(h.ref,S),p.push(h))}d=p}else r.length>0&&(d=f.filter(p=>{const h=`${p.title}
4
- ${p.nodeName}
5
- ${p.nodeDesc}${s?`
6
- `+p.loadBody():""}`.toLowerCase();return r.some(I=>h.includes(I))}));let g=Be(d,b,y);if(u){const p=new Set;g=g.filter(h=>!p.has(h.nodeId)&&p.add(h.nodeId))}const M=u?g:g.slice(i,i+c),k=!u&&i+c<g.length?z(i+c):null;return{status:200,body:{hits:M.map(p=>{const h={ref:p.ref,node:`${p.nodeName} (${p.nodeId})`,kind:p.nodeKind,source:p.source,ts:p.ts,...u?{node_id:p.nodeId}:{}};return b==="relevance"&&y!==void 0&&(h.score=y.get(p.ref)??0),a?h.body=p.loadBody():h.snippet=$e(p,r,o),h}),next_cursor:k,total:g.length}}}l(Ae,"handleHistorySearch");function Fe(t){const e=(t.query.get("ref")??"").trim();if(!e.includes(":"))throw _(`ref must be <node-id>:inbox/<n>, <node-id>:session, or <node-id>:session/<n>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search`. Reports and documents are `crtr canvas read <name>`."});const n=ce(e);if(n===null)throw me(`no inbox entry or message for ref: ${e}`,{ref:e,next:"Re-run `crtr canvas history search` for a current ref. Reports and documents are `crtr canvas read <name>`."});if(H(t)?.has(n.nodeId)===!1)throw new T(404,"not_found","artifact not found");const s=n.source,o=t.query.get("format")==="raw"&&n.raw!==null?n.raw:n.body;return{status:200,body:{ref:e,node:`${n.nodeName} (${n.nodeId})`,source:s,ts:n.ts,content:o}}}l(Fe,"handleHistoryRead");function Ge(t){for(const[s]of t.query)if(s!=="live")throw _(`unknown snapshot query parameter: ${s}`);const e=t.query.getAll("live");if(e.length>1)throw _("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 _("live must be true or false")}l(Ge,"snapshotLiveOnly");async function Pe(t){const e=new Set(D().map(r=>r.node_id)),n=N(t),s=(await re(P,e,Ge(t))).filter(r=>n===null||n.has(r.node_id)),a=q(s.map(r=>r.node_id));await ie(P,s,a);const o=s.map(r=>{const d=r.srcRow,y=d?.host_kind??"tmux";return{node_id:r.node_id,name:r.name,title:r.handle??r.name,description:r.description??null,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle??d?.lifecycle,status:r.status,cwd:r.cwd,profile_id:r.profile_id??null,parent:d?.parent??null,created:r.created,host_kind:y,enterable:y==="broker",attention_count:r.asks,...d?.cycles!=null?{cycles:d.cycles}:{},...r.mtimeMs!==void 0?{last_activity:new Date(r.mtimeMs).toISOString()}:{},ctx_tokens:r.ctx_tokens,streaming:r.streaming??!1,jobs_active:d!==void 0&&oe(d.pi_pid)?ne(se(r.node_id)).length:0,waiting_for:d?.waiting_for??null,hanging:r.hanging??null,viewed:r.viewed??!1,final_report:d?.final_report??null,finalized_at:d?.finalized_at??null}}),c=new Map;for(const r of w()){const d=c.get(r.from_id);d===void 0?c.set(r.from_id,[r.to_id]):d.push(r.to_id)}const u=new Set(s.map(r=>r.node_id)),f=Object.fromEntries(s.map(r=>[r.node_id,(c.get(r.node_id)??[]).filter(d=>u.has(d))]));return{status:200,body:{generated_at:$(),nodes:o,subscriptions:f}}}l(Pe,"handleSnapshot");function K(){const t=te().map(n=>{const s=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:s,enterable:s==="broker",parent:n.parent,created:n.created}}),e=w().map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created}));return{generated_at:$(),nodes:t,edges:e}}l(K,"buildRoster");let R=null,B=null;function qe(){return R===null?(R=Promise.resolve().then(()=>K()).finally(()=>{R=null}),R):(B===null&&(B=R.then(()=>K()).finally(()=>{B=null})),B)}l(qe,"rosterCoalesced");async function De(t){const e=await qe(),n=N(t);return n===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(s=>n.has(s.node_id)),edges:e.edges.filter(s=>n.has(s.from_id)&&n.has(s.to_id))}}}l(De,"handleRoster");function U(t){if(t.name!==""&&t.name!==t.kind)return t.name;const e=(t.description??"").trim();return e!==""?e:t.name}l(U,"liveRootName");function He(){const t=F(),e=new Map(t.map(i=>[i.node_id,i])),n=new Map(_e(he(),"SELECT node_id, reply_at, read_at FROM nodes WHERE parent IS NULL").all().map(i=>[i.node_id,i])),s=t.filter(i=>i.parent===null&&i.kind!=="human"&&(be(i.status)||!ge({lifecycle:i.lifecycle,finalized:i.final_report!=null}))),a=we(),o=new Map;for(const i of a)o.set(i.requester_node_id,(o.get(i.requester_node_id)??0)+1);const c=new Map;for(const i of w())c.set(i.from_id,[...c.get(i.from_id)??[],i.to_id]);const u=l(i=>{const r=e.get(i)?.fault;return r&&r.link!=="broker\u2194crtrd"?Se(r):null},"faultOf"),f=s.map(i=>{const r=[i.node_id,...ye(i.node_id)].filter(m=>e.get(m)?.kind!=="human"&&e.has(m)),d=new Set(r),y=a.filter(m=>d.has(m.requester_node_id)),b=n.get(i.node_id),g=b?.reply_at??null,M=b?.read_at??null;let k=i.created;for(const m of r){const v=e.get(m).telemetry_updated_at;v!=null&&v>k&&(k=v)}return g!==null&&g>k&&(k=g),{node_id:i.node_id,name:U(i),cwd:i.cwd,profile_id:i.profile_id,status:i.status,state_line:(()=>{const m=ve(i.node_id)?.state.trim();return m||null})(),goal:ke(i.node_id)?.trim()||null,asks:y.length,first_ask_ticket_id:y[0]?.inbox_ticket_id??null,fault:r.map(u).find(m=>m!==null)??null,running_count:r.filter(m=>e.get(m).streaming===!0).length,unread:g!==null&&(M===null||g>M),last_activity:k,children:(c.get(i.node_id)??[]).filter(m=>e.has(m)&&e.get(m).kind!=="human").map(m=>{const v=e.get(m);return{node_id:m,name:U(v),status:v.status,streaming:v.streaming===!0,asks:o.get(m)??0,fault:u(m)}})}});return{generated_at:$(),rows:f}}l(He,"buildLiveRoots");let C=null,E=null;function ze(){const t=l(()=>Promise.resolve().then(He),"run");return C===null?(C=t().finally(()=>{C=null}),C):(E===null&&(E=C.then(t).finally(()=>{E=null})),E)}l(ze,"liveRootsCoalesced");async function xe(t){if(!Re(t.principal))throw new T(403,"permission_error","only the person reads the dashboard");const e=await ze(),n=t.query.get("profile");return{status:200,body:n===null?e:{...e,rows:e.rows.filter(s=>s.profile_id===n)}}}l(xe,"handleLiveRoots");function Je(t){const e=F().filter(o=>t.principal.class==="person"||O(t.principal,o.grantee??"app:terminal",o.node_id)).map(o=>({node_id:o.node_id,name:o.name,description:o.description,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle,status:o.status,cwd:o.cwd,profile_id:o.profile_id,grantee:o.grantee??"app:terminal",parent:o.parent,created:o.created,frozen_at:o.frozen_at??null,terminal_reason:o.terminal_reason??null,final_report:o.final_report??null,telemetry_tokens_in:o.telemetry_tokens_in??null,telemetry_updated_at:o.telemetry_updated_at??null,fault:o.fault&&o.fault.link!=="broker\u2194crtrd"?{...o.fault,link:o.fault.link}:null,streaming:o.streaming??!1})),n=new Set(e.map(o=>o.node_id)),s=w().filter(o=>n.has(o.from_id)&&n.has(o.to_id));return{status:200,rawBody:V(JSON.stringify({nodes:e,edges:s}),{level:1}),headers:{"content-type":"application/gzip"}}}l(Je,"handleBrowse");function Ke(t){const e=N(t);return{status:200,body:{generated_at:$(),nodes:X().filter(s=>e===null||e.has(s.node_id)).map(Ne),edges:w().filter(s=>e===null||e.has(s.from_id)&&e.has(s.to_id)).map(s=>({from_id:s.from_id,to_id:s.to_id,active:s.active,created:s.created})),focused_node_ids:D().map(s=>s.node_id).filter(s=>e===null||e.has(s))}}}l(Ke,"handleGraph");function Ue(t){if(t==null)return{};if(typeof t!="object")throw _("prune body must be a JSON object");const e=t,n=l(r=>{const d=e[r];if(d!==void 0){if(typeof d!="number"||!Number.isFinite(d))throw _(`${r} must be a number`);return d}},"num"),s=l(r=>{const d=e[r];if(d!==void 0){if(typeof d!="boolean")throw _(`${r} must be a boolean`);return d}},"bool"),a={},o=n("limit");o!==void 0&&(a.limit=o);const c=n("ttl_days");c!==void 0&&(a.ttl_days=c);const u=s("include_stale");u!==void 0&&(a.include_stale=u);const f=s("empty");f!==void 0&&(a.empty=f);const i=s("dry_run");return i!==void 0&&(a.dry_run=i),a}l(Ue,"parsePruneBody");function We(t){const e=Ue(t.body),n=e.ttl_days??14,s=e.dry_run??!1,a=pe(fe());let o;return e.limit!==void 0?o=ee({maxNodes:e.limit,held:a,dryRun:s}).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})):e.empty===!0?o=ue({dryRun:s}).map(f=>({node_id:f,status:"empty",created:""})):o=Z({ttlDays:n,held:a,dryRun:s,includeStale:e.include_stale??!1}).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})),{status:200,body:{pruned:o,dry_run:s,ttl_days:n}}}l(We,"handlePrune");const kt=[{method:"GET",pattern:"/v1/canvas/attention",handler:Me},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:Le},{method:"POST",pattern:"/v1/canvas/history/search",handler:Ae},{method:"POST",pattern:"/v1/canvas/history/grep",handler:je},{method:"GET",pattern:"/v1/canvas/history/read",handler:Fe},{method:"POST",pattern:"/v1/canvas/history/stats",handler:Te},{method:"GET",pattern:"/v1/canvas/snapshot",handler:Pe},{method:"GET",pattern:"/v1/canvas/roster",handler:De},{method:"GET",pattern:"/v1/canvas/live-roots",handler:xe},{method:"GET",pattern:"/v1/canvas/browse",handler:Je},{method:"GET",pattern:"/v1/canvas/graph",handler:Ke},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:We}];export{kt as canvasRoutes,Je as handleBrowse};
1
+ var Y=Object.defineProperty;var l=(t,e)=>Y(t,"name",{value:e,configurable:!0});import{gzipSync as V}from"node:zlib";import{browseNodes as P,graphNodes as X,listNodes as F,pruneNodes as Z,pruneToLimit as ee,rosterEdges as w,rosterNodes as te}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as ne}from"../../../core/bash-jobs.js";import{contextDir as se}from"../../../core/canvas/node-agent-paths.js";import{nowIso as L}from"../../../core/fs-utils.js";import{isPidPresent as oe}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as re,enrichRowsFromSource as ie}from"../../../core/canvas/render-source.js";import{localCanvasSource as G}from"../../../core/canvas/source.js";import{ticketCountsForNodes as q,ticketsAcrossCanvas as ae}from"../../../core/canvas/attention.js";import{buildCorpus as de,groupCorpus as le,resolveRef as ue}from"../../../core/canvas/history.js";import{listFocuses as D,reapEmptyNodes as ce}from"../../../core/runtime/placement.js";import{boundFleet as fe}from"../../../core/runtime/fleet.js";import{retentionHold as pe}from"../../reconcilers/live-obligation.js";import{notFound as me,usage as _}from"../../../core/errors.js";import{openDb as _e}from"../../../core/canvas/db.js";import{prepared as he}from"../../../core/sqlite-statements.js";import{view as ye}from"../../../core/canvas/tree.js";import{isLiveStatus as ge}from"../../../core/canvas/node-order.js";import{readNodeRecap as be}from"../../../core/canvas/node-recap.js";import{readGoal as ve}from"../../../core/runtime/kickoff.js";import{faultSummary as ke}from"../../../core/canvas/status-glyph.js";import{listPendingAsks as Se}from"../../../core/human/requests.js";import{toGraphNodeDTO as we}from"../map.js";import{actsAsPerson as Re,canReadNode as B,canReadRun as Ne}from"../router.js";import{ApiError as T}from"../../../api/errors.js";function R(t){return t.principal.class==="person"?null:new Set(F().filter(e=>B(t.principal,e.grantee??"app:terminal",e.node_id)).map(e=>e.node_id))}l(R,"visibleNodes");function H(t){return t.principal.class==="person"?null:new Set(F().filter(e=>e.run_id?Ne(t.principal,e.grantee??"app:terminal",e.node_id):B(t.principal,e.grantee??"app:terminal",e.node_id)).map(e=>e.node_id))}l(H,"visibleHistoryNodes");function Ce(t){const e=R(t);return{status:200,body:{items:ae().filter(s=>e===null||e.has(s.node_id)).map(s=>({node_id:s.node_id,name:s.name,cwd:s.cwd,count:s.count,subjects:s.subjects}))}}}l(Ce,"handleAttention");function Me(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw _("attention count request requires node_ids: string[]");const n=e.node_ids;if(!n.every(r=>typeof r=="string"))throw _("attention count request node_ids must contain only strings");const s=R(t);return{status:200,body:{counts:q(n.filter(r=>s===null||s.has(r)))}}}l(Me,"handleAttentionCounts");function x(t){return Buffer.from(String(t),"utf8").toString("base64")}l(x,"encodeCursor");function z(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw _(`invalid cursor: ${t}`);return e}l(z,"decodeCursor");function Le(t,e,n){const a=t.loadBody().split(`
2
+ `);if(e.length>0){const u=a.findIndex(p=>{const f=p.toLowerCase();return e.some(h=>f.includes(h))});if(u!==-1)return a.slice(u,u+n).map(p=>p.trim()).filter(p=>p!=="").join(" \u23CE ")}const r=a.map(u=>u.trim()).filter(u=>u!=="").slice(0,n).join(" \u23CE ");return r!==""?r:t.title}l(Le,"snippet");function Ee(t,e,n){const s=[...t];return e==="relevance"&&n!==void 0?s.sort((a,r)=>(n.get(r.ref)??0)-(n.get(a.ref)??0)||r.tsMs-a.tsMs||a.ref.localeCompare(r.ref)):e==="oldest"?s.sort((a,r)=>a.tsMs-r.tsMs||a.ref.localeCompare(r.ref)):s.sort((a,r)=>r.tsMs-a.tsMs||a.ref.localeCompare(r.ref)),s}l(Ee,"sortArtifacts");function Ie(t){if(t==null)return{};if(typeof t!="object")throw _("history search body must be a JSON object");return t}l(Ie,"parseSearchBody");function Oe(t){if(t===null||typeof t!="object")throw _("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw _("history grep body requires a non-empty pattern");return e}l(Oe,"parseGrepBody");function j(t,e){const n={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},s={types:t.types,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from},a=H(e);return de(n,s).filter(r=>a===null||a.has(r.nodeId))}l(j,"buildCorpusFromQuery");function $e(t){if(t==null)return{};if(typeof t!="object")throw _("history stats body must be a JSON object");return t}l($e,"parseStatsBody");const J=["origin","node","kind","day","type","role"];function Be(t){const e=$e(t.body),n=e.group_by??"type";if(!J.includes(n))throw _(`--group-by must be one of: ${J.join(", ")}; received: ${String(e.group_by)}`);const s=j(e,t),a=le(s,n);return{status:200,body:{group_by:n,groups:a,total:a.reduce((u,p)=>u+p.count,0),scanned:s.length}}}l(Be,"handleHistoryStats");function Te(t){const e=Oe(t.body),n=Math.min(100,Math.max(1,e.limit??20)),s=j(e,t),a=e.cursor!==void 0?z(e.cursor):0;let r;try{r=new RegExp(e.pattern,"i")}catch{throw _(`invalid regex pattern: ${e.pattern}`)}const u=[];for(const i of s)i.loadBody().split(`
3
+ `).forEach((c,b)=>{r.test(c)&&u.push({ref:i.ref,node:`${i.nodeName} (${i.nodeId})`,ts:i.ts,line:b+1,text:c.trim()})});u.sort((i,o)=>i.ref.localeCompare(o.ref)||i.line-o.line);const p=u.slice(a,a+n),f=a+n<u.length?x(a+n):null;return{status:200,body:{hits:p,next_cursor:f,total:u.length}}}l(Te,"handleHistoryGrep");function je(t){const e=Ie(t.body),n=(e.query??"").trim(),s=e.weigh_body===!0,a=e.full===!0,r=Math.max(1,e.snippet_lines??1),u=Math.min(100,Math.max(1,e.limit??20)),p=e.per_node===!0;if(p&&(e.nodes===void 0||e.nodes.length===0))throw new T(400,"invalid_request","`per_node` requires a non-empty `nodes` list",{param:"nodes"});const f=j(e,t),h=e.cursor!==void 0?z(e.cursor):0,i=n.toLowerCase().split(/\s+/).filter(d=>d.length>0);let o=f,c;const b=e.sort??(i.length>0?"relevance":"recency");if(i.length>0&&b==="relevance"){c=new Map;const d=[];for(const m of f){const $=m.title.toLowerCase(),Q=m.nodeName.toLowerCase(),W=m.nodeDesc.toLowerCase(),A=s?m.loadBody().toLowerCase():null;let S=0;for(const M of i)$.includes(M)&&(S+=10),Q.includes(M)&&(S+=5),W.includes(M)&&(S+=3),A!==null&&A.includes(M)&&(S+=1);S>0&&(c.set(m.ref,S),d.push(m))}o=d}else i.length>0&&(o=f.filter(d=>{const m=`${d.title}
4
+ ${d.nodeName}
5
+ ${d.nodeDesc}${s?`
6
+ `+d.loadBody():""}`.toLowerCase();return i.some($=>m.includes($))}));let g=Ee(o,b,c);if(p){const d=new Set;g=g.filter(m=>!d.has(m.nodeId)&&d.add(m.nodeId))}const v=p?g:g.slice(h,h+u),y=!p&&h+u<g.length?x(h+u):null;return{status:200,body:{hits:v.map(d=>{const m={ref:d.ref,node:`${d.nodeName} (${d.nodeId})`,kind:d.nodeKind,source:d.source,ts:d.ts,...p?{node_id:d.nodeId}:{}};return b==="relevance"&&c!==void 0&&(m.score=c.get(d.ref)??0),a?m.body=d.loadBody():m.snippet=Le(d,i,r),m}),next_cursor:y,total:g.length}}}l(je,"handleHistorySearch");function Ae(t){const e=(t.query.get("ref")??"").trim();if(!e.includes(":"))throw _(`ref must be <node-id>:inbox/<n>, <node-id>:session, or <node-id>:session/<n>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search`. Reports and documents are `crtr canvas read <name>`."});const n=ue(e);if(n===null)throw me(`no inbox entry or message for ref: ${e}`,{ref:e,next:"Re-run `crtr canvas history search` for a current ref. Reports and documents are `crtr canvas read <name>`."});if(H(t)?.has(n.nodeId)===!1)throw new T(404,"not_found","artifact not found");const s=n.source,r=t.query.get("format")==="raw"&&n.raw!==null?n.raw:n.body;return{status:200,body:{ref:e,node:`${n.nodeName} (${n.nodeId})`,source:s,ts:n.ts,content:r}}}l(Ae,"handleHistoryRead");function Pe(t){for(const[s]of t.query)if(s!=="live")throw _(`unknown snapshot query parameter: ${s}`);const e=t.query.getAll("live");if(e.length>1)throw _("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 _("live must be true or false")}l(Pe,"snapshotLiveOnly");async function Fe(t){const e=new Set(D().map(i=>i.node_id)),n=R(t),s=(await re(G,e,Pe(t))).filter(i=>n===null||n.has(i.node_id)),a=q(s.map(i=>i.node_id));await ie(G,s,a);const r=s.map(i=>{const o=i.srcRow,c=o?.host_kind??"tmux";return{node_id:i.node_id,name:i.name,title:i.handle??i.name,description:i.description??null,kind:i.kind,mode:i.mode,lifecycle:i.lifecycle??o?.lifecycle,status:i.status,cwd:i.cwd,profile_id:i.profile_id??null,parent:o?.parent??null,created:i.created,host_kind:c,enterable:c==="broker",attention_count:i.asks,...o?.cycles!=null?{cycles:o.cycles}:{},...i.mtimeMs!==void 0?{last_activity:new Date(i.mtimeMs).toISOString()}:{},ctx_tokens:i.ctx_tokens,streaming:i.streaming??!1,jobs_active:o!==void 0&&oe(o.pi_pid)?ne(se(i.node_id)).length:0,waiting_for:o?.waiting_for??null,hanging:i.hanging??null,viewed:i.viewed??!1,final_report:o?.final_report??null,finalized_at:o?.finalized_at??null}}),u=new Map;for(const i of w()){const o=u.get(i.from_id);o===void 0?u.set(i.from_id,[i.to_id]):o.push(i.to_id)}const p=new Set(s.map(i=>i.node_id)),f=Object.fromEntries(s.map(i=>[i.node_id,(u.get(i.node_id)??[]).filter(o=>p.has(o))]));return{status:200,body:{generated_at:L(),nodes:r,subscriptions:f}}}l(Fe,"handleSnapshot");function K(){const t=te().map(n=>{const s=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:s,enterable:s==="broker",parent:n.parent,created:n.created}}),e=w().map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created}));return{generated_at:L(),nodes:t,edges:e}}l(K,"buildRoster");let N=null,E=null;function Ge(){return N===null?(N=Promise.resolve().then(()=>K()).finally(()=>{N=null}),N):(E===null&&(E=N.then(()=>K()).finally(()=>{E=null})),E)}l(Ge,"rosterCoalesced");async function qe(t){const e=await Ge(),n=R(t);return n===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(s=>n.has(s.node_id)),edges:e.edges.filter(s=>n.has(s.from_id)&&n.has(s.to_id))}}}l(qe,"handleRoster");function U(t){if(t.name!==""&&t.name!==t.kind)return t.name;const e=(t.description??"").trim();return e!==""?e:t.name}l(U,"liveRootName");const De=1440*6e4;function He(){const t=P(),e=new Map(t.map(o=>[o.node_id,o])),n=new Map(he(_e(),"SELECT node_id, reply_at, read_at, intent FROM nodes WHERE parent IS NULL").all().map(o=>[o.node_id,o])),s=Se(),a=new Map;for(const o of s)a.set(o.requester_node_id,(a.get(o.requester_node_id)??0)+1);const r=new Date(Date.now()-De).toISOString(),u=l(o=>{const c=n.get(o.node_id);return c?.reply_at!=null&&(c.read_at==null||c.reply_at>c.read_at)||(a.get(o.node_id)??0)>0?!0:o.status!=="done"||c?.intent!=="parked"?!1:[o.created,o.telemetry_updated_at,c.reply_at].reduce((v,y)=>y!=null&&y>v?y:v,"")>=r},"keepFinished"),p=t.filter(o=>o.parent===null&&o.kind!=="human"&&(ge(o.status)||u(o))),f=new Map;for(const o of w())f.set(o.from_id,[...f.get(o.from_id)??[],o.to_id]);const h=l(o=>{const c=e.get(o)?.fault;return c&&c.link!=="broker\u2194crtrd"?ke(c):null},"faultOf"),i=p.map(o=>{const c=[o.node_id,...ye(o.node_id)].filter(d=>e.get(d)?.kind!=="human"&&e.has(d)),b=new Set(c),g=s.filter(d=>b.has(d.requester_node_id)),v=n.get(o.node_id),y=v?.reply_at??null,O=v?.read_at??null;let k=o.created;for(const d of c){const m=e.get(d).telemetry_updated_at;m!=null&&m>k&&(k=m)}return y!==null&&y>k&&(k=y),{node_id:o.node_id,name:U(o),cwd:o.cwd,profile_id:o.profile_id,status:o.status,state_line:(()=>{const d=be(o.node_id)?.state.trim();return d||null})(),goal:ve(o.node_id)?.trim()||null,asks:g.length,first_ask_ticket_id:g[0]?.inbox_ticket_id??null,fault:c.map(h).find(d=>d!==null)??null,running_count:c.filter(d=>e.get(d).streaming===!0).length,unread:y!==null&&(O===null||y>O),last_activity:k,children:(f.get(o.node_id)??[]).filter(d=>e.has(d)&&e.get(d).kind!=="human").map(d=>{const m=e.get(d);return{node_id:d,name:U(m),status:m.status,streaming:m.streaming===!0,asks:a.get(d)??0,fault:h(d)}})}});return{generated_at:L(),rows:i}}l(He,"buildLiveRoots");let C=null,I=null;function xe(){const t=l(()=>Promise.resolve().then(He),"run");return C===null?(C=t().finally(()=>{C=null}),C):(I===null&&(I=C.then(t).finally(()=>{I=null})),I)}l(xe,"liveRootsCoalesced");async function ze(t){if(!Re(t.principal))throw new T(403,"permission_error","only the person reads the dashboard");const e=await xe(),n=t.query.get("profile");return{status:200,body:n===null?e:{...e,rows:e.rows.filter(s=>s.profile_id===n)}}}l(ze,"handleLiveRoots");function Je(t){const e=P().filter(r=>t.principal.class==="person"||B(t.principal,r.grantee??"app:terminal",r.node_id)).map(r=>({node_id:r.node_id,name:r.name,description:r.description,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,status:r.status,cwd:r.cwd,profile_id:r.profile_id,grantee:r.grantee??"app:terminal",parent:r.parent,created:r.created,frozen_at:r.frozen_at??null,terminal_reason:r.terminal_reason??null,final_report:r.final_report??null,telemetry_tokens_in:r.telemetry_tokens_in??null,telemetry_updated_at:r.telemetry_updated_at??null,fault:r.fault&&r.fault.link!=="broker\u2194crtrd"?{...r.fault,link:r.fault.link}:null,streaming:r.streaming??!1})),n=new Set(e.map(r=>r.node_id)),s=w().filter(r=>n.has(r.from_id)&&n.has(r.to_id));return{status:200,rawBody:V(JSON.stringify({nodes:e,edges:s}),{level:1}),headers:{"content-type":"application/gzip"}}}l(Je,"handleBrowse");function Ke(t){const e=R(t);return{status:200,body:{generated_at:L(),nodes:X().filter(s=>e===null||e.has(s.node_id)).map(we),edges:w().filter(s=>e===null||e.has(s.from_id)&&e.has(s.to_id)).map(s=>({from_id:s.from_id,to_id:s.to_id,active:s.active,created:s.created})),focused_node_ids:D().map(s=>s.node_id).filter(s=>e===null||e.has(s))}}}l(Ke,"handleGraph");function Ue(t){if(t==null)return{};if(typeof t!="object")throw _("prune body must be a JSON object");const e=t,n=l(i=>{const o=e[i];if(o!==void 0){if(typeof o!="number"||!Number.isFinite(o))throw _(`${i} must be a number`);return o}},"num"),s=l(i=>{const o=e[i];if(o!==void 0){if(typeof o!="boolean")throw _(`${i} must be a boolean`);return o}},"bool"),a={},r=n("limit");r!==void 0&&(a.limit=r);const u=n("ttl_days");u!==void 0&&(a.ttl_days=u);const p=s("include_stale");p!==void 0&&(a.include_stale=p);const f=s("empty");f!==void 0&&(a.empty=f);const h=s("dry_run");return h!==void 0&&(a.dry_run=h),a}l(Ue,"parsePruneBody");function Qe(t){const e=Ue(t.body),n=e.ttl_days??14,s=e.dry_run??!1,a=pe(fe());let r;return e.limit!==void 0?r=ee({maxNodes:e.limit,held:a,dryRun:s}).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})):e.empty===!0?r=ce({dryRun:s}).map(f=>({node_id:f,status:"empty",created:""})):r=Z({ttlDays:n,held:a,dryRun:s,includeStale:e.include_stale??!1}).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})),{status:200,body:{pruned:r,dry_run:s,ttl_days:n}}}l(Qe,"handlePrune");const kt=[{method:"GET",pattern:"/v1/canvas/attention",handler:Ce},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:Me},{method:"POST",pattern:"/v1/canvas/history/search",handler:je},{method:"POST",pattern:"/v1/canvas/history/grep",handler:Te},{method:"GET",pattern:"/v1/canvas/history/read",handler:Ae},{method:"POST",pattern:"/v1/canvas/history/stats",handler:Be},{method:"GET",pattern:"/v1/canvas/snapshot",handler:Fe},{method:"GET",pattern:"/v1/canvas/roster",handler:qe},{method:"GET",pattern:"/v1/canvas/live-roots",handler:ze},{method:"GET",pattern:"/v1/canvas/browse",handler:Je},{method:"GET",pattern:"/v1/canvas/graph",handler:Ke},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:Qe}];export{kt as canvasRoutes,Je as handleBrowse};
@@ -1,3 +1,3 @@
1
- var Re=Object.defineProperty;var l=(e,t)=>Re(e,"name",{value:t,configurable:!0});import{prepared as $e}from"../../../core/sqlite-statements.js";import{ApiError as y}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as Ie}from"../../../api/dto/objects.js";import{openDb as T,withCanvasWrite as _}from"../../../core/canvas/db.js";import{actorOf as ee}from"../../../core/graph/documents.js";import{readerForObject as D,readerFor as Se}from"../../../core/graph/reader.js";import{resolveName as Ae}from"../../../core/graph/names.js";import{canRead as te,customReachable as Ne,holdsObjectsScope as Fe,mayActAs as ne}from"../../../core/graph/access.js";import{customObjectRef as re,authorizeCustom as oe,fenceArgv as M}from"./custom-objects.js";import{edgesOf as Le}from"../../../core/graph/edges.js";import{publish as G}from"../../../core/graph/events.js";import{objectDTO as g}from"../../../core/graph/kinds/dto.js";import{isKind as We,kindNames as Pe,kindOf as z}from"../../../core/graph/kinds/registry.js";import{listObjects as Ce,searchObjects as ie}from"../../../core/graph/objects.js";import{checkoutsForCwd as De}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as W,unwatch as Me,watchersOf as Ge,watchesOf as ze}from"../../../core/graph/watches.js";import{readerFor as v,resolveRef as H}from"../reader.js";import{readDelegationFor as se,runReadLeaf as He}from"../../plugin-objects/read-leaf.js";import{invalidRequest as P,isRecord as R}from"./validate.js";import{callerNode as ue,callerStub as U,forwardVerb as ae,originates as ce,queryWithoutMachine as V,relayError as C,remoteStub as Ue,unknownError as le,forwarding as F,withMachine as B}from"../../peer/forward.js";import{getById as L,getByRowid as fe}from"../../../core/graph/objects.js";import{ensureNodeStub as Ve,isStub as K,stubOf as Be,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as Ke}from"../../../core/peer/client.js";import{normalizeMachineId as I}from"../../../core/peer/directory.js";const S=l(e=>t=>De(e,t),"reposFnFor");function de(e,t){return{...g(e,t),...z(e,t.type).listItem?.(e,t)}}l(de,"listItem");function Ze(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Ze,"remoteMessage");function me(e,t,r){try{return q(e,t,r)}catch(n){if(n instanceof y&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(me,"ownerFilter");function q(e,t,r){const n=H(e,t,r);if("remote"in n)throw new y(404,"not_found",Ze(n.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new y(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});return n}l(q,"liveRef");const k=l(e=>decodeURIComponent(e.params.ref),"refParam"),he=l(e=>{const t=e.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),r=t.indexOf("/");return r>0?t.slice(0,r):t},"idOf");function pe(e){const t=L(T(),he(e));return t!==null&&K(T(),t)?t.id:null}l(pe,"stubIdOf");function Je(e,t){const r=pe(e);return r!==null?{stub:r,hit:!0}:_(n=>{try{const o=H(n,v(n,t),e);if("remote"in o)return{stub:null,hit:!1};const i="deleted"in o?o.deleted:o;return{stub:K(n,i)?i.id:null,hit:!0}}catch{return{stub:null,hit:!1}}})}l(Je,"resolvedLocally");async function Z(e,t,r){const n=Je(t,e);return n.stub!==null?ae(e,n.stub,r):n.hit||!ce(e.principal)?{kind:"local"}:ae(e,he(t),r)}l(Z,"forwardRef");const J=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");function we(e,t,r,n,o){const i=t?.object;!i?.id||!i.type||_(s=>{const u=ue(s,e);if(u===null)return;const c=Ue(s,i.id,i.type,r,{kind:i.kind??null,name:i.name??i.id,...i.preview===void 0?{}:{preview:i.preview},owner:i.owner??null,...i.kind_decl===void 0?{}:{kind_decl:i.kind_decl},...i.privacy===void 0?{}:{privacy:i.privacy}});W(s,u,c,n,o===void 0?{}:{patterns:o})})}l(we,"watchRemote");async function Qe(e){const t=k(e),r=["1","true"].includes(e.query.get("fields")??""),n=await Z(e,t,{method:"GET",path:J(t),query:V(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw C(n.status,n.body);return we(e,n.body,n.machine.id,"read"),B(n.body,n.machine)}const o=l(u=>{const c=U(u,e);return c===null?v(u,e):D(u,c,S(u))},"readerOf"),i=_(u=>{const c=o(u),a=H(u,c,t);if("remote"in a)return{state:"remote",remote:a.remote};if("deleted"in a)return{state:"deleted",deleted:g(u,a.deleted)};const f=se(u,a);if(f!==null)return{delegate:f,hitId:a.id};const{data:p,text:b}=z(u,a.type).read(u,c,a,{fields:r,reposFn:S(u)});return{state:"object",type:a.type,object:$(u,a,g(u,a)),text:b,data:p}});if(!("delegate"in i))return i;const s=await He(i.delegate,e.principal);return _(u=>{const c=o(u),a=L(u,i.hitId);if(a===null)throw new y(404,"not_found","object not found");if(a.deleted_at!==null)return{state:"deleted",deleted:g(u,a)};if(!te(u,c,a))throw new y(404,"not_found","object not found");const{data:f,text:p}=z(u,a.type).read(u,c,a,{fields:r,reposFn:S(u)});return se(u,a)===null?{state:"object",type:a.type,object:$(u,a,g(u,a)),text:p,data:f}:{state:"object",type:a.type,object:$(u,a,g(u,a)),text:"markdown"in s?s.markdown:`${p}
2
- content unavailable: ${s.unavailable}`,data:{...f,content:"markdown"in s?"live":"unavailable"}}})}l(Qe,"read");function Q(e,t,r,n){if(e!=null){if(!r.includes(e)){n.push({field:t,problem:`must be one of ${r.join(", ")}`,received:e});return}return e}}l(Q,"oneOf");function ye(e,t,r){if(t!=null){if(typeof t!="string"||!We(e,t)){r.push({field:"type",problem:`must be a kind: one of ${Pe(e).join(", ")}`,received:t});return}return t}}l(ye,"kindName");function ge(e,t,r,n){if(e==null)return n;const o=Number(e);return!Number.isInteger(o)||o<1||o>100?(r.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):o}l(ge,"limitOf");function be(e){const t=e.query,r=[],n=ye(T(),t.get("type"),r),o=Q(t.get("privacy"),"privacy",Ie,r),i=ge(t.get("limit"),"limit",r,50),s=t.get("cursor");s!==null&&!/^\d+$/.test(s)&&r.push({field:"cursor",problem:"is not a cursor from a previous page",received:s});const u=t.get("deleted");return u!==null&&!["0","1","true","false"].includes(u)&&r.push({field:"deleted",problem:"must be true or false",received:u}),r.length>0&&P("object list request",r),_(c=>{const a=v(c,e),f={...n?{type:n}:{},...o?{privacy:o}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...u==="1"||u==="true"?{deleted:!0}:{}},p=t.get("owner");if(p!==null){const m=me(c,a,p);if(m===null)return{items:[],next_cursor:null};f.owner=m}const b=t.get("name"),j=[];let h=s===null?0:Number(s),w=!0;for(;j.length<i&&w;){const m=Ce(c,a,f,{limit:100,after_rowid:h});w=m.length===100;for(const E of m)if(h=E.rowid,(b===null||E.name.startsWith(b))&&j.push(E),j.length===i)break}const d=j.at(-1);return{items:j.map(m=>de(c,m)),next_cursor:j.length===i&&d?String(d.rowid):null}})}l(be,"listLocal");const Ye={ms:3e4},Xe="self",Y=l((e,t)=>e.map(r=>({...r,machine:t})),"labelItems");async function je(e,t,r,n){const o=F.current;try{const i=await o.call(t.id,{method:"GET",path:"/v1/objects",query:r},o.envelope(e.principal),n);if(Ke(i))return{state:"unreachable",items:[],next:null};if(i.status===426)return{state:"too_old",items:[],next:null};const s=i.body;return i.status!==200||!Array.isArray(s?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:Y(s.items,t),next:s.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(je,"remotePage");async function xe(e){const t=new Promise(r=>e.addEventListener("abort",()=>r(null),{once:!0}));return Promise.race([F.current.machines().catch(()=>null),t])}l(xe,"machinesWithin");async function et(e){const t=e.query.get("machine");if(!ce(e.principal)||!F.current.joined()||t===Xe)return be(_e(e));const n=F.current.self(),o=t!==null&&I(t)!==n,i=o?null:be(_e(e)),s=new AbortController,u=setTimeout(()=>s.abort(),Ye.ms);u.unref?.();try{const c=await xe(s.signal);if(c===null){if(o)throw new y(503,"runtime_unreachable",`The directory did not answer, so ${I(t)} cannot be listed.`,{machine:I(t)});return i}const a=l(d=>({id:d,name:c.find(m=>m.machine_id===d)?.name??d}),"labelOf"),f=a(n),p=c.filter(d=>d.machine_id!==n&&d.kind!=="device"),b=V(e);if(t!==null){if(!o)return{items:Y(i.items,f),next_cursor:i.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:i.next_cursor!==null}]};const d=I(t);if(!p.some(E=>E.machine_id===d))throw new y(404,"not_found",`no machine ${d} on your account`,{machine:d});const m=await je(e,a(d),b,s.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:d,name:a(d).name,state:m.state,more:m.next!==null}]}}const{cursor:j,...h}=b,w=await Promise.all(p.map(d=>je(e,a(d.machine_id),h,s.signal)));return{items:[...Y(i.items,f),...w.flatMap(d=>d.items)],next_cursor:i.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:i.next_cursor!==null},...p.map((d,m)=>({machine_id:d.machine_id,name:d.name,state:w[m].state,more:w[m].next!==null}))]}}finally{clearTimeout(u)}}l(et,"list");function _e(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(_e,"withoutMachine");function tt(e){const t=[],r=R(e.body)?e.body:{};R(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=r.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const o=r.grep;if(o!==void 0)if(typeof o!="string")t.push({field:"grep",problem:"must be a regular expression string",received:o});else try{new RegExp(o)}catch(u){t.push({field:"grep",problem:`is not a valid regular expression: ${u.message}`,received:o})}r.body!==void 0&&typeof r.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:r.body});const i=ye(T(),r.type,t);r.kind!==void 0&&typeof r.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:r.kind}),r.owner!==void 0&&typeof r.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:r.owner});const s=ge(r.limit,"limit",t,50);return t.length>0&&P("object search request",t),_(u=>{const c=v(u,e),a=typeof r.owner=="string"?me(u,c,r.owner):null;if(typeof r.owner=="string"&&a===null)return{items:[]};const f=ie(u,c,{text:n,body:r.body===!0||typeof o=="string"}),p=new Set(f.map(h=>h.object.rowid));return{items:(typeof o=="string"?ie(u,c,{text:o,grep:!0}).filter(h=>p.has(h.object.rowid)):f).filter(h=>(!i||h.object.type===i)&&(r.kind===void 0||h.object.kind===r.kind)&&(!a||h.object.owner===a.rowid)).slice(0,s).map(h=>({object:de(u,h.object),...h.line!==void 0?{matches:[{line:h.line,text:h.text??""}]}:{}}))}})}l(tt,"search");const ke=["interrupt","steer","after-turn","next-turn"],nt=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function rt(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(r=>typeof r!="string"||!nt.test(r)||r.includes(">")&&!r.endsWith(">"))){t.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}l(rt,"patternsOf");function ot(e,t){if(e===void 0)return;if(!R(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const r=[];for(const[n,o]of Object.entries(e)){const i=Number(n);!Number.isInteger(i)||i<1||i>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):ke.includes(o)?r.push({threshold:i,delivery:o}):t.push({field:`config.${n}`,problem:`delivery must be one of ${ke.join(", ")}`,received:o})}return r.sort((n,o)=>o.threshold-n.threshold)}l(ot,"configOf");function ve(e){const t=pe(e);if(t!==null)throw new y(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}l(ve,"refuseStubWatch");function X(e,t){const r=L(e,t)??(()=>{const n=Ae(e,Se(e,{class:"person"},()=>[]),t);return"object"in n?n.object:null})();return r===null||r.deleted_at!==null||!(r.type.includes(".")||r.type==="node")?null:r}l(X,"findWatcher");const O=l(()=>{throw new y(404,"not_found","watcher not found")},"watcherNotFound");async function Oe(e,t,r){if(typeof t!="string"||r===void 0||r===null)return null;if(typeof r!="string")throw new y(400,"invalid_request","invalid watcher_machine");if(X(e,t)!==null)return null;const n=F.current;let o;try{o=await n.machines()}catch{throw new y(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const i=I(r);return(i===n.self()||!o.some(s=>I(s.machine_id)===i))&&O(),i}l(Oe,"remoteWatcherMachine");function Ee(e,t,r,n){if(t.publishToken||t.principal.class==="anonymous")return O();const o=v(e,t);if(o.class==="person")return O();let i;try{i=q(e,o,n)}catch{return O()}const s=i.owner===null?null:fe(e,i.owner);return s===null||!ne(e,o,s)||!Fe(e,o,"link",r)?O():(M(e,t,r),{actor:o.app,object:i})}l(Ee,"linkWatcher");function qe(e,t,r){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!r.type.includes("."))return!1;const n=v(e,t),o=r.owner===null?null:fe(e,r.owner);return o!==null&&ne(e,n,o)&&Ne(e,n,r)}l(qe,"ownsWatcher");async function it(e){const t=k(e),r=R(e.body)?e.body:{};if(typeof r.watcher=="string"&&ve(t),typeof r.watcher!="string"){const o=await Z(e,t,{method:"POST",path:`${J(t)}/watch`,body:e.body});if(o.kind==="unknown")throw le(t,o.unreachable);if(o.kind==="remote"){if(o.status>=400)throw C(o.status,o.body);const i=o.body.patterns;return we(e,o.body,o.machine.id,"ask",i),B(o.body,o.machine)}}const n=await Oe(T(),r.watcher,r.watcher_machine);return st(e,n)}l(it,"watch");function st(e,t=null){const r=[],n=e.body===void 0?{}:R(e.body)?e.body:(r.push({field:"body",problem:"must be an object"}),{}),o=rt(n.patterns,r),i=ot(n.config,r);return n.filter!==void 0&&!R(n.filter)&&r.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&r.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&r.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),r.length>0&&P("watch request",r),_(s=>{const u=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!u)throw new y(404,"not_found","watcher not found");const c=o??[">"],a={patterns:c,...i?{config:i}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(u){const j=n.watcher,h=t===null?null:ut(s,e,j,t),w=h??(e.publishToken?re(s,j):X(s,j));if(w===null)return O();if(h===null&&qe(s,e,w)){const E=oe(s,e,w);M(s,e,w);const x=D(s,w),N=q(s,x,k(e));if(!te(s,x,N))throw new y(404,"not_found","object not found");return W(s,w,N,"act",a),G(s,{event:"watched",object:N,actor:E,attrs:{}},S(s)),{object:$(s,N,g(s,N)),patterns:c}}const{actor:d,object:m}=Ee(s,e,w,k(e));return W(s,w,m,"act",{...a,linkApp:d}),G(s,{event:"watched",object:m,actor:d,attrs:{}},S(s)),{object:$(s,m,g(s,m)),patterns:c}}const f=v(s,e),p=U(s,e)??ee(f),b=q(s,f,k(e));return W(s,p,b,"ask",a),G(s,{event:"watched",object:b,actor:p,attrs:{}},S(s)),{object:$(s,b,g(s,b)),patterns:c}})}l(st,"watchLocal");function ut(e,t,r,n){return t.publishToken||t.principal.class==="anonymous"?O():Ve(e,r,n)}l(ut,"ensureNodeStubFor");function Te(e,t,r,n){const o=l(()=>$e(e,`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
3
- WHERE w.watcher = ? AND w.object = ?`).get(t.rowid,r.rowid).n,"count"),i=o();return Me(e,t,r,n??void 0),{object:g(e,r),removed:i-o()}}l(Te,"dropWatch");async function at(e){const t=k(e);if(e.query.get("watcher")&&ve(t),!e.query.get("watcher")){const n=await Z(e,t,{method:"DELETE",path:`${J(t)}/watch`,query:V(e)});if(n.kind==="unknown")throw le(t,n.unreachable);if(n.kind==="remote"){const o=n.status===404?n.body.error?.details:void 0,i=o?.deleted===!0?o.id:void 0;if(n.status>=400&&i===void 0)throw C(n.status,n.body);const s=i??n.body.object?.id,u=_(c=>{const a=ue(c,e),f=s===void 0?null:L(c,s);return a===null||f===null||!K(c,f)?null:Te(c,a,f,e.query.get("pattern"))});if(i!==void 0){if(u===null)throw C(n.status,n.body);return{...u,machine:n.machine}}return B(n.body,n.machine)}}const r=await Oe(T(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return ct(e,r)}l(at,"unwatchRoute");function ct(e,t=null){const r=e.query.get("pattern"),n=e.query.get("watcher");return _(o=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new y(404,"not_found","watcher not found");const i=l((c,a)=>Te(o,c,a,r),"drop");if(n){const c=t===null?null:(()=>{const f=L(o,n);return f!==null&&Be(o,f)!==null?f:null})();if(t!==null&&c===null)return O();const a=c??(e.publishToken?re(o,n):X(o,n));return a===null?O():c===null&&qe(o,e,a)?(oe(o,e,a),M(o,e,a),i(a,q(o,D(o,a),k(e)))):i(a,Ee(o,e,a,k(e)).object)}const s=v(o,e),u=U(o,e)??ee(s);return i(u,q(o,s,k(e)))})}l(ct,"unwatchLocal");function lt(e){const t=[],r=Q(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Q(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&P("edges request",t),_(o=>{const i=v(o,e),s=q(o,i,k(e)),u=[];if(r!=="watches")for(const c of Le(o,i,s,{...r?{type:r}:{},direction:n??"both"}))u.push({type:c.type,src:g(o,c.src),dst:g(o,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(r===void 0||r==="watches"){const c=[...n!=="in"?ze(o,i,s):[],...n!=="out"?Ge(o,i,s):[]];for(const a of c)u.push({type:"watches",src:g(o,a.watcher),dst:g(o,a.object)})}return{items:u}})}l(lt,"edges");const A=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Wt=[{method:"POST",pattern:"/v1/objects/search",handler:A(tt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:A(lt)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:A(it)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:A(at)},{method:"GET",pattern:"/v1/objects/:ref",handler:A(Qe)},{method:"GET",pattern:"/v1/objects",handler:A(et)}];export{Ye as listBudget,Wt as objectRoutes};
1
+ var Te=Object.defineProperty;var l=(e,t)=>Te(e,"name",{value:t,configurable:!0});import{prepared as $e}from"../../../core/sqlite-statements.js";import{ApiError as p}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as Ie}from"../../../api/dto/objects.js";import{openDb as R,withCanvasWrite as _}from"../../../core/canvas/db.js";import{actorOf as ee}from"../../../core/graph/documents.js";import{readerForObject as D,readerFor as Se}from"../../../core/graph/reader.js";import{resolveName as Ne,stubsNamed as Ae}from"../../../core/graph/names.js";import{canRead as te,customReachable as Fe,holdsObjectsScope as Le,mayActAs as ne}from"../../../core/graph/access.js";import{customObjectRef as re,authorizeCustom as oe,fenceArgv as M}from"./custom-objects.js";import{edgesOf as We}from"../../../core/graph/edges.js";import{publish as G}from"../../../core/graph/events.js";import{objectDTO as b}from"../../../core/graph/kinds/dto.js";import{isKind as Pe,kindNames as Ce,kindOf as z}from"../../../core/graph/kinds/registry.js";import{listObjects as De,searchObjects as ie}from"../../../core/graph/objects.js";import{checkoutsForCwd as Me}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as W,unwatch as Ge,watchersOf as ze,watchesOf as He}from"../../../core/graph/watches.js";import{readerFor as v,resolveRef as H}from"../reader.js";import{readDelegationFor as se,runReadLeaf as Ue}from"../../plugin-objects/read-leaf.js";import{invalidRequest as P,isRecord as T}from"./validate.js";import{callerNode as ue,callerStub as U,forwardVerb as ae,originates as ce,queryWithoutMachine as V,relayError as C,remoteStub as Ve,unknownError as le,forwarding as F,withMachine as B}from"../../peer/forward.js";import{getById as L,getByRowid as fe}from"../../../core/graph/objects.js";import{ensureNodeStub as Be,isStub as K,stubOf as Ke,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as Ze}from"../../../core/peer/client.js";import{normalizeMachineId as I}from"../../../core/peer/directory.js";const S=l(e=>t=>Me(e,t),"reposFnFor");function de(e,t){return{...b(e,t),...z(e,t.type).listItem?.(e,t)}}l(de,"listItem");function Je(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Je,"remoteMessage");function me(e,t,r){try{return q(e,t,r)}catch(n){if(n instanceof p&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(me,"ownerFilter");function q(e,t,r){const n=H(e,t,r);if("remote"in n)throw new p(404,"not_found",Je(n.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new p(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});return n}l(q,"liveRef");const k=l(e=>decodeURIComponent(e.params.ref),"refParam"),he=l(e=>{const t=e.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),r=t.indexOf("/");return r>0?t.slice(0,r):t},"idOf");function pe(e){const t=L(R(),he(e));return t!==null&&K(R(),t)?t.id:null}l(pe,"stubIdOf");function Qe(e,t){const r=pe(e);return r!==null?{stub:r,hit:!0}:_(n=>{try{const o=v(n,t),i=l(()=>{const u=Ae(n,o,e);if(u.length>1)throw new p(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:u.map(c=>c.id),next:"Read one by its object id."});return{stub:u[0]?.id??null,hit:!1}},"named");let s;try{s=H(n,o,e)}catch(u){if(u instanceof p&&u.code==="not_found")return i();throw u}if("remote"in s)return i();if("deleted"in s){const u=i();return u.stub===null?{stub:null,hit:!0}:u}return{stub:K(n,s)?s.id:null,hit:!0}}catch(o){if(o instanceof p&&o.code==="ambiguous_name")throw o;return{stub:null,hit:!1}}})}l(Qe,"resolvedLocally");async function Z(e,t,r){const n=Qe(t,e);return n.stub!==null?ae(e,n.stub,r):n.hit||!ce(e.principal)?{kind:"local"}:ae(e,he(t),r)}l(Z,"forwardRef");const J=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");function we(e,t,r,n,o){const i=t?.object;!i?.id||!i.type||_(s=>{const u=ue(s,e);if(u===null)return;const c=Ve(s,i.id,i.type,r,{kind:i.kind??null,name:i.name??i.id,...i.preview===void 0?{}:{preview:i.preview},owner:i.owner??null,...i.kind_decl===void 0?{}:{kind_decl:i.kind_decl},...i.privacy===void 0?{}:{privacy:i.privacy}});W(s,u,c,n,o===void 0?{}:{patterns:o})})}l(we,"watchRemote");async function Ye(e){const t=k(e),r=["1","true"].includes(e.query.get("fields")??""),n=await Z(e,t,{method:"GET",path:J(t),query:V(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw C(n.status,n.body);return we(e,n.body,n.machine.id,"read"),B(n.body,n.machine)}const o=l(u=>{const c=U(u,e);return c===null?v(u,e):D(u,c,S(u))},"readerOf"),i=_(u=>{const c=o(u),a=H(u,c,t);if("remote"in a)return{state:"remote",remote:a.remote};if("deleted"in a)return{state:"deleted",deleted:b(u,a.deleted)};const f=se(u,a);if(f!==null)return{delegate:f,hitId:a.id};const{data:w,text:g}=z(u,a.type).read(u,c,a,{fields:r,reposFn:S(u)});return{state:"object",type:a.type,object:$(u,a,b(u,a)),text:g,data:w}});if(!("delegate"in i))return i;const s=await Ue(i.delegate,e.principal);return _(u=>{const c=o(u),a=L(u,i.hitId);if(a===null)throw new p(404,"not_found","object not found");if(a.deleted_at!==null)return{state:"deleted",deleted:b(u,a)};if(!te(u,c,a))throw new p(404,"not_found","object not found");const{data:f,text:w}=z(u,a.type).read(u,c,a,{fields:r,reposFn:S(u)});return se(u,a)===null?{state:"object",type:a.type,object:$(u,a,b(u,a)),text:w,data:f}:{state:"object",type:a.type,object:$(u,a,b(u,a)),text:"markdown"in s?s.markdown:`${w}
2
+ content unavailable: ${s.unavailable}`,data:{...f,content:"markdown"in s?"live":"unavailable"}}})}l(Ye,"read");function Q(e,t,r,n){if(e!=null){if(!r.includes(e)){n.push({field:t,problem:`must be one of ${r.join(", ")}`,received:e});return}return e}}l(Q,"oneOf");function ye(e,t,r){if(t!=null){if(typeof t!="string"||!Pe(e,t)){r.push({field:"type",problem:`must be a kind: one of ${Ce(e).join(", ")}`,received:t});return}return t}}l(ye,"kindName");function be(e,t,r,n){if(e==null)return n;const o=Number(e);return!Number.isInteger(o)||o<1||o>100?(r.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):o}l(be,"limitOf");function ge(e){const t=e.query,r=[],n=ye(R(),t.get("type"),r),o=Q(t.get("privacy"),"privacy",Ie,r),i=be(t.get("limit"),"limit",r,50),s=t.get("cursor");s!==null&&!/^\d+$/.test(s)&&r.push({field:"cursor",problem:"is not a cursor from a previous page",received:s});const u=t.get("deleted");return u!==null&&!["0","1","true","false"].includes(u)&&r.push({field:"deleted",problem:"must be true or false",received:u}),r.length>0&&P("object list request",r),_(c=>{const a=v(c,e),f={...n?{type:n}:{},...o?{privacy:o}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...u==="1"||u==="true"?{deleted:!0}:{}},w=t.get("owner");if(w!==null){const m=me(c,a,w);if(m===null)return{items:[],next_cursor:null};f.owner=m}const g=t.get("name"),j=[];let h=s===null?0:Number(s),y=!0;for(;j.length<i&&y;){const m=De(c,a,f,{limit:100,after_rowid:h});y=m.length===100;for(const E of m)if(h=E.rowid,(g===null||E.name.startsWith(g))&&j.push(E),j.length===i)break}const d=j.at(-1);return{items:j.map(m=>de(c,m)),next_cursor:j.length===i&&d?String(d.rowid):null}})}l(ge,"listLocal");const Xe={ms:3e4},xe="self",Y=l((e,t)=>e.map(r=>({...r,machine:t})),"labelItems");async function je(e,t,r,n){const o=F.current;try{const i=await o.call(t.id,{method:"GET",path:"/v1/objects",query:r},o.envelope(e.principal),n);if(Ze(i))return{state:"unreachable",items:[],next:null};if(i.status===426)return{state:"too_old",items:[],next:null};const s=i.body;return i.status!==200||!Array.isArray(s?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:Y(s.items,t),next:s.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(je,"remotePage");async function et(e){const t=new Promise(r=>e.addEventListener("abort",()=>r(null),{once:!0}));return Promise.race([F.current.machines().catch(()=>null),t])}l(et,"machinesWithin");async function tt(e){const t=e.query.get("machine");if(!ce(e.principal)||!F.current.joined()||t===xe)return ge(_e(e));const n=F.current.self(),o=t!==null&&I(t)!==n,i=o?null:ge(_e(e)),s=new AbortController,u=setTimeout(()=>s.abort(),Xe.ms);u.unref?.();try{const c=await et(s.signal);if(c===null){if(o)throw new p(503,"runtime_unreachable",`The directory did not answer, so ${I(t)} cannot be listed.`,{machine:I(t)});return i}const a=l(d=>({id:d,name:c.find(m=>m.machine_id===d)?.name??d}),"labelOf"),f=a(n),w=c.filter(d=>d.machine_id!==n&&d.kind!=="device"),g=V(e);if(t!==null){if(!o)return{items:Y(i.items,f),next_cursor:i.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:i.next_cursor!==null}]};const d=I(t);if(!w.some(E=>E.machine_id===d))throw new p(404,"not_found",`no machine ${d} on your account`,{machine:d});const m=await je(e,a(d),g,s.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:d,name:a(d).name,state:m.state,more:m.next!==null}]}}const{cursor:j,...h}=g,y=await Promise.all(w.map(d=>je(e,a(d.machine_id),h,s.signal)));return{items:[...Y(i.items,f),...y.flatMap(d=>d.items)],next_cursor:i.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:i.next_cursor!==null},...w.map((d,m)=>({machine_id:d.machine_id,name:d.name,state:y[m].state,more:y[m].next!==null}))]}}finally{clearTimeout(u)}}l(tt,"list");function _e(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(_e,"withoutMachine");function nt(e){const t=[],r=T(e.body)?e.body:{};T(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=r.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const o=r.grep;if(o!==void 0)if(typeof o!="string")t.push({field:"grep",problem:"must be a regular expression string",received:o});else try{new RegExp(o)}catch(u){t.push({field:"grep",problem:`is not a valid regular expression: ${u.message}`,received:o})}r.body!==void 0&&typeof r.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:r.body});const i=ye(R(),r.type,t);r.kind!==void 0&&typeof r.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:r.kind}),r.owner!==void 0&&typeof r.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:r.owner});const s=be(r.limit,"limit",t,50);return t.length>0&&P("object search request",t),_(u=>{const c=v(u,e),a=typeof r.owner=="string"?me(u,c,r.owner):null;if(typeof r.owner=="string"&&a===null)return{items:[]};const f=ie(u,c,{text:n,body:r.body===!0||typeof o=="string"}),w=new Set(f.map(h=>h.object.rowid));return{items:(typeof o=="string"?ie(u,c,{text:o,grep:!0}).filter(h=>w.has(h.object.rowid)):f).filter(h=>(!i||h.object.type===i)&&(r.kind===void 0||h.object.kind===r.kind)&&(!a||h.object.owner===a.rowid)).slice(0,s).map(h=>({object:de(u,h.object),...h.line!==void 0?{matches:[{line:h.line,text:h.text??""}]}:{}}))}})}l(nt,"search");const ke=["interrupt","steer","after-turn","next-turn"],rt=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function ot(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(r=>typeof r!="string"||!rt.test(r)||r.includes(">")&&!r.endsWith(">"))){t.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}l(ot,"patternsOf");function it(e,t){if(e===void 0)return;if(!T(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const r=[];for(const[n,o]of Object.entries(e)){const i=Number(n);!Number.isInteger(i)||i<1||i>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):ke.includes(o)?r.push({threshold:i,delivery:o}):t.push({field:`config.${n}`,problem:`delivery must be one of ${ke.join(", ")}`,received:o})}return r.sort((n,o)=>o.threshold-n.threshold)}l(it,"configOf");function ve(e){const t=pe(e);if(t!==null)throw new p(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}l(ve,"refuseStubWatch");function X(e,t){const r=L(e,t)??(()=>{const n=Ne(e,Se(e,{class:"person"},()=>[]),t);return"object"in n?n.object:null})();return r===null||r.deleted_at!==null||!(r.type.includes(".")||r.type==="node")?null:r}l(X,"findWatcher");const O=l(()=>{throw new p(404,"not_found","watcher not found")},"watcherNotFound");async function Oe(e,t,r){if(typeof t!="string"||r===void 0||r===null)return null;if(typeof r!="string")throw new p(400,"invalid_request","invalid watcher_machine");if(X(e,t)!==null)return null;const n=F.current;let o;try{o=await n.machines()}catch{throw new p(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const i=I(r);return(i===n.self()||!o.some(s=>I(s.machine_id)===i))&&O(),i}l(Oe,"remoteWatcherMachine");function Ee(e,t,r,n){if(t.publishToken||t.principal.class==="anonymous")return O();const o=v(e,t);if(o.class==="person")return O();let i;try{i=q(e,o,n)}catch{return O()}const s=i.owner===null?null:fe(e,i.owner);return s===null||!ne(e,o,s)||!Le(e,o,"link",r)?O():(M(e,t,r),{actor:o.app,object:i})}l(Ee,"linkWatcher");function qe(e,t,r){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!r.type.includes("."))return!1;const n=v(e,t),o=r.owner===null?null:fe(e,r.owner);return o!==null&&ne(e,n,o)&&Fe(e,n,r)}l(qe,"ownsWatcher");async function st(e){const t=k(e),r=T(e.body)?e.body:{};if(typeof r.watcher=="string"&&ve(t),typeof r.watcher!="string"){const o=await Z(e,t,{method:"POST",path:`${J(t)}/watch`,body:e.body});if(o.kind==="unknown")throw le(t,o.unreachable);if(o.kind==="remote"){if(o.status>=400)throw C(o.status,o.body);const i=o.body.patterns;return we(e,o.body,o.machine.id,"ask",i),B(o.body,o.machine)}}const n=await Oe(R(),r.watcher,r.watcher_machine);return ut(e,n)}l(st,"watch");function ut(e,t=null){const r=[],n=e.body===void 0?{}:T(e.body)?e.body:(r.push({field:"body",problem:"must be an object"}),{}),o=ot(n.patterns,r),i=it(n.config,r);return n.filter!==void 0&&!T(n.filter)&&r.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&r.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&r.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),r.length>0&&P("watch request",r),_(s=>{const u=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!u)throw new p(404,"not_found","watcher not found");const c=o??[">"],a={patterns:c,...i?{config:i}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(u){const j=n.watcher,h=t===null?null:at(s,e,j,t),y=h??(e.publishToken?re(s,j):X(s,j));if(y===null)return O();if(h===null&&qe(s,e,y)){const E=oe(s,e,y);M(s,e,y);const x=D(s,y),A=q(s,x,k(e));if(!te(s,x,A))throw new p(404,"not_found","object not found");return W(s,y,A,"act",a),G(s,{event:"watched",object:A,actor:E,attrs:{}},S(s)),{object:$(s,A,b(s,A)),patterns:c}}const{actor:d,object:m}=Ee(s,e,y,k(e));return W(s,y,m,"act",{...a,linkApp:d}),G(s,{event:"watched",object:m,actor:d,attrs:{}},S(s)),{object:$(s,m,b(s,m)),patterns:c}}const f=v(s,e),w=U(s,e)??ee(f),g=q(s,f,k(e));return W(s,w,g,"ask",a),G(s,{event:"watched",object:g,actor:w,attrs:{}},S(s)),{object:$(s,g,b(s,g)),patterns:c}})}l(ut,"watchLocal");function at(e,t,r,n){return t.publishToken||t.principal.class==="anonymous"?O():Be(e,r,n)}l(at,"ensureNodeStubFor");function Re(e,t,r,n){const o=l(()=>$e(e,`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
3
+ WHERE w.watcher = ? AND w.object = ?`).get(t.rowid,r.rowid).n,"count"),i=o();return Ge(e,t,r,n??void 0),{object:b(e,r),removed:i-o()}}l(Re,"dropWatch");async function ct(e){const t=k(e);if(e.query.get("watcher")&&ve(t),!e.query.get("watcher")){const n=await Z(e,t,{method:"DELETE",path:`${J(t)}/watch`,query:V(e)});if(n.kind==="unknown")throw le(t,n.unreachable);if(n.kind==="remote"){const o=n.status===404?n.body.error?.details:void 0,i=o?.deleted===!0?o.id:void 0;if(n.status>=400&&i===void 0)throw C(n.status,n.body);const s=i??n.body.object?.id,u=_(c=>{const a=ue(c,e),f=s===void 0?null:L(c,s);return a===null||f===null||!K(c,f)?null:Re(c,a,f,e.query.get("pattern"))});if(i!==void 0){if(u===null)throw C(n.status,n.body);return{...u,machine:n.machine}}return B(n.body,n.machine)}}const r=await Oe(R(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return lt(e,r)}l(ct,"unwatchRoute");function lt(e,t=null){const r=e.query.get("pattern"),n=e.query.get("watcher");return _(o=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new p(404,"not_found","watcher not found");const i=l((c,a)=>Re(o,c,a,r),"drop");if(n){const c=t===null?null:(()=>{const f=L(o,n);return f!==null&&Ke(o,f)!==null?f:null})();if(t!==null&&c===null)return O();const a=c??(e.publishToken?re(o,n):X(o,n));return a===null?O():c===null&&qe(o,e,a)?(oe(o,e,a),M(o,e,a),i(a,q(o,D(o,a),k(e)))):i(a,Ee(o,e,a,k(e)).object)}const s=v(o,e),u=U(o,e)??ee(s);return i(u,q(o,s,k(e)))})}l(lt,"unwatchLocal");function ft(e){const t=[],r=Q(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Q(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&P("edges request",t),_(o=>{const i=v(o,e),s=q(o,i,k(e)),u=[];if(r!=="watches")for(const c of We(o,i,s,{...r?{type:r}:{},direction:n??"both"}))u.push({type:c.type,src:b(o,c.src),dst:b(o,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(r===void 0||r==="watches"){const c=[...n!=="in"?He(o,i,s):[],...n!=="out"?ze(o,i,s):[]];for(const a of c)u.push({type:"watches",src:b(o,a.watcher),dst:b(o,a.object)})}return{items:u}})}l(ft,"edges");const N=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Pt=[{method:"POST",pattern:"/v1/objects/search",handler:N(nt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:N(ft)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:N(st)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:N(ct)},{method:"GET",pattern:"/v1/objects/:ref",handler:N(Ye)},{method:"GET",pattern:"/v1/objects",handler:N(tt)}];export{Xe as listBudget,Pt as objectRoutes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.506",
3
+ "version": "0.3.507",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  "license": "UNLICENSED",
140
140
  "dependencies": {
141
- "@north-light/identity": "0.3.506",
141
+ "@north-light/identity": "0.3.507",
142
142
  "@earendil-works/pi-agent-core": "1.1.0",
143
143
  "@earendil-works/pi-ai": "1.1.0",
144
144
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.506",
3
+ "version": "0.3.507",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.506",
3
+ "version": "0.3.507",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.506",
9
+ "version": "0.3.507",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "1.1.0",
19
19
  "@earendil-works/pi-coding-agent": "1.1.0",
20
20
  "@earendil-works/pi-tui": "1.1.0",
21
- "@north-light/identity": "0.3.506",
21
+ "@north-light/identity": "0.3.507",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12116,17 +12116,17 @@
12116
12116
  },
12117
12117
  "packages/crouter-api": {
12118
12118
  "name": "@north-light/api",
12119
- "version": "0.3.506",
12119
+ "version": "0.3.507",
12120
12120
  "license": "UNLICENSED"
12121
12121
  },
12122
12122
  "packages/crouter-env-docker": {
12123
12123
  "name": "@north-light/env-docker",
12124
- "version": "0.3.506",
12124
+ "version": "0.3.507",
12125
12125
  "license": "UNLICENSED"
12126
12126
  },
12127
12127
  "packages/crouter-identity": {
12128
12128
  "name": "@north-light/identity",
12129
- "version": "0.3.506",
12129
+ "version": "0.3.507",
12130
12130
  "license": "UNLICENSED",
12131
12131
  "dependencies": {
12132
12132
  "jose": "^6.2.1"
@@ -12134,20 +12134,20 @@
12134
12134
  },
12135
12135
  "packages/crouter-plugin": {
12136
12136
  "name": "@north-light/plugin",
12137
- "version": "0.3.506",
12137
+ "version": "0.3.507",
12138
12138
  "license": "UNLICENSED",
12139
12139
  "dependencies": {
12140
- "@north-light/api": "0.3.506",
12141
- "@north-light/identity": "0.3.506"
12140
+ "@north-light/api": "0.3.507",
12141
+ "@north-light/identity": "0.3.507"
12142
12142
  }
12143
12143
  },
12144
12144
  "packages/crouter-sdk": {
12145
12145
  "name": "@north-light/sdk",
12146
- "version": "0.3.506",
12146
+ "version": "0.3.507",
12147
12147
  "license": "UNLICENSED",
12148
12148
  "dependencies": {
12149
- "@north-light/api": "0.3.506",
12150
- "@north-light/identity": "0.3.506",
12149
+ "@north-light/api": "0.3.507",
12150
+ "@north-light/identity": "0.3.507",
12151
12151
  "jose": "^6.2.1"
12152
12152
  },
12153
12153
  "bin": {