@north-light/cli 0.3.534 → 0.3.536

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/api/client.d.ts +3 -0
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/nodes.d.ts +2 -0
  6. package/dist/api/dto/recovery.d.ts +2 -1
  7. package/dist/builtin-memory/crouter-sdk/release-notes.md +1 -1
  8. package/dist/clients/attach/viewer.js +406 -406
  9. package/dist/commands/api-client.d.ts +1 -0
  10. package/dist/commands/api-client.js +3 -3
  11. package/dist/commands/node/inspect.js +9 -9
  12. package/dist/core/bash-jobs.d.ts +4 -0
  13. package/dist/core/bash-jobs.js +8 -8
  14. package/dist/core/canvas/canvas.d.ts +26 -2
  15. package/dist/core/canvas/canvas.js +19 -19
  16. package/dist/core/canvas/crons.d.ts +4 -2
  17. package/dist/core/canvas/crons.js +1 -1
  18. package/dist/core/canvas/paths.d.ts +5 -0
  19. package/dist/core/canvas/paths.js +1 -1
  20. package/dist/core/canvas/recovery.d.ts +7 -0
  21. package/dist/core/canvas/recovery.js +2 -2
  22. package/dist/core/canvas/remote-canvas-source.d.ts +1 -0
  23. package/dist/core/canvas/remote-canvas-source.js +1 -1
  24. package/dist/core/canvas/source.d.ts +4 -0
  25. package/dist/core/canvas/source.js +1 -1
  26. package/dist/core/canvas/tree.d.ts +2 -0
  27. package/dist/core/canvas/tree.js +12 -5
  28. package/dist/core/feed/feed.js +3 -3
  29. package/dist/core/feed/messages.d.ts +6 -0
  30. package/dist/core/feed/messages.js +5 -5
  31. package/dist/core/graph/kinds/node.js +5 -5
  32. package/dist/core/graph/watches.d.ts +0 -2
  33. package/dist/core/graph/watches.js +7 -12
  34. package/dist/core/providers/mint.d.ts +2 -0
  35. package/dist/core/providers/mint.js +1 -1
  36. package/dist/core/runtime/broker/cli-relay.js +1 -1
  37. package/dist/core/runtime/broker/fault-retry.d.ts +18 -0
  38. package/dist/core/runtime/broker/fault-retry.js +1 -1
  39. package/dist/core/runtime/broker/run-turn-end.d.ts +3 -2
  40. package/dist/core/runtime/broker/run-turn-end.js +1 -1
  41. package/dist/core/runtime/launch.js +2 -2
  42. package/dist/core/runtime/lifecycle.d.ts +4 -0
  43. package/dist/core/runtime/lifecycle.js +2 -2
  44. package/dist/core/runtime/nodes.js +1 -1
  45. package/dist/core/runtime/revive.d.ts +1 -1
  46. package/dist/core/runtime/revive.js +1 -1
  47. package/dist/core/worktree-mutation-async.d.ts +10 -0
  48. package/dist/core/worktree-mutation-async.js +5 -5
  49. package/dist/core/worktree-sweep.js +6 -6
  50. package/dist/core/worktree.d.ts +1 -0
  51. package/dist/core/worktree.js +1 -1
  52. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  53. package/dist/daemon/api/handlers/messages.js +2 -2
  54. package/dist/daemon/api/handlers/nodes.js +1 -1
  55. package/dist/daemon/api/handlers/objects.js +3 -3
  56. package/dist/daemon/messaging/node-message.js +1 -1
  57. package/dist/daemon/peer/forward.js +1 -1
  58. package/dist/daemon/reconcilers/bash-deadline.d.ts +6 -0
  59. package/dist/daemon/reconcilers/bash-deadline.js +3 -2
  60. package/dist/daemon/runs/observer.d.ts +2 -0
  61. package/dist/daemon/runs/observer.js +2 -2
  62. package/docs/sdk/release-notes.md +1 -1
  63. package/package.json +2 -2
  64. package/packages/crouter-identity/package.json +1 -1
  65. package/runtime.lock.json +12 -12
  66. package/dist/core/canvas/nav-model.d.ts +0 -44
  67. package/dist/core/canvas/nav-model.js +0 -1
