@north-light/cli 0.3.534 → 0.3.535
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/dto/nodes.d.ts +2 -0
- package/dist/builtin-memory/crouter-sdk/release-notes.md +1 -1
- package/dist/clients/attach/viewer.js +2 -2
- package/dist/commands/api-client.d.ts +1 -0
- package/dist/commands/api-client.js +1 -1
- package/dist/commands/node/inspect.js +9 -9
- package/dist/core/bash-jobs.d.ts +4 -0
- package/dist/core/bash-jobs.js +8 -8
- package/dist/core/canvas/canvas.d.ts +16 -2
- package/dist/core/canvas/canvas.js +20 -20
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/remote-canvas-source.d.ts +1 -0
- package/dist/core/canvas/remote-canvas-source.js +1 -1
- package/dist/core/canvas/source.d.ts +4 -0
- package/dist/core/canvas/source.js +1 -1
- package/dist/core/canvas/tree.d.ts +2 -0
- package/dist/core/canvas/tree.js +12 -5
- package/dist/core/graph/watches.d.ts +0 -2
- package/dist/core/graph/watches.js +7 -12
- package/dist/core/runtime/broker/fault-retry.d.ts +6 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.d.ts +6 -0
- package/dist/daemon/reconcilers/bash-deadline.js +3 -2
- package/dist/daemon/runs/observer.d.ts +2 -0
- package/dist/daemon/runs/observer.js +2 -2
- package/docs/sdk/release-notes.md +1 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
- package/dist/core/canvas/nav-model.d.ts +0 -44
- package/dist/core/canvas/nav-model.js +0 -1
package/dist/api/dto/nodes.d.ts
CHANGED
|
@@ -273,6 +273,8 @@ export interface ListNodesQuery {
|
|
|
273
273
|
top_level?: boolean;
|
|
274
274
|
/** Restrict to the subtree under this node. */
|
|
275
275
|
under?: NodeIdDTO;
|
|
276
|
+
/** With `under`: also return the node itself and the human ask nodes below it, which the plain subtree leaves out. */
|
|
277
|
+
under_inclusive?: boolean;
|
|
276
278
|
/** Only nodes with a dangling/hanging manager edge. */
|
|
277
279
|
hanging?: boolean;
|
|
278
280
|
/** Opt into richer per-node payloads that require filesystem reads. */
|
|
@@ -9,7 +9,7 @@ when-and-why-to-read: When you need Release notes, this knowledge should be read
|
|
|
9
9
|
|
|
10
10
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
11
11
|
|
|
12
|
-
## 0.3.
|
|
12
|
+
## 0.3.534
|
|
13
13
|
|
|
14
14
|
A cron armed by a caller with no scope limit follows the grant, and a narrowed scope pauses it.
|
|
15
15
|
|
|
@@ -1625,10 +1625,10 @@ ${i}`}function Wun(t,e,n){return t.children.filter(i=>Cx(i)&&i.tag==="li").map((
|
|
|
1625
1625
|
`).replace(/[ \t]+\n/g,`
|
|
1626
1626
|
`).trim()}};function pN(t){let e=new Uze,n=[],r=[],i=[],o=0,s=!1,a=!1,c=0,u=()=>" ".repeat(Math.max(0,n.length-1));for(let l of rKr(t)){if(l.kind==="text"){if(i.length>0)continue;if(o>0){e.write(l.text);continue}let m=qun(l.text).replace(/\s+/g," ");if(m.trim()===""){/\s/.test(m)&&e.write(" ");continue}e.write(Hun(m));continue}let{name:d,closing:p,attrs:h}=l;if(Y9r.has(d)){if(p){let m=i.lastIndexOf(d);m>=0&&(i.length=m)}else l.selfClosing||i.push(d);continue}if(i.length>0)continue;let f=/^h([1-6])$/.exec(d);if(f!==null){e.block(),p||e.write(`${"#".repeat(Number(f[1]))} `);continue}if(d==="pre"){p?(o=Math.max(0,o-1),e.line(),e.write("```"),e.block()):(e.block(),e.write("```\n"),o++);continue}if(d==="br"){e.line();continue}if(d==="hr"){e.block(),e.write("---"),e.block();continue}if(d==="ul"||d==="ol"){p?n.pop():(e.block(),n.push({ordered:d==="ol",index:0})),p&&e.block();continue}if(d==="li"){if(p)continue;let m=n[n.length-1];e.line(),m===void 0?e.write("- "):(m.index++,e.write(`${u()}${m.ordered?`${m.index}. `:"- "}`));continue}if(d==="dt"||d==="dd"){e.line(),p||e.write(d==="dt"?"":" ");continue}if(d==="tr"){p?(e.write(c>0?" |":""),a&&c>0&&(e.line(),e.write(`|${" --- |".repeat(c)}`)),e.line()):(e.line(),a=!1,c=0);continue}if(d==="td"||d==="th"){if(p){if(!s)continue;s=!1,e.write(e.pop().replace(/\s+/g," ").trim())}else d==="th"&&(a=!0),c++,e.write(c===1?"| ":" | "),e.push(),s=!0;continue}if(d==="a"){if(p){if(r.length===0)continue;let y=r.pop();if(y===null)continue;let w=e.pop().replace(/\s+/g," ").trim();w!==""&&e.write(`[${w}](${y})`);continue}let m=h.get("href"),g=m!==void 0&&m!==""&&!m.startsWith("#");r.push(g?m:null),g&&e.push();continue}if(d==="code"&&o===0){e.write("`");continue}if(d==="strong"||d==="b"){e.write("**");continue}if(d==="em"||d==="i"){e.write("*");continue}if(d==="img"){let m=h.get("alt");m!==void 0&&m!==""&&e.write(Hun(m));continue}if(d==="blockquote"){e.block(),p||e.write("> ");continue}if(J9r.has(d)&&!X9r.has(d)){e.block();continue}}return e.done()}import{closeSync as wYr,fstatSync as bYr,openSync as EYr,readSync as vYr}from"node:fs";import{join as SYr}from"node:path";import{gunzipSync as _Yr}from"node:zlib";var NTs=256*1024;var hf=class extends Lp{payload;constructor(e,n=Mu.USAGE){super(e.error,e.message,n,{...e}),this.name="InputError",this.payload=e}};function iKr(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}var oKr={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"};function Gun(t,e,n={}){if(t.code==="daemon_restarting")return new Lp("daemon_restarting",t.message,Mu.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(t.code==="layout_migration_required")return new Lp("layout_migration_required",t.message,Mu.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(t.code==="daemon_unavailable")return new Lp("daemon_unavailable",t.message,Mu.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});let r=t.details,i=sKr(t,r,n.providerCall===!0);if(t.status===503||n.providerCall===!0&&t.status===504&&i.code!==void 0){let a=i.code??t.code,c={next:i.next??e??"Retry the command; if it persists, inspect the unavailable service named in the error."};return i.details!==void 0&&(c.details=i.details),i.code!==void 0&&(i.field!==void 0&&(c.field=i.field),i.received!==void 0&&(c.received=i.received),i.retryAfterS!==void 0&&(c.retry_after_s=i.retryAfterS)),new Lp(a,t.message,Mu.NETWORK,c)}let o=Array.isArray(r?.violations)?r.violations.map(a=>`${String(a.field)} ${String(a.problem)}${a.received!==void 0?` (received ${JSON.stringify(a.received)})`:""}`):[],s=r&&typeof r.error=="string"&&typeof r.message=="string"&&typeof r.next=="string"?r:{error:i.code??oKr[t.status]??t.code,...i.field!==void 0?{field:i.field}:{},...i.received!==void 0?{received:i.received}:{},...i.retryAfterS!==void 0?{retry_after_s:i.retryAfterS}:{},...i.details!==void 0?{details:i.details}:{},message:o.length>0?`${t.message}: ${o.join("; ")}`:t.message.trim()!==""?t.message:`request refused (HTTP ${t.status}, ${t.code}) with no message`,next:i.next??e??(i.retryAfterS!==void 0?`Wait ${i.retryAfterS}s, then retry; do not retry sooner.`:t.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":t.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new hf(s,aKr(s.error,t.status))}function sKr(t,e,n){let r=o=>typeof o=="string"&&/^[a-z][a-z0-9_]*$/.test(o);if(n&&t.origin!==void 0&&t.origin!=="provider"&&r(t.code)){let o={code:t.code};return(t.status===503||t.status===504)&&(o.next=t.retryable===!0?"Retry the command; if it persists, the machine or service named in the error is unavailable.":"Read the error before retrying: the action may already have run."),iKr(t.details)&&(o.details=t.details),t.param!==void 0&&(o.field=t.param),typeof t.retryAfterS=="number"&&(o.retryAfterS=t.retryAfterS),o}if(t.origin!=="provider"||e===void 0||e===null||typeof e!="object")return{};let i={};return typeof e.status=="number"&&r(e.code)&&(i.code=e.code),typeof e.next=="string"&&e.next.trim()!==""&&(i.next=e.next),typeof e.field=="string"&&e.field!==""?i.field=e.field:t.param!==void 0&&(i.field=t.param),e.received!==void 0&&e.received!==null&&(i.received=e.received),typeof t.retryAfterS=="number"&&(i.retryAfterS=t.retryAfterS),i}function aKr(t,e){return t==="not_found"||e===404?Mu.NOT_FOUND:t==="ambiguous"?Mu.AMBIGUOUS:Mu.USAGE}import{spawn as QKr,execFileSync as cRs}from"node:child_process";import{createRequire as WKr}from"node:module";import{dirname as Hze,join as mN}from"node:path";import{fileURLToPath as HKr,pathToFileURL as qze}from"node:url";import{existsSync as aln,lstatSync as qKr,mkdirSync as GKr,openSync as cln,closeSync as uln,fstatSync as lln,readSync as jKr}from"node:fs";import{copyFileSync as cKr,mkdirSync as Mle,existsSync as Rle,readFileSync as uKr,writeFileSync as Vun,chmodSync as lKr,readdirSync as dKr,renameSync as yT,realpathSync as ij,unlinkSync as pKr,rmSync as hKr,linkSync as jun}from"node:fs";import{homedir as Kun}from"node:os";import{dirname as Yun,join as us}from"node:path";import{execFile as fKr,spawn as mKr,spawnSync as Dle}from"node:child_process";var Ble="crouter";function fN(){return us(Kun(),sS,"host")}function Jun(){return us(fN(),Ble)}function Wze(){return us(fN(),".source.json")}function gKr(t){let e=Yun(t);for(let n of[e,us(e,"..","lib")]){if(!Rle(n))continue;let r=dKr(n).find(i=>i.startsWith("libnode.")&&i.endsWith(".dylib"));if(r!==void 0)return us(n,r)}return null}function zun(t,e,n){let r=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;cKr(t,r),n!==void 0&&lKr(r,n),yT(r,e)}function Qze(t=Wze()){try{return JSON.parse(uKr(t,"utf8"))}catch{return null}}var AKr=3e4;function yKr(t){let e=us(Kun(),sS),n=us(e,"host.lock");return Mle(e,{recursive:!0}),Kc(n,t,{timeoutMs:AKr,timeoutError:()=>new Error(`timed out waiting for branded host lock: ${n}`)})}function xKr(t={}){let e=t.configured?.trim();return e?[e]:[t.discovered?.trim()||"-"]}function wKr(){if(process.platform!=="darwin")return null;let t=Dle("security",["find-identity","-v","-p","codesigning"],{stdio:["pipe","pipe","pipe"]});if(t.status!==0)return null;let n=(t.stdout??"").toString().split(`
|
|
1627
1627
|
`).map(r=>r.match(/\)\s+[A-Fa-f0-9]{40}\s+"([^"]+)"/)?.[1]??null).filter(r=>r!==null);return n.find(r=>r.startsWith("Apple Development:"))??n.find(r=>r.startsWith("Developer ID Application:"))??n[0]??null}function bKr(t,e){let n=Dle("codesign",["-s",e,"--deep","--force",t],{stdio:["pipe","pipe","pipe"]});return{ok:n.status===0,stderr:(n.stderr??"").toString().trim()}}function EKr(t){if(process.platform!=="darwin")return;let e=xKr({configured:process.env.CRTR_CODESIGN_IDENTITY,discovered:wKr()}),n="";for(let r of e){let i=bKr(t,r);if(i.ok)return;n=i.stderr}throw n&&!n.includes("valid on disk")&&Cf({event:"host.codesign.failed",level:"debug",error:n}),new Error(`codesign failed for ${t}: ${n||"codesign did not exit successfully"}`)}function vKr(t,e,n=EKr){e!==null&&n(e),n(t)}function hN(t,e=5e3){try{return Dle(t,["-e",""],{stdio:"ignore",timeout:e}).status===0}catch{return!1}}function SKr(t={}){return yKr(()=>{let e=fN(),n=Jun(),r=ij(t.execPath??process.execPath);if(Rle(n)&&ij(n)===r){if(hN(n))return n;let h=kKr();if(h===null)throw new Error(`branded host cannot start and no working node was found to rebuild it from: ${n}`);r=h}let i=Qze(),o=gKr(r),s=o!==null?o.split("/").pop():null,a=h=>Rle(n)&&h!==null&&h.version===2&&(h.libnode===null||Rle(us(e,h.libnode))),c=h=>a(h)&&h.source===r&&h.libnode===s;if(c(i)&&hN(n))return n;Mle(e,{recursive:!0});let u=us(e,`.reconcile.${process.pid}.${Math.random().toString(36).slice(2)}`),l=us(u,"previous");Mle(u);let d=!1,p=a(i)&&hN(n);try{let h=us(u,Ble),f=s!==null?us(u,s):null;if(o!==null&&f!==null&&zun(o,f),zun(r,h,493),vKr(h,f),!hN(h))throw new Error(`rebuilt branded host failed its startup check: ${h}`);if(p&&CKr(l,n,i),d=!0,f!==null&&yT(f,us(e,s)),yT(h,n),_Kr({version:2,source:r,libnode:s}),!c(Qze())||!hN(n))throw new Error(`published branded host tuple failed validation: ${n}`);if(i?.libnode!=null&&i.libnode!==s)try{pKr(us(e,i.libnode))}catch{}return n}catch(h){throw d&&p&&IKr(l,n,i),h}finally{hKr(u,{recursive:!0,force:!0})}})}function _Kr(t){let e=Wze(),n=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;Vun(n,JSON.stringify(t)),yT(n,e)}function CKr(t,e,n){Mle(t),jun(e,us(t,Ble)),n.libnode!==null&&jun(us(fN(),n.libnode),us(t,n.libnode)),Vun(us(t,".source.json"),JSON.stringify(n))}function IKr(t,e,n){if(n.libnode!==null&&yT(us(t,n.libnode),us(fN(),n.libnode)),yT(us(t,Ble),e),yT(us(t,".source.json"),Wze()),!hN(e))throw new Error(`failed to restore previous branded host tuple: ${e}`)}function Ple(t){try{let e=ij(fN());return Yun(ij(t))===e}catch{return!1}}function Xun(){let t=["/opt/homebrew/bin/node","/usr/local/bin/node"];Ple(process.execPath)||t.push(process.execPath);for(let i of(process.env.PATH??"").split(":"))i!==""&&t.push(us(i,"node"));let e=Qze();e!==null&&typeof e.source=="string"&&t.push(e.source);let n=new Set,r=[];for(let i of t){let o;try{o=ij(i)}catch{continue}n.has(o)||Ple(o)||(n.add(o),r.push(o))}return r}var Zun=["-p","process.versions.modules"];function eln(t){return t!==null&&t.trim()===process.versions.modules}function kKr(){for(let t of Xun())try{let e=Dle(t,Zun,{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]});if(e.status===0&&eln(e.stdout))return t}catch{}return null}function tln(t,e,n){return new Promise(r=>{try{fKr(t,e,{encoding:"utf8",timeout:n},(i,o)=>r(i===null?o:null))}catch{r(null)}})}async function TKr(){for(let t of Xun())if(eln(await tln(t,Zun,5e3)))return t;return null}var RKr=15e3,MKr=6e4,Cd={checkedAt:0,fallback:null,probing:null,lastHealAt:0};function PKr(t){if(import.meta.url.endsWith(".ts"))return;let e=Date.now();if(!(e-Cd.lastHealAt<MKr)){Cd.lastHealAt=e;try{let n=`import(${JSON.stringify(import.meta.url)}).then((m) => m.ensureBrandedHost())`,r=mKr(t,["--input-type=module","-e",n],{detached:!0,stdio:"ignore"});r.on("error",()=>{}),r.unref()}catch{}}}function DKr(t){return Cd.probing!==null||(Cd.probing=(async()=>{try{if(await tln(t,["-e",""],5e3)!==null){Cd.fallback=null;return}let e=await TKr();e!==Cd.fallback&&e!==null&&Cf({event:"host.fallback.node",level:"warn",fields:{host:t,node:e}}),Cd.fallback=e,e!==null&&PKr(e)}finally{Cd.checkedAt=Date.now(),Cd.probing=null}})()),Cd.probing}function BKr(t=process.execPath){return Ple(t)?(Date.now()-Cd.checkedAt>RKr&&Cd.probing===null&&DKr(t),Cd.fallback??t):t}function nln(){if(process.env.CRTR_BRANDED_HOST==="0"||process.platform!=="darwin"||import.meta.url.endsWith(".ts"))return process.execPath;if(Ple(process.execPath))return BKr();try{return SKr()}catch(t){return Cf({event:"host.fallback.node",level:"warn",error:t,fields:{host:Jun(),node:process.execPath}}),process.execPath}}import{existsSync as LKr,readFileSync as OKr}from"node:fs";import{join as NKr}from"node:path";function $Kr(){return K7e()??NKr(Na(),"crtrd.pid")}function xT(){let t=$Kr();if(!LKr(t))return null;let e=OKr(t,"utf8").trim(),n=Number(e);return Number.isFinite(n)&&n>0?n:null}function rln(){let t=xT();return t!==null&&Rf(t)}import{join as FKr}from"node:path";function UKr(){return FKr(Na(),"join.lock")}function Lle(){let t=AR(UKr());return t!==null&&Rf(t)?t:null}function iln(){return Lle()!==null}function oln(t){return new hf({error:"join_in_progress",message:t===null?"`crtr sys join` is running and holds the daemon down until it finishes":`\`crtr sys join\` (pid ${t}) is running and holds the daemon down until it finishes`,next:"Wait for the join to finish; it starts the daemon again itself. If it is stuck, `crtr sys daemon start --force`."})}async function sln(t,e=100){let n=Date.now()+t;for(;;){let r=Lle();if(r===null||r===process.pid||Date.now()>=n)return;await new Promise(i=>setTimeout(i,e))}}var zKr=["CRTR_NODE_ID","CRTR_KIND","CRTR_MODE","CRTR_LIFECYCLE","CRTR_NODE_CWD","CRTR_CONTEXT_DIR","CRTR_CYCLES","CRTR_PROFILE_ID","CRTR_PARENT_NODE_ID","CRTR_FRONT_DOOR","TMUX","TMUX_PANE","CRTR_BROKER_ENGINE","CRTR_PI_BINARY","NODE_OPTIONS"];function VKr(){let t={...process.env};for(let e of zKr)delete t[e];return t}function KKr(){for(let t=Hze(HKr(import.meta.url));;t=Hze(t)){if(aln(mN(t,"bin","runtime-generation-manifest.mjs")))return t;if(Hze(t)===t)throw new Error(`cannot locate the crouter generation root from ${import.meta.url}`)}}async function YKr(){let t=KKr(),e=qze(mN(t,"bin","runtime-generation-manifest.mjs")).href,{runtimeHome:n}=await import(e);try{qKr(mN(n(),"selected"))}catch(s){if(s.code!=="ENOENT")throw s;return["--conditions","crtr-src","--import",qze(WKr(import.meta.url).resolve("tsx/esm")).href,mN(t,"src","daemon","crtrd-cli.ts")]}let r=qze(mN(t,"bin","runtime-selector.mjs")).href,{tryResolveRuntime:i}=await import(r),o=i("daemon");if(!o.ok)throw new Error(`cannot resolve the selected runtime generation's daemon entry: ${o.error}`);return[o.runtime.entryPath]}var JKr=3*6e4,dln=2e4,zze=10,jze=1e3;async function Vze(t=jze){let e=Math.min(t,jze);return Sy({autostart:!1,timeoutMs:e}).probeHealthz(e)}function XKr(t){let e=t instanceof Error?t.message:String(t);if(typeof t!="object"||t===null)return e;let n=t.code,r=t.cause,i=typeof n=="string"?n:r?.code;return typeof i=="string"&&!e.includes(i)?`${e}: ${i}`:e}async function ZKr(t=jze){let e=await Vze(t);if(e.startup_phase==="blocked"){let n=xT()??process.pid;throw new gN(n,e.startup_blocked??"daemon startup is blocked")}if(!e.ok)throw new Error(e.startup_blocked??"crtrd health check reported not ready")}function Kze(t){return new Promise(e=>{setTimeout(e,t)})}var sj=class extends Error{stderrTail;constructor(e,n){super(n===""?e:`${e}
|
|
1628
|
-
${n}`),this.name="DaemonExitedBeforeReadyError",this.stderrTail=n}},gN=class extends Error{constructor(e,n){super(`daemon ${e} is running but normal startup is blocked: ${n}`),this.name="DaemonStartupBlockedError"}},aj=class extends Error{constructor(e,n){super(n===void 0?`daemon ${e} is serving but did not report the prepared startup phase`:`daemon ${e} reported startup phase ${n}, not prepared`),this.name="DaemonNotPreparedError"}};async function eYr(t,e=3e5,n={},r="ready"){let i=n.readPidfile??xT,o=n.isPidAlive??Rf,s=n.childExited,a=n.isDaemonServing,c=n.probeDaemonServing??(async f=>{if(a!==void 0){if(await a())return;throw new Error("crtrd health check reported not ready")}await ZKr(f)}),u=n.probeDaemonHealth??Vze,l=n.sleepMs??Kze,d=n.now??Date.now,p=null,h=null;return await X3({windowMs:e,pollIntervalMs:zze,now:d,sleep:l,retry:f=>f!==h,probe:async f=>{let m=i();if(m===null||!o(m)){let y=s?.();throw y!=null&&(y.signal!==null?h=new sj(`daemon ${t} exited before becoming ready (by ${y.signal})`,n.childStderrTail?.()??""):y.code!==0&&(h=new sj(`daemon ${t} exited before becoming ready (with exit code ${y.code??"?"})`,n.childStderrTail?.()??"")),h!==null)?h:new Error(`daemon ${t} has no live pidfile owner`)}if(r==="ready"){try{await c(f)}catch(y){throw y instanceof gN&&(h=y),y}p=m;return}let g=await u(f);if(g.startup_phase==="prepared"){p=m;return}throw g.startup_phase==="blocked"?(h=new gN(m,g.startup_blocked??"on-disk migration is blocked"),h):g.startup_phase==="ready"?(h=new aj(m,g.startup_phase),h):new Error(`daemon ${m} is ${g.startup_phase??"not reporting a startup phase"}; waiting for prepared`)}}),p===t?null:p}async function tYr(t,e=dln,n={}){let r=n.readPidfile??xT,i=n.isPidAlive??Rf,o=n.sleepMs??Kze,s=n.now??Date.now,a=s()+e;for(;s()<=a;){if(!i(t)&&r()!==t)return;await o(zze)}throw new Error(`daemon ${t} did not exit and release its pidfile within ${e}ms`)}var nYr=2e3,rYr=5e3;async function iYr(t,e=dln,n={}){let r=n.isPidAlive??Rf,i=n.sleepMs??Kze,o=n.now??Date.now;try{process.kill(t,"SIGTERM")}catch{}try{return await tYr(t,e,n),"terminated"}catch{}try{process.kill(t,"SIGKILL")}catch{}let s=o()+nYr;for(;o()<=s;){if(!r(t))return"killed";await i(zze)}throw new Error(`daemon ${t} survived both SIGTERM and SIGKILL`)}function oYr(t,e,n=2048){let r;try{r=cln(t,"r");let{size:i}=lln(r),o=Math.max(e,i-n),s=i-o;if(s<=0)return"";let a=Buffer.alloc(s);return jKr(r,a,0,s,o),a.toString("utf8").trim()}catch{return""}finally{if(r!==void 0)try{uln(r)}catch{}}}async function sYr(t={}){if(process.platform==="linux"&&aln("/run/crtr/launcher.sock")&&!Rf(xT()??-1))throw new Error("crtrd is managed by the root launcher; it cannot self-daemonize");let e=t.targetPhase??"ready",n=xT();if(n!==null&&Rf(n))try{let p=await Vze();if(e==="prepared"){if(p.startup_phase==="prepared")return{started:!1,existing_pid:n,startup_phase:p.startup_phase};throw new aj(n,p.startup_phase)}return p.ok?{started:!1,existing_pid:n,...p.startup_phase===void 0?{}:{startup_phase:p.startup_phase}}:{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:p.startup_blocked??"crtrd health check reported not ready",...p.startup_phase===void 0?{}:{startup_phase:p.startup_phase}}}catch(p){if(p instanceof aj)throw p;return{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:XKr(p)}}GKr(Na(),{recursive:!0});let r=await YKr();t.waitForJoinLock===!0&&await sln(JKr);let i=Lle();if(i!==null&&i!==process.pid&&t.ignoreJoinLock!==!0)throw oln(i);let o=mN(Na(),"crtrd.err"),s=cln(o,"a"),a=(()=>{try{return lln(s).size}catch{return 0}})();Y3()===void 0&&sYe();let c=QKr(nln(),[...r,"--canvas-home",Na(),...e==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",s,s],env:VKr()});uln(s);let u=c.pid;if(u===void 0)throw new Error("daemon spawn did not return a pid");let l=null;c.once("exit",(p,h)=>{l={code:p,signal:h}}),c.unref();let d;try{d=await eYr(u,3e5,{childExited:()=>l,childStderrTail:()=>oYr(o,a)},e)}catch(p){let h=AR(nYe())===u;if(l===null&&!h&&!(p instanceof gN))try{await iYr(u,rYr)}catch{}throw p}return d!==null?{started:!1,existing_pid:d,startup_phase:e}:{started:!0,pid:u,startup_phase:e}}function $le(){return Y7e()||process.argv.includes("--no-autostart")}var aYr=5e3,cYr=6e4,Gze=!1,oj,Ole=0,Nle=0;function uYr(t){return Math.min(aYr*2**(t-1),cYr)}function lYr(){oj=void 0,Ole=0,Nle=0}function pln(){return oj}function hln(t={}){let e=t.isDaemonRunning??rln,n=t.spawnDaemon??sYr,r=t.now??Date.now;if(!$le()&&!iln()&&!Gze&&!(r()<Nle)){if(e()){lYr();return}oj=void 0,Gze=!0,n().then(()=>{oj=void 0,Ole=0,Nle=0},i=>{i instanceof sj&&(oj=i.message),Ole+=1,Nle=r()+uYr(Ole)}).finally(()=>{Gze=!1})}}import{existsSync as dYr,readFileSync as pYr,statSync as IRs}from"node:fs";import{join as hYr}from"node:path";var fYr="secrets.json";function mYr(t){return hYr(t===Yc()?vy():t,fYr)}function gYr(t){let e=ig(t);if(!e)return{relayTokens:{}};let n=mYr(e);if(!dYr(n))return{relayTokens:{}};try{let r=JSON.parse(pYr(n,"utf8")),i=Array.isArray(r.scopedApiTokens)?r.scopedApiTokens.filter(o=>typeof o?.token=="string"&&o.token!==""&&typeof o.grantee=="string"&&/^app:[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(o.grantee)&&Array.isArray(o.scopes)&&typeof o.created=="string"):[];return{relayTokens:r.relayTokens??{},...typeof r.apiToken=="string"&&r.apiToken!==""?{apiToken:r.apiToken}:{},...i.length>0?{scopedApiTokens:i}:{}}}catch{return{relayTokens:{}}}}function fln(t,e){return gYr(e).relayTokens[t]}function Fle(t,e="user"){let n=zc(e),r=n.remoteCanvas.targets[t];if(r===void 0){let o=Object.keys(n.remoteCanvas.targets);throw lS(`no remote canvas target named '${t}'`+(o.length>0?` \u2014 configured: ${o.join(", ")}`:" \u2014 none configured yet")+`. Add one with \`crtr canvas config add ${t} --preview <url> --relay-token -\`.`)}let i=fln(r.relayTokenRef,e);if(i===void 0||i==="")throw lS(`target '${t}' has no stored relay token \u2014 add it with \`crtr canvas config add ${t} --relay-token -\`.`);return{previewEndpoint:r.previewEndpoint,relayToken:i}}function mln(t,e,n=5e3){let r=/^[\x20-\x7e]+$/.test(e);return async function(o,s){if(!r)return{ok:!1,stdout:"",stderr:"remote source: invalid stored relay token"};let a={kind:"exec",bin:o,args:s},c=new AbortController,u=setTimeout(()=>c.abort(),n),l;try{l=await fetch(new URL("/__crtr/source",t),{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify(a),signal:c.signal})}catch{return c.signal.aborted?{ok:!1,stdout:"",stderr:`remote source: timeout after ${n}ms`}:{ok:!1,stdout:"",stderr:"remote source: network error"}}finally{clearTimeout(u)}return l.ok?await l.json():{ok:!1,stdout:"",stderr:`remote source: HTTP ${l.status} ${l.statusText}`}}}var Ule=1e3;function bl(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function AYr(t){if(!bl(t))return!1;let e=t.node;if(!bl(e)||typeof e.node_id!="string"||!Array.isArray(t.reports)||!Array.isArray(t.managers))return!1;let n=t.artifacts;if(!bl(n)||typeof n.report!="number"||typeof n.doc!="number"||typeof n.roadmap!="number"||typeof t.pending_crons!="number")return!1;let r=t.paths;if(!bl(r)||typeof r.context_dir!="string"||"session_file"in r&&r.session_file!==null&&typeof r.session_file!="string"||typeof t.follow_up!="string")return!1;let i=t.fault;if(i!=null){if(!bl(i)||typeof i.link!="string"||typeof i.kind!="string"||typeof i.since!="string")return!1;let o=i.retry;if(!bl(o)||typeof o.disposition!="string")return!1}return!0}function gln(t){return bl(t)&&typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.status=="string"&&typeof t.active=="boolean"}function yYr(t){return bl(t)&&typeof t.from_id=="string"&&typeof t.to_id=="string"&&typeof t.active=="boolean"&&typeof t.created=="string"}function xYr(t){return bl(t)?typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.mode=="string"&&typeof t.lifecycle=="string"&&typeof t.status=="string"&&typeof t.cwd=="string"&&typeof t.created=="string":!1}var Nv=class{constructor(e,n){this.previewEndpoint=e;this.relayToken=n;this.exec=mln(e,n)}previewEndpoint;relayToken;exec;nodeCache=new Map;rosterCache=new Map;topologyCache=null;viewCache=new Map;async execJson(e){let n;try{n=await this.exec("crtr",["--json",...e])}catch{return null}if(!n.ok||n.exitCode!==void 0&&n.exitCode!==0)return null;try{return JSON.parse(n.stdout.trim())}catch{return null}}async fetchShow(e){let n=this.nodeCache.get(e);if(n&&Date.now()-n.at<Ule)return n.value;let r=await this.execJson(["node","inspect","show",e]),i=AYr(r)?{...r,fault:r.fault??null,reports:r.reports.filter(gln),managers:r.managers.filter(gln)}:null;return this.nodeCache.set(e,{value:i,at:Date.now()}),i}topology(){if(this.topologyCache!==null&&Date.now()-this.topologyCache.at<Ule)return this.topologyCache.value;let e=this.loadTopology();return this.topologyCache={value:e,at:Date.now()},e}async loadTopology(){let e=await this.exec("crtr",["--json","canvas","roster"]);if(!e.ok||e.exitCode!==void 0&&e.exitCode!==0)throw new Error("remote canvas topology is unavailable");let n;try{n=JSON.parse(e.stdout.trim())}catch{throw new Error("remote canvas topology is invalid")}if(!bl(n)||!Array.isArray(n.edges)||!n.edges.every(yYr))throw new Error("remote canvas topology is invalid");let r=n.edges,i={subscriptions:new Map,subscribers:new Map};for(let o of r){let s={node_id:o.to_id,active:o.active,created:o.created},a={node_id:o.from_id,active:o.active,created:o.created},c=i.subscriptions.get(o.from_id);c===void 0?i.subscriptions.set(o.from_id,[s]):c.push(s);let u=i.subscribers.get(o.to_id);u===void 0?i.subscribers.set(o.to_id,[a]):u.push(a)}return i}async rawShow(e){return this.fetchShow(e)}async getNode(e){return(await this.fetchShow(e))?.node??null}async getRow(e){let n=(await this.fetchShow(e))?.node;return n?{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:n.host_kind??null,profile_id:n.profile_id??null,scopes:n.scopes??null,isolated:n.isolated===!0,parent:n.parent??null,created:n.created,intent:n.intent??null,frozen_at:n.frozen_at??null,terminal_reason:n.terminal_reason??null,pi_pid:n.pi_pid??null,pi_pid_identity:n.pi_pid_identity??null,window:n.window??null,tmux_session:n.tmux_session??null,pane:n.pane??null,fault:n.fault??null,streaming:n.streaming===!0}:null}async listNodes(e){let n=JSON.stringify(e?.status??null),r=this.rosterCache.get(n);if(r&&Date.now()-r.at<Ule)return r.value;let i=["node","inspect","list"];e?.status&&i.push("--status",(Array.isArray(e.status)?e.status:[e.status]).join(","));let o=await this.execJson(i),a=(bl(o)&&Array.isArray(o.nodes)?o.nodes:[]).filter(xYr).map(c=>({...c,isolated:c.isolated===!0}));return this.rosterCache.set(n,{value:a,at:Date.now()}),a}async subscriptionsOf(e){return(await this.topology()).subscriptions.get(e)??[]}async subscribersOf(e){return(await this.topology()).subscribers.get(e)??[]}async view(e){let n=this.viewCache.get(e);if(n&&Date.now()-n.at<Ule)return n.value;let r=new Set([e]),i=[],o=(await this.subscriptionsOf(e)).map(s=>s.node_id);for(;o.length>0;){let s=o.shift();if(!r.has(s)){r.add(s),i.push(s);for(let a of await this.subscriptionsOf(s))r.has(a.node_id)||o.push(a.node_id)}}return this.viewCache.set(e,{value:i,at:Date.now()}),i}async ticketCountsForNodes(e){if(e.length===0)return{};let n=await this.execJson(["canvas","attention","map","--nodes",e.join(",")]);return bl(n)&&bl(n.counts)?n.counts:{}}async ticketCountsForView(e){let n=await this.execJson(["canvas","attention","map","--view",e]);return bl(n)&&bl(n.counts)?n.counts:{}}async hasActiveLiveSubscription(e){let n=(await this.subscriptionsOf(e)).filter(r=>r.active);for(let r of n){let i=await this.getRow(r.node_id);if(i&&(i.status==="active"||i.status==="idle"))return!0}return!1}};function Qle(t){return{...t,fault:t.fault??null}}function Yze(t,e){throw t instanceof hn?Gun(t,e):t}var CYr=4096,IYr=20;function kYr(){let t;try{t=EYr(SYr(Na(),"crtrd.log"),"r");let{size:e}=bYr(t),n=Math.max(0,e-CYr),r=e-n;if(r<=0)return;let i=Buffer.alloc(r);vYr(t,i,0,r,n);let s=i.toString("utf8").split(`
|
|
1628
|
+
${n}`),this.name="DaemonExitedBeforeReadyError",this.stderrTail=n}},gN=class extends Error{constructor(e,n){super(`daemon ${e} is running but normal startup is blocked: ${n}`),this.name="DaemonStartupBlockedError"}},aj=class extends Error{constructor(e,n){super(n===void 0?`daemon ${e} is serving but did not report the prepared startup phase`:`daemon ${e} reported startup phase ${n}, not prepared`),this.name="DaemonNotPreparedError"}};async function eYr(t,e=3e5,n={},r="ready"){let i=n.readPidfile??xT,o=n.isPidAlive??Rf,s=n.childExited,a=n.isDaemonServing,c=n.probeDaemonServing??(async f=>{if(a!==void 0){if(await a())return;throw new Error("crtrd health check reported not ready")}await ZKr(f)}),u=n.probeDaemonHealth??Vze,l=n.sleepMs??Kze,d=n.now??Date.now,p=null,h=null;return await X3({windowMs:e,pollIntervalMs:zze,now:d,sleep:l,retry:f=>f!==h,probe:async f=>{let m=i();if(m===null||!o(m)){let y=s?.();throw y!=null&&(y.signal!==null?h=new sj(`daemon ${t} exited before becoming ready (by ${y.signal})`,n.childStderrTail?.()??""):y.code!==0&&(h=new sj(`daemon ${t} exited before becoming ready (with exit code ${y.code??"?"})`,n.childStderrTail?.()??"")),h!==null)?h:new Error(`daemon ${t} has no live pidfile owner`)}if(r==="ready"){try{await c(f)}catch(y){throw y instanceof gN&&(h=y),y}p=m;return}let g=await u(f);if(g.startup_phase==="prepared"){p=m;return}throw g.startup_phase==="blocked"?(h=new gN(m,g.startup_blocked??"on-disk migration is blocked"),h):g.startup_phase==="ready"?(h=new aj(m,g.startup_phase),h):new Error(`daemon ${m} is ${g.startup_phase??"not reporting a startup phase"}; waiting for prepared`)}}),p===t?null:p}async function tYr(t,e=dln,n={}){let r=n.readPidfile??xT,i=n.isPidAlive??Rf,o=n.sleepMs??Kze,s=n.now??Date.now,a=s()+e;for(;s()<=a;){if(!i(t)&&r()!==t)return;await o(zze)}throw new Error(`daemon ${t} did not exit and release its pidfile within ${e}ms`)}var nYr=2e3,rYr=5e3;async function iYr(t,e=dln,n={}){let r=n.isPidAlive??Rf,i=n.sleepMs??Kze,o=n.now??Date.now;try{process.kill(t,"SIGTERM")}catch{}try{return await tYr(t,e,n),"terminated"}catch{}try{process.kill(t,"SIGKILL")}catch{}let s=o()+nYr;for(;o()<=s;){if(!r(t))return"killed";await i(zze)}throw new Error(`daemon ${t} survived both SIGTERM and SIGKILL`)}function oYr(t,e,n=2048){let r;try{r=cln(t,"r");let{size:i}=lln(r),o=Math.max(e,i-n),s=i-o;if(s<=0)return"";let a=Buffer.alloc(s);return jKr(r,a,0,s,o),a.toString("utf8").trim()}catch{return""}finally{if(r!==void 0)try{uln(r)}catch{}}}async function sYr(t={}){if(process.platform==="linux"&&aln("/run/crtr/launcher.sock")&&!Rf(xT()??-1))throw new Error("crtrd is managed by the root launcher; it cannot self-daemonize");let e=t.targetPhase??"ready",n=xT();if(n!==null&&Rf(n))try{let p=await Vze();if(e==="prepared"){if(p.startup_phase==="prepared")return{started:!1,existing_pid:n,startup_phase:p.startup_phase};throw new aj(n,p.startup_phase)}return p.ok?{started:!1,existing_pid:n,...p.startup_phase===void 0?{}:{startup_phase:p.startup_phase}}:{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:p.startup_blocked??"crtrd health check reported not ready",...p.startup_phase===void 0?{}:{startup_phase:p.startup_phase}}}catch(p){if(p instanceof aj)throw p;return{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:XKr(p)}}GKr(Na(),{recursive:!0});let r=await YKr();t.waitForJoinLock===!0&&await sln(JKr);let i=Lle();if(i!==null&&i!==process.pid&&t.ignoreJoinLock!==!0)throw oln(i);let o=mN(Na(),"crtrd.err"),s=cln(o,"a"),a=(()=>{try{return lln(s).size}catch{return 0}})();Y3()===void 0&&sYe();let c=QKr(nln(),[...r,"--canvas-home",Na(),...e==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",s,s],env:VKr()});uln(s);let u=c.pid;if(u===void 0)throw new Error("daemon spawn did not return a pid");let l=null;c.once("exit",(p,h)=>{l={code:p,signal:h}}),c.unref();let d;try{d=await eYr(u,3e5,{childExited:()=>l,childStderrTail:()=>oYr(o,a)},e)}catch(p){let h=AR(nYe())===u;if(l===null&&!h&&!(p instanceof gN))try{await iYr(u,rYr)}catch{}throw p}return d!==null?{started:!1,existing_pid:d,startup_phase:e}:{started:!0,pid:u,startup_phase:e}}function $le(){return Y7e()||process.argv.includes("--no-autostart")}var aYr=5e3,cYr=6e4,Gze=!1,oj,Ole=0,Nle=0;function uYr(t){return Math.min(aYr*2**(t-1),cYr)}function lYr(){oj=void 0,Ole=0,Nle=0}function pln(){return oj}function hln(t={}){let e=t.isDaemonRunning??rln,n=t.spawnDaemon??sYr,r=t.now??Date.now;if(!$le()&&!iln()&&!Gze&&!(r()<Nle)){if(e()){lYr();return}oj=void 0,Gze=!0,n().then(()=>{oj=void 0,Ole=0,Nle=0},i=>{i instanceof sj&&(oj=i.message),Ole+=1,Nle=r()+uYr(Ole)}).finally(()=>{Gze=!1})}}import{existsSync as dYr,readFileSync as pYr,statSync as IRs}from"node:fs";import{join as hYr}from"node:path";var fYr="secrets.json";function mYr(t){return hYr(t===Yc()?vy():t,fYr)}function gYr(t){let e=ig(t);if(!e)return{relayTokens:{}};let n=mYr(e);if(!dYr(n))return{relayTokens:{}};try{let r=JSON.parse(pYr(n,"utf8")),i=Array.isArray(r.scopedApiTokens)?r.scopedApiTokens.filter(o=>typeof o?.token=="string"&&o.token!==""&&typeof o.grantee=="string"&&/^app:[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(o.grantee)&&Array.isArray(o.scopes)&&typeof o.created=="string"):[];return{relayTokens:r.relayTokens??{},...typeof r.apiToken=="string"&&r.apiToken!==""?{apiToken:r.apiToken}:{},...i.length>0?{scopedApiTokens:i}:{}}}catch{return{relayTokens:{}}}}function fln(t,e){return gYr(e).relayTokens[t]}function Fle(t,e="user"){let n=zc(e),r=n.remoteCanvas.targets[t];if(r===void 0){let o=Object.keys(n.remoteCanvas.targets);throw lS(`no remote canvas target named '${t}'`+(o.length>0?` \u2014 configured: ${o.join(", ")}`:" \u2014 none configured yet")+`. Add one with \`crtr canvas config add ${t} --preview <url> --relay-token -\`.`)}let i=fln(r.relayTokenRef,e);if(i===void 0||i==="")throw lS(`target '${t}' has no stored relay token \u2014 add it with \`crtr canvas config add ${t} --relay-token -\`.`);return{previewEndpoint:r.previewEndpoint,relayToken:i}}function mln(t,e,n=5e3){let r=/^[\x20-\x7e]+$/.test(e);return async function(o,s){if(!r)return{ok:!1,stdout:"",stderr:"remote source: invalid stored relay token"};let a={kind:"exec",bin:o,args:s},c=new AbortController,u=setTimeout(()=>c.abort(),n),l;try{l=await fetch(new URL("/__crtr/source",t),{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify(a),signal:c.signal})}catch{return c.signal.aborted?{ok:!1,stdout:"",stderr:`remote source: timeout after ${n}ms`}:{ok:!1,stdout:"",stderr:"remote source: network error"}}finally{clearTimeout(u)}return l.ok?await l.json():{ok:!1,stdout:"",stderr:`remote source: HTTP ${l.status} ${l.statusText}`}}}var Ule=1e3;function bl(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function AYr(t){if(!bl(t))return!1;let e=t.node;if(!bl(e)||typeof e.node_id!="string"||!Array.isArray(t.reports)||!Array.isArray(t.managers))return!1;let n=t.artifacts;if(!bl(n)||typeof n.report!="number"||typeof n.doc!="number"||typeof n.roadmap!="number"||typeof t.pending_crons!="number")return!1;let r=t.paths;if(!bl(r)||typeof r.context_dir!="string"||"session_file"in r&&r.session_file!==null&&typeof r.session_file!="string"||typeof t.follow_up!="string")return!1;let i=t.fault;if(i!=null){if(!bl(i)||typeof i.link!="string"||typeof i.kind!="string"||typeof i.since!="string")return!1;let o=i.retry;if(!bl(o)||typeof o.disposition!="string")return!1}return!0}function gln(t){return bl(t)&&typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.status=="string"&&typeof t.active=="boolean"}function yYr(t){return bl(t)&&typeof t.from_id=="string"&&typeof t.to_id=="string"&&typeof t.active=="boolean"&&typeof t.created=="string"}function xYr(t){return bl(t)?typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.mode=="string"&&typeof t.lifecycle=="string"&&typeof t.status=="string"&&typeof t.cwd=="string"&&typeof t.created=="string":!1}var Nv=class{constructor(e,n){this.previewEndpoint=e;this.relayToken=n;this.exec=mln(e,n)}previewEndpoint;relayToken;exec;nodeCache=new Map;rosterCache=new Map;topologyCache=null;viewCache=new Map;async execJson(e){let n;try{n=await this.exec("crtr",["--json",...e])}catch{return null}if(!n.ok||n.exitCode!==void 0&&n.exitCode!==0)return null;try{return JSON.parse(n.stdout.trim())}catch{return null}}async fetchShow(e){let n=this.nodeCache.get(e);if(n&&Date.now()-n.at<Ule)return n.value;let r=await this.execJson(["node","inspect","show",e]),i=AYr(r)?{...r,fault:r.fault??null,reports:r.reports.filter(gln),managers:r.managers.filter(gln)}:null;return this.nodeCache.set(e,{value:i,at:Date.now()}),i}topology(){if(this.topologyCache!==null&&Date.now()-this.topologyCache.at<Ule)return this.topologyCache.value;let e=this.loadTopology();return this.topologyCache={value:e,at:Date.now()},e}async loadTopology(){let e=await this.exec("crtr",["--json","canvas","roster"]);if(!e.ok||e.exitCode!==void 0&&e.exitCode!==0)throw new Error("remote canvas topology is unavailable");let n;try{n=JSON.parse(e.stdout.trim())}catch{throw new Error("remote canvas topology is invalid")}if(!bl(n)||!Array.isArray(n.edges)||!n.edges.every(yYr))throw new Error("remote canvas topology is invalid");let r=n.edges,i={subscriptions:new Map,subscribers:new Map};for(let o of r){let s={node_id:o.to_id,active:o.active,created:o.created},a={node_id:o.from_id,active:o.active,created:o.created},c=i.subscriptions.get(o.from_id);c===void 0?i.subscriptions.set(o.from_id,[s]):c.push(s);let u=i.subscribers.get(o.to_id);u===void 0?i.subscribers.set(o.to_id,[a]):u.push(a)}return i}async rawShow(e){return this.fetchShow(e)}async getNode(e){return(await this.fetchShow(e))?.node??null}async getRow(e){let n=(await this.fetchShow(e))?.node;return n?{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:n.host_kind??null,profile_id:n.profile_id??null,scopes:n.scopes??null,isolated:n.isolated===!0,parent:n.parent??null,created:n.created,intent:n.intent??null,frozen_at:n.frozen_at??null,terminal_reason:n.terminal_reason??null,pi_pid:n.pi_pid??null,pi_pid_identity:n.pi_pid_identity??null,window:n.window??null,tmux_session:n.tmux_session??null,pane:n.pane??null,fault:n.fault??null,streaming:n.streaming===!0}:null}async listNodes(e){let n=JSON.stringify([e?.status??null,e?.under??null]),r=this.rosterCache.get(n);if(r&&Date.now()-r.at<Ule)return r.value;let i=["node","inspect","list"];e?.status&&i.push("--status",(Array.isArray(e.status)?e.status:[e.status]).join(",")),e?.under&&i.push("--under",e.under);let o=await this.execJson(i),a=(bl(o)&&Array.isArray(o.nodes)?o.nodes:[]).filter(xYr).map(c=>({...c,isolated:c.isolated===!0}));return this.rosterCache.set(n,{value:a,at:Date.now()}),a}async subscriptionsOf(e){return(await this.topology()).subscriptions.get(e)??[]}async subscribersOf(e){return(await this.topology()).subscribers.get(e)??[]}async view(e){let n=this.viewCache.get(e);if(n&&Date.now()-n.at<Ule)return n.value;let r=new Set([e]),i=[],o=(await this.subscriptionsOf(e)).map(s=>s.node_id);for(;o.length>0;){let s=o.shift();if(!r.has(s)){r.add(s),i.push(s);for(let a of await this.subscriptionsOf(s))r.has(a.node_id)||o.push(a.node_id)}}return this.viewCache.set(e,{value:i,at:Date.now()}),i}async ticketCountsForNodes(e){if(e.length===0)return{};let n=await this.execJson(["canvas","attention","map","--nodes",e.join(",")]);return bl(n)&&bl(n.counts)?n.counts:{}}async ticketCountsForView(e){let n=await this.execJson(["canvas","attention","map","--view",e]);return bl(n)&&bl(n.counts)?n.counts:{}}async hasActiveLiveSubscription(e){let n=(await this.subscriptionsOf(e)).filter(r=>r.active);for(let r of n){let i=await this.getRow(r.node_id);if(i&&(i.status==="active"||i.status==="idle"))return!0}return!1}};function Qle(t){return{...t,fault:t.fault??null}}function Yze(t,e){throw t instanceof hn?Gun(t,e):t}var CYr=4096,IYr=20;function kYr(){let t;try{t=EYr(SYr(Na(),"crtrd.log"),"r");let{size:e}=bYr(t),n=Math.max(0,e-CYr),r=e-n;if(r<=0)return;let i=Buffer.alloc(r);vYr(t,i,0,r,n);let s=i.toString("utf8").split(`
|
|
1629
1629
|
`).filter(a=>a.trim()!=="").slice(-IYr).join(`
|
|
1630
1630
|
`).trim();return s===""?void 0:`crtrd.log (tail):
|
|
1631
|
-
${s}`}catch{return}finally{if(t!==void 0)try{wYr(t)}catch{}}}function Ht(t){return process.env.CRTR_API_SOCKET?Sy({autostart:!1,coldStartPollWindowMs:($le()?J7e():void 0)??3e5,...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{}}):$le()?Sy({autostart:!1,...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{}}):Sy({...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{},onColdSocket:async()=>{hln()},coldStartDiagnostic:kYr,coldStartFailure:pln,coldStartPollWindowMs:3e5})}var TYr=2e3,AN=class{client;rosterCache=null;rosterInFlight=null;constructor(e=Ht()){this.client=e}async roster(){let e=Date.now();return this.rosterCache!==null&&e-this.rosterCache.at<TYr?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(n=>{let r={snapshot:n,subscriptions:new Map,subscribers:new Map};for(let i of n.edges){let o={node_id:i.to_id,active:i.active,created:i.created},s={node_id:i.from_id,active:i.active,created:i.created},a=r.subscriptions.get(i.from_id);a===void 0?r.subscriptions.set(i.from_id,[o]):a.push(o);let c=r.subscribers.get(i.to_id);c===void 0?r.subscribers.set(i.to_id,[s]):c.push(s)}return this.rosterCache={at:Date.now(),index:r},r}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(e){try{return await e()}catch(n){if(n instanceof hn&&n.status===404)return null;throw n}}async getNode(e){let n=await this.orNull(()=>this.client.getNode(e));return n===null?null:Qle(n)}async getRow(e){let n=await this.orNull(()=>this.client.getNode(e));return n===null?null:Qle(n)}async listNodes(e){let n=e?.status,r;if(Array.isArray(n)){let
|
|
1631
|
+
${s}`}catch{return}finally{if(t!==void 0)try{wYr(t)}catch{}}}function Ht(t){return process.env.CRTR_API_SOCKET?Sy({autostart:!1,coldStartPollWindowMs:($le()?J7e():void 0)??3e5,...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{}}):$le()?Sy({autostart:!1,...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{}}):Sy({...t?.timeoutMs!==void 0?{timeoutMs:t.timeoutMs}:{},onColdSocket:async()=>{hln()},coldStartDiagnostic:kYr,coldStartFailure:pln,coldStartPollWindowMs:3e5})}var TYr=2e3,AN=class{client;rosterCache=null;rosterInFlight=null;constructor(e=Ht()){this.client=e}async roster(){let e=Date.now();return this.rosterCache!==null&&e-this.rosterCache.at<TYr?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(n=>{let r={snapshot:n,subscriptions:new Map,subscribers:new Map};for(let i of n.edges){let o={node_id:i.to_id,active:i.active,created:i.created},s={node_id:i.from_id,active:i.active,created:i.created},a=r.subscriptions.get(i.from_id);a===void 0?r.subscriptions.set(i.from_id,[o]):a.push(o);let c=r.subscribers.get(i.to_id);c===void 0?r.subscribers.set(i.to_id,[s]):c.push(s)}return this.rosterCache={at:Date.now(),index:r},r}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(e){try{return await e()}catch(n){if(n instanceof hn&&n.status===404)return null;throw n}}async getNode(e){let n=await this.orNull(()=>this.client.getNode(e));return n===null?null:Qle(n)}async getRow(e){let n=await this.orNull(()=>this.client.getNode(e));return n===null?null:Qle(n)}async listNodes(e){let n=e?.status,r=e?.under===void 0?{}:{under:e.under,under_inclusive:!0},i;if(Array.isArray(n)){let o=new Set(n);i=(await this.client.listNodes(r)).filter(a=>o.has(a.status))}else i=await this.client.listNodes({...n!==void 0?{status:n}:{},...r});return i.map(o=>Qle(o))}async browseSnapshot(){let e=await this.client.canvasBrowseCompressed(),n=JSON.parse(_Yr(e).toString("utf8")),r={subscriptions:new Map,subscribers:new Map};for(let i of n.edges){let o=r.subscriptions.get(i.from_id)??[];o.push({node_id:i.to_id,active:i.active,created:i.created}),r.subscriptions.set(i.from_id,o);let s=r.subscribers.get(i.to_id)??[];s.push({node_id:i.from_id,active:i.active,created:i.created}),r.subscribers.set(i.to_id,s)}return this.rosterCache={at:Date.now(),index:r},n.nodes.map(i=>Qle(i))}async panelRoster(){let e=await this.roster();return e.snapshot!==void 0?e.snapshot:(this.rosterCache=null,(await this.roster()).snapshot)}async subscriptionsOf(e){return this.roster().then(n=>n.subscriptions.get(e)??[])}async subscribersOf(e){return this.roster().then(n=>n.subscribers.get(e)??[])}async view(e){let n=new Set([e]),r=[],i=(await this.subscriptionsOf(e)).map(o=>o.node_id);for(;i.length>0;){let o=i.shift();if(!n.has(o)){n.add(o),r.push(o);for(let s of await this.subscriptionsOf(o))n.has(s.node_id)||i.push(s.node_id)}}return r}async ticketCountsForNodes(e){return(await this.client.attentionCounts([...e])).counts}async ticketCountsForView(e){return this.ticketCountsForNodes([e,...await this.view(e)])}async newestReport(e){return(await this.client.getReports(e,{limit:1}))[0]??null}async hasActiveLiveSubscription(e){let n=(await this.subscriptionsOf(e)).filter(r=>r.active);for(let r of n){let i=await this.getRow(r.node_id);if(i&&(i.status==="active"||i.status==="idle"))return!0}return!1}};function Aln(t,e=ZN()){let n=t?.scope??"user";if(e){if(t?.canvasName!==void 0)throw TKe("--canvas selects the person's remote canvas targets, which an app's node cannot reach","Omit --canvas; this node reads its own runtime's canvas.");return new AN}let r=t?.canvasName??ret(n).activeCanvas??null;if(!r)return new AN;let{previewEndpoint:i,relayToken:o}=Fle(r,n);return new Nv(i,o)}function RYr(t){return{dir:t.request_dir,id:t.request_id,inboxTicketId:t.ticket_id,kind:"page",title:t.title,subtitle:t.subtitle??"",dialect:t.dialect,placement:t.placement,inbox:t.inbox,steps:t.steps,slotKinds:t.slot_kinds,awaitsResponse:t.awaits_response,source:t.source,emittedAt:t.emitted_at,recommendedOptions:(t.recommended_options??[]).map(e=>({slotId:e.slot_id,optionId:e.option_id,label:e.label})),...t.fast_action===void 0?{}:{fastAction:{kind:t.fast_action.kind,responses:t.fast_action.responses}},state:t.state,...t.answer_digest===void 0?{}:{answerDigest:t.answer_digest}}}function MYr(t){return{dir:t.request_dir,id:t.request_id,inboxTicketId:t.ticket_id,kind:"review",title:t.title,subtitle:t.subtitle,blockedSince:t.blocked_since,source:t.source}}function Km(t){return t.kind==="page"?RYr(t):MYr(t)}function wT(t){return{manifest:AT(t.page),document:t.source_document,progress:t.progress===null?null:t.progress.responses,state:t.state,revision:t.revision}}function yln(t){let e=t.result;if(!(e===null||e.kind!=="page"))return e.summary.replace(/\s+/g," ").trim()}function yN(t){let e=t.result;return e!==null&&e.kind==="canceled"?"ticket was already canceled":e!==null&&e.kind==="page"?"ticket was already resolved: page submitted":"ticket was already resolved"}function $v(t,e){let n=r=>r.kind==="page"?r.emittedAt:r.blockedSince;return n(e).localeCompare(n(t))||t.id.localeCompare(e.id)}var PYr=new Set(["c","r","e","a","n","p","q","j","k","u","d"," "]);function xN(t){let e=t.config.label;return typeof e=="string"&&e!==""?e:t.unvalidated===!0?t.kind:t.kind==="options"?"Options":t.kind==="text"?"Text":t.kind==="table"?"Table":t.kind==="cards"?"Cards":t.kind==="chart"?"Chart":t.kind}function Ip(t){return!(t.unvalidated===!0||t.kind==="cards"&&t.config.cards===void 0)}function Wle(t){if(!Ip(t))return[];let e=[];if(t.kind==="options"){let r=t.config;e=r.options.map(i=>({kind:"select",group:"option",id:i.id,label:i.label,...i.description===void 0?{}:{description:i.description},mode:r.mode})),r.allowFreetext===!0&&e.push({kind:"freetext",label:r.freetextLabel??"Something else"})}else if(t.kind==="cards"){let r=t.config;e=(r.cards??[]).map(i=>({kind:"select",group:"card",id:i.id,label:i.subtitle===void 0?i.title:`${i.title} \u2014 ${i.subtitle}`,...i.body===void 0?{}:{description:i.body},mode:r.mode}))}else if(t.kind==="text")e.push({kind:"edit",label:"Edit"}),e.push({kind:"accept",label:"Accept as-is"});else if(t.kind==="table"){let r=t.config;if(r.rowSelect!=="none"){let i=r.columns[0];e.push(...(r.rows??[]).map(o=>({kind:"select",group:"row",id:o.id,label:i===void 0?o.id:String(o.cells[i.id]??o.id),mode:r.rowSelect})))}r.columnSelect!=="none"&&e.push(...r.columns.map(i=>({kind:"select",group:"column",id:i.id,label:i.label,mode:r.columnSelect})))}let n=new Set;return e.map(r=>{if(r.kind!=="select")return r;let i;for(let o of[...r.label.toLowerCase()].filter(s=>/[a-z]/.test(s)))if(!n.has(o)&&!PYr.has(o)){i=o;break}if(i===void 0){for(let o=1;o<=9;o++)if(!n.has(String(o))){i=String(o);break}}return i!==void 0&&n.add(i),{...r,...i===void 0?{}:{shortcut:i}}})}function xln(t,e=!1){if(t==null)return"";let n=String(t).replaceAll("|","\\|").replaceAll(`
|
|
1632
1632
|
`,"<br>");return e&&n!==""?`\`${n.replaceAll("`","\\`")}\``:n}function Hle(t){let e=`| ${t.columns.map(r=>xln(r.label)).join(" | ")} |`,n=`| ${t.columns.map(r=>r.align==="right"?"---:":"---").join(" | ")} |`;return[e,n,...(t.rows??[]).map(r=>`| ${t.columns.map(i=>xln(r.cells[i.id],i.mono===!0)).join(" | ")} |`)].join(`
|
|
1633
1633
|
`)}function Jze(t,e,n){if(e.id===void 0)return!1;try{return Oun(t.manifest,{[e.id]:n}),!0}catch{return!1}}function Ix(t,e){return!Ip(e)||e.id===void 0||!t.responses.has(e.id)?!1:Jze(t,e,t.responses.get(e.id))}function Fv(t){if(t.manifest.slots.some(e=>fc(e)&&!Ip(e)))return!1;try{return Lun(t.manifest,Object.fromEntries(t.responses)),!0}catch{return!1}}function wN(t){switch(t.kind){case"option":return`option:${t.optionId}`;case"row":return`row:${t.rowId}`}}function bN(t){return Ip(t)?t.kind==="options"?t.config.options.map(e=>({kind:"option",optionId:e.id})):t.kind==="table"?(t.config.rows??[]).map(e=>({kind:"row",rowId:e.id})):[]:[]}tt();var kp="\x1B[",Oe=`${kp}0m`,ls=`${kp}1m`,ut=`${kp}2m`,bln=`${kp}3m`,Eln=`${kp}31m`,bT=`${kp}32m`,Hs=`${kp}33m`,ds=`${kp}36m`,qle=`${kp}90m`,uj=`${kp}7m`,DYr=/\x1b\[[0-9;?]*[a-zA-Z]|\x1b[@-_]|[\x00-\x08\x0B\x0E-\x1F\x7F-\x9F]/g;function Vr(t){return typeof t!="string"?"":t.replace(DYr,"")}function El(t){return Vr(t).replace(/\s+/g," ").trim()}function kx(t,e="\u2500"){return t<1?"":e.repeat(t)}function Tp(t,e){if(e<1)return"";if(Ws(t)<=e)return t;let n=[...t],r=0,i="";for(let o of n){let s=Ws(o);if(r+s+1>e)break;i+=o,r+=s}return i+"\u2026"}function Gle(t,e){let n=t.replace(/\n/g," ").replace(/✅/g,"\u2713").replace(/❌/g,"\u2717").replace(new RegExp("\\p{Emoji_Presentation}","gu"),"");if(e<4)return n.slice(0,e);if(Ws(n)<=e)return n;let i=n;for(;Ws(i)>e-1&&i.length>0;){let o=i.lastIndexOf(" ",i.length-2);o>e*.4?i=i.slice(0,o):i=i.slice(0,i.length-1)}return i+"\u2026"}function BYr(t,e){let n=0,r="";for(let i of t){let o=Ws(i);if(n+o>e)break;r+=i,n+=o}return r===""&&t.length>0&&(r=[...t][0]),r}function vl(t,e){if(e<1)return[t];let n=[],r=t.split(`
|
|
1634
1634
|
`);for(let i=0;i<r.length;i++){let o=r[i];if(o===""){n.push("");continue}let s=o.split(/[ \t]+/).filter(Boolean),a="";for(let c of s){for(;Ws(c)>e;){a&&(n.push(a),a="");let l=BYr(c,e);n.push(l),c=c.slice(l.length)}let u=a?`${a} ${c}`:c;Ws(u)<=e?a=u:(a&&n.push(a),a=c)}a&&n.push(a)}return n.length>0?n:[""]}function dy(t,e,n){let r=Math.max(0,Math.floor((e-n)/2));if(r===0)return t;let i=" ".repeat(r);return t.map(o=>o===""?"":i+o)}function zo(t){return Ce(t)}var Xze=/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[0-9;?]*[a-zA-Z]|\x1b[@-^]/g,Zze=/\x1b\]8;[^;\x07\x1b]*;([^\x07\x1b]*)(\x07|\x1b\\)/g,wln=new Intl.Segmenter(void 0,{granularity:"grapheme"});function LYr(t){let e=[],n=0;Xze.lastIndex=0;for(let r=Xze.exec(t);r!==null;r=Xze.exec(t)){for(let i of wln.segment(t.slice(n,r.index)))e.push({ansi:!1,text:i.segment,width:zo(i.segment)});e.push({ansi:!0,text:r[0]}),n=r.index+r[0].length}for(let r of wln.segment(t.slice(n)))e.push({ansi:!1,text:r.segment,width:zo(r.segment)});return e}function vln(t,e,n){if(n<1)return"";let r=Math.max(0,e),i=r+n,o="",s="",a=!1,c=0;for(let l of LYr(t)){if(l.ansi){c<r?o+=l.text:(s+=l.text,a=!0);continue}if(c>=i)break;let d=l.width;if(d===0){c>=r&&(s+=l.text);continue}if(c+d<=r){c+=d;continue}if(c<r){s+=" ".repeat(c+d-r),c+=d;continue}if(c+d>i){s+=" ".repeat(i-c),c=i;break}s+=l.text,c+=d}if(s==="")return"";o!==""&&(s=o+s,a=!0);let u=OYr(s);return a?s+u+Oe:s}function OYr(t){let e="";Zze.lastIndex=0;for(let n=Zze.exec(t);n!==null;n=Zze.exec(t))e=n[1]===""?"":`\x1B]8;;${n[2]}`;return e}function ma(t,e){return e<1?"":zo(t)<=e?t:vln(t,0,e)}function jle(t,e,n){if(n<1)return"";let r=zo(t);if(r<=n)return t;let i=r-n,o=Math.max(0,Math.min(e,i)),s=o>0,a=o<i,c=n-(s?1:0)-(a?1:0),u=c>0?vln(t,o+(s?1:0),c):"";return`${s?`${ut}\u2039${Oe}`:""}${u}${a?`${ut}\u203A${Oe}`:""}`}function zle(t,e,n,r){let i=a=>mce(yce(a),n,r);if(t.dialect==="html")return e===""?[`${ut}HTML page \u2014 open in Northlight to read this${Oe}`]:i(e);let o=e===""?[]:i(e),s=-1;for(let a of t.slots){t.steps>1&&a.step!==s&&(o.length>0&&o.push(""),o.push(`${ls}Step ${a.step+1}/${t.steps}${Oe}`),s=a.step),o.length>0&&o.push("");for(let u of vl(El(xN(a)),n))o.push(`${ls}${u}${Oe}`);let c=a.config.body;if(typeof c=="string"&&c!==""&&o.push(...i(c)),!Ip(a)){o.push(`${ut}${Vr(a.kind)} \u2014 open in Northlight to answer this${Oe}`);continue}if(a.kind==="text")o.push(...i(a.config.initialText));else if(a.kind==="table")o.push(...i(Hle(a.config)));else if(a.kind==="cards"){for(let u of a.config.cards??[])if(o.push(` \u2022 ${Tp(Vr(El(u.subtitle===void 0?u.title:`${u.title} \u2014 ${u.subtitle}`)),Math.max(10,n-4))}`),u.body!==void 0)for(let l of vl(Vr(u.body),Math.max(10,n-6)))o.push(` ${ut}${l}${Oe}`)}else if(a.kind==="options"){for(let u of a.config.options)if(o.push(` \u2022 ${Tp(Vr(El(u.label)),Math.max(10,n-4))}`),u.description!==void 0)for(let l of vl(Vr(u.description),Math.max(10,n-6)))o.push(` ${ut}${l}${Oe}`)}else if(a.kind==="chart"){let u=a.config,l=u.title??`${u.x??""} vs ${(u.y??[]).map(d=>d.label??d.field).join(", ")}`;o.push(`${ut}chart \u2014 ${Vr(u.kind??"chart")}: ${Vr(l)}${Oe}`)}}return o}var Sln=16;function _ln(t){if(t===null||typeof t!="object")return;let e=t.details;if(e===null||typeof e!="object")return;let n=e.crtrPreview;if(n===null||typeof n!="object")return;let r=n;if(r.path!=="human send")return;let i=r.result;if(i===null||typeof i!="object")return;let o=i,s=o.page_id;if(typeof s=="string"&&o.placement==="inline")return{pageId:s}}function NYr(t){return t.document_media_type==="text/html"?pN(t.source_document):dN(t.source_document,t.page)}var Vle=class{constructor(e,n){this.pageId=e;this.openHint=n}pageId;openHint;expanded=!1;generation=0;stamp;snapshot;status="loading";cache;get settled(){return this.snapshot?.state==="resolved"||this.snapshot?.state==="canceled"}async refresh(){let e;try{e=(await Ht().getHumanRequest(this.pageId)).page}catch{e=void 0}if(e===void 0)return this.settle("unavailable",void 0,void 0);let n=`${e.revision}|${e.state}`;if(this.status==="ready"&&n===this.stamp)return!1;let r;try{r={manifest:e.page,displayMarkdown:NYr(e),state:e.state,...e.state==="resolved"?$Yr(yln(e)):{}}}catch{return this.settle("unavailable",void 0,n)}return this.settle("ready",r,n)}setExpanded(e){e!==this.expanded&&(this.expanded=e,this.cache=void 0)}render(e){let n=e>0?e:80,r=this.cache;if(r!==void 0&&r.width===n&&r.generation===this.generation&&r.expanded===this.expanded)return r.lines;let i=this.compose(n);return this.cache={width:n,generation:this.generation,expanded:this.expanded,lines:i},i}invalidate(){this.cache=void 0}settle(e,n,r){return e===this.status&&e==="unavailable"?!1:(this.status=e,this.snapshot=n,this.stamp=r,this.generation++,this.cache=void 0,!0)}compose(e){let n=this.snapshot;if(n===void 0){let a=this.status==="loading"?"[page] loading\u2026":"[page] no longer available";return["",` ${ut}${a}${Oe}`,""]}let r=Math.min(Math.max(20,e-4),100),i=["",` ${ls}${ds}${Tp(Vr(El(n.manifest.title)),r)}${Oe}`];if(n.manifest.subtitle)for(let a of vl(Vr(n.manifest.subtitle),r))i.push(` ${ut}${a}${Oe}`);let o=zle(n.manifest,n.displayMarkdown,r,Math.max(20,e-4));if(o.length>0){i.push("");let a=this.expanded||o.length<=Sln?o:o.slice(0,Sln);for(let c of a)i.push(` ${c}`);a.length<o.length&&i.push(` ${ut}\u2026 +${o.length-a.length} lines \u2014 ctrl+o to expand${Oe}`)}let s=this.footerLine(n,r);return s!==void 0&&i.push("",` ${s}`),i.push(""),i}footerLine(e,n){switch(e.state){case"pending":return Ile(e.manifest)?`${Hs}\u25B8 awaiting your answer${Oe} ${ut}\u2014 ${Vr(this.openHint())}${Oe}`:`${ut}\u25E6 queued in your inbox \u2014 ${Vr(this.openHint())}${Oe}`;case"resolved":return e.answerDigest===void 0?`${bT}\u2713 answered${Oe}`:`${bT}\u2713 answered${Oe} ${ut}\u2014 ${Tp(Vr(e.answerDigest),Math.max(10,n-12))}${Oe}`;case"canceled":return`${ut}\u2298 canceled${Oe}`;case"passive":return}}};function $Yr(t){return t===void 0?{}:{answerDigest:t}}fa();tt();var FYr=new Set(["canvas roster","canvas snapshot","node inspect snapshot","node inspect show","sys context sysprompt"]);function Iln(t){for(let e of FYr){let n=e.split(" ");if(n.length<=t.length&&n.every((r,i)=>t[i]===r))return!0}return!1}var UYr=61529,kln=String.fromCodePoint(UYr),mf={bash:String.fromCodePoint(61728),read:String.fromCodePoint(61788),write:String.fromCodePoint(61639),edit:String.fromCodePoint(61508)},QYr={canvas:61672,capture:61501,device:61705,doc:61485,human:61447,node:61842,pkg:61874,profile:62141,push:61678,"exa-search":61442,surface:61704,sys:61459},WYr={"canvas dashboard":61668,"canvas snapshot":61488,"canvas browse":61774,"canvas attention count":62098,"canvas attention list":61498,"canvas attention map":62073,"canvas revive":61473,"node lifecycle revive":61473,"canvas list":61498,"canvas read":61485,"canvas search":61442,"canvas history search":61442,"canvas history grep":61616,"sys daemon start":61515,"sys daemon status":61713,"sys daemon stop":61517,"canvas chord":61441,"surface tmux-spread":61449,"canvas issue new":61832,"canvas prune":61636,"human send":61529,"human review":61508,"human show":61704,"human cancel":61453,"human list":61498,"human resolve":61452,"doc write":61504,"doc edit":61508,"doc history":61914,"doc lint":61770,"node new":61543,"node message send":61664,"node message request":61664,"cron add":61463,"node wait deadline":61463,"node subscription add":61683,"node subscription remove":61942,"node promote":61698,"node yield":62093,"surface node focus":61531,"surface node cycle":61473,"node inspect list":61498,"node inspect show":61550,"node inspect snapshot":61488,"node inspect context":61564,"node lifecycle recycle":61880,"node lifecycle close":61453,"node lifecycle demote":61699,"node config":61459,"cron list":61463,"cron cancel":61534,"pkg plugin install":61465,"pkg plugin remove":61460,"pkg plugin enable":61452,"pkg plugin disable":61534,"pkg plugin update":61473,"pkg plugin list":61498,"pkg plugin show":61550,"pkg market add":61543,"pkg market remove":61460,"pkg market update":61473,"pkg market list":61498,"pkg market browse":61774,"push update":61587,"push final":61726,"exa-search web":61612,"exa-search answer":61557,"exa-search contents":61686,"surface attach to":61926,"sys config get":61465,"sys config set":61504,"sys config path":61563,"sys settings":61459,"sys setup":61613,"sys doctor":61681,"sys context sysprompt":61788,"sys context prompt-review":61442,"sys feedback":61557,"sys update":61473,"sys version":61483,"sys sync":61561};function Tln(t){let e;for(let[r,i]of Object.entries(WYr)){let o=r.split(" ");o.length<=t.length&&o.every((s,a)=>t[a]===s)&&(e===void 0||o.length>e.words)&&(e={words:o.length,cp:i})}if(e!==void 0)return String.fromCodePoint(e.cp);let n=t.length>0?QYr[t[0]]:void 0;return n!==void 0?String.fromCodePoint(n):"\u25C6"}function EN(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)?t:void 0}function Kle(t){let e=EN(EN(t)?.details);if(e===void 0)return[];let n=e.crtrPreviews;return(Array.isArray(n)?n:[e.crtrPreview]).flatMap(i=>{let o=EN(i);if(o===void 0||typeof o.path!="string")return[];let s=o.jsonl;return[{path:o.path,result:EN(o.result),jsonl:Array.isArray(s)?s.flatMap(a=>{let c=EN(a);return c===void 0?[]:[c]}):void 0,error:EN(o.error)}]})}var HYr=4;function Uv(t){return t.result}function ff(t,e){let n=t[e];return typeof n=="string"&&n!==""?n:void 0}function t6e(t,e){return typeof t[e]=="boolean"?t[e]:void 0}function ET(t,e){return typeof t[e]=="number"&&Number.isFinite(t[e])?t[e]:void 0}function qYr(t,e){let n=t[e];return Array.isArray(n)&&n.every(r=>r!==null&&typeof r=="object"&&!Array.isArray(r))?n:void 0}function GYr(t,e){return t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t}function jYr(t,e,n=5){let r=t.map(s=>ff(s,e));if(r.some(s=>s===void 0))return;let i=r.slice(0,n),o=r.length-i.length;return o>0?`${i.join(", ")}, \u2026 ${o} more`:i.join(", ")}function zYr(t){let e=t.error;if(e===void 0)return null;let n=ff(e,"error"),r=ff(e,"message");return n===void 0||r===void 0?null:[{text:n,tone:"error"},{text:GYr(r,160),tone:"muted"}]}function VYr(t){let e=Uv(t);if(e===void 0)return null;let n=ff(e,"deleted")??ff(e,"remote");if(n!==void 0)return[{text:n.trim().split(`
|
|
@@ -67,6 +67,7 @@ export declare class ApiCanvasSource implements CanvasSource {
|
|
|
67
67
|
getRow(nodeId: string): Promise<NodeRow | null>;
|
|
68
68
|
listNodes(filter?: {
|
|
69
69
|
status?: NodeStatus | NodeStatus[];
|
|
70
|
+
under?: string;
|
|
70
71
|
}): Promise<NodeRow[]>;
|
|
71
72
|
/** The browse screen uses one slim, compressed read for rows AND topology.
|
|
72
73
|
* The same roster index feeds subscriptionsOf/view until its normal TTL ends. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
var b=Object.defineProperty;var a=(r,t)=>b(r,"name",{value:t,configurable:!0});import{closeSync as _,fstatSync as S,openSync as g,readSync as v}from"node:fs";import{join as y}from"node:path";import{gunzipSync as C}from"node:zlib";import{ApiError as l}from"../api/index.js";import{localClient as d}from"../api/node-transport.js";import{apiErrorToCliError as N}from"../core/io.js";import{autostartDisabled as h,daemonAutostartStartupFailure as M,ensureDaemon as T}from"../daemon/manage.js";import{DAEMON_STARTUP_WINDOW_MS as p}from"../daemon/startup-policy.js";import{readState as A}from"../core/config.js";import{resolveRemoteCanvasTarget as O}from"../core/remote-canvas-target.js";import{RemoteCanvasSource as R}from"../core/canvas/remote-canvas-source.js";import{crtrHome as I}from"../core/canvas/paths.js";import{envTestNodeSocketWindowMs as x,isSandboxedNode as D}from"../shared/env.js";import{ownerOnly as F}from"../core/errors.js";function u(r){return{...r,fault:r.fault??null}}a(u,"withRowFault");function E(r,t){throw r instanceof l?N(r,t):r}a(E,"rethrowAsCliError");async function tt(r){try{return await m().getNode(r)}catch(t){if(t instanceof l&&t.status===404)return null;E(t)}}a(tt,"getNodeOrNull");const L=4096,k=20;function W(){let r;try{r=g(y(I(),"crtrd.log"),"r");const{size:t}=S(r),s=Math.max(0,t-L),n=t-s;if(n<=0)return;const e=Buffer.alloc(n);v(r,e,0,n,s);const o=e.toString("utf8").split(`
|
|
2
2
|
`).filter(c=>c.trim()!=="").slice(-k).join(`
|
|
3
3
|
`).trim();return o===""?void 0:`crtrd.log (tail):
|
|
4
|
-
${o}`}catch{return}finally{if(r!==void 0)try{_(r)}catch{}}}a(W,"readColdStartDiagnostic");function m(r){return process.env.CRTR_API_SOCKET?d({autostart:!1,coldStartPollWindowMs:(h()?x():void 0)??p,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):h()?d({autostart:!1,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):d({...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{},onColdSocket:a(async()=>{T()},"onColdSocket"),coldStartDiagnostic:W,coldStartFailure:M,coldStartPollWindowMs:p})}a(m,"cliClient");const P=2e3;class w{static{a(this,"ApiCanvasSource")}client;rosterCache=null;rosterInFlight=null;constructor(t=m()){this.client=t}async roster(){const t=Date.now();return this.rosterCache!==null&&t-this.rosterCache.at<P?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(s=>{const n={snapshot:s,subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i={node_id:e.to_id,active:e.active,created:e.created},o={node_id:e.from_id,active:e.active,created:e.created},c=n.subscriptions.get(e.from_id);c===void 0?n.subscriptions.set(e.from_id,[i]):c.push(i);const f=n.subscribers.get(e.to_id);f===void 0?n.subscribers.set(e.to_id,[o]):f.push(o)}return this.rosterCache={at:Date.now(),index:n},n}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(t){try{return await t()}catch(s){if(s instanceof l&&s.status===404)return null;throw s}}async getNode(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async getRow(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async listNodes(t){const s=t?.status;let
|
|
4
|
+
${o}`}catch{return}finally{if(r!==void 0)try{_(r)}catch{}}}a(W,"readColdStartDiagnostic");function m(r){return process.env.CRTR_API_SOCKET?d({autostart:!1,coldStartPollWindowMs:(h()?x():void 0)??p,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):h()?d({autostart:!1,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):d({...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{},onColdSocket:a(async()=>{T()},"onColdSocket"),coldStartDiagnostic:W,coldStartFailure:M,coldStartPollWindowMs:p})}a(m,"cliClient");const P=2e3;class w{static{a(this,"ApiCanvasSource")}client;rosterCache=null;rosterInFlight=null;constructor(t=m()){this.client=t}async roster(){const t=Date.now();return this.rosterCache!==null&&t-this.rosterCache.at<P?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(s=>{const n={snapshot:s,subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i={node_id:e.to_id,active:e.active,created:e.created},o={node_id:e.from_id,active:e.active,created:e.created},c=n.subscriptions.get(e.from_id);c===void 0?n.subscriptions.set(e.from_id,[i]):c.push(i);const f=n.subscribers.get(e.to_id);f===void 0?n.subscribers.set(e.to_id,[o]):f.push(o)}return this.rosterCache={at:Date.now(),index:n},n}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(t){try{return await t()}catch(s){if(s instanceof l&&s.status===404)return null;throw s}}async getNode(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async getRow(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async listNodes(t){const s=t?.status,n=t?.under===void 0?{}:{under:t.under,under_inclusive:!0};let e;if(Array.isArray(s)){const i=new Set(s);e=(await this.client.listNodes(n)).filter(c=>i.has(c.status))}else e=await this.client.listNodes({...s!==void 0?{status:s}:{},...n});return e.map(i=>u(i))}async browseSnapshot(){const t=await this.client.canvasBrowseCompressed(),s=JSON.parse(C(t).toString("utf8")),n={subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i=n.subscriptions.get(e.from_id)??[];i.push({node_id:e.to_id,active:e.active,created:e.created}),n.subscriptions.set(e.from_id,i);const o=n.subscribers.get(e.to_id)??[];o.push({node_id:e.from_id,active:e.active,created:e.created}),n.subscribers.set(e.to_id,o)}return this.rosterCache={at:Date.now(),index:n},s.nodes.map(e=>u(e))}async panelRoster(){const t=await this.roster();return t.snapshot!==void 0?t.snapshot:(this.rosterCache=null,(await this.roster()).snapshot)}async subscriptionsOf(t){return this.roster().then(s=>s.subscriptions.get(t)??[])}async subscribersOf(t){return this.roster().then(s=>s.subscribers.get(t)??[])}async view(t){const s=new Set([t]),n=[],e=(await this.subscriptionsOf(t)).map(i=>i.node_id);for(;e.length>0;){const i=e.shift();if(!s.has(i)){s.add(i),n.push(i);for(const o of await this.subscriptionsOf(i))s.has(o.node_id)||e.push(o.node_id)}}return n}async ticketCountsForNodes(t){return(await this.client.attentionCounts([...t])).counts}async ticketCountsForView(t){return this.ticketCountsForNodes([t,...await this.view(t)])}async newestReport(t){return(await this.client.getReports(t,{limit:1}))[0]??null}async hasActiveLiveSubscription(t){const s=(await this.subscriptionsOf(t)).filter(n=>n.active);for(const n of s){const e=await this.getRow(n.node_id);if(e&&(e.status==="active"||e.status==="idle"))return!0}return!1}}function et(r,t=D()){const s=r?.scope??"user";if(t){if(r?.canvasName!==void 0)throw F("--canvas selects the person's remote canvas targets, which an app's node cannot reach","Omit --canvas; this node reads its own runtime's canvas.");return new w}const n=r?.canvasName??A(s).activeCanvas??null;if(!n)return new w;const{previewEndpoint:e,relayToken:i}=O(n,s);return new R(e,i)}a(et,"cliCanvasSource");export{w as ApiCanvasSource,L as COLD_START_DIAGNOSTIC_TAIL_BYTES,et as cliCanvasSource,m as cliClient,tt as getNodeOrNull,W as readColdStartDiagnostic,E as rethrowAsCliError};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var R=Object.defineProperty;var h=(n,e)=>R(n,"name",{value:e,configurable:!0});import{defineBranch as P,defineLeaf as k}from"../../core/command.js";import{InputError as v}from"../../core/io.js";import{requireScope as I}from"../../core/errors.js";import{isPidAlive as O}from"../../core/canvas/pid.js";import{fullName as
|
|
2
|
-
`),"leaf")},run:h(async n=>{const e=h(
|
|
3
|
-
`)}},"run"),render:h(n=>{const e=n.node,
|
|
4
|
-
`));const
|
|
5
|
-
`);return`${f.length} ${
|
|
1
|
+
var R=Object.defineProperty;var h=(n,e)=>R(n,"name",{value:e,configurable:!0});import{defineBranch as P,defineLeaf as k}from"../../core/command.js";import{InputError as v}from"../../core/io.js";import{requireScope as I}from"../../core/errors.js";import{isPidAlive as O}from"../../core/canvas/pid.js";import{fullName as $}from"../../core/canvas/labels.js";import{fuzzyMatch as F}from"../../core/tui/fuzzy.js";import{nodeSnapshotLeaf as L}from"../node-snapshot.js";import{nodeTranscriptLeaf as A}from"../node-transcript.js";import{nodeContextLeaf as C}from"../node-context.js";import{cliClient as x,cliCanvasSource as q,rethrowAsCliError as w}from"../api-client.js";import{RemoteCanvasSource as S}from"../../core/canvas/remote-canvas-source.js";import{kindsStateBlock as U,profilesStateBlock as D,resolveProfileViaDaemon as z}from"../profile/daemon-profiles.js";import{focusViewer as E,nodeInPane as B}from"../surface/node/placement.js";const M=k({name:"list",description:"list nodes on the canvas",whenToUse:"you want a flat roster of the nodes on the canvas, sliced by displayed name, status, kind, mode, lifecycle, profile, cwd, and graph scope (--under a node, for that node plus its subscription descendants). The filters AND together. Use `node inspect show` instead to drill into one node and its spine neighbors, `canvas dashboard` for the tree shape, and `canvas attention` to find nodes blocked on the user",help:{name:"node inspect list",summary:"list nodes on the canvas, filtered by any combination of attribute slices and a graph-scope (--under) that AND together",params:[{kind:"flag",name:"status",type:"string",required:!1,constraint:"Filter status (comma-separated for several; accepted values: active, idle, done, dead, canceled). NOTE: `active` means the engine process is live (never closed), NOT that the node is generating right now \u2014 an active node is usually dormant between turns. To tell working-vs-idle, check the pi session-file mtime or CPU, not status."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Filter by persona kind (comma-separated for several). The <kinds> list below names every top-level installable kind; a registered sub-kind filters too by exact path even though it is not listed."},{kind:"flag",name:"mode",type:"string",required:!1,constraint:"Filter by mode (comma-separated for several; accepted values: base, orchestrator)."},{kind:"flag",name:"lifecycle",type:"string",required:!1,constraint:"Filter by lifecycle (comma-separated for several; accepted values: terminal, resident)."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Filter by profile. On the local canvas, accepts a profile id or manifest name from the <profiles> list below, or a close-enough name that resolves to the nearest profile. Against a remote canvas, pass the exact profile id carried by its node rows."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Filter by the displayed node label (handle plus generated description) with the canvas browser\u2019s case-insensitive fuzzy subsequence match."},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Filter to nodes pinned to this exact cwd (absolute path). Roster is canvas-wide (all cwds) by default."},{kind:"flag",name:"under",type:"string",required:!1,constraint:'Graph scope: restrict to this node and its subscription descendants (the sub-DAG reachable downward \u2014 its reports, theirs, \u2026). This is "one initiative / my subtree". ANDs with every attribute filter above, narrowing any of them to this subtree.'},{kind:"flag",name:"canvas",type:"string",required:!1,constraint:"Read from the named remote canvas target (see `crtr canvas config list`) instead of the local canvas. Overrides `crtr canvas use`."}],output:[{name:"nodes",type:"object[]",required:!0,constraint:"Rows include {node_id, name, kind, mode, lifecycle, status, cwd, profile_id, parent, created}. `name` is the displayed node label searched by --name and shown in canvas views. `profile_id` is the stable profile-directory id (null only for historical no-profile nodes)."}],outputKind:"object",effects:["Read-only: lists nodes through the daemon API."]},helpState:{leaf:h(async()=>(await Promise.all([U(),D()])).join(`
|
|
2
|
+
`),"leaf")},run:h(async n=>{const e=h(a=>{const g=n[a];return g!==void 0&&g!==""?g.split(",").map(y=>y.trim()).filter(y=>y!==""):void 0},"csv"),s=e("status"),t=e("kind"),u=e("mode"),d=e("lifecycle"),m=n.profile,c=n.name,l=n.cwd,i=n.under,p=q({canvasName:n.canvas}),r=p instanceof S?m:m===void 0?void 0:(await z(m)).id,o=i!==void 0&&i!=="";if(o&&await p.getNode(i).catch(w)===null)throw new v({error:"not_found",message:`no node: ${i}`,next:"List nodes with `crtr node inspect list`, then pass a real id to --under."});return{nodes:(await p.listNodes({...s!==void 0?{status:s}:{},...o?{under:i}:{}}).catch(w)).filter(a=>!(t!==void 0&&!t.includes(a.kind)||u!==void 0&&!u.includes(a.mode)||d!==void 0&&!d.includes(a.lifecycle)||r!==void 0&&a.profile_id!==r||l!==void 0&&l!==""&&a.cwd!==l)).map(a=>({...a,name:$(a)})).filter(a=>c===void 0||c===""||F(c,a.name))}},"run")}),j=new WeakSet;async function T(n,e){const s=await n.getNode(e.node_id).catch(w);return{node_id:e.node_id,name:s?$(s):"(missing)",kind:s?.kind??"?",status:s?s.intent?`${s.status}/${s.intent}`:s.status:"?",active:e.active}}h(T,"enrichNeighbor");const K=k({name:"show",description:"show a node + its spine neighbors and drill-in pointers",whenToUse:"you want one node in depth \u2014 the debugging entrypoint: a glanceable meta slice, named spine neighbors, a pending-cron count, and exact drill-in paths. Use `node inspect list` for the flat roster or `canvas dashboard` for the whole-tree shape",help:{name:"node inspect show",summary:"show a node in depth \u2014 meta slice, named neighbors, pending-cron count, and drill-in pointers",params:[{kind:"positional",name:"node",required:!0,constraint:"Node id."},{kind:"flag",name:"canvas",type:"string",required:!1,constraint:"Read from the named remote canvas target (see `crtr canvas config list`) instead of the local canvas. Overrides `crtr canvas use`."}],output:[{name:"node",type:"object",required:!0,constraint:"The full node meta (system prompt + every telemetry field). The render surfaces a glanceable slice; `--json` carries the complete dump."},{name:"fault",type:"object",required:!0,constraint:"The active runtime fault projection, or null: {link, kind, retry: {disposition}, since}."},{name:"reports",type:"object[]",required:!0,constraint:"Who this node subscribes to (its reports/down), each enriched with {node_id, name, kind, status, active} \u2014 these are typically its spawned children."},{name:"managers",type:"object[]",required:!0,constraint:"Who subscribes to this node (its managers/up), same enriched shape."},{name:"pending_crons",type:"number",required:!0,constraint:"How many pending crons were created by this node. Inspect with `crtr cron list`."},{name:"paths",type:"object",required:!0,constraint:"Resolved on-disk locations: {context_dir, session_file} \u2014 read these directly to debug. Reports are documents: `crtr canvas read <node>/reports/<name>`."},{name:"follow_up",type:"string",required:!0,constraint:"The concrete next commands to drill deeper."}],outputKind:"object",effects:["Read-only: reads the node, its edges, and pending crons through crtrd."],preview:{suppressOutput:!0}},run:h(async n=>{const e=n.node,s=n.canvas,t=q({canvasName:s});if(t instanceof S){const o=await t.rawShow(e);if(o===null)throw new v({error:"not_found",message:`no node: ${e}`,next:"List nodes with `crtr node inspect list --canvas <name>`."});const f={...o};return j.add(f),f}const u=await t.getNode(e).catch(o=>w(o,"List nodes with `crtr node inspect list`."));if(u===null)throw new v({error:"not_found",message:`no node: ${e}`,next:"List nodes with `crtr node inspect list`."});const d=u,m=x(),c=await Promise.all((await t.subscriptionsOf(e)).map(o=>T(t,o))),l=await Promise.all((await t.subscribersOf(e)).map(o=>T(t,o))),i=(await m.listCrons({created_by:e}).catch(w)).filter(o=>o.created_by===e).length,p={context_dir:d.paths.context_dir,...d.pi_session_file!==void 0?{session_file:d.pi_session_file}:{}},r=[];return r.push(`List the documents it owns (reports, plans, notes): \`crtr canvas list --owner ${e}\`.`),r.push(`Browse its context dir (and its subscriptions') in nvim: \`crtr node inspect context ${e}\`.`),p.session_file&&r.push(`Read the raw conversation transcript: ${p.session_file}`),r.push(`On-disk context dir (ls/read directly): ${p.context_dir}`),i>0&&r.push(`It created ${i} pending cron(s): \`crtr cron list\`.`),c.length>0&&r.push(`Drill into a child/report: \`crtr node inspect show <node_id>\` (${c.map(o=>o.node_id).join(", ")}).`),r.push(`Full machine dump (system prompt + all telemetry): \`crtr --json node inspect show ${e}\`.`),{node:d,fault:d.fault??null,reports:c,managers:l,pending_crons:i,paths:p,follow_up:r.join(`
|
|
3
|
+
`)}},"run"),render:h(n=>{const e=n.node,s=String(e.node_id),t=e.pi_pid,d=j.has(n)?"remote (liveness not checked locally)":O(t)?"alive":"dead",m=e.intent?`/${String(e.intent)}`:"",c=n.fault,l=[];l.push(`# ${$(e)} (${s})`);const i=[`- kind/mode/lifecycle: ${e.kind} / ${e.mode} / ${e.lifecycle}`,`- status: ${e.status}${m}`,...c==null?[]:[`- fault: ${String(c.kind)} / ${String(c.retry?.disposition)} since ${String(c.since)}`],`- broker pid: ${t??"(none)"} \u2014 ${d}`,`- cwd: ${e.cwd}`,`- host: ${e.host_kind}`+(e.profile_id?` \xB7 profile ${e.profile_id}`:""),`- cycles: ${e.cycles} \xB7 created ${e.created}`],p=e.machine;p&&i.push(`- machine: ${p.name??p.id}`),e.parent&&i.push(`- parent: ${e.parent}`),i.push(`- creator: ${e.creator??"an external process"}`),e.waiting_for&&i.push(`- waiting for message: ${e.waiting_for}`),l.push(i.join(`
|
|
4
|
+
`));const r=h((o,f)=>{if(f.length===0)return`${o}: none`;const b=["node_id","name","kind","status","active"],_=`| ${b.join(" | ")} |`,a=`| ${b.map(()=>"---").join(" | ")} |`,g=f.map(y=>`| ${b.map(N=>String(y[N]??"").replace(/\|/g,"\\|").replace(/\n/g," ")).join(" | ")} |`).join(`
|
|
5
|
+
`);return`${f.length} ${o}:
|
|
6
6
|
|
|
7
|
-
${
|
|
8
|
-
${
|
|
9
|
-
${
|
|
7
|
+
${_}
|
|
8
|
+
${a}
|
|
9
|
+
${g}`},"table");return l.push(r("reports (down \u2014 subscriptions, usually children)",n.reports)),l.push(r("managers (up \u2014 subscribers)",n.managers)),l.push(`${n.pending_crons} pending cron(s)`),l.push(`Drill deeper:
|
|
10
10
|
${String(n.follow_up)}`),l.join(`
|
|
11
11
|
|
|
12
|
-
`)},"render")}),ie=k({name:"fork",description:"fork a node into an independent idle root with the same conversation and durable context",whenToUse:"a conversation has already accumulated the context you want, and you want a new user-driven branch beside it without sending a prompt or inheriting any graph-management responsibility. This copies the conversation and durable context, then waits for the fork\u2019s first real user message to supply its mandate. Use `node new --fork-from` instead when spawning a managed worker with an immediate task",help:{name:"node fork",summary:"create an independent resident root from a node\u2019s conversation and durable context, with no kickoff prompt or model turn",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Source node id. Mutually exclusive with --pane; one of them is required."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane showing the source node. Mutually exclusive with --node; one of them is required. The prefix menu passes this for you and the new viewer splits beside this pane."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The new independent root id."},{name:"focused",type:"boolean",required:!0,constraint:"True when a new viewer pane opened beside the caller; false outside tmux."},{name:"session",type:"string",required:!1,constraint:"The tmux session containing the new viewer, when one opened."}],outputKind:"object",effects:["Creates a resident base-mode root with the source node\u2019s copied pi conversation, cwd, profile, kind, model override, and durable context files. Top-level initial-prompt.md, yield-message.md, result.json, and the jobs/ folder of background bash jobs are omitted.","Copies no parent, subscriptions, subscribers, children, crons, worktree, situational context, or lifecycle responsibility. Sends no prompt and consumes no model turn; the first real user message becomes the fork\u2019s mandate.","Inside tmux, opens and focuses a surface-attach viewer as an even-horizontal split in the source pane\u2019s window. Outside tmux, the root is still created but no interactive fallback opens."]},run:h(async n=>{I("crtr:act","crtr node fork");const e=n.pane,
|
|
12
|
+
`)},"render")}),ie=k({name:"fork",description:"fork a node into an independent idle root with the same conversation and durable context",whenToUse:"a conversation has already accumulated the context you want, and you want a new user-driven branch beside it without sending a prompt or inheriting any graph-management responsibility. This copies the conversation and durable context, then waits for the fork\u2019s first real user message to supply its mandate. Use `node new --fork-from` instead when spawning a managed worker with an immediate task",help:{name:"node fork",summary:"create an independent resident root from a node\u2019s conversation and durable context, with no kickoff prompt or model turn",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Source node id. Mutually exclusive with --pane; one of them is required."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane showing the source node. Mutually exclusive with --node; one of them is required. The prefix menu passes this for you and the new viewer splits beside this pane."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The new independent root id."},{name:"focused",type:"boolean",required:!0,constraint:"True when a new viewer pane opened beside the caller; false outside tmux."},{name:"session",type:"string",required:!1,constraint:"The tmux session containing the new viewer, when one opened."}],outputKind:"object",effects:["Creates a resident base-mode root with the source node\u2019s copied pi conversation, cwd, profile, kind, model override, and durable context files. Top-level initial-prompt.md, yield-message.md, result.json, and the jobs/ folder of background bash jobs are omitted.","Copies no parent, subscriptions, subscribers, children, crons, worktree, situational context, or lifecycle responsibility. Sends no prompt and consumes no model turn; the first real user message becomes the fork\u2019s mandate.","Inside tmux, opens and focuses a surface-attach viewer as an even-horizontal split in the source pane\u2019s window. Outside tmux, the root is still created but no interactive fallback opens."]},run:h(async n=>{I("crtr:act","crtr node fork");const e=n.pane,s=n.node;if(s!==void 0&&e!==void 0)throw new v({error:"conflicting_target",message:"--node and --pane are mutually exclusive",next:"Pass the source node id or its viewer pane, not both."});let t=s;if(t===void 0&&e!==void 0&&(t=B(e)),t===void 0||t==="")throw new v({error:"no_node",message:"no source node was provided or found in the pane",next:"Pass --node <id>, or --pane <pane-id> for a pane showing a node."});const u=await x().forkNode(t).catch(w),d=await E(u.node_id,{cwd:u.cwd,name:u.name,...e!==void 0?{pane:e}:{},newPane:!0});return{node_id:u.node_id,focused:d.focused,session:d.session}},"run"),render:h(n=>{const e=n.focused===!0?` Viewer opened beside the source${n.session?` in session ${n.session}`:""}.`:" No viewer opened because no tmux pane was available.";return`Forked independent idle root ${n.node_id}.${e} It will make no model call until its first real user message.`},"render")}),re=P({name:"inspect",description:"read one node \u2014 its graph position, conversation, and context dir",whenToUse:"reading everything about ONE node you can name: enumerate the roster (`list`), inspect a node and its spine neighbors (`show`), or browse its on-disk context dir (`context`). The documents a node owns are `crtr canvas list --owner <id>`. Use `canvas dashboard` instead to render the whole tree SHAPE, or `canvas attention` to find which nodes are blocked on the user",help:{name:"node inspect",summary:"read one node (or the roster) \u2014 topology, conversation, and context dir",model:"Inspection is read-only and never revives a node. The roster is the selection surface; one-node metadata points to progressively heavier views: a parsed broker snapshot, rendered conversation, or context browser."},children:[M,K,L,A,C]});export{ie as nodeFork,re as nodeInspect};
|
package/dist/core/bash-jobs.d.ts
CHANGED
|
@@ -81,6 +81,10 @@ export declare function clearJobDeadline(paths: BashJobPaths): void;
|
|
|
81
81
|
/** Launcher jobs have a root-owned bwrap pid, not a process group; direct
|
|
82
82
|
* jobs keep their detached supervisor process group. */
|
|
83
83
|
export declare function isBashJobProcessGroupAlive(pgid: number, identity?: string): boolean;
|
|
84
|
+
/** Whether the job's process is CONFIRMED gone: a direct job's process group has no member
|
|
85
|
+
* (signal 0 answers ESRCH), a launcher job's pid is dead. EPERM, any other error, and a missing
|
|
86
|
+
* pgid or identity are not confirmation, so a job that cannot be read is never declared gone. */
|
|
87
|
+
export declare function isBashJobProcessConfirmedGone(pgid: number | undefined, identity: string | undefined): boolean;
|
|
84
88
|
/** Best-effort cancellation for a detached bash supervisor. It snapshots the
|
|
85
89
|
* observable descendant tree while the supervisor is still alive, signals its
|
|
86
90
|
* leaves before their parents, then uses the shared identity-guarded KILL
|
package/dist/core/bash-jobs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}o(
|
|
3
|
-
`)}o(Q,"writeJobDeadlineMs");function
|
|
4
|
-
`)}catch(
|
|
5
|
-
`)}catch(b){if(b.code!=="EEXIST")throw b}return{kind:"stopped",signaled:
|
|
6
|
-
`)+1):
|
|
7
|
-
`);return h[h.length-1]===""&&h.pop(),h.slice(-
|
|
8
|
-
`).map(n=>n.trim()).find(n=>n!=="")??"").replace(/\s+/g," ")}o(
|
|
1
|
+
var $=Object.defineProperty;var o=(e,t)=>$(e,"name",{value:t,configurable:!0});import{randomBytes as R}from"node:crypto";import{closeSync as B,openSync as j,readSync as y,statSync as T}from"node:fs";import{dirname as g,join as a}from"node:path";import{captureTeardownSnapshot as I,isAnyPidAlive as _,isPidAlive as S,killProcessTreePids as x}from"./canvas/pid.js";import{launcherRequest as C}from"../launcher/client.js";import{LaunchRefused as F}from"../launcher/spec.js";import{createFileBeneath as P,existsBeneath as O,readdirBeneath as v,readFileBeneath as z,renameBeneath as G,unlinkBeneath as H,writeFileBeneath as E}from"./spaces/open-beneath.js";const X=280;function q(e){if(typeof e!="string"||/[\p{Cc}\p{Cf}]/u.test(e))return null;const t=e.trim();return t===""?null:Buffer.byteLength(t,"utf8")<=X?t:null}o(q,"normalizeBashJobPurpose");function m(e){return a(e,"jobs")}o(m,"bashJobsDir");function p(e,t){return z(g(e),t).toString("utf8")}o(p,"readJobText");function J(e){return v(g(e),m(e)).map(t=>t.name)}o(J,"jobIds");function c(e,t){return O(e.root,t)}o(c,"has");function M(e,t){try{H(e,t)}catch(n){if(n.code!=="ENOENT")throw n}}o(M,"unlinkIfPresent");function ae(e){return typeof e=="string"&&e!==""&&e!=="."&&e!==".."&&/^[A-Za-z0-9._~-]+$/u.test(e)&&Buffer.byteLength(e,"utf8")<=128}o(ae,"isSafeBashJobId");function l(e,t){const n=a(m(e),t);return{jobId:t,root:g(e),dir:n,cmdSh:a(n,"cmd.sh"),jobLog:a(n,"job.log"),jobExit:a(n,"job.exit"),jobRun:a(n,"job.run"),jobBg:a(n,"job.bg"),jobDone:a(n,"job.done"),jobPgid:a(n,"job.pgid"),jobPgidIdentity:a(n,"job.pgid-identity"),jobPurpose:a(n,"purpose"),jobDeadline:a(n,"job.deadline")}}o(l,"bashJobPaths");function U(e,t){try{const n=Number(p(e,l(e,t).jobPgid).trim());return Number.isInteger(n)&&n>1?n:void 0}catch{return}}o(U,"readJobPgid");function W(e,t){try{const n=p(e,l(e,t).jobPgidIdentity).trim();return n===""?void 0:n}catch{return}}o(W,"readJobPgidIdentity");function K(e,t){try{return q(p(e,l(e,t).jobPurpose))}catch{return null}}o(K,"readJobPurpose");const A=10,Y=19;function k(e){return a(m(e),"niceness")}o(k,"bashNicenessPath");function ce(e){try{const t=Number(p(e,k(e)).trim());return!Number.isInteger(t)||t<0||t>Y?A:t}catch{return A}}o(ce,"readBashNiceness");function fe(e,t){E(g(e),k(e),`${Math.trunc(t)}
|
|
2
|
+
`)}o(fe,"writeBashNiceness");function Z(e,t){try{const n=Number(p(e,l(e,t).jobDeadline).trim());return Number.isFinite(n)?n:void 0}catch{return}}o(Z,"readJobDeadlineMs");function Q(e,t){E(e.root,e.jobDeadline,`${Math.trunc(t)}
|
|
3
|
+
`)}o(Q,"writeJobDeadlineMs");function de(e){try{M(e.root,e.jobDeadline)}catch{}}o(de,"clearJobDeadline");function le(e,t){if(t===`launcher:${e}`)return S(e);try{return process.kill(-e,0),!0}catch(n){return n.code==="EPERM"}}o(le,"isBashJobProcessGroupAlive");function he(e,t){if(e===void 0||t===void 0)return!1;if(t===`launcher:${e}`)return!S(e);try{return process.kill(-e,0),!1}catch(n){return n.code==="ESRCH"}}o(he,"isBashJobProcessConfirmedGone");async function V(e,t){const n=I(e,t);if(n.reused||n.tree.length===0)return!1;const r=[...n.tree].reverse(),u=_(r);return x(r,"SIGTERM",n.identities),await new Promise(i=>setTimeout(i,400)),x(r,"SIGKILL",n.identities),u}o(V,"cancelBashJobProcessTree");async function be(e,t,n=!1,r,u){const i=l(e,t);if(!c(i,i.dir))return{kind:"missing"};if(!c(i,i.jobBg)&&!(n&&c(i,i.jobRun))||c(i,i.jobExit))return{kind:"retired",logPath:i.jobLog};const s=U(e,t),f=W(e,t);if(s===void 0||f===void 0)return{kind:"not-stoppable",logPath:i.jobLog};const h=a(i.dir,"job.stop");try{P(i.root,h,u===void 0?"":`${u}
|
|
4
|
+
`)}catch(d){if(d.code==="EEXIST")return{kind:"retired",logPath:i.jobLog};throw d}try{let d;if(f===`launcher:${s}`){if(r===void 0)throw new Error("launcher job stop requires its owning node");try{if(!("ok"in await C({operation:"stop",pid:s,nodeId:r})))throw new Error("launcher did not stop job");d=!0}catch(b){if(!(b instanceof F&&b.refusal==="invalid_spec"))throw b;d=!1}}else d=await V(s,f);try{P(i.root,i.jobExit,`143
|
|
5
|
+
`)}catch(b){if(b.code!=="EEXIST")throw b}return{kind:"stopped",signaled:d,pgid:s,logPath:i.jobLog}}catch(d){throw M(i.root,h),d}}o(be,"stopBackgroundBashJob");function pe(e,t){if(t<=0)return[];const n=64*1024;let r;try{const u=T(e).size,i=Math.max(0,u-n),s=Buffer.alloc(Math.min(u,n));r=j(e,"r"),y(r,s,0,s.length,i);const f=s.toString("utf8"),h=(i>0?f.slice(f.indexOf(`
|
|
6
|
+
`)+1):f).split(`
|
|
7
|
+
`);return h[h.length-1]===""&&h.pop(),h.slice(-t)}catch{return[]}finally{r!==void 0&&B(r)}}o(pe,"tailJobLog");function ge(e){let t;try{t=j(e,"r");const n=Buffer.alloc(64*1024);let r=0,u=0;for(;;){const i=y(t,n,0,n.length,null);if(i===0)break;for(let s=0;s<i;s+=1)n[s]===10&&(r+=1);u=n[i-1]}return u!==0&&u!==10?r+1:r}catch{return 0}finally{t!==void 0&&B(t)}}o(ge,"countJobLogLines");function me(){return`${Date.now()}-${R(4).toString("hex")}`}o(me,"newBashJobId");function w(e){const t=e.indexOf("-");if(t<=0||t===e.length-1)return;const n=Number(e.slice(0,t));return Number.isFinite(n)?n:void 0}o(w,"jobStartedAtMs");function Be(e){const t=Math.max(0,Math.floor(e/1e3));if(t<60)return`${t}s`;const n=Math.floor(t/60),r=t%60;if(n<60)return`${n}m ${String(r).padStart(2,"0")}s`;const u=Math.floor(n/60),i=n%60;return`${u}h ${String(i).padStart(2,"0")}m`}o(Be,"formatBashElapsed");function je(e){return(e.split(`
|
|
8
|
+
`).map(n=>n.trim()).find(n=>n!=="")??"").replace(/\s+/g," ")}o(je,"bashJobCommandLine");function N(e,t=!1){let n;try{n=J(e)}catch{return[]}const r=[];for(const u of n){const i=w(u);if(i===void 0)continue;const s=l(e,u);let f;try{if(!c(s,s.jobBg)&&!(t&&c(s,s.jobRun))||c(s,s.jobExit))continue;f=p(e,s.cmdSh)}catch{continue}r.push({jobId:u,command:f,purpose:K(e,u),startedAtMs:i,logPath:s.jobLog,deadlineAtMs:Z(e,u)??null})}return r.sort((u,i)=>u.startedAtMs-i.startedAtMs)}o(N,"activeBackgroundBashJobs");function ye(e,t){return N(e).filter(n=>n.deadlineAtMs!==null&&t>=n.deadlineAtMs)}o(ye,"expiredAutoBackgroundBashJobs");function Se(e,t){if(!Number.isFinite(t)||t<=0)return 0;let n=0;for(const r of N(e))if(r.deadlineAtMs!==null)try{Q(l(e,r.jobId),r.deadlineAtMs+t),n+=1}catch{}return n}o(Se,"shiftAutoBackgroundBashDeadlines");function D(e){try{return G(e.root,e.jobRun,e.jobBg),"backgrounded"}catch(t){if(t.code!=="ENOENT")throw t;return c(e,e.jobBg)?"already-backgrounded":c(e,e.jobDone)?"finished":"missing"}}o(D,"backgroundBashJob");function L(e){let t;try{t=J(e)}catch{return[]}return t.flatMap(n=>{const r=l(e,n);try{return c(r,r.cmdSh)&&c(r,r.jobLog)&&c(r,r.jobRun)?[r]:[]}catch{return[]}})}o(L,"runningBashJobs");function xe(e){let t;for(const n of L(e)){const r=w(n.jobId);r!==void 0&&(t===void 0||r<t)&&(t=r)}return t}o(xe,"oldestRunningBashJobStartedAtMs");function Pe(e){const t=[];for(const n of L(e))D(n)==="backgrounded"&&t.push(n);return t}o(Pe,"backgroundRunningBashJobs");export{A as DEFAULT_BASH_NICENESS,Y as MAX_BASH_NICENESS,N as activeBackgroundBashJobs,D as backgroundBashJob,Pe as backgroundRunningBashJobs,je as bashJobCommandLine,l as bashJobPaths,m as bashJobsDir,k as bashNicenessPath,V as cancelBashJobProcessTree,de as clearJobDeadline,ge as countJobLogLines,ye as expiredAutoBackgroundBashJobs,Be as formatBashElapsed,he as isBashJobProcessConfirmedGone,le as isBashJobProcessGroupAlive,ae as isSafeBashJobId,w as jobStartedAtMs,me as newBashJobId,q as normalizeBashJobPurpose,xe as oldestRunningBashJobStartedAtMs,ce as readBashNiceness,Z as readJobDeadlineMs,U as readJobPgid,W as readJobPgidIdentity,K as readJobPurpose,Se as shiftAutoBackgroundBashDeadlines,be as stopBackgroundBashJob,pe as tailJobLog,fe as writeBashNiceness,Q as writeJobDeadlineMs};
|
|
@@ -149,11 +149,25 @@ export interface GraphNodeRow {
|
|
|
149
149
|
* needs. This keeps the interactive graph off the full node-summary projection
|
|
150
150
|
* and its unused runtime, outcome, and placement fields. */
|
|
151
151
|
export declare function graphNodes(): Promise<GraphNodeRow[]>;
|
|
152
|
-
export
|
|
152
|
+
export interface ListNodesFilter {
|
|
153
153
|
status?: NodeStatus | NodeStatus[];
|
|
154
154
|
withRecordedPid?: boolean;
|
|
155
155
|
withRecordedPidOrFrozen?: boolean;
|
|
156
|
-
|
|
156
|
+
/** Only the navigable nodes below this node (excluding it), resolved by one recursive query. */
|
|
157
|
+
under?: string;
|
|
158
|
+
/** With `under`: the node itself plus every node below it, human ask nodes included (the scope `node inspect list --under` shows). */
|
|
159
|
+
underInclusive?: boolean;
|
|
160
|
+
lifecycle?: string;
|
|
161
|
+
kind?: string;
|
|
162
|
+
mode?: string;
|
|
163
|
+
profileId?: string;
|
|
164
|
+
profilePrefix?: string;
|
|
165
|
+
parent?: string;
|
|
166
|
+
topLevel?: boolean;
|
|
167
|
+
/** Only nodes whose manager has no node row. */
|
|
168
|
+
hanging?: boolean;
|
|
169
|
+
}
|
|
170
|
+
export declare function listNodes(filter?: ListNodesFilter): Promise<NodeRow[]>;
|
|
157
171
|
/** Placement-only terminal rows for the daemon's residue pass. These columns
|
|
158
172
|
* preserve lastActivityMs's timestamp inputs and the teardown event fields;
|
|
159
173
|
* unlike node_rows, the nodes table needs no execution/session/fault joins. */
|