@@ -1,3 +1,3 @@
1
- var Ne=Object.defineProperty;var l=(e,t)=>Ne(e,"name",{value:t,configurable:!0});import{ApiError as y}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as $e}from"../../../api/dto/objects.js";import{openDb as I,withCanvasWrite as _}from"../../../core/canvas/db.js";import{actorOf as te}from"../../../core/graph/documents.js";import{readerForObject as U,readerFor as Ae}from"../../../core/graph/reader.js";import{resolveName as Fe,stubsNamed as Se,unwrapRef as ne}from"../../../core/graph/names.js";import{canRead as ae,customReachable as We,holdsObjectsScope as Le,mayActAs as ie}from"../../../core/graph/access.js";import{customObjectRef as re,authorizeCustom as oe,fenceArgv as z}from"./custom-objects.js";import{edgesOf as Pe}from"../../../core/graph/edges.js";import{publish as H}from"../../../core/graph/events.js";import{objectDTO as g}from"../../../core/graph/kinds/dto.js";import{isKind as Ce,kindNames as De,kindOf as V}from"../../../core/graph/kinds/registry.js";import{listObjects as Me,searchObjects as se}from"../../../core/graph/objects.js";import{checkoutsForCwd as Ge}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as L,unwatch as Ue,watchersOf as ze,watchesOf as He}from"../../../core/graph/watches.js";import{armObjectWaitForWatch as P,settleObjectWaitForUnwatch as Ve}from"../../../core/graph/object-waits.js";import{readerFor as v,resolveRef as B}from"../reader.js";import{readDelegationFor as ue,runReadLeaf as Be}from"../../plugin-objects/read-leaf.js";import{invalidRequest as C,isRecord as N}from"./validate.js";import{callerNode as ce,callerStub as K,forwardNamed as Ke,forwardVerb as le,originates as fe,queryWithoutMachine as D,relayError as M,remoteStub as Ze,unknownError as de,forwarding as W,withMachine as Z}from"../../peer/forward.js";import{getById as E}from"../../../core/graph/objects.js";import{ensureNodeStub as Je,isStub as J,stubOf as Qe,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as Ye}from"../../../core/peer/client.js";import{normalizeMachineId as A}from"../../../core/peer/directory.js";import{mapAsync as we}from"../../../core/async-array.js";const F=l(async e=>async t=>await Ge(e,t),"reposFnFor");async function me(e,t){return{...await g(e,t),...await(await V(e,t.type)).listItem?.(e,t)}}l(me,"listItem");function Xe(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Xe,"remoteMessage");async function he(e,t,a){try{return await T(e,t,a)}catch(n){if(n instanceof y&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(he,"ownerFilter");async function T(e,t,a){const n=await B(e,t,a);if("remote"in n)throw new y(404,"not_found",Xe(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(T,"liveRef");const k=l(e=>decodeURIComponent(e.params.ref),"refParam"),pe=l(e=>{const t=ne(e),a=t.indexOf("/");return a>0?t.slice(0,a):t},"idOf");async function ye(e){const t=await E(await I(),pe(e));return t!==null&&await J(await I(),t)?t.id:null}l(ye,"stubIdOf");async function xe(e,t){const a=await ye(e);return a!==null?{stub:a,hit:!0}:await _(async n=>{try{const i=await v(n,t),o=l(async()=>{const s=await Se(n,i,e);if(s.length>1)throw new y(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:s.map(c=>c.id),next:"Read one by its object id."});return{stub:s[0]?.id??null,hit:!1}},"named");let r;try{r=await B(n,i,e)}catch(s){if(s instanceof y&&s.code==="not_found")return await o();throw s}if("remote"in r)return await o();if("deleted"in r){const s=await o();return s.stub===null?{stub:null,hit:!0}:s}return{stub:await J(n,r)?r.id:null,hit:!0}}catch(i){if(i instanceof y&&i.code==="ambiguous_name")throw i;return{stub:null,hit:!1}}})}l(xe,"resolvedLocally");async function Q(e,t,a){const n=await xe(t,e);if(n.stub!==null)return le(e,n.stub,a);if(n.hit||!fe(e.principal))return{kind:"local"};const i=await le(e,pe(t),a);return i.kind==="local"&&ne(t).includes("/")?Ke(e,a,{method:"GET",path:G(t),query:D(e)}):i}l(Q,"forwardRef");const G=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");async function be(e,t,a,n,i){const o=t?.object;!o?.id||!o.type||await _(async r=>{const s=await ce(r,e);if(s===null)return;const c=await Ze(r,o.id,o.type,a,{kind:o.kind??null,name:o.name??o.id,...o.preview===void 0?{}:{preview:o.preview},owner:o.owner??null,...o.kind_decl===void 0?{}:{kind_decl:o.kind_decl},...o.privacy===void 0?{}:{privacy:o.privacy}});await L(r,s,c,n,i===void 0?{}:{patterns:i}),n==="ask"&&await P(r,s,c)})}l(be,"watchRemote");async function et(e){const t=k(e),a=["1","true"].includes(e.query.get("fields")??""),n=await Q(e,t,{method:"GET",path:G(t),query:D(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw M(n.status,n.body);return await be(e,n.body,n.machine.id,"read"),Z(n.body,n.machine)}const i=l(async s=>{const c=await K(s,e);return c===null?await v(s,e):await U(s,c,await F(s))},"readerOf"),o=await _(async s=>{const c=await i(s),u=await B(s,c,t);if("remote"in u)return{state:"remote",remote:u.remote};if("deleted"in u)return{state:"deleted",deleted:await g(s,u.deleted)};const f=await ue(s,u);if(f!==null)return{delegate:f,hitId:u.id};const{data:h,text:b}=await(await V(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:b,data:h}});if(!("delegate"in o))return o;const r=await Be(o.delegate,e.principal);return await _(async s=>{const c=await i(s),u=await E(s,o.hitId);if(u===null)throw new y(404,"not_found","object not found");if(u.deleted_at!==null)return{state:"deleted",deleted:await g(s,u)};if(!await ae(s,c,u))throw new y(404,"not_found","object not found");const{data:f,text:h}=await(await V(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return await ue(s,u)===null?{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:h,data:f}:{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:"markdown"in r?r.markdown:`${h}
2
- content unavailable: ${r.unavailable}`,data:{...f,content:"markdown"in r?"live":"unavailable"}}})}l(et,"read");function Y(e,t,a,n){if(e!=null){if(!a.includes(e)){n.push({field:t,problem:`must be one of ${a.join(", ")}`,received:e});return}return e}}l(Y,"oneOf");async function ge(e,t,a){if(t!=null){if(typeof t!="string"||!await Ce(e,t)){a.push({field:"type",problem:`must be a kind: one of ${(await De(e)).join(", ")}`,received:t});return}return t}}l(ge,"kindName");function je(e,t,a,n){if(e==null)return n;const i=Number(e);return!Number.isInteger(i)||i<1||i>100?(a.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):i}l(je,"limitOf");async function _e(e){const t=e.query,a=[],n=await ge(await I(),t.get("type"),a),i=Y(t.get("privacy"),"privacy",$e,a),o=je(t.get("limit"),"limit",a,50),r=t.get("cursor");r!==null&&!/^\d+$/.test(r)&&a.push({field:"cursor",problem:"is not a cursor from a previous page",received:r});const s=t.get("deleted");return s!==null&&!["0","1","true","false"].includes(s)&&a.push({field:"deleted",problem:"must be true or false",received:s}),a.length>0&&C("object list request",a),await _(async c=>{const u=await v(c,e),f={...n?{type:n}:{},...i?{privacy:i}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{}},h=t.get("owner");if(h!==null){const w=await he(c,u,h);if(w===null)return{items:[],next_cursor:null};f.owner=w}const b=t.get("name"),j=[];let m=r===null?0:Number(r),p=!0;for(;j.length<o&&p;){const w=await Me(c,u,f,{limit:100,after_seq:m});p=w.length===100;for(const q of w)if(m=q.seq,(b===null||q.name.startsWith(b))&&j.push(q),j.length===o)break}const d=j.at(-1);return{items:await we(j,async w=>await me(c,w)),next_cursor:j.length===o&&d?String(d.seq):null}})}l(_e,"listLocal");const tt={ms:3e4},nt="self",X=l((e,t)=>e.map(a=>({...a,machine:t})),"labelItems");async function ke(e,t,a,n){const i=W.current;try{const o=await i.call(t.id,{method:"GET",path:"/v1/objects",query:a},await i.envelope(e.principal),n);if(Ye(o))return{state:"unreachable",items:[],next:null};if(o.status===426)return{state:"too_old",items:[],next:null};const r=o.body;return o.status!==200||!Array.isArray(r?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:X(r.items,t),next:r.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(ke,"remotePage");async function at(e){const t=new Promise(a=>e.addEventListener("abort",()=>a(null),{once:!0}));return Promise.race([W.current.machines().catch(()=>null),t])}l(at,"machinesWithin");async function it(e){const t=e.query.get("machine");if(!fe(e.principal)||!W.current.joined()||t===nt)return await _e(ve(e));const n=W.current.self(),i=t!==null&&A(t)!==n,o=i?null:await _e(ve(e)),r=new AbortController,s=setTimeout(()=>r.abort(),tt.ms);s.unref?.();try{const c=await at(r.signal);if(c===null){if(i)throw new y(503,"runtime_unreachable",`The directory did not answer, so ${A(t)} cannot be listed.`,{machine:A(t)});return o}const u=l(d=>({id:d,name:c.find(w=>w.machine_id===d)?.name??d}),"labelOf"),f=u(n),h=c.filter(d=>d.machine_id!==n&&d.kind!=="device"),b=D(e);if(t!==null){if(!i)return{items:X(o.items,f),next_cursor:o.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:o.next_cursor!==null}]};const d=A(t);if(!h.some(q=>q.machine_id===d))throw new y(404,"not_found",`no machine ${d} on your account`,{machine:d});const w=await ke(e,u(d),b,r.signal);return{items:w.items,next_cursor:w.next,machines:[{machine_id:d,name:u(d).name,state:w.state,more:w.next!==null}]}}const{cursor:j,...m}=b,p=await Promise.all(h.map(d=>ke(e,u(d.machine_id),m,r.signal)));return{items:[...X(o.items,f),...p.flatMap(d=>d.items)],next_cursor:o.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:o.next_cursor!==null},...h.map((d,w)=>({machine_id:d.machine_id,name:d.name,state:p[w].state,more:p[w].next!==null}))]}}finally{clearTimeout(s)}}l(it,"list");function ve(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(ve,"withoutMachine");async function rt(e){const t=[],a=N(e.body)?e.body:{};N(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=a.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const i=a.grep;if(i!==void 0)if(typeof i!="string")t.push({field:"grep",problem:"must be a regular expression string",received:i});else try{new RegExp(i)}catch(s){t.push({field:"grep",problem:`is not a valid regular expression: ${s.message}`,received:i})}a.body!==void 0&&typeof a.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:a.body});const o=await ge(await I(),a.type,t);a.kind!==void 0&&typeof a.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:a.kind}),a.owner!==void 0&&typeof a.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:a.owner});const r=je(a.limit,"limit",t,50);return t.length>0&&C("object search request",t),await _(async s=>{const c=await v(s,e),u=typeof a.owner=="string"?await he(s,c,a.owner):null;if(typeof a.owner=="string"&&u===null)return{items:[]};const f=await se(s,c,{text:n,body:a.body===!0||typeof i=="string"}),h=new Set(f.map(m=>m.object.id)),j=(typeof i=="string"?(await se(s,c,{text:i,grep:!0})).filter(m=>h.has(m.object.id)):f).filter(m=>(!o||m.object.type===o)&&(a.kind===void 0||m.object.kind===a.kind)&&(!u||m.object.owner===u.id));return{items:await we(j.slice(0,r),async m=>({object:await me(s,m.object),...m.line!==void 0?{matches:[{line:m.line,text:m.text??""}]}:{}}))}})}l(rt,"search");const Oe=["interrupt","steer","after-turn","next-turn"],ot=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function st(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(a=>typeof a!="string"||!ot.test(a)||a.includes(">")&&!a.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(st,"patternsOf");function ut(e,t){if(e===void 0)return;if(!N(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const a=[];for(const[n,i]of Object.entries(e)){const o=Number(n);!Number.isInteger(o)||o<1||o>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):Oe.includes(i)?a.push({threshold:o,delivery:i}):t.push({field:`config.${n}`,problem:`delivery must be one of ${Oe.join(", ")}`,received:i})}return a.sort((n,i)=>i.threshold-n.threshold)}l(ut,"configOf");async function qe(e){const t=await ye(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(qe,"refuseStubWatch");async function x(e,t){const a=await E(e,t)??await(async()=>{const n=await Fe(e,await Ae(e,{class:"person"},async()=>[]),t);return"object"in n?n.object:null})();return a===null||a.deleted_at!==null||!(a.type.includes(".")||a.type==="node")?null:a}l(x,"findWatcher");const O=l(()=>{throw new y(404,"not_found","watcher not found")},"watcherNotFound");async function Ee(e,t,a){if(typeof t!="string"||a===void 0||a===null)return null;if(typeof a!="string")throw new y(400,"invalid_request","invalid watcher_machine");if(await x(e,t)!==null)return null;const n=W.current;let i;try{i=await n.machines()}catch{throw new y(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const o=A(a);return(o===n.self()||!i.some(r=>A(r.machine_id)===o))&&O(),o}l(Ee,"remoteWatcherMachine");async function Te(e,t,a,n){if(t.publishToken||t.principal.class==="anonymous")return O();const i=await v(e,t);if(i.class==="person")return O();let o;try{o=await T(e,i,n)}catch{return O()}const r=o.owner===null?null:await E(e,o.owner);return r===null||!await ie(e,i,r)||!await Le(e,i,"link",a)?O():(await z(e,t,a),{actor:i.app,object:o})}l(Te,"linkWatcher");async function Re(e,t,a){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!a.type.includes("."))return!1;const n=await v(e,t),i=a.owner===null?null:await E(e,a.owner);return i!==null&&await ie(e,n,i)&&await We(e,n,a)}l(Re,"ownsWatcher");async function ct(e){const t=k(e),a=N(e.body)?e.body:{};if(typeof a.watcher=="string"&&await qe(t),typeof a.watcher!="string"){const i=await Q(e,t,{method:"POST",path:`${G(t)}/watch`,body:e.body});if(i.kind==="unknown")throw de(t,i.unreachable);if(i.kind==="remote"){if(i.status>=400)throw M(i.status,i.body);const o=i.body.patterns;return await be(e,i.body,i.machine.id,"ask",o),Z(i.body,i.machine)}}const n=await Ee(await I(),a.watcher,a.watcher_machine);return await lt(e,n)}l(ct,"watch");async function lt(e,t=null){const a=[],n=e.body===void 0?{}:N(e.body)?e.body:(a.push({field:"body",problem:"must be an object"}),{}),i=st(n.patterns,a),o=ut(n.config,a);return n.filter!==void 0&&!N(n.filter)&&a.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&a.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&a.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),a.length>0&&C("watch request",a),await _(async r=>{const s=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!s)throw new y(404,"not_found","watcher not found");const c=i??[">"],u={patterns:c,...o?{config:o}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(s){const j=n.watcher,m=t===null?null:await ft(r,e,j,t),p=m??(e.publishToken?await re(r,j):await x(r,j));if(p===null)return O();if(m===null&&await Re(r,e,p)){const q=await oe(r,e,p);await z(r,e,p);const ee=await U(r,p),R=await T(r,ee,k(e));if(!await ae(r,ee,R))throw new y(404,"not_found","object not found");return await L(r,p,R,"act",u),await P(r,p,R),await H(r,{event:"watched",object:R,actor:q,attrs:{}},await F(r)),{object:await $(r,R,await g(r,R)),patterns:c}}const{actor:d,object:w}=await Te(r,e,p,k(e));return await L(r,p,w,"act",{...u,linkApp:d}),await P(r,p,w),await H(r,{event:"watched",object:w,actor:d,attrs:{}},await F(r)),{object:await $(r,w,await g(r,w)),patterns:c}}const f=await v(r,e),h=await K(r,e)??te(f),b=await T(r,f,k(e));return await L(r,h,b,"ask",u),await P(r,h,b),await H(r,{event:"watched",object:b,actor:h,attrs:{}},await F(r)),{object:await $(r,b,await g(r,b)),patterns:c}})}l(lt,"watchLocal");async function ft(e,t,a,n){return t.publishToken||t.principal.class==="anonymous"?O():await Je(e,a,n)}l(ft,"ensureNodeStubFor");async function Ie(e,t,a,n){const i=l(async()=>(await e.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.watch_id = s.watch
3
- WHERE w.watcher = ? AND w.object = ?`).get(t.id,a.id)).n,"count"),o=await i();await Ue(e,t,a,n??void 0);const r=await i();return r===0&&await Ve(e,t,a),{object:await g(e,a),removed:o-r}}l(Ie,"dropWatch");async function dt(e){const t=k(e);if(e.query.get("watcher")&&await qe(t),!e.query.get("watcher")){const n=await Q(e,t,{method:"DELETE",path:`${G(t)}/watch`,query:D(e)});if(n.kind==="unknown")throw de(t,n.unreachable);if(n.kind==="remote"){const i=n.status===404?n.body.error?.details:void 0,o=i?.deleted===!0?i.id:void 0;if(n.status>=400&&o===void 0)throw M(n.status,n.body);const r=o??n.body.object?.id,s=await _(async c=>{const u=await ce(c,e),f=r===void 0?null:await E(c,r);return u===null||f===null||!await J(c,f)?null:await Ie(c,u,f,e.query.get("pattern"))});if(o!==void 0){if(s===null)throw M(n.status,n.body);return{...s,machine:n.machine}}return Z(n.body,n.machine)}}const a=await Ee(await I(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return await wt(e,a)}l(dt,"unwatchRoute");async function wt(e,t=null){const a=e.query.get("pattern"),n=e.query.get("watcher");return await _(async i=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new y(404,"not_found","watcher not found");const o=l(async(c,u)=>await Ie(i,c,u,a),"drop");if(n){const c=t===null?null:await(async()=>{const f=await E(i,n);return f!==null&&await Qe(i,f)!==null?f:null})();if(t!==null&&c===null)return O();const u=c??(e.publishToken?await re(i,n):await x(i,n));return u===null?O():c===null&&await Re(i,e,u)?(await oe(i,e,u),await z(i,e,u),await o(u,await T(i,await U(i,u),k(e)))):await o(u,(await Te(i,e,u,k(e))).object)}const r=await v(i,e),s=await K(i,e)??te(r);return await o(s,await T(i,r,k(e)))})}l(wt,"unwatchLocal");async function mt(e){const t=[],a=Y(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Y(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&C("edges request",t),await _(async i=>{const o=await v(i,e),r=await T(i,o,k(e)),s=[];if(a!=="watches")for(const c of await Pe(i,o,r,{...a?{type:a}:{},direction:n??"both"}))s.push({type:c.type,src:await g(i,c.src),dst:await g(i,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(a===void 0||a==="watches"){const c=[...n!=="in"?await He(i,o,r):[],...n!=="out"?await ze(i,o,r):[]];for(const u of c)s.push({type:"watches",src:await g(i,u.watcher),dst:await g(i,u.object)})}return{items:s}})}l(mt,"edges");const S=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Gt=[{method:"POST",pattern:"/v1/objects/search",handler:S(rt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:S(mt)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:S(ct)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:S(dt)},{method:"GET",pattern:"/v1/objects/:ref",handler:S(et)},{method:"GET",pattern:"/v1/objects",handler:S(it)}];export{tt as listBudget,Gt as objectRoutes};
1
+ var Ne=Object.defineProperty;var l=(e,t)=>Ne(e,"name",{value:t,configurable:!0});import{ApiError as p}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as $e}from"../../../api/dto/objects.js";import{openDb as E,withCanvasWrite as j}from"../../../core/canvas/db.js";import{actorOf as te}from"../../../core/graph/documents.js";import{readerForObject as U,readerFor as Ae}from"../../../core/graph/reader.js";import{resolveName as Fe,stubsNamed as Se,unwrapRef as ne}from"../../../core/graph/names.js";import{canRead as ae,customReachable as We,holdsObjectsScope as Le,mayActAs as ie}from"../../../core/graph/access.js";import{customObjectRef as re,authorizeCustom as oe,fenceArgv as z}from"./custom-objects.js";import{edgesOf as Pe}from"../../../core/graph/edges.js";import{publish as H}from"../../../core/graph/events.js";import{objectDTO as b}from"../../../core/graph/kinds/dto.js";import{isKind as Ce,kindNames as De,kindOf as V}from"../../../core/graph/kinds/registry.js";import{listObjects as Me,searchObjects as se}from"../../../core/graph/objects.js";import{checkoutsForCwd as Ge}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as L,unwatch as Ue,watchersOf as ze,watchesOf as He}from"../../../core/graph/watches.js";import{armObjectWaitForWatch as P,settleObjectWaitForUnwatch as Ve}from"../../../core/graph/object-waits.js";import{readerFor as v,resolveRef as B}from"../reader.js";import{readDelegationFor as ue,runReadLeaf as Be}from"../../plugin-objects/read-leaf.js";import{invalidRequest as C,isRecord as N}from"./validate.js";import{callerNode as ce,callerStub as K,forwardNamed as Ke,forwardVerb as le,originates as fe,queryWithoutMachine as D,relayError as M,remoteStub as Ze,unknownError as de,forwarding as W,withMachine as Z}from"../../peer/forward.js";import{getById as T}from"../../../core/graph/objects.js";import{ensureNodeStub as Je,isStub as J,stubOf as Qe,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as Ye}from"../../../core/peer/client.js";import{normalizeMachineId as A}from"../../../core/peer/directory.js";import{mapAsync as we}from"../../../core/async-array.js";const F=l(async e=>async t=>await Ge(e,t),"reposFnFor");async function me(e,t){return{...await b(e,t),...await(await V(e,t.type)).listItem?.(e,t)}}l(me,"listItem");function Xe(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Xe,"remoteMessage");async function he(e,t,a){try{return await R(e,t,a)}catch(n){if(n instanceof p&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(he,"ownerFilter");async function R(e,t,a){const n=await B(e,t,a);if("remote"in n)throw new p(404,"not_found",Xe(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(R,"liveRef");const _=l(e=>decodeURIComponent(e.params.ref),"refParam"),pe=l(e=>{const t=ne(e),a=t.indexOf("/");return a>0?t.slice(0,a):t},"idOf");async function ye(e){const t=await T(await E(),pe(e));return t!==null&&await J(await E(),t)?t.id:null}l(ye,"stubIdOf");async function xe(e,t){const a=await ye(e);return a!==null?{stub:a,hit:!0}:await j(async n=>{try{const i=await v(n,t),o=l(async()=>{const s=await Se(n,i,e);if(s.length>1)throw new p(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:s.map(c=>c.id),next:"Read one by its object id."});return{stub:s[0]?.id??null,hit:!1}},"named");let r;try{r=await B(n,i,e)}catch(s){if(s instanceof p&&s.code==="not_found")return await o();throw s}if("remote"in r)return await o();if("deleted"in r){const s=await o();return s.stub===null?{stub:null,hit:!0}:s}return{stub:await J(n,r)?r.id:null,hit:!0}}catch(i){if(i instanceof p&&i.code==="ambiguous_name")throw i;return{stub:null,hit:!1}}})}l(xe,"resolvedLocally");async function Q(e,t,a){const n=await xe(t,e);if(n.stub!==null)return le(e,n.stub,a);if(n.hit||!fe(e.principal))return{kind:"local"};const i=await le(e,pe(t),a);return i.kind==="local"&&ne(t).includes("/")?Ke(e,a,{method:"GET",path:G(t),query:D(e)}):i}l(Q,"forwardRef");const G=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");async function be(e,t,a,n,i){const o=t?.object;!o?.id||!o.type||await j(async r=>{const s=await ce(r,e);if(s===null)return;const c=await Ze(r,o.id,o.type,a,{kind:o.kind??null,name:o.name??o.id,...o.preview===void 0?{}:{preview:o.preview},owner:o.owner??null,...o.kind_decl===void 0?{}:{kind_decl:o.kind_decl},...o.privacy===void 0?{}:{privacy:o.privacy}});await L(r,s,c,n,i===void 0?{}:{patterns:i}),n==="ask"&&await P(r,s,c)})}l(be,"watchRemote");async function et(e){const t=_(e),a=["1","true"].includes(e.query.get("fields")??""),n=await Q(e,t,{method:"GET",path:G(t),query:D(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw M(n.status,n.body);return await be(e,n.body,n.machine.id,"read"),Z(n.body,n.machine)}const i=l(async s=>{const c=await K(s,e);return c===null?await v(s,e):await U(s,c,await F(s))},"readerOf"),o=await j(async s=>{const c=await i(s),u=await B(s,c,t);if("remote"in u)return{state:"remote",remote:u.remote};if("deleted"in u)return{state:"deleted",deleted:await b(s,u.deleted)};const w=await ue(s,u);if(w!==null)return{delegate:w,hitId:u.id};const{data:h,text:y}=await(await V(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:y,data:h}});if(!("delegate"in o))return o;const r=await Be(o.delegate,e.principal);return await j(async s=>{const c=await i(s),u=await T(s,o.hitId);if(u===null)throw new p(404,"not_found","object not found");if(u.deleted_at!==null)return{state:"deleted",deleted:await b(s,u)};if(!await ae(s,c,u))throw new p(404,"not_found","object not found");const{data:w,text:h}=await(await V(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return await ue(s,u)===null?{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:h,data:w}:{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:"markdown"in r?r.markdown:`${h}
2
+ content unavailable: ${r.unavailable}`,data:{...w,content:"markdown"in r?"live":"unavailable"}}})}l(et,"read");function Y(e,t,a,n){if(e!=null){if(!a.includes(e)){n.push({field:t,problem:`must be one of ${a.join(", ")}`,received:e});return}return e}}l(Y,"oneOf");async function ge(e,t,a){if(t!=null){if(typeof t!="string"||!await Ce(e,t)){a.push({field:"type",problem:`must be a kind: one of ${(await De(e)).join(", ")}`,received:t});return}return t}}l(ge,"kindName");function je(e,t,a,n){if(e==null)return n;const i=Number(e);return!Number.isInteger(i)||i<1||i>100?(a.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):i}l(je,"limitOf");async function _e(e){const t=e.query,a=[],n=await ge(await E(),t.get("type"),a),i=Y(t.get("privacy"),"privacy",$e,a),o=je(t.get("limit"),"limit",a,50),r=t.get("cursor");r!==null&&!/^\d+$/.test(r)&&a.push({field:"cursor",problem:"is not a cursor from a previous page",received:r});const s=t.get("deleted");return s!==null&&!["0","1","true","false"].includes(s)&&a.push({field:"deleted",problem:"must be true or false",received:s}),a.length>0&&C("object list request",a),await j(async c=>{const u=await v(c,e),w={...n?{type:n}:{},...i?{privacy:i}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{}},h=t.get("owner");if(h!==null){const m=await he(c,u,h);if(m===null)return{items:[],next_cursor:null};w.owner=m}const y=t.get("name"),g=[];let k=r===null?0:Number(r),f=!0;for(;g.length<o&&f;){const m=await Me(c,u,w,{limit:100,after_seq:k});f=m.length===100;for(const q of m)if(k=q.seq,(y===null||q.name.startsWith(y))&&g.push(q),g.length===o)break}const d=g.at(-1);return{items:await we(g,async m=>await me(c,m)),next_cursor:g.length===o&&d?String(d.seq):null}})}l(_e,"listLocal");const tt={ms:3e4},nt="self",X=l((e,t)=>e.map(a=>({...a,machine:t})),"labelItems");async function ke(e,t,a,n){const i=W.current;try{const o=await i.call(t.id,{method:"GET",path:"/v1/objects",query:a},await i.envelope(e.principal),n);if(Ye(o))return{state:"unreachable",items:[],next:null};if(o.status===426)return{state:"too_old",items:[],next:null};const r=o.body;return o.status!==200||!Array.isArray(r?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:X(r.items,t),next:r.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(ke,"remotePage");async function at(e){const t=new Promise(a=>e.addEventListener("abort",()=>a(null),{once:!0}));return Promise.race([W.current.machines().catch(()=>null),t])}l(at,"machinesWithin");async function it(e){const t=e.query.get("machine");if(!fe(e.principal)||!W.current.joined()||t===nt)return await _e(ve(e));const n=W.current.self(),i=t!==null&&A(t)!==n,o=i?null:await _e(ve(e)),r=new AbortController,s=setTimeout(()=>r.abort(),tt.ms);s.unref?.();try{const c=await at(r.signal);if(c===null){if(i)throw new p(503,"runtime_unreachable",`The directory did not answer, so ${A(t)} cannot be listed.`,{machine:A(t)});return o}const u=l(d=>({id:d,name:c.find(m=>m.machine_id===d)?.name??d}),"labelOf"),w=u(n),h=c.filter(d=>d.machine_id!==n&&d.kind!=="device"),y=D(e);if(t!==null){if(!i)return{items:X(o.items,w),next_cursor:o.next_cursor,machines:[{machine_id:n,name:w.name,state:"ok",more:o.next_cursor!==null}]};const d=A(t);if(!h.some(q=>q.machine_id===d))throw new p(404,"not_found",`no machine ${d} on your account`,{machine:d});const m=await ke(e,u(d),y,r.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:d,name:u(d).name,state:m.state,more:m.next!==null}]}}const{cursor:g,...k}=y,f=await Promise.all(h.map(d=>ke(e,u(d.machine_id),k,r.signal)));return{items:[...X(o.items,w),...f.flatMap(d=>d.items)],next_cursor:o.next_cursor,machines:[{machine_id:n,name:w.name,state:"ok",more:o.next_cursor!==null},...h.map((d,m)=>({machine_id:d.machine_id,name:d.name,state:f[m].state,more:f[m].next!==null}))]}}finally{clearTimeout(s)}}l(it,"list");function ve(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(ve,"withoutMachine");async function rt(e){const t=[],a=N(e.body)?e.body:{};N(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=a.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const i=a.grep;if(i!==void 0)if(typeof i!="string")t.push({field:"grep",problem:"must be a regular expression string",received:i});else try{new RegExp(i)}catch(f){t.push({field:"grep",problem:`is not a valid regular expression: ${f.message}`,received:i})}a.body!==void 0&&typeof a.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:a.body});const o=await ge(await E(),a.type,t);a.kind!==void 0&&typeof a.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:a.kind}),a.owner!==void 0&&typeof a.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:a.owner});const r=je(a.limit,"limit",t,50);t.length>0&&C("object search request",t);const s=await j(async f=>{const d=await v(f,e),m=typeof a.owner=="string"?await he(f,d,a.owner):null;return{reader:d,owner:m}}),{reader:c,owner:u}=s;if(typeof a.owner=="string"&&u===null)return{items:[]};const w=await E(),h=await se(w,c,{text:n,body:a.body===!0||typeof i=="string"}),y=new Set(h.map(f=>f.object.id)),k=(typeof i=="string"?(await se(w,c,{text:i,grep:!0})).filter(f=>y.has(f.object.id)):h).filter(f=>(!o||f.object.type===o)&&(a.kind===void 0||f.object.kind===a.kind)&&(!u||f.object.owner===u.id));return{items:await we(k.slice(0,r),async f=>({object:await me(w,f.object),...f.line!==void 0?{matches:[{line:f.line,text:f.text??""}]}:{}}))}}l(rt,"search");const Oe=["interrupt","steer","after-turn","next-turn"],ot=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function st(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(a=>typeof a!="string"||!ot.test(a)||a.includes(">")&&!a.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(st,"patternsOf");function ut(e,t){if(e===void 0)return;if(!N(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const a=[];for(const[n,i]of Object.entries(e)){const o=Number(n);!Number.isInteger(o)||o<1||o>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):Oe.includes(i)?a.push({threshold:o,delivery:i}):t.push({field:`config.${n}`,problem:`delivery must be one of ${Oe.join(", ")}`,received:i})}return a.sort((n,i)=>i.threshold-n.threshold)}l(ut,"configOf");async function qe(e){const t=await ye(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(qe,"refuseStubWatch");async function x(e,t){const a=await T(e,t)??await(async()=>{const n=await Fe(e,await Ae(e,{class:"person"},async()=>[]),t);return"object"in n?n.object:null})();return a===null||a.deleted_at!==null||!(a.type.includes(".")||a.type==="node")?null:a}l(x,"findWatcher");const O=l(()=>{throw new p(404,"not_found","watcher not found")},"watcherNotFound");async function Ee(e,t,a){if(typeof t!="string"||a===void 0||a===null)return null;if(typeof a!="string")throw new p(400,"invalid_request","invalid watcher_machine");if(await x(e,t)!==null)return null;const n=W.current;let i;try{i=await n.machines()}catch{throw new p(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const o=A(a);return(o===n.self()||!i.some(r=>A(r.machine_id)===o))&&O(),o}l(Ee,"remoteWatcherMachine");async function Te(e,t,a,n){if(t.publishToken||t.principal.class==="anonymous")return O();const i=await v(e,t);if(i.class==="person")return O();let o;try{o=await R(e,i,n)}catch{return O()}const r=o.owner===null?null:await T(e,o.owner);return r===null||!await ie(e,i,r)||!await Le(e,i,"link",a)?O():(await z(e,t,a),{actor:i.app,object:o})}l(Te,"linkWatcher");async function Re(e,t,a){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!a.type.includes("."))return!1;const n=await v(e,t),i=a.owner===null?null:await T(e,a.owner);return i!==null&&await ie(e,n,i)&&await We(e,n,a)}l(Re,"ownsWatcher");async function ct(e){const t=_(e),a=N(e.body)?e.body:{};if(typeof a.watcher=="string"&&await qe(t),typeof a.watcher!="string"){const i=await Q(e,t,{method:"POST",path:`${G(t)}/watch`,body:e.body});if(i.kind==="unknown")throw de(t,i.unreachable);if(i.kind==="remote"){if(i.status>=400)throw M(i.status,i.body);const o=i.body.patterns;return await be(e,i.body,i.machine.id,"ask",o),Z(i.body,i.machine)}}const n=await Ee(await E(),a.watcher,a.watcher_machine);return await lt(e,n)}l(ct,"watch");async function lt(e,t=null){const a=[],n=e.body===void 0?{}:N(e.body)?e.body:(a.push({field:"body",problem:"must be an object"}),{}),i=st(n.patterns,a),o=ut(n.config,a);return n.filter!==void 0&&!N(n.filter)&&a.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&a.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&a.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),a.length>0&&C("watch request",a),await j(async r=>{const s=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!s)throw new p(404,"not_found","watcher not found");const c=i??[">"],u={patterns:c,...o?{config:o}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(s){const g=n.watcher,k=t===null?null:await ft(r,e,g,t),f=k??(e.publishToken?await re(r,g):await x(r,g));if(f===null)return O();if(k===null&&await Re(r,e,f)){const q=await oe(r,e,f);await z(r,e,f);const ee=await U(r,f),I=await R(r,ee,_(e));if(!await ae(r,ee,I))throw new p(404,"not_found","object not found");return await L(r,f,I,"act",u),await P(r,f,I),await H(r,{event:"watched",object:I,actor:q,attrs:{}},await F(r)),{object:await $(r,I,await b(r,I)),patterns:c}}const{actor:d,object:m}=await Te(r,e,f,_(e));return await L(r,f,m,"act",{...u,linkApp:d}),await P(r,f,m),await H(r,{event:"watched",object:m,actor:d,attrs:{}},await F(r)),{object:await $(r,m,await b(r,m)),patterns:c}}const w=await v(r,e),h=await K(r,e)??te(w),y=await R(r,w,_(e));return await L(r,h,y,"ask",u),await P(r,h,y),await H(r,{event:"watched",object:y,actor:h,attrs:{}},await F(r)),{object:await $(r,y,await b(r,y)),patterns:c}})}l(lt,"watchLocal");async function ft(e,t,a,n){return t.publishToken||t.principal.class==="anonymous"?O():await Je(e,a,n)}l(ft,"ensureNodeStubFor");async function Ie(e,t,a,n){const i=l(async()=>(await e.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.watch_id = s.watch
3
+ WHERE w.watcher = ? AND w.object = ?`).get(t.id,a.id)).n,"count"),o=await i();await Ue(e,t,a,n??void 0);const r=await i();return r===0&&await Ve(e,t,a),{object:await b(e,a),removed:o-r}}l(Ie,"dropWatch");async function dt(e){const t=_(e);if(e.query.get("watcher")&&await qe(t),!e.query.get("watcher")){const n=await Q(e,t,{method:"DELETE",path:`${G(t)}/watch`,query:D(e)});if(n.kind==="unknown")throw de(t,n.unreachable);if(n.kind==="remote"){const i=n.status===404?n.body.error?.details:void 0,o=i?.deleted===!0?i.id:void 0;if(n.status>=400&&o===void 0)throw M(n.status,n.body);const r=o??n.body.object?.id,s=await j(async c=>{const u=await ce(c,e),w=r===void 0?null:await T(c,r);return u===null||w===null||!await J(c,w)?null:await Ie(c,u,w,e.query.get("pattern"))});if(o!==void 0){if(s===null)throw M(n.status,n.body);return{...s,machine:n.machine}}return Z(n.body,n.machine)}}const a=await Ee(await E(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return await wt(e,a)}l(dt,"unwatchRoute");async function wt(e,t=null){const a=e.query.get("pattern"),n=e.query.get("watcher");return await j(async i=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new p(404,"not_found","watcher not found");const o=l(async(c,u)=>await Ie(i,c,u,a),"drop");if(n){const c=t===null?null:await(async()=>{const w=await T(i,n);return w!==null&&await Qe(i,w)!==null?w:null})();if(t!==null&&c===null)return O();const u=c??(e.publishToken?await re(i,n):await x(i,n));return u===null?O():c===null&&await Re(i,e,u)?(await oe(i,e,u),await z(i,e,u),await o(u,await R(i,await U(i,u),_(e)))):await o(u,(await Te(i,e,u,_(e))).object)}const r=await v(i,e),s=await K(i,e)??te(r);return await o(s,await R(i,r,_(e)))})}l(wt,"unwatchLocal");async function mt(e){const t=[],a=Y(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Y(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&C("edges request",t),await j(async i=>{const o=await v(i,e),r=await R(i,o,_(e)),s=[];if(a!=="watches")for(const c of await Pe(i,o,r,{...a?{type:a}:{},direction:n??"both"}))s.push({type:c.type,src:await b(i,c.src),dst:await b(i,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(a===void 0||a==="watches"){const c=[...n!=="in"?await He(i,o,r):[],...n!=="out"?await ze(i,o,r):[]];for(const u of c)s.push({type:"watches",src:await b(i,u.watcher),dst:await b(i,u.object)})}return{items:s}})}l(mt,"edges");const S=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Gt=[{method:"POST",pattern:"/v1/objects/search",handler:S(rt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:S(mt)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:S(ct)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:S(dt)},{method:"GET",pattern:"/v1/objects/:ref",handler:S(et)},{method:"GET",pattern:"/v1/objects",handler:S(it)}];export{tt as listBudget,Gt as objectRoutes};
@@ -1 +1 @@
1
- var u=Object.defineProperty;var r=(e,i)=>u(e,"name",{value:i,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{cancelCronsOnWake as c}from"../../core/canvas/crons.js";import{withFreshTerminalGuard as s}from"../../core/canvas/canvas.js";import{emitEvent as _}from"../../core/events/emit.js";import{enqueueNodeMail as y}from"../../core/feed/messages.js";import{BrokerUnreachableError as p}from"../../core/runtime/broker-request.js";import{deliverLive as v}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as l}from"../../core/runtime/model-swap.js";import{reviveNode as w}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as b}from"../../core/runtime/revive-all.js";import{ReviewOperationError as h}from"../../core/review/types.js";import{formatCard as k}from"../../shared/generated-context.js";import{isProfilePaused as N}from"../../core/profiles/manifest.js";function t(e,i){throw new h("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(t,"deliveryUnroutable");async function a(e,i){const n=await s(e,b,i);return n.kind==="missing"&&t(e,"origin_missing"),n.kind==="terminal"&&t(e,"no_natural_cycle"),n.result}r(a,"guardRoutable");async function G(e){await a(e.node_id,async()=>{});let i=await f(e.node_id);if(i===null&&t(e.node_id,"origin_missing"),e.mode==="interactive"&&!i.run_id&&!N(i.profile_id)&&l(i))try{return await v(e.node_id,e.runtime===void 0?e.body:k(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),await a(e.node_id,async()=>{}),await c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof p))throw o}const n=await a(e.node_id,async()=>await y(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let m=!1,d;if(n.urgency!=="deferred"&&(i=await f(e.node_id),i===null&&t(e.node_id,"origin_missing"),!l(i)))try{const o=await w(e.node_id,{resume:!0,capacity:"freeze"});m=o.launch!==void 0,o.outcome==="frozen"&&(d="capacity_frozen")}catch(o){_({level:"error",event:"message.wake_failed",node_id:e.node_id,error:o,fields:{message_id:n.messageId}})}return{entry_id:n.messageId,via:"inbox",revived:m,...d===void 0?{}:{reason:d}}}r(G,"deliverNodeMessage");export{G as deliverNodeMessage};
1
+ var u=Object.defineProperty;var r=(e,i)=>u(e,"name",{value:i,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{consumeDeadlineOnWake as c}from"../../core/feed/messages.js";import{withFreshTerminalGuard as s}from"../../core/canvas/canvas.js";import{emitEvent as _}from"../../core/events/emit.js";import{enqueueNodeMail as y}from"../../core/feed/messages.js";import{BrokerUnreachableError as p}from"../../core/runtime/broker-request.js";import{deliverLive as v}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as l}from"../../core/runtime/model-swap.js";import{reviveNode as w}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as b}from"../../core/runtime/revive-all.js";import{ReviewOperationError as h}from"../../core/review/types.js";import{formatCard as k}from"../../shared/generated-context.js";import{isProfilePaused as N}from"../../core/profiles/manifest.js";function t(e,i){throw new h("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(t,"deliveryUnroutable");async function a(e,i){const n=await s(e,b,i);return n.kind==="missing"&&t(e,"origin_missing"),n.kind==="terminal"&&t(e,"no_natural_cycle"),n.result}r(a,"guardRoutable");async function F(e){await a(e.node_id,async()=>{});let i=await f(e.node_id);if(i===null&&t(e.node_id,"origin_missing"),e.mode==="interactive"&&!i.run_id&&!N(i.profile_id)&&l(i))try{return await v(e.node_id,e.runtime===void 0?e.body:k(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),await a(e.node_id,async()=>{}),await c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof p))throw o}const n=await a(e.node_id,async()=>await y(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let m=!1,d;if(n.urgency!=="deferred"&&(i=await f(e.node_id),i===null&&t(e.node_id,"origin_missing"),!l(i)))try{const o=await w(e.node_id,{resume:!0,capacity:"freeze"});m=o.launch!==void 0,o.outcome==="frozen"&&(d="capacity_frozen")}catch(o){_({level:"error",event:"message.wake_failed",node_id:e.node_id,error:o,fields:{message_id:n.messageId}})}return{entry_id:n.messageId,via:"inbox",revived:m,...d===void 0?{}:{reason:d}}}r(F,"deliverNodeMessage");export{F as deliverNodeMessage};
@@ -1 +1 @@
1
- var $=Object.defineProperty;var i=(n,e)=>$(n,"name",{value:e,configurable:!0});import{ApiError as m}from"../../api/errors.js";import{openDb as g}from"../../core/canvas/db.js";import{getById as j,nodeObject as A}from"../../core/graph/objects.js";import{envelopeFor as D}from"../../core/peer/envelope.js";import{isUnreachable as w}from"../../core/peer/client.js";import{machineReach as E}from"../../core/peer/directory.js";import{defaultHomeDeps as O,homeOf as S,peersToAsk as F,relocate as N}from"../../core/peer/home.js";import{ensureStub as y,rehomeStub as q,stubOf as C}from"../../core/peer/stubs.js";import{peerCall as M}from"../../core/peer/client.js";const T={...O,call:i((n,e,o,t)=>M(n,e,{...o===void 0?{}:{envelope:o},...t===void 0?{}:{signal:t}}),"call"),envelope:i(async n=>await D(n),"envelope"),label:i(async n=>{try{const e=await E(n);return{id:n,name:e?.name??n}}catch{return{id:n,name:n}}},"label")},_={current:T},v=i(n=>n.class==="person"||n.class==="broker"||n.class==="cron","originates"),k=i(n=>{const e=n?.error;return typeof e=="object"&&e!==null&&typeof e.code=="string"?e.code:null},"errorCode");function K(n,e){const o=e?.error;return new m(n,o?.code??"error",o?.message??`the home machine answered ${n}`,o?.details)}i(K,"relayError");function L(n,e){return new m(503,"runtime_unreachable",`No machine of yours answers for ${n} (unreachable: ${e.join(", ")}).`,{id:n,unreachable:e})}i(L,"unknownError");const Q=i((n,e)=>n!==null&&typeof n=="object"&&!Array.isArray(n)?{...n,machine:e}:n,"withMachine");async function X(n,e,o){const t=_.current,a=await g(),c=await j(a,e),u=c===null?null:await C(a,c),p=n.principal;if(!v(p)){if(u!==null)throw new m(404,"not_here",`${e} is not homed on this machine (it is a stub of ${u.home_machine})`,{id:e,home_machine:u.home_machine});return{kind:"local"}}if(c!==null&&u===null)return{kind:"local"};const h={...t,call:i((r,d)=>t.call(r,d),"call")};let l=await S(a,e,{hint:n.query.get("machine"),deps:h});for(let r=0;r<2;r++){if(l.where==="nowhere"||l.where==="here"){if(u!==null)throw new m(404,"not_found",`${e} is no longer on any machine of yours`,{id:e});return{kind:"local"}}if(l.where==="unknown")return{kind:"unknown",unreachable:l.unreachable};const d=l.machine,s=await t.call(d,o,await t.envelope(p)),b=await t.label(d);if(w(s))return{kind:"unknown",unreachable:[`${b.name} (${s.unreachable.reason})`]};const x=l.source!=="locate";if(s.status===404&&r===0&&(k(s.body)==="not_here"||x&&k(s.body)==="not_found")){const f=await N(a,e,d,h);if(f.where==="machine"){l=f;continue}if(f.where==="unknown")return{kind:"unknown",unreachable:f.unreachable};if(k(s.body)==="not_found")return{kind:"remote",status:s.status,body:s.body,machine:b};if(u!==null)throw new m(404,"not_found",`${e} is no longer on any machine of yours`,{id:e});return{kind:"local"}}return{kind:"remote",status:s.status,body:s.body,machine:b}}return{kind:"unknown",unreachable:[]}}i(X,"forwardVerb");async function Y(n,e,o){const t=_.current,a=n.principal;if(!v(a))return{kind:"local"};const c=await F(t);if("where"in c)return{kind:"unknown",unreachable:c.unreachable};if(c.length===0)return{kind:"local"};const u=await t.envelope(a),p=await Promise.all(c.map(async r=>({m:r,out:await t.call(r.machine_id,o,u)}))),h=p.find(r=>!w(r.out)&&r.out.status<400);if(h){const r=e.method==="GET"?h.out:await t.call(h.m.machine_id,e,u),d=await t.label(h.m.machine_id);return w(r)?{kind:"unknown",unreachable:[`${d.name} (${r.unreachable.reason})`]}:{kind:"remote",status:r.status,body:r.body,machine:d}}const l=p.filter(r=>w(r.out)||r.out.status!==404).map(r=>r.m.name||r.m.machine_id);return l.length>0?{kind:"unknown",unreachable:l}:{kind:"local"}}i(Y,"forwardNamed");function W(n){if(n.actor.kind==="person")return{sub:n.sub,act:{sub:n.via}};const{app:e,node:o,node_scopes:t,place:a}=n.actor;return{sub:n.sub,act:{sub:n.via,act:{sub:e,node:o,node_scopes:t,place:a}}}}i(W,"envelopeOfForwarded");function Z(n){const e={};for(const[o,t]of n.query)o!=="machine"&&(e[o]=t);return e}i(Z,"queryWithoutMachine");async function nn(n,e){const o=e.principal;return o.class!=="forwarded"||o.actor.kind!=="app"||o.actor.node===null?null:await y(n,o.actor.node,"node",o.via,W(o))}i(nn,"callerStub");async function en(n,e){return e.principal.class==="broker"?await A(n,e.principal.node):null}i(en,"callerNode");async function on(n,e,o,t,a){await q(n,e,t);const c=a?.owner,u=c&&c.type==="app"?{id:"",type:"app",scheme:"app",external_id:c.external_id??(c.handle.startsWith("app:")?c.handle:`app:${c.handle}`),handle:c.handle}:null;return await y(n,e,o,t,void 0,a===void 0?void 0:{id:e,type:o,kind:a.kind??null,name:a.name??e,...a.preview===void 0?{}:{preview:a.preview},owner:u,...a.kind_decl===void 0?{}:{kind_decl:a.kind_decl},...a.privacy===void 0?{}:{privacy:a.privacy}})}i(on,"remoteStub");export{en as callerNode,nn as callerStub,T as defaultForwardDeps,W as envelopeOfForwarded,Y as forwardNamed,X as forwardVerb,_ as forwarding,v as originates,Z as queryWithoutMachine,K as relayError,on as remoteStub,L as unknownError,Q as withMachine};
1
+ var $=Object.defineProperty;var i=(e,n)=>$(e,"name",{value:n,configurable:!0});import{ApiError as m}from"../../api/errors.js";import{openDb as g}from"../../core/canvas/db.js";import{getById as A,nodeObject as D}from"../../core/graph/objects.js";import{envelopeFor as j}from"../../core/peer/envelope.js";import{isUnreachable as w}from"../../core/peer/client.js";import{machineReach as E}from"../../core/peer/directory.js";import{defaultHomeDeps as O,homeOf as S,peersToAsk as F,relocate as N}from"../../core/peer/home.js";import{ensureStub as y,rehomeStub as q,stubOf as C}from"../../core/peer/stubs.js";import{peerCall as M}from"../../core/peer/client.js";const T={...O,call:i((e,n,o,t)=>M(e,n,{...o===void 0?{}:{envelope:o},...t===void 0?{}:{signal:t}}),"call"),envelope:i(async e=>await j(e),"envelope"),label:i(async e=>{try{const n=await E(e);return{id:e,name:n?.name??e}}catch{return{id:e,name:e}}},"label")},_={current:T},v=i(e=>e.class==="person"||e.class==="broker"||e.class==="cron","originates"),W=i(e=>e?.error?.details?.deleted===!0,"isDeletedAnswer"),k=i(e=>{const n=e?.error;return typeof n=="object"&&n!==null&&typeof n.code=="string"?n.code:null},"errorCode");function L(e,n){const o=n?.error;return new m(e,o?.code??"error",o?.message??`the home machine answered ${e}`,o?.details)}i(L,"relayError");function Q(e,n){return new m(503,"runtime_unreachable",`No machine of yours answers for ${e} (unreachable: ${n.join(", ")}).`,{id:e,unreachable:n})}i(Q,"unknownError");const X=i((e,n)=>e!==null&&typeof e=="object"&&!Array.isArray(e)?{...e,machine:n}:e,"withMachine");async function Y(e,n,o){const t=_.current,a=await g(),c=await A(a,n),u=c===null?null:await C(a,c),p=e.principal;if(!v(p)){if(u!==null)throw new m(404,"not_here",`${n} is not homed on this machine (it is a stub of ${u.home_machine})`,{id:n,home_machine:u.home_machine});return{kind:"local"}}if(c!==null&&u===null)return{kind:"local"};const h={...t,call:i((r,d)=>t.call(r,d),"call")};let s=await S(a,n,{hint:e.query.get("machine"),deps:h});for(let r=0;r<2;r++){if(s.where==="nowhere"||s.where==="here"){if(u!==null)throw new m(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}if(s.where==="unknown")return{kind:"unknown",unreachable:s.unreachable};const d=s.machine,l=await t.call(d,o,await t.envelope(p)),b=await t.label(d);if(w(l))return{kind:"unknown",unreachable:[`${b.name} (${l.unreachable.reason})`]};const x=s.source!=="locate";if(l.status===404&&r===0&&!W(l.body)&&(k(l.body)==="not_here"||x&&k(l.body)==="not_found")){const f=await N(a,n,d,h);if(f.where==="machine"){s=f;continue}if(f.where==="unknown")return{kind:"unknown",unreachable:f.unreachable};if(k(l.body)==="not_found")return{kind:"remote",status:l.status,body:l.body,machine:b};if(u!==null)throw new m(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}return{kind:"remote",status:l.status,body:l.body,machine:b}}return{kind:"unknown",unreachable:[]}}i(Y,"forwardVerb");async function Z(e,n,o){const t=_.current,a=e.principal;if(!v(a))return{kind:"local"};const c=await F(t);if("where"in c)return{kind:"unknown",unreachable:c.unreachable};if(c.length===0)return{kind:"local"};const u=await t.envelope(a),p=await Promise.all(c.map(async r=>({m:r,out:await t.call(r.machine_id,o,u)}))),h=p.find(r=>!w(r.out)&&r.out.status<400);if(h){const r=n.method==="GET"?h.out:await t.call(h.m.machine_id,n,u),d=await t.label(h.m.machine_id);return w(r)?{kind:"unknown",unreachable:[`${d.name} (${r.unreachable.reason})`]}:{kind:"remote",status:r.status,body:r.body,machine:d}}const s=p.filter(r=>w(r.out)||r.out.status!==404).map(r=>r.m.name||r.m.machine_id);return s.length>0?{kind:"unknown",unreachable:s}:{kind:"local"}}i(Z,"forwardNamed");function B(e){if(e.actor.kind==="person")return{sub:e.sub,act:{sub:e.via}};const{app:n,node:o,node_scopes:t,place:a}=e.actor;return{sub:e.sub,act:{sub:e.via,act:{sub:n,node:o,node_scopes:t,place:a}}}}i(B,"envelopeOfForwarded");function ee(e){const n={};for(const[o,t]of e.query)o!=="machine"&&(n[o]=t);return n}i(ee,"queryWithoutMachine");async function ne(e,n){const o=n.principal;return o.class!=="forwarded"||o.actor.kind!=="app"||o.actor.node===null?null:await y(e,o.actor.node,"node",o.via,B(o))}i(ne,"callerStub");async function oe(e,n){return n.principal.class==="broker"?await D(e,n.principal.node):null}i(oe,"callerNode");async function re(e,n,o,t,a){await q(e,n,t);const c=a?.owner,u=c&&c.type==="app"?{id:"",type:"app",scheme:"app",external_id:c.external_id??(c.handle.startsWith("app:")?c.handle:`app:${c.handle}`),handle:c.handle}:null;return await y(e,n,o,t,void 0,a===void 0?void 0:{id:n,type:o,kind:a.kind??null,name:a.name??n,...a.preview===void 0?{}:{preview:a.preview},owner:u,...a.kind_decl===void 0?{}:{kind_decl:a.kind_decl},...a.privacy===void 0?{}:{privacy:a.privacy}})}i(re,"remoteStub");export{oe as callerNode,ne as callerStub,T as defaultForwardDeps,B as envelopeOfForwarded,Z as forwardNamed,Y as forwardVerb,_ as forwarding,v as originates,ee as queryWithoutMachine,L as relayError,re as remoteStub,Q as unknownError,X as withMachine};
@@ -23,5 +23,11 @@ export declare class BashDeadlineReconciler {
23
23
  /** Give every backgrounded job dir (job.bg) that has no job object one; the next tick's
24
24
  * `publishExits` then ends it like any other job. */
25
25
  private adoptUnrecorded;
26
+ /** A running job whose process is confirmed gone without job.exit (killed outright, so its
27
+ * supervisor never wrote one) is ended once as killed, with a null exit code, through
28
+ * `finishJob`. job.exit is then written so the file-based listing and stop guard stop counting
29
+ * the job. A job.exit that appears by the re-check is a real exit: `publishExits` reports it.
30
+ * A job being stopped (job.stop) is ended by its killer. */
31
+ private settleVanished;
26
32
  private cancel;
27
33
  }
@@ -1,2 +1,3 @@
1
- var u=Object.defineProperty;var f=(l,t)=>u(l,"name",{value:t,configurable:!0});import{existsSync as n,readFileSync as m,readdirSync as j,statSync as _}from"node:fs";import{join as b}from"node:path";import{bashJobPaths as y,bashJobsDir as w,expiredAutoBackgroundBashJobs as S,stopBackgroundBashJob as x}from"../../core/bash-jobs.js";import{killBashJobObject as N,recordBashJobObject as E}from"../../core/spaces/stop.js";import{withCanvasWrite as h}from"../../core/canvas/db.js";import{finishJob as v}from"../../core/graph/jobs.js";import{getById as p}from"../../core/graph/objects.js";import{isSafeNodeId as c}from"../../core/canvas/paths.js";import{contextDir as A}from"../../core/canvas/node-agent-paths.js";import{emitEvent as s}from"../../core/events/emit.js";import{operationIdContext as d}from"../../core/events/operation-id.js";import{isProfilePaused as g}from"../../core/profiles/manifest.js";const B=5*1e3;class V{static{f(this,"BashDeadlineReconciler")}lastScanAt=Number.NEGATIVE_INFINITY;startedAt=Date.now();async run(t,a){if(await this.publishExits(),!(t-this.lastScanAt<B)){this.lastScanAt=t;for(const e of a.rows){if(e.status==="dead"||g(e.profile_id))continue;const r=await A(e.node_id);let i;try{await this.adoptUnrecorded(e.node_id,r),i=S(r,t)}catch(o){d.fresh(()=>{s({level:"error",event:"bash_deadline.scan_failed",...c(e.node_id)?{node_id:e.node_id}:{},error:o})});continue}for(const o of i)await this.cancel(e.node_id,r,o.jobId)}}}async publishExits(){try{await h(async t=>{const a=await t.prepare(`SELECT j.object, j.job_dir FROM jobs j JOIN objects o ON o.id = j.object
2
- WHERE j.status = 'running' AND o.deleted_at IS NULL`).all();for(const{object:e,job_dir:r}of a){const i=b(r,"job.exit");if(!n(i)||n(b(r,"job.stop")))continue;const o=Number(m(i,"utf8").trim());Number.isSafeInteger(o)&&await v(t,await p(t,e),{exitCode:o})}})}catch(t){d.fresh(()=>s({level:"error",event:"bash_completion.delivery_failed",error:t}))}}async adoptUnrecorded(t,a){let e;try{e=j(w(a))}catch{return}await h(async r=>{for(const i of e){if(await p(r,i)!==null)continue;const o=y(a,i);!n(o.jobBg)||!n(o.cmdSh)||n(o.jobExit)&&_(o.jobExit).mtimeMs<this.startedAt||await E(t,i,{command:m(o.cmdSh,"utf8"),jobDir:o.dir,logPath:o.jobLog})}})}async cancel(t,a,e){(await x(a,e,!1,t)).kind==="stopped"&&await d.fresh(async()=>{try{s({level:"info",event:"bash_deadline.canceled",...c(t)?{node_id:t}:{},fields:{job_id:e}}),await N(e,async()=>null,"deadline")}catch(i){s({level:"error",event:"bash_deadline.notice_failed",...c(t)?{node_id:t}:{},error:i,fields:{job_id:e}})}})}}export{V as BashDeadlineReconciler};
1
+ var y=Object.defineProperty;var p=(h,t)=>y(h,"name",{value:t,configurable:!0});import{existsSync as n,readFileSync as m,readdirSync as _,statSync as w}from"node:fs";import{join as s}from"node:path";import{bashJobPaths as u,bashJobsDir as x,activeBackgroundBashJobs as E,expiredAutoBackgroundBashJobs as S,isBashJobProcessConfirmedGone as B,readJobPgid as N,readJobPgidIdentity as g,stopBackgroundBashJob as v}from"../../core/bash-jobs.js";import{killBashJobObject as J,recordBashJobObject as A}from"../../core/spaces/stop.js";import{createFileBeneath as I}from"../../core/spaces/open-beneath.js";import{withCanvasWrite as d}from"../../core/canvas/db.js";import{finishJob as j}from"../../core/graph/jobs.js";import{getById as l}from"../../core/graph/objects.js";import{isSafeNodeId as f}from"../../core/canvas/paths.js";import{contextDir as P}from"../../core/canvas/node-agent-paths.js";import{emitEvent as c}from"../../core/events/emit.js";import{operationIdContext as b}from"../../core/events/operation-id.js";import{isProfilePaused as k}from"../../core/profiles/manifest.js";const C=5*1e3;class q{static{p(this,"BashDeadlineReconciler")}lastScanAt=Number.NEGATIVE_INFINITY;startedAt=Date.now();async run(t,r){if(await this.publishExits(),!(t-this.lastScanAt<C)){this.lastScanAt=t;for(const e of r.rows){if(e.status==="dead"||k(e.profile_id))continue;const a=await P(e.node_id);let i;try{await this.adoptUnrecorded(e.node_id,a),await this.settleVanished(a),i=S(a,t)}catch(o){b.fresh(()=>{c({level:"error",event:"bash_deadline.scan_failed",...f(e.node_id)?{node_id:e.node_id}:{},error:o})});continue}for(const o of i)await this.cancel(e.node_id,a,o.jobId)}}}async publishExits(){try{await d(async t=>{const r=await t.prepare(`SELECT j.object, j.job_dir FROM jobs j JOIN objects o ON o.id = j.object
2
+ WHERE j.status = 'running' AND o.deleted_at IS NULL`).all();for(const{object:e,job_dir:a}of r){const i=s(a,"job.exit");if(!n(i)||n(s(a,"job.stop")))continue;const o=Number(m(i,"utf8").trim());Number.isSafeInteger(o)&&await j(t,await l(t,e),{exitCode:o})}})}catch(t){b.fresh(()=>c({level:"error",event:"bash_completion.delivery_failed",error:t}))}}async adoptUnrecorded(t,r){let e;try{e=_(x(r))}catch{return}await d(async a=>{for(const i of e){if(await l(a,i)!==null)continue;const o=u(r,i);!n(o.jobBg)||!n(o.cmdSh)||n(o.jobExit)&&w(o.jobExit).mtimeMs<this.startedAt||await A(t,i,{command:m(o.cmdSh,"utf8"),jobDir:o.dir,logPath:o.jobLog})}})}async settleVanished(t){for(const{jobId:r}of E(t)){const e=u(t,r);n(e.jobExit)||n(s(e.dir,"job.stop"))||B(N(t,r),g(t,r))&&await d(async a=>{const i=await l(a,r);if(!(i===null||i.type!=="job")&&!(n(e.jobExit)||n(s(e.dir,"job.stop")))){await j(a,i,{killedBy:null,reason:"process disappeared without an exit record"});try{I(e.root,e.jobExit,`-1
3
+ `)}catch(o){if(o.code!=="EEXIST")throw o}}})}}async cancel(t,r,e){(await v(r,e,!1,t)).kind==="stopped"&&await b.fresh(async()=>{try{c({level:"info",event:"bash_deadline.canceled",...f(t)?{node_id:t}:{},fields:{job_id:e}}),await J(e,async()=>null,"deadline")}catch(i){c({level:"error",event:"bash_deadline.notice_failed",...f(t)?{node_id:t}:{},error:i,fields:{job_id:e}})}})}}export{q as BashDeadlineReconciler};
@@ -8,6 +8,8 @@ export type OpenAssistantBlock = {
8
8
  };
9
9
  /** The newest block of the node's open assistant message; null when no message is open or nothing has streamed yet. */
10
10
  export declare function openAssistantBlock(nodeId: string): OpenAssistantBlock | null;
11
+ /** Test-only: stop every observer and wait out the polls in flight, so none touches a home the test is about to delete. */
12
+ export declare function closeRunObserversForTests(): Promise<void>;
11
13
  export declare function ensureRunObserver(nodeId: string, runId: string): Promise<void>;
12
14
  /** Observes run nodes with a live broker, plus those whose current outcome
13
15
  * (settled within the event retention window) has no `node.settled` event yet. */
@@ -1,5 +1,5 @@
1
- var k=Object.defineProperty;var r=(s,t)=>k(s,"name",{value:t,configurable:!0});import{randomUUID as y}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as m}from"../../core/canvas/canvas.js";import{BrokerClient as D,SocketTransport as I}from"../../core/broker-client/client.js";import{emitRunEvent as p,emitRunSettlement as E}from"../../core/runs/events.js";import{cancelOpenQuestions as T}from"../../core/runs/questions.js";import{emitEvent as h}from"../../core/events/emit.js";import{toRunOutcomeDTO as N}from"../api/map.js";import{readOutputResult as R}from"../../core/runtime/structured-output.js";const A=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),u=new Map,b=250;class g{static{r(this,"RunObserver")}nodeId;runId;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;polling;frames=Promise.resolve();constructor(t,i,n,e){this.nodeId=t,this.runId=i,this.status=n,this.outcomeRevision=e,this.timer=setInterval(()=>{this.pollOrClose()},250),this.timer.unref(),u.set(t,this)}static async start(t,i){const n=await l(),e=await n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===i?"node.settled":"child.settled"),o=await n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t),d=new g(t,i,o?JSON.parse(o.body_json).status:void 0,e?JSON.parse(e.body_json).outcome.revision:void 0);return await d.poll(),d}async pollOrClose(){try{await this.poll()}catch(t){this.close(),h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:t})}}poll(){return this.polling===void 0&&(this.polling=this.pollOnce().finally(()=>{this.polling=void 0})),this.polling}async pollOnce(){const t=await m(this.nodeId);if(!t||t.run_id!==this.runId||!await S(this.runId)){this.close();return}this.piPid=t.pi_pid??null;const i=t.pi_pid===null?"dormant":t.status;this.status!==i&&await p(this.runId,this.nodeId,"node.status.changed",{status:i,reason:t.intent??null}),this.status=i;const n=N(t);if(n&&n.revision!==this.outcomeRevision&&Date.now()-Date.parse(n.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const e=await(await l()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const o of e)await w(o.node_id,this.runId),await u.get(o.node_id)?.poll()}if(this.outcomeRevision=n.revision,this.nodeId===this.runId){const e=n.kind==="result"?R(this.nodeId,t.grantee):void 0;await E(this.runId,this.nodeId,"node.settled",{outcome:n,usage:JSON.parse(t.usage_json??A),...e===void 0?{}:{result:e}})}else await E(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:n});if(t.grantee&&t.grantee!=="app:terminal"){const e=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};T(e,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(o=>h({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:o}))}}t.pi_pid===null?this.close():await this.connect()}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&this.piPid!==null?this.assistantStartSequence:null}get openBlock(){return this.assistantMessageStartSequence===null?null:this.block}async connect(){if(this.client||this.closed)return;const t=new D(this.nodeId,{transport:new I(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:y(),attends:!1}));const i=r(async n=>{if(!(this.closed||this.client!==t)){if(n.type==="message_start"&&n.message.role==="assistant"&&(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",this.assistantStartSequence=(await(await l()).prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId)).event_cursor),n.type==="message_update"&&n.message.role==="assistant"&&this.openAssistant){const e=n.message.content;if(!Array.isArray(e))return;const o=e.at(-1);o&&typeof o=="object"&&"type"in o&&(o.type==="toolCall"?this.block={kind:"tool_call",name:"name"in o&&typeof o.name=="string"?o.name:""}:(o.type==="text"||o.type==="thinking")&&(this.block={kind:o.type}));const d=e.filter(a=>a?.type==="thinking").map(a=>a.thinking).join(""),c=e.filter(a=>a?.type==="text").map(a=>a.text).join(""),v=d.startsWith(this.thinking)?d.slice(this.thinking.length):d,O=c.startsWith(this.output)?c.slice(this.output.length):c;this.thinking=d,this.output=c,this.pendingThinking+=v,this.pendingOutput+=O,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>{this.flushDeltas().catch(a=>h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:a}))},b),this.flushTimer.unref())}n.type==="message_end"&&n.message.role==="assistant"&&(await this.flushDeltas(),this.openAssistant=!1,this.block=null)}},"handleFrame");t.on("frame",n=>{this.frames=this.frames.then(()=>i(n)).catch(e=>{this.close(),h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:e})})}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null)}),t.connect()}async flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const t=this.pendingThinking,i=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!t&&!i)return;if(await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}t&&await p(this.runId,this.nodeId,"node.thinking.delta",{delta:t}),i&&await p(this.runId,this.nodeId,"node.output_text.delta",{delta:i})}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){this.closed=!0,this.discardDeltas(),clearInterval(this.timer),u.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function P(s){return u.get(s)?.assistantMessageStartSequence??null}r(P,"openAssistantMessageStartSequence");function Y(s){return u.get(s)?.openBlock??null}r(Y,"openAssistantBlock");async function S(s){return await(await l()).prepare("SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(s,s)!==void 0}r(S,"runRootExists");const f=new Map;async function w(s,t){const i=f.get(s);if(i)return i;if(u.has(s))return;const n=L(s,t).finally(()=>f.delete(s));return f.set(s,n),n}r(w,"ensureRunObserver");async function L(s,t){if(await S(t)){if(s!==t){const i=await m(s);!await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,s)&&i&&Date.now()-Date.parse(i.created)<720*60*6e4&&await p(t,s,"child.started",{child_node_id:s,kind:i.kind})}await g.start(s,t)}}r(L,"startRunObserver");async function G(){const s=new Date(Date.now()-2592e6).toISOString(),t=await(await l()).prepare(`SELECT n.node_id, n.run_id, n.pi_pid, COALESCE(n.outcome_revision, 1) AS revision, e.body_json
1
+ var y=Object.defineProperty;var r=(n,t)=>y(n,"name",{value:t,configurable:!0});import{randomUUID as k}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as g}from"../../core/canvas/canvas.js";import{BrokerClient as D,SocketTransport as T}from"../../core/broker-client/client.js";import{emitRunEvent as p,emitRunSettlement as w}from"../../core/runs/events.js";import{cancelOpenQuestions as I}from"../../core/runs/questions.js";import{emitEvent as c}from"../../core/events/emit.js";import{toRunOutcomeDTO as N}from"../api/map.js";import{readOutputResult as R}from"../../core/runtime/structured-output.js";const b=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),u=new Map,A=250;class m{static{r(this,"RunObserver")}nodeId;runId;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;polling;frames=Promise.resolve();constructor(t,i,s,e){this.nodeId=t,this.runId=i,this.status=s,this.outcomeRevision=e,this.timer=setInterval(()=>{this.pollOrClose()},250),this.timer.unref(),u.set(t,this)}static async start(t,i){const s=await l(),e=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===i?"node.settled":"child.settled"),o=await s.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t),d=new m(t,i,o?JSON.parse(o.body_json).status:void 0,e?JSON.parse(e.body_json).outcome.revision:void 0);return await d.poll(),d}async pollOrClose(){try{await this.poll()}catch(t){this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:t})}}poll(){return this.polling===void 0&&(this.polling=this.pollOnce().finally(()=>{this.polling=void 0})),this.polling}async pollOnce(){const t=await g(this.nodeId);if(!t||t.run_id!==this.runId||!await E(this.runId)){this.close();return}this.piPid=t.pi_pid??null;const i=t.pi_pid===null?"dormant":t.status;this.status!==i&&await p(this.runId,this.nodeId,"node.status.changed",{status:i,reason:t.intent??null}),this.status=i;const s=N(t);if(s&&s.revision!==this.outcomeRevision&&Date.now()-Date.parse(s.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const e=await(await l()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const o of e)await v(o.node_id,this.runId),await u.get(o.node_id)?.poll()}if(this.outcomeRevision=s.revision,this.nodeId===this.runId){const e=s.kind==="result"?R(this.nodeId,t.grantee):void 0;await w(this.runId,this.nodeId,"node.settled",{outcome:s,usage:JSON.parse(t.usage_json??b),...e===void 0?{}:{result:e}})}else await w(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:s});if(t.grantee&&t.grantee!=="app:terminal"){const e=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};I(e,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(o=>c({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:o}))}}t.pi_pid===null?this.close():await this.connect()}async settlePoll(){await this.polling?.catch(()=>{}),await this.frames}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&this.piPid!==null?this.assistantStartSequence:null}get openBlock(){return this.assistantMessageStartSequence===null?null:this.block}async connect(){if(this.client||this.closed)return;const t=new D(this.nodeId,{transport:new T(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:k(),attends:!1}));const i=r(async s=>{if(!(this.closed||this.client!==t)){if(s.type==="message_start"&&s.message.role==="assistant"&&(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",this.assistantStartSequence=(await(await l()).prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId)).event_cursor),s.type==="message_update"&&s.message.role==="assistant"&&this.openAssistant){const e=s.message.content;if(!Array.isArray(e))return;const o=e.at(-1);o&&typeof o=="object"&&"type"in o&&(o.type==="toolCall"?this.block={kind:"tool_call",name:"name"in o&&typeof o.name=="string"?o.name:""}:(o.type==="text"||o.type==="thinking")&&(this.block={kind:o.type}));const d=e.filter(a=>a?.type==="thinking").map(a=>a.thinking).join(""),h=e.filter(a=>a?.type==="text").map(a=>a.text).join(""),S=d.startsWith(this.thinking)?d.slice(this.thinking.length):d,O=h.startsWith(this.output)?h.slice(this.output.length):h;this.thinking=d,this.output=h,this.pendingThinking+=S,this.pendingOutput+=O,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>{this.flushDeltas().catch(a=>c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:a}))},A),this.flushTimer.unref())}s.type==="message_end"&&s.message.role==="assistant"&&(await this.flushDeltas(),this.openAssistant=!1,this.block=null)}},"handleFrame");t.on("frame",s=>{this.frames=this.frames.then(()=>i(s)).catch(e=>{this.close(),c({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:e})})}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null)}),t.connect()}async flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const t=this.pendingThinking,i=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!t&&!i)return;if(await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}t&&await p(this.runId,this.nodeId,"node.thinking.delta",{delta:t}),i&&await p(this.runId,this.nodeId,"node.output_text.delta",{delta:i})}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){this.closed=!0,this.discardDeltas(),clearInterval(this.timer),u.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function J(n){return u.get(n)?.assistantMessageStartSequence??null}r(J,"openAssistantMessageStartSequence");function Y(n){return u.get(n)?.openBlock??null}r(Y,"openAssistantBlock");async function G(){const n=[...u.values()];for(const t of n)t.close();await Promise.all(n.map(t=>t.settlePoll())),await Promise.all([...f.values()].map(t=>t.catch(()=>{})))}r(G,"closeRunObserversForTests");async function E(n){return await(await l()).prepare("SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(n,n)!==void 0}r(E,"runRootExists");const f=new Map;async function v(n,t){const i=f.get(n);if(i)return i;if(u.has(n))return;const s=L(n,t).finally(()=>f.delete(n));return f.set(n,s),s}r(v,"ensureRunObserver");async function L(n,t){if(await E(t)){if(n!==t){const i=await g(n);!await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,n)&&i&&Date.now()-Date.parse(i.created)<720*60*6e4&&await p(t,n,"child.started",{child_node_id:n,kind:i.kind})}await m.start(n,t)}}r(L,"startRunObserver");async function Q(){const n=new Date(Date.now()-2592e6).toISOString(),t=await(await l()).prepare(`SELECT n.node_id, n.run_id, n.pi_pid, COALESCE(n.outcome_revision, 1) AS revision, e.body_json
2
2
  FROM node_rows n
3
3
  LEFT JOIN run_events e ON n.pi_pid IS NULL AND e.run_id = n.run_id AND e.node_id = n.node_id
4
4
  AND e.type = CASE WHEN n.node_id = n.run_id THEN 'node.settled' ELSE 'child.settled' END
5
- WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ? AND n.outcome_reason != 'parked'))`).all(s),i=new Map;for(const e of t){const o=i.get(e.node_id)??{node_id:e.node_id,run_id:e.run_id,reported:!1};e.body_json!==null&&JSON.parse(e.body_json).outcome?.revision===e.revision&&(o.reported=!0),i.set(e.node_id,o)}const n=[...i.values()].filter(e=>!e.reported);for(const e of n)try{await w(e.node_id,e.run_id),_.delete(e.node_id)}catch(o){M(e.node_id,o)}}r(G,"pollRunObservers");const _=new Map;function M(s,t){const i=t instanceof Error?t.message:String(t);_.get(s)!==i&&(_.set(s,i),h({level:"error",event:"daemon.runs.observer_failed",node_id:s,error:t}))}r(M,"reportObserverFailure");export{w as ensureRunObserver,Y as openAssistantBlock,P as openAssistantMessageStartSequence,G as pollRunObservers};
5
+ WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ? AND n.outcome_reason != 'parked'))`).all(n),i=new Map;for(const e of t){const o=i.get(e.node_id)??{node_id:e.node_id,run_id:e.run_id,reported:!1};e.body_json!==null&&JSON.parse(e.body_json).outcome?.revision===e.revision&&(o.reported=!0),i.set(e.node_id,o)}const s=[...i.values()].filter(e=>!e.reported);for(const e of s)try{await v(e.node_id,e.run_id),_.delete(e.node_id)}catch(o){M(e.node_id,o)}}r(Q,"pollRunObservers");const _=new Map;function M(n,t){const i=t instanceof Error?t.message:String(t);_.get(n)!==i&&(_.set(n,i),c({level:"error",event:"daemon.runs.observer_failed",node_id:n,error:t}))}r(M,"reportObserverFailure");export{G as closeRunObserversForTests,v as ensureRunObserver,Y as openAssistantBlock,J as openAssistantMessageStartSequence,Q as pollRunObservers};
@@ -7,7 +7,7 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
- ## 0.3.533
10
+ ## 0.3.534
11
11
 
12
12
  A cron armed by a caller with no scope limit follows the grant, and a narrowed scope pauses it.
13
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.534",
3
+ "version": "0.3.536",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -140,7 +140,7 @@
140
140
  },
141
141
  "license": "UNLICENSED",
142
142
  "dependencies": {
143
- "@north-light/identity": "0.3.534",
143
+ "@north-light/identity": "0.3.536",
144
144
  "@earendil-works/pi-agent-core": "1.1.0",
145
145
  "@earendil-works/pi-ai": "1.1.0",
146
146
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.534",
3
+ "version": "0.3.536",
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.534",
3
+ "version": "0.3.536",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.534",
9
+ "version": "0.3.536",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -24,7 +24,7 @@
24
24
  "@milkdown/preset-gfm": "^7.22.3",
25
25
  "@milkdown/prose": "^7.22.3",
26
26
  "@milkdown/utils": "^7.22.3",
27
- "@north-light/identity": "0.3.534",
27
+ "@north-light/identity": "0.3.536",
28
28
  "cron-parser": "^5.6.0",
29
29
  "esbuild": "^0.27.7",
30
30
  "jose": "^6.2.12",
@@ -12455,17 +12455,17 @@
12455
12455
  },
12456
12456
  "packages/crouter-api": {
12457
12457
  "name": "@north-light/api",
12458
- "version": "0.3.534",
12458
+ "version": "0.3.536",
12459
12459
  "license": "UNLICENSED"
12460
12460
  },
12461
12461
  "packages/crouter-env-docker": {
12462
12462
  "name": "@north-light/env-docker",
12463
- "version": "0.3.534",
12463
+ "version": "0.3.536",
12464
12464
  "license": "UNLICENSED"
12465
12465
  },
12466
12466
  "packages/crouter-identity": {
12467
12467
  "name": "@north-light/identity",
12468
- "version": "0.3.534",
12468
+ "version": "0.3.536",
12469
12469
  "license": "UNLICENSED",
12470
12470
  "dependencies": {
12471
12471
  "jose": "^6.2.1"
@@ -12473,20 +12473,20 @@
12473
12473
  },
12474
12474
  "packages/crouter-plugin": {
12475
12475
  "name": "@north-light/plugin",
12476
- "version": "0.3.534",
12476
+ "version": "0.3.536",
12477
12477
  "license": "UNLICENSED",
12478
12478
  "dependencies": {
12479
- "@north-light/api": "0.3.534",
12480
- "@north-light/identity": "0.3.534"
12479
+ "@north-light/api": "0.3.536",
12480
+ "@north-light/identity": "0.3.536"
12481
12481
  }
12482
12482
  },
12483
12483
  "packages/crouter-sdk": {
12484
12484
  "name": "@north-light/sdk",
12485
- "version": "0.3.534",
12485
+ "version": "0.3.536",
12486
12486
  "license": "UNLICENSED",
12487
12487
  "dependencies": {
12488
- "@north-light/api": "0.3.534",
12489
- "@north-light/identity": "0.3.534",
12488
+ "@north-light/api": "0.3.536",
12489
+ "@north-light/identity": "0.3.536",
12490
12490
  "jose": "^6.2.1"
12491
12491
  },
12492
12492
  "bin": {
@@ -1,44 +0,0 @@
1
- import { type FlatRow, type FoldState, type SubtreeActivity } from './nav-render.js';
2
- import type { NodeMeta } from './index.js';
3
- export { PI_MAX_WIDGET_LINES, VIEWPORT_FALLBACK_ROWS, ESC, RESET, BOLD, DIM, REVERSE, BG_ATTACHED, GREEN, RED, YELLOW, CYAN, GRAY, nodeGlyph, visibleWidth, truncate, fillWidth, fillBar, fmtTokens, tokensCell, activityCell, cycleBadge, navLabel, shortId, askBadge, liveBelowBadge, isAttached, hasBrokerViewers, fetchAsksMap, graphWidgetBudget, GRAPH_HINT, type FlatRow, type FoldState, type SubtreeActivity, } from './nav-render.js';
4
- /** First manager (by created) — the UP step for the ancestry spine. */
5
- export declare function managerOf(id: string): Promise<string | undefined>;
6
- /** A kind:'human' node is a control-plane ASK (a page on the human's
7
- * screen), NOT a pi conversation — it has no session, so focusing/reviving it
8
- * boots a confused blank "you have been revived" pi. Its pending-ask signal
9
- * already rides the ⚑ badge on the ASKING node (attention.ts follows the
10
- * bridge node's parent relation), so the row carries no signal of its
11
- * own. Drop it from every navigable list (the tree, BASE reports, child counts,
12
- * subtree expansion) so it can never be selected. */
13
- export declare function isHumanAsk(id: string): Promise<boolean>;
14
- /** A node's direct children that are navigable conversations — human-ask nodes
15
- * dropped. The one place the nav chrome enumerates children. */
16
- export declare function convoChildIds(id: string): Promise<string[]>;
17
- /** Live reports (active|idle) of a node — the DOWN set in BASE. */
18
- export declare function liveReports(id: string): Promise<string[]>;
19
- /** Direct navigable children — used for the ⤳ badge (human-ask nodes excluded,
20
- * so the count matches what the tree actually shows). */
21
- export declare function childCount(id: string): Promise<number>;
22
- /** Climb first-manager edges from `self` to the ancestry root (cycle-guarded). */
23
- export declare function climbRoot(self: string): Promise<string>;
24
- /** Space-joined ids of a node's subtree (cursor-relative {subtree} var). */
25
- export declare function subtreeIds(root: string): Promise<string[]>;
26
- /** ⤳M direct-children badge — the single child-count signal, shown on any row
27
- * with navigable children (folded or not). In GRAPH the ▸ caret separately marks
28
- * a collapsed row, so this stays a pure count and never doubles as a fold badge. */
29
- export declare function childBadge(node: NodeMeta | null): Promise<string>;
30
- /** Direct children, live-first — the sibling order used both when flattening
31
- * the tree and when stepping into a subtree (`l`). Array.sort is stable, so
32
- * equal-status siblings keep their creation order. */
33
- export declare function sortedChildIds(id: string): Promise<string[]>;
34
- export declare function computeSubtreeActivity(root: string, self: string): Promise<SubtreeActivity>;
35
- /** Fold policy alone — thin wrapper over computeSubtreeActivity for the keypress
36
- * path (buildGraphModel without a precomputed set). The render path computes the
37
- * activity once and threads `expand` in, so it never recomputes here. */
38
- export declare function computeDefaultExpanded(root: string, self: string): Promise<Set<string>>;
39
- export declare function buildGraphModel(self: string, folds: FoldState, expand?: ReadonlySet<string>): Promise<FlatRow[]>;
40
- /** Render one GRAPH row. CURSOR (selected) → reverse-video bar; an ATTACHED
41
- * (human-watched) node → a coloured background bar; SELF → bold name. The
42
- * cursor outranks the attached tint when both land on the same row. The
43
- * overlay-aware glyph alone carries the live signal (status / ⟳ / ⚠). */
44
- export declare function renderGraphRow(r: FlatRow, isCursor: boolean, focused: ReadonlySet<string>, activeBelow: ReadonlyMap<string, number>, asks: Record<string, number>): Promise<string>;
@@ -1 +0,0 @@
1
- var S=Object.defineProperty;var n=(t,a)=>S(t,"name",{value:a,configurable:!0});import{getNode as v,subscribersOf as R,subscriptionsOf as I}from"./index.js";import{faultSummary as C}from"./status-glyph.js";import{statusRank as _}from"./node-order.js";import{nodeGlyph as G,navLabel as O,shortId as T,tokensCell as D,activityCell as W,cycleBadge as L,askBadge as M,liveBelowBadge as N,truncate as H,fillBar as k,fillWidth as B,isAttached as K,BOLD as P,DIM as E,RESET as p,REVERSE as V,BG_ATTACHED as Y}from"./nav-render.js";import{filterAsync as b,mapAsync as F}from"../async-array.js";import{PI_MAX_WIDGET_LINES as wt,VIEWPORT_FALLBACK_ROWS as pt,ESC as yt,RESET as $t,BOLD as mt,DIM as vt,REVERSE as Et,BG_ATTACHED as xt,GREEN as gt,RED as kt,YELLOW as Bt,CYAN as bt,GRAY as At,nodeGlyph as St,visibleWidth as Rt,truncate as It,fillWidth as Ct,fillBar as _t,fmtTokens as Gt,tokensCell as Ot,activityCell as Tt,cycleBadge as Dt,navLabel as Wt,shortId as Lt,askBadge as Mt,liveBelowBadge as Nt,isAttached as Ht,hasBrokerViewers as Kt,fetchAsksMap as Pt,graphWidgetBudget as Vt,GRAPH_HINT as Yt}from"./nav-render.js";async function q(t){try{return await I(t)}catch{return[]}}n(q,"subsOf");async function X(t){try{return await R(t)}catch{return[]}}n(X,"mgrsOf");async function j(t){return(await X(t))[0]?.node_id}n(j,"managerOf");async function z(t){return(await v(t))?.kind==="human"}n(z,"isHumanAsk");async function y(t){return await b((await q(t)).map(a=>a.node_id),async a=>!await z(a))}n(y,"convoChildIds");async function it(t){return await b(await y(t),async a=>{const s=(await v(a))?.status;return s==="active"||s==="idle"})}n(it,"liveReports");async function J(t){return(await y(t)).length}n(J,"childCount");async function Q(t){let a=t;const s=new Set([a]);for(;;){const o=await j(a);if(o===void 0||s.has(o))break;s.add(o),a=o}return a}n(Q,"climbRoot");async function lt(t){const a=[],s=new Set([t]),o=await y(t);for(;o.length>0;){const i=o.shift();if(!s.has(i)){s.add(i),a.push(i);for(const l of await y(i))s.has(l)||o.push(l)}}return a}n(lt,"subtreeIds");async function U(t){if(t===null)return"";const a=await J(t.node_id);return a>0?` ${E}\u2933${a}${p}`:""}n(U,"childBadge");async function Z(t){return(await F(await y(t),async a=>({cid:a,rank:_((await v(a))?.status)}))).sort((a,s)=>a.rank-s.rank).map(({cid:a})=>a)}n(Z,"sortedChildIds");async function tt(t,a){const s=new Set,o=new Map,i=new Set,l=n(async e=>{const u=(await v(e))?.status==="active";if(i.has(e))return{active:u?1:0,reveal:u||e===a};i.add(e);let d=0,c=!1;for(const h of await y(e)){const f=await l(h);d+=f.active,f.reveal&&(c=!0)}return o.set(e,d),c&&s.add(e),{active:d+(u?1:0),reveal:c||u||e===a}},"visit");return await l(t),{expand:s,activeBelow:o}}n(tt,"computeSubtreeActivity");async function at(t,a){return(await tt(t,a)).expand}n(at,"computeDefaultExpanded");async function ut(t,a,s){const o=await Q(t),i=s??await at(o,t),l=n(c=>a.userExpanded.has(c)?!1:a.userCollapsed.has(c)?!0:!i.has(c),"isFolded"),e=[],u=new Set,d=n(async(c,h,f,$)=>{if(u.has(c)){const r=f?"":$?"\u2514\u2500 ":"\u251C\u2500 ";e.push({id:c,hasKids:!1,isSelf:c===t,branch:h+r,cycle:!0,collapsed:!1});return}u.add(c);const w=await Z(c),m=l(c),x=f?"":$?"\u2514\u2500 ":"\u251C\u2500 ";if(e.push({id:c,hasKids:w.length>0,isSelf:c===t,branch:h+x,cycle:!1,collapsed:m}),m)return;const g=f?"":h+($?" ":"\u2502 ");for(let r=0;r<w.length;r++)await d(w[r],g,!1,r===w.length-1)},"walk");return await d(o,"",!0,!0),e}n(ut,"buildGraphModel");async function dt(t,a,s,o,i){const l=n((r,A)=>a?k(r,B(),V):A?k(r,B(),Y):H(r),"wrap");if(t.cycle){const r=`${t.branch} ${E}\u21BA ${T(t.id)}${p}`;return l(r,!1)}const e=await v(t.id),u=G(e),d=O(e,t.id),c=t.isSelf?`${P}${d}${p}`:d,h=`${E}${e?.kind??""}${p}`,f=`${E}${D(e)}${p}`,$=t.hasKids&&t.collapsed,w=!a&&$?`${E}\u25B8${p} `:" ",m=e?.fault??null,x=m!==null?` \xB7 ${C(m)}`:"",g=`${t.branch}${w}${u} ${c} ${h} ${f}${L(e)}${await U(e)}${N(e,o)}${M(t.id,i)}${W(e)}${x}`;return l(g,K(t.id,e,s))}n(dt,"renderGraphRow");export{xt as BG_ATTACHED,mt as BOLD,bt as CYAN,vt as DIM,yt as ESC,Yt as GRAPH_HINT,At as GRAY,gt as GREEN,wt as PI_MAX_WIDGET_LINES,kt as RED,$t as RESET,Et as REVERSE,pt as VIEWPORT_FALLBACK_ROWS,Bt as YELLOW,Tt as activityCell,Mt as askBadge,ut as buildGraphModel,U as childBadge,J as childCount,Q as climbRoot,at as computeDefaultExpanded,tt as computeSubtreeActivity,y as convoChildIds,Dt as cycleBadge,Pt as fetchAsksMap,_t as fillBar,Ct as fillWidth,Gt as fmtTokens,Vt as graphWidgetBudget,Kt as hasBrokerViewers,Ht as isAttached,z as isHumanAsk,Nt as liveBelowBadge,it as liveReports,j as managerOf,Wt as navLabel,St as nodeGlyph,dt as renderGraphRow,Lt as shortId,Z as sortedChildIds,lt as subtreeIds,Ot as tokensCell,It as truncate,Rt as visibleWidth};