@north-light/cli 0.3.584 → 0.3.586

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/api/client.d.ts +3 -1
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/bash-jobs.d.ts +17 -0
  6. package/dist/api/dto/bash-jobs.js +1 -1
  7. package/dist/api/routes.d.ts +1 -0
  8. package/dist/api/routes.js +1 -1
  9. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  10. package/dist/clients/attach/command.js +1 -1
  11. package/dist/clients/attach/input/capabilities.d.ts +4 -4
  12. package/dist/clients/attach/input/capabilities.js +1 -1
  13. package/dist/clients/attach/session/connection.d.ts +7 -8
  14. package/dist/clients/attach/session/connection.js +1 -1
  15. package/dist/clients/attach/session/context.d.ts +2 -2
  16. package/dist/clients/attach/session/reconnect.d.ts +2 -0
  17. package/dist/clients/attach/session/reconnect.js +1 -1
  18. package/dist/clients/attach/viewer.js +500 -500
  19. package/dist/commands/node/bash.js +4 -3
  20. package/dist/commands/sys/desktop.js +1 -1
  21. package/dist/core/broker-client/index.d.ts +1 -0
  22. package/dist/core/broker-client/index.js +1 -1
  23. package/dist/core/broker-client/transport-relay.js +1 -1
  24. package/dist/core/broker-client/transport.d.ts +11 -1
  25. package/dist/core/broker-client/transport.js +1 -1
  26. package/dist/core/canvas/export-sqlite.js +2 -2
  27. package/dist/core/canvas/schema-pg/010-package-publications.sql +16 -0
  28. package/dist/core/canvas/schema-version.d.ts +1 -1
  29. package/dist/core/canvas/schema-version.js +1 -1
  30. package/dist/core/events/read.js +1 -1
  31. package/dist/core/graph/kinds/job.js +2 -2
  32. package/dist/core/graph/package-docs.d.ts +11 -0
  33. package/dist/core/graph/package-docs.js +6 -6
  34. package/dist/core/graph/package-publish.d.ts +30 -0
  35. package/dist/core/graph/package-publish.js +3 -0
  36. package/dist/core/log.d.ts +2 -0
  37. package/dist/core/log.js +5 -5
  38. package/dist/core/providers/bundles.js +2 -2
  39. package/dist/core/providers/call.js +1 -1
  40. package/dist/core/providers/device.js +1 -1
  41. package/dist/daemon/api/handlers/bash-jobs.js +3 -1
  42. package/dist/daemon/api/handlers/package-docs.js +1 -1
  43. package/dist/daemon/api/operations.js +1 -1
  44. package/dist/daemon/crtrd.js +18 -17
  45. package/dist/shared/inbox-entry-body.js +7 -7
  46. package/docs/sdk/release-notes.md +4 -0
  47. package/package.json +2 -2
  48. package/packages/crouter-identity/package.json +1 -1
  49. package/runtime.lock.json +13 -13
@@ -1,18 +1,19 @@
1
- var er=Object.defineProperty;var s=(e,l)=>er(e,"name",{value:l,configurable:!0});import{applyBootSettings as rr}from"./boot-settings.js";import{startPeerOutbox as tr}from"./peer/outbox.js";import{reportMachineStatus as nr}from"../core/peer/directory.js";import{createPeerRelay as or}from"./peer/relay-service.js";import{writeFileSync as ir,readFileSync as ar,rmSync as sr,mkdirSync as ye,existsSync as k,unlinkSync as _e,chmodSync as be}from"node:fs";import{createServer as J}from"node:http";import{dirname as cr}from"node:path";import{envCrtrdTcp as ke,envDocumentPort as lr}from"../shared/env.js";import{openCanvasConversationStore as dr,serveCanvasConversationStore as mr}from"../core/canvas/sessions.js";import{installConversationStore as pr}from"../core/conversation-store/index.js";import{pollRunObservers as fr}from"./runs/observer.js";import{randomBytes as Re}from"node:crypto";import{apiSocketPath as Pe,crtrHome as ur}from"../core/canvas/paths.js";import{activeAppUsers as wr}from"../core/spaces/users.js";import{ensureAppSpace as hr,ensureUserFiles as vr}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as L}from"../launcher/client.js";import{installLauncherEventSink as gr}from"./launcher-events.js";import{initializeEmptyLayout as Sr,layoutNeedsMigration as yr,socketDir as Ee}from"../core/layout.js";import{migrateLooseKeys as _r}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as br}from"../core/profiles/relocate.js";import{getNode as kr,listNodesForSupervision as Ie,listParkedResidentsWithWakeMail as Rr,setFrozen as xe}from"../core/canvas/index.js";import{createApiServer as Pr,closeServer as Te}from"./api/server.js";import{Router as Er}from"./api/router.js";import{healthRoutes as Ir}from"./api/handlers/health.js";import{createDocumentListener as xr}from"./api/document-listener.js";import{documentSecret as Tr}from"./api/document-secret.js";import{createAppListener as Dr}from"./api/app-listener.js";import{registerMachineEnvironment as Cr}from"../core/environments.js";import{registerBlaxelRunnerFromEnv as Lr}from"../core/secrets/blaxel-register.js";import{markCloudRole as $r,resolvePerson as Ar,retireLocalPerson as Nr,setPersonId as Mr}from"../core/canvas/person.js";import{backfillNodeApps as Gr,runPermissionsBoot as Or}from"../core/permissions/boot.js";import{startRunNotices as Fr}from"./run-notices.js";import{startGrantEffects as Br}from"./reconcilers/grant-effects.js";import{createGrantSync as Hr,GRANT_SYNC_INTERVAL_S as jr}from"../core/grants/sync.js";import{sweepSandboxes as zr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as Ur}from"./cron/run-socket.js";import{hasSyncedGrants as qr}from"../core/grants/mirror.js";import{readConfig as se}from"../core/config.js";import{reconcileUndeliveredTickets as Wr}from"./human/sweep.js";import{resetHandedOffDeliveries as Jr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as Kr}from"../core/canvas/daemon-actions.js";import{sweepReviews as Vr}from"./review/sweep.js";import{pidfilePath as ce}from"./pidfile.js";import{rendererWarning as Yr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Qr}from"./supervise-cadence.js";import{createResumeDetector as Xr}from"./resume-detector.js";import{setFatalFaultAnnouncer as Zr}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as et}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as rt}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as tt}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as nt}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as ot}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as it}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as at}from"./reconcilers/action-lane.js";import{endLiveExecution as st,migrateLegacyExecutionIdentities as ct}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as lt}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as dt}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as mt}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as pt}from"./reconcilers/storage-due-work.js";import{PurgeDueWorkReconciler as ft}from"./reconcilers/purge-due-work.js";import{assertLedgerEnv as ut}from"../core/ledger/rates.js";import{LedgerSandboxReconciler as wt}from"./reconcilers/ledger-sandbox.js";import{LedgerStorageReconciler as ht}from"./reconcilers/ledger-storage.js";import{LedgerR2Reconciler as vt}from"./reconcilers/ledger-r2.js";import{ImportLaneReconciler as gt}from"./reconcilers/import-lane.js";import{BashDeadlineReconciler as St}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as yt}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as _t}from"./reconcilers/structured-request-lane.js";import{RecipeImageReconciler as bt,subscribeImageBuilt as kt}from"./reconcilers/recipe-image.js";import{reconcileStructuredRequestSidecars as Rt}from"./structured-requests/boot.js";import{captureLivenessSnapshot as De,capturePidCommand as Pt,captureTeardownSnapshot as Ce,isPidAlive as Et,isAnyPidAlive as Le,killProcessTreePids as $e}from"../core/canvas/pid.js";import{bindFleet as It,boundFleet as xt}from"../core/runtime/fleet.js";import{bindDaemonControl as Tt,clearDaemonControl as Dt}from"./control.js";import{execDaemon as Ct,spawnDaemon as Lt}from"./manage.js";import{reconcileAndMigrateBoot as $t}from"../core/canvas/boot.js";import{resolveInstallId as At}from"../core/canvas/install-id.js";import{setInstallId as Nt}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Mt,daemonOwnershipApplies as Gt,daemonOwnershipClaimed as Ot,releaseDaemonOwnership as Ae}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as Ft,closeAllDbs as le,openDb as Ne,withCanvasWrite as Bt}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as Ht}from"../core/canvas/import-sqlite.js";import{ensurePostgres as jt,ensurePostgresHealthy as zt,stopPostgres as Ut,withPostgresStartLock as qt}from"./postgres/index.js";import{brokerSignalBus as F}from"./broker-signals/bus.js";import{brokerSignalStreams as Wt}from"./api/handlers/broker-signals.js";import{setRequestsStartRunObservers as Jt}from"./api/handlers/broker-ops.js";import{reconcilePackages as Kt}from"../core/graph/package-reconcile.js";import{startRepoSync as Vt}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Yt,reapStaleSpares as Qt}from"../core/runtime/warm-pool.js";import{DaemonFleet as Xt}from"./fleet.js";import{copyNodeFilesToRows as Zt}from"../core/runtime/first-boot-rows.js";import{BOOT_MIGRATIONS as en}from"./boot-migrations.js";import{emitEvent as p}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as rn}from"../core/events/source.js";import{activateCanvasImport as tn,MigrationBlockedError as nn,runForcedCanvasImport as on}from"../migrations/activation.js";import{adoptInstallPerson as an,convertLegacyScopedStore as sn,personStoresCopied as cn}from"../core/scoped-state/migrate.js";import{readLegacyUserSnapshot as ln}from"../core/scoped-state/legacy-profiles.js";import{heldPersons as Me,installPreludeSnapshot as dn}from"../core/scoped-state/person-store.js";import{loadPersonSettings as Ge}from"../core/scoped-state/person-rows.js";import{userScopeRoot as Oe}from"../core/scope.js";import{brokerCommandDeclaresCanvasHome as de}from"../core/runtime/broker-ownership.js";import{brokerCommandDeclaresCanvasHome as Oi}from"../core/runtime/broker-ownership.js";function me(e){return/ --epoch (\S+) /.exec(e)?.[1]??null}s(me,"brokerCommandEpoch");const mn=5e3,Fe=150;async function pn(e){const l=De();if(l===null)throw p({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const u=ur(),f=[];for(const[n,d]of l.processes){const y=d.command;if(d.zombie||!y.includes("broker-cli.js")||!de(y,u)||me(y)===e)continue;const b=y.trim().split(/\s+/).at(-1)??"";b===""||b.endsWith("broker-cli.js")||f.push({pid:n,nodeId:b})}let v=0;const a=[];for(const n of f){const d=Pt(n.pid);if(d===null||!d.includes("broker-cli.js")||!de(d,u)||me(d)===e||d.trim().split(/\s+/).at(-1)!==n.nodeId)continue;const y=Ce(n.pid,null);if(!y.reused){try{process.platform==="linux"&&k(x)?await L({operation:"stop",pid:n.pid}):process.kill(n.pid,"SIGTERM")}catch{continue}v++,a.push({pid:n.pid,snap:y})}}const w=Date.now()+mn;for(;Date.now()<w&&a.some(n=>Le(n.snap.tree.length>0?n.snap.tree:[n.pid]));)await new Promise(n=>setTimeout(n,Fe));let g=0;for(const n of a){const d=n.snap.tree.length>0?n.snap.tree:[n.pid];Le(d)&&(process.platform==="linux"&&k(x)?await L({operation:"stop",pid:n.pid}):$e(d,"SIGKILL",n.snap.identities),g++)}g>0&&await new Promise(n=>setTimeout(n,Fe));const m=De();if(m===null)throw p({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const c=[];for(const[n,d]of m.processes){const y=d.command;d.zombie||!y.includes("broker-cli.js")||de(y,u)&&me(y)!==e&&c.push(n)}if(c.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${c.join(", ")}`);p({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:f.length,sigtermed:v,sigkilled:g}})}s(pn,"reapPriorEpochBrokers");const fn=5e3;async function un(e){const l=Array.from(e.entries());if(l.length===0)return;for(const[a]of l){const w=(await kr(a))?.status;(w==="active"||w==="idle")&&await xe(a,new Date().toISOString())}const u=l.map(([,a])=>({pid:a.pid,snap:Ce(a.pid,null),exited:a.handle.exited}));for(const a of u)if(!a.snap.reused)try{process.platform==="linux"&&k(x)?await L({operation:"stop",pid:a.pid}):process.kill(a.pid,"SIGTERM")}catch{}const f=new Promise(a=>{setTimeout(a,fn).unref()});await Promise.allSettled(u.map(a=>Promise.race([a.exited.then(()=>{}),f])));const v=[];for(const a of u)Et(a.pid)&&(process.platform==="linux"&&k(x)?await L({operation:"stop",pid:a.pid}):$e(a.snap.tree.length>0?a.snap.tree:[a.pid],"SIGKILL",a.snap.identities),v.push(a));await Promise.all(v.map(a=>a.exited));for(const[a]of l)await st(a,{reason:"daemon-teardown"});p({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:u.length,sigkilled:v.length}})}s(un,"teardownFleet");function Be(){ye(cr(ce()),{recursive:!0}),ir(ce(),String(process.pid),"utf8")}s(Be,"writePidfile");function He(e){return typeof e=="object"&&e!==null&&e.code==="ENOENT"}s(He,"isMissingPathError");function je(e){const l=ce();let u;try{u=ar(l,"utf8")}catch(f){if(He(f))return;throw f}if(u.trim()!==String(e))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${e})`);try{sr(l)}catch(f){if(He(f))return;throw f}}s(je,"removeOwnedPidfileMirror");const wn={acceptsDetachedWork:s(()=>!0,"acceptsDetachedWork"),registerDetached:s(e=>{e.catch(()=>{})},"registerDetached")},K=new et;Zr(e=>K.handleFatalFault(e,!1));const hn=new rt,vn=new tt,gn=new nt,Sn=new ot,yn=new it,_n=new at,bn=new dt,kn=new mt,Rn=new pt,Pn=new ft,En=new wt,In=new ht,xn=new vt,Tn=new gt,Dn=new St,Cn=new yt,Ln=new _t,$n=new bt;async function An(e=Date.now(),l=wn){const u=xt(),f=await K.runFleetPreamble(u);let v,a;try{const g=await Ie();v=g.filter(c=>c.status==="active"||c.status==="idle"),a=g.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead");const m=new Set(a.map(c=>c.node_id));a.push(...(await Rr()).filter(c=>!m.has(c.node_id)))}catch(g){p({level:"error",event:"canvas.node_list.failed",error:g});return}await K.run(e,{rows:v,fleet:u,lifecycle:l}),await hn.run(e,{rows:v});const w=await vn.run(e,{rows:[...v,...a],fleet:u});await gn.run(e),await Ln.run(e),await $n.run(e,{lifecycle:l}),await Sn.run(e,{lifecycle:l}),await yn.run(e,{lifecycle:l}),await _n.run(e,{lifecycle:l}),await bn.run(e,{lifecycle:l}),await kn.run(e,{lifecycle:l,fleet:u}),Rn.run(e,{lifecycle:l}),Pn.run(e,{lifecycle:l}),En.run(e,{lifecycle:l}),In.run(e,{lifecycle:l}),xn.run(e,{lifecycle:l}),Tn.run(e,{lifecycle:l}),await fr(),Cn.run(e,{fleet:u,lifecycle:l}),await Dn.run(e,{rows:v}),K.warnIfSaturated({fleet:u,lifecycle:l,thresholds:f,frozen:w})}s(An,"superviseTick");function V(e){return e===void 0||e==="reconcile"}s(V,"roleRunsLanes");function $(e){return e===void 0||e==="api"}s($,"roleServesRequests");const Nn=66e4;function Mn(e){const l=new Er().registerAll(Ir(()=>null).filter(n=>n.pattern==="/healthz")),u=s((n,d)=>{const y=(n.url??"/").split("?")[0];if((n.method??"GET").toUpperCase()==="GET"&&y==="/healthz"){l.handle(n,d,null,{class:"person"});return}d.writeHead(404,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({error:{code:"not_found",message:"this process serves only /healthz",origin:"runtime"}}))},"handler"),f=Pe();k(f)&&_e(f);const v=J(u),a=new Promise((n,d)=>{v.once("error",d),v.listen(f,()=>{v.off("error",d),be(f,384),n()})});let w,g=null;const m=e.tcp??ke()??se("user").api.tcp;if(m!==void 0&&m!==""){const n=/^(.*):(\d+)$/.exec(m.trim());if(n===null||Number(n[2])>65535)throw new Error(`invalid reconcile probe TCP address: ${m}`);const d=J(u);d.on("error",y=>p({event:"api.server.failed",level:"error",error:y})),d.listen(Number(n[2]),n[1]===""?"0.0.0.0":n[1],()=>{g=`${n[1]===""?"0.0.0.0":n[1]}:${n[2]}`}),w=d}let c=!1;return{ready:a,tcpAddress:s(()=>g,"tcpAddress"),async close(n={}){if(!c){c=!0,await Promise.all([Te(v,new Set,n.graceMs),w===void 0?Promise.resolve():Te(w,new Set,n.graceMs)]);try{k(f)&&_e(f)}catch{}}}}}s(Mn,"createProbeServer");const Gn="daemon is draining for shutdown and admits no new work";async function On(e){ye(Ee(),{recursive:!0,mode:493}),process.platform==="linux"&&be(Ee(),493);const l=Pe();if(k(l))throw new Error(`layout refusal cannot bind occupied socket: ${l}`);const u=J((m,c)=>{if(m.method==="GET"&&m.url==="/healthz"){c.writeHead(200,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}c.writeHead(503,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((m,c)=>{u.once("error",c),u.listen(l,()=>{u.off("error",c),m()})});let f;const v=e.tcp??ke();if(v){const m=/^(.*):(\d+)$/.exec(v);if(!m||Number(m[2])>65535)throw new Error(`invalid refusal TCP address: ${v}`);const c=J(u.listeners("request")[0]);await new Promise((n,d)=>{c.once("error",d),c.listen(Number(m[2]),m[1],()=>{c.off("error",d),n()})}),f=c}Be();let a;const w=s(()=>(a??=(async()=>{u.closeAllConnections(),f?.closeAllConnections(),await Promise.all([u,f].filter(m=>m!==void 0).map(m=>new Promise((c,n)=>m.close(d=>d?n(d):c())))),je(process.pid),process.off("SIGINT",g),process.off("SIGTERM",g)})(),a),"cleanup"),g=s(()=>{w().then(()=>process.exit(0),m=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(m)}
2
- `),process.exit(1)})},"onSignal");return process.on("SIGINT",g),process.on("SIGTERM",g),w}s(On,"serveLayoutRefusal");async function Fn(e={}){if(e.role==="machine")return(await import("./machine-daemon.js")).runMachineDaemon();if(yr())return On(e);Sr();const l=s(r=>{process.stderr.write(`[crtrd] ${r}
3
- `)},"logPostgres"),u=!!process.env.CRTR_TEST_PG_URL,f=Gt(e.role);Jt(V(e.role));const v=s(async()=>f?await Mt(Re(16).toString("hex")):{claimed:!0,claim:{pid:process.pid,pid_identity:"",token:Re(16).toString("hex")}},"claimOwnership"),{database:a,ownership:w}=u?{database:{url:await Ft()},ownership:await v()}:await qt(async()=>({database:await jt({log:l,startLockHeld:!0}),ownership:await v()}));if(!w.claimed){if(w.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${w.incumbentPid??"?"})
4
- `);else{const r=[w.incumbentPid!==void 0?`pid ${w.incumbentPid}`:void 0,w.verdict!==void 0?`verdict ${w.verdict}`:void 0].filter(h=>h!==void 0),o=r.length>0?` (${r.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${w.reason}${o}
5
- `),w.reason==="own_identity_indeterminate"&&process.stderr.write("[crtrd] cannot read its own process identity. crouter needs /proc on Linux, or the `ps` command elsewhere (Debian/Ubuntu: apt-get install procps).\n"),(w.reason==="own_identity_indeterminate"||w.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const g=w.claim;let m=null,c=null,n=null,d,y="";try{f&&await pn(g.token);for(const t of br())process.stderr.write(`[crtrd] ${t}
6
- `);for(const t of await _r())process.stderr.write(`[crtrd] ${t}
7
- `);await Ne(),await Ht(a.url,l);const r=e.role===void 0&&!await cn();let o=null;r&&(sn({kind:"user",root:Oe()}),o=ln(Oe())),e.role===void 0&&dn(o??{profiles:[],defaults:{},settings:{},state:{}}),await F.listen(a.url);const h=s(t=>{Ge(t).catch(O=>p({level:"error",event:"daemon.settings.reload_failed",error:O}))},"reloadPerson");d=await F.subscribe(t=>{Me().includes(t)&&h(t)},{kinds:["settings"],onListenStart:s(()=>{for(const t of Me())h(t)},"onListenStart")}),e.role!==void 0&&$r();const i=await Bt(async t=>(await Gr(t),await Kt(t)));for(const t of i.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${t.message}
8
- `);for(const t of i.invalid)process.stderr.write(`[crtrd] package file is not a document: ${t.path}: ${t.error}
9
- `);for(const t of i.quarantined)process.stderr.write(`[crtrd] plugin "${t.name}" has a damaged ${t.file} (${t.reason}); ${t.movedTo!==void 0?`moved to ${t.movedTo}`:"left in place and skipped"}
10
- `);for(const t of i.kinds.refused)process.stderr.write(`[crtrd] plugin "${t.plugin}" kind ${t.kind} not registered: ${t.message}
11
- `);for(const t of i.kinds.invalid)process.stderr.write(`[crtrd] plugin "${t.plugin}" declares invalid object kinds or scopes; no kinds registered and no app token: ${t.error}
12
- `);if(y=await At(),Nt(y),e.role===void 0&&(m=await Ar(),m!==null)){if(Mr(m.id),await an(m.id),process.platform==="darwin"){const{readConfig:t,updateConfig:O}=await import("../core/config.js");if(t("user").paths?.user_files===void 0){const{homedir:Ze}=await import("node:os");await O("user",Se=>{Se.paths??={},Se.paths.user_files??=Ze()})}}c=await Nr(),c.joinedFrom!==null&&await Ge(c.person),await rr(),n=await Or()}if(process.platform==="linux"&&k(x)&&(gr(),await L({operation:"users.sync",users:await wr()})),f){await lt(g.token);const t=await Zt();Object.values(t).some(O=>O>0)&&process.stderr.write(`[crtrd] node files copied into rows: ${JSON.stringify(t)}
13
- `)}}catch(r){await F.close();try{if(f){const{released:o}=await Ae(g);if(!o)throw new Error("daemon ownership claim was not released")}await le()}catch(o){throw new AggregateError([r,o],"daemon startup failed and cleanup also failed")}throw r}let b=!0,Y,B=Promise.resolve(),Q=!1,H,X,Z,T;const j=new Set;let ee=!1,pe=!1,P,D,re,z=!1,U,A,N,M,te,ne,oe;const ze=Xr();let E,S={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},C="initial startup activation",Ue=null;function qe(){return S.phase==="ready"?null:{phase:S.phase,message:S.message,blockerPaths:S.blockerPaths}}s(qe,"startupBlock");function R(r){j.add(r),r.finally(()=>{j.delete(r)}).catch(()=>{})}s(R,"registerDetached");const fe={acceptsDetachedWork:s(()=>b,"acceptsDetachedWork"),registerDetached:R};V(e.role)&&await Vt(fe,Ne);async function We(){try{b=!1,Wt.close(),X?.(),X=void 0,Z?.(),d?.(),Z=void 0,ne?.(),ne=void 0,await F.close(),H!==void 0&&(clearInterval(H),H=void 0),N!==void 0&&(clearInterval(N),N=void 0),oe?.(),oe=void 0;let r;do r=B,await r;while(r!==B);for(;j.size>0;)await Promise.allSettled([...j]);if(T!==void 0&&(f&&await un(T),await T.exitsSettled(),T.dispose()),re!==void 0&&await re.close(),D!==void 0&&!z&&(z=!0,await D.close()),te?.(),te=void 0,M!==void 0){const o=M;M=void 0,await o.stop()}if(A!==void 0){const o=A;A=void 0,await o.close()}if(U!==void 0){const o=U;U=void 0,await o.close()}if(ee||(je(process.pid),ee=!0),ee&&!pe){if(f){const{released:o}=await Ae(g);if(!o)throw new Error("daemon ownership claim was not released")}pe=!0,await le()}}finally{Dt(),process.off("SIGINT",he),process.off("SIGTERM",ve),process.off("exit",ge)}}s(We,"cleanupAttempt");const q=1e3;let ue=!1;function Je(){return ue?{graceMs:q}:(ue=!0,_.fresh(()=>{p({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:q}})}),setTimeout(()=>{Ke()},q),{graceMs:q})}s(Je,"requestHandover");async function Ke(){try{await I()}catch(r){const o=r instanceof Error?r.stack??r.message:String(r);process.stderr.write(`[crtrd] handover cleanup failed:
1
+ var rr=Object.defineProperty;var s=(e,l)=>rr(e,"name",{value:l,configurable:!0});import{applyBootSettings as tr}from"./boot-settings.js";import{startPeerOutbox as nr}from"./peer/outbox.js";import{reportMachineStatus as or}from"../core/peer/directory.js";import{createPeerRelay as ir}from"./peer/relay-service.js";import{writeFileSync as ar,readFileSync as sr,rmSync as cr,mkdirSync as ye,existsSync as k,unlinkSync as _e,chmodSync as be}from"node:fs";import{createServer as J}from"node:http";import{dirname as lr}from"node:path";import{envCrtrdTcp as ke,envDocumentPort as dr}from"../shared/env.js";import{openCanvasConversationStore as mr,serveCanvasConversationStore as pr}from"../core/canvas/sessions.js";import{installConversationStore as fr}from"../core/conversation-store/index.js";import{pollRunObservers as ur}from"./runs/observer.js";import{randomBytes as Re}from"node:crypto";import{apiSocketPath as Pe,crtrHome as hr}from"../core/canvas/paths.js";import{activeAppUsers as wr}from"../core/spaces/users.js";import{ensureAppSpace as vr,ensureUserFiles as gr}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as T}from"../launcher/spec.js";import{launcherRequest as $}from"../launcher/client.js";import{installLauncherEventSink as Sr}from"./launcher-events.js";import{initializeEmptyLayout as yr,layoutNeedsMigration as _r,socketDir as Ee}from"../core/layout.js";import{migrateLooseKeys as br}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as kr}from"../core/profiles/relocate.js";import{getNode as Rr,listNodesForSupervision as Ie,listParkedResidentsWithWakeMail as Pr,setFrozen as xe}from"../core/canvas/index.js";import{createApiServer as Er,closeServer as Te}from"./api/server.js";import{Router as Ir}from"./api/router.js";import{healthRoutes as xr}from"./api/handlers/health.js";import{createDocumentListener as Tr}from"./api/document-listener.js";import{documentSecret as Dr}from"./api/document-secret.js";import{createAppListener as Cr}from"./api/app-listener.js";import{registerMachineEnvironment as Lr}from"../core/environments.js";import{registerBlaxelRunnerFromEnv as $r}from"../core/secrets/blaxel-register.js";import{markCloudRole as Ar,resolvePerson as Nr,retireLocalPerson as Mr,setPersonId as Gr}from"../core/canvas/person.js";import{backfillNodeApps as De,runPermissionsBoot as Or}from"../core/permissions/boot.js";import{startRunNotices as Fr}from"./run-notices.js";import{startGrantEffects as Br}from"./reconcilers/grant-effects.js";import{createGrantSync as Hr,GRANT_SYNC_INTERVAL_S as jr}from"../core/grants/sync.js";import{sweepSandboxes as zr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as Ur}from"./cron/run-socket.js";import{hasSyncedGrants as qr}from"../core/grants/mirror.js";import{readConfig as se}from"../core/config.js";import{reconcileUndeliveredTickets as Wr}from"./human/sweep.js";import{resetHandedOffDeliveries as Jr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as Kr}from"../core/canvas/daemon-actions.js";import{sweepReviews as Vr}from"./review/sweep.js";import{pidfilePath as ce}from"./pidfile.js";import{rendererWarning as Yr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Qr}from"./supervise-cadence.js";import{createResumeDetector as Xr}from"./resume-detector.js";import{setFatalFaultAnnouncer as Zr}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as et}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as rt}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as tt}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as nt}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as ot}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as it}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as at}from"./reconcilers/action-lane.js";import{endLiveExecution as st,migrateLegacyExecutionIdentities as ct}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as lt}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as dt}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as mt}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as pt}from"./reconcilers/storage-due-work.js";import{PurgeDueWorkReconciler as ft}from"./reconcilers/purge-due-work.js";import{assertLedgerEnv as ut}from"../core/ledger/rates.js";import{LedgerSandboxReconciler as ht}from"./reconcilers/ledger-sandbox.js";import{LedgerStorageReconciler as wt}from"./reconcilers/ledger-storage.js";import{LedgerR2Reconciler as vt}from"./reconcilers/ledger-r2.js";import{ImportLaneReconciler as gt}from"./reconcilers/import-lane.js";import{BashDeadlineReconciler as St}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as yt}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as _t}from"./reconcilers/structured-request-lane.js";import{RecipeImageReconciler as bt,subscribeImageBuilt as kt}from"./reconcilers/recipe-image.js";import{reconcileStructuredRequestSidecars as Rt}from"./structured-requests/boot.js";import{captureLivenessSnapshot as Ce,capturePidCommand as Pt,captureTeardownSnapshot as Le,isPidAlive as Et,isAnyPidAlive as $e,killProcessTreePids as Ae}from"../core/canvas/pid.js";import{bindFleet as It,boundFleet as xt}from"../core/runtime/fleet.js";import{bindDaemonControl as Tt,clearDaemonControl as Dt}from"./control.js";import{execDaemon as Ct,spawnDaemon as Lt}from"./manage.js";import{reconcileAndMigrateBoot as $t}from"../core/canvas/boot.js";import{resolveInstallId as At}from"../core/canvas/install-id.js";import{setInstallId as Nt}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Mt,daemonOwnershipApplies as Gt,daemonOwnershipClaimed as Ot,releaseDaemonOwnership as Ne}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as Ft,closeAllDbs as le,openDb as Me,withCanvasWrite as Ge}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as Bt}from"../core/canvas/import-sqlite.js";import{ensurePostgres as Ht,ensurePostgresHealthy as jt,stopPostgres as zt,withPostgresStartLock as Ut}from"./postgres/index.js";import{brokerSignalBus as F}from"./broker-signals/bus.js";import{brokerSignalStreams as qt}from"./api/handlers/broker-signals.js";import{setRequestsStartRunObservers as Wt}from"./api/handlers/broker-ops.js";import{reconcilePackages as Jt}from"../core/graph/package-reconcile.js";import{publish as Kt,readBuiltinSnapshot as Vt}from"../core/graph/package-publish.js";import{startRepoSync as Yt}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Qt,reapStaleSpares as Xt}from"../core/runtime/warm-pool.js";import{DaemonFleet as Zt}from"./fleet.js";import{copyNodeFilesToRows as en}from"../core/runtime/first-boot-rows.js";import{BOOT_MIGRATIONS as rn}from"./boot-migrations.js";import{emitEvent as m}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as tn}from"../core/events/source.js";import{activateCanvasImport as nn,MigrationBlockedError as on,runForcedCanvasImport as an}from"../migrations/activation.js";import{adoptInstallPerson as sn,convertLegacyScopedStore as cn,personStoresCopied as ln}from"../core/scoped-state/migrate.js";import{readLegacyUserSnapshot as dn}from"../core/scoped-state/legacy-profiles.js";import{heldPersons as Oe,installPreludeSnapshot as mn}from"../core/scoped-state/person-store.js";import{loadPersonSettings as Fe}from"../core/scoped-state/person-rows.js";import{userScopeRoot as Be}from"../core/scope.js";import{brokerCommandDeclaresCanvasHome as de}from"../core/runtime/broker-ownership.js";import{brokerCommandDeclaresCanvasHome as Bi}from"../core/runtime/broker-ownership.js";function me(e){return/ --epoch (\S+) /.exec(e)?.[1]??null}s(me,"brokerCommandEpoch");const pn=5e3,He=150;async function fn(e){const l=Ce();if(l===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const u=hr(),f=[];for(const[n,d]of l.processes){const y=d.command;if(d.zombie||!y.includes("broker-cli.js")||!de(y,u)||me(y)===e)continue;const b=y.trim().split(/\s+/).at(-1)??"";b===""||b.endsWith("broker-cli.js")||f.push({pid:n,nodeId:b})}let v=0;const a=[];for(const n of f){const d=Pt(n.pid);if(d===null||!d.includes("broker-cli.js")||!de(d,u)||me(d)===e||d.trim().split(/\s+/).at(-1)!==n.nodeId)continue;const y=Le(n.pid,null);if(!y.reused){try{process.platform==="linux"&&k(T)?await $({operation:"stop",pid:n.pid}):process.kill(n.pid,"SIGTERM")}catch{continue}v++,a.push({pid:n.pid,snap:y})}}const h=Date.now()+pn;for(;Date.now()<h&&a.some(n=>$e(n.snap.tree.length>0?n.snap.tree:[n.pid]));)await new Promise(n=>setTimeout(n,He));let g=0;for(const n of a){const d=n.snap.tree.length>0?n.snap.tree:[n.pid];$e(d)&&(process.platform==="linux"&&k(T)?await $({operation:"stop",pid:n.pid}):Ae(d,"SIGKILL",n.snap.identities),g++)}g>0&&await new Promise(n=>setTimeout(n,He));const p=Ce();if(p===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const c=[];for(const[n,d]of p.processes){const y=d.command;d.zombie||!y.includes("broker-cli.js")||de(y,u)&&me(y)!==e&&c.push(n)}if(c.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${c.join(", ")}`);m({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:f.length,sigtermed:v,sigkilled:g}})}s(fn,"reapPriorEpochBrokers");const un=5e3;async function hn(e){const l=Array.from(e.entries());if(l.length===0)return;for(const[a]of l){const h=(await Rr(a))?.status;(h==="active"||h==="idle")&&await xe(a,new Date().toISOString())}const u=l.map(([,a])=>({pid:a.pid,snap:Le(a.pid,null),exited:a.handle.exited}));for(const a of u)if(!a.snap.reused)try{process.platform==="linux"&&k(T)?await $({operation:"stop",pid:a.pid}):process.kill(a.pid,"SIGTERM")}catch{}const f=new Promise(a=>{setTimeout(a,un).unref()});await Promise.allSettled(u.map(a=>Promise.race([a.exited.then(()=>{}),f])));const v=[];for(const a of u)Et(a.pid)&&(process.platform==="linux"&&k(T)?await $({operation:"stop",pid:a.pid}):Ae(a.snap.tree.length>0?a.snap.tree:[a.pid],"SIGKILL",a.snap.identities),v.push(a));await Promise.all(v.map(a=>a.exited));for(const[a]of l)await st(a,{reason:"daemon-teardown"});m({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:u.length,sigkilled:v.length}})}s(hn,"teardownFleet");function je(){ye(lr(ce()),{recursive:!0}),ar(ce(),String(process.pid),"utf8")}s(je,"writePidfile");function ze(e){return typeof e=="object"&&e!==null&&e.code==="ENOENT"}s(ze,"isMissingPathError");function Ue(e){const l=ce();let u;try{u=sr(l,"utf8")}catch(f){if(ze(f))return;throw f}if(u.trim()!==String(e))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${e})`);try{cr(l)}catch(f){if(ze(f))return;throw f}}s(Ue,"removeOwnedPidfileMirror");const wn={acceptsDetachedWork:s(()=>!0,"acceptsDetachedWork"),registerDetached:s(e=>{e.catch(()=>{})},"registerDetached")},K=new et;Zr(e=>K.handleFatalFault(e,!1));const vn=new rt,gn=new tt,Sn=new nt,yn=new ot,_n=new it,bn=new at,kn=new dt,Rn=new mt,Pn=new pt,En=new ft,In=new ht,xn=new wt,Tn=new vt,Dn=new gt,Cn=new St,Ln=new yt,$n=new _t,An=new bt;async function Nn(e=Date.now(),l=wn){const u=xt(),f=await K.runFleetPreamble(u);let v,a;try{const g=await Ie();v=g.filter(c=>c.status==="active"||c.status==="idle"),a=g.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead");const p=new Set(a.map(c=>c.node_id));a.push(...(await Pr()).filter(c=>!p.has(c.node_id)))}catch(g){m({level:"error",event:"canvas.node_list.failed",error:g});return}await K.run(e,{rows:v,fleet:u,lifecycle:l}),await vn.run(e,{rows:v});const h=await gn.run(e,{rows:[...v,...a],fleet:u});await Sn.run(e),await $n.run(e),await An.run(e,{lifecycle:l}),await yn.run(e,{lifecycle:l}),await _n.run(e,{lifecycle:l}),await bn.run(e,{lifecycle:l}),await kn.run(e,{lifecycle:l}),await Rn.run(e,{lifecycle:l,fleet:u}),Pn.run(e,{lifecycle:l}),En.run(e,{lifecycle:l}),In.run(e,{lifecycle:l}),xn.run(e,{lifecycle:l}),Tn.run(e,{lifecycle:l}),Dn.run(e,{lifecycle:l}),await ur(),Ln.run(e,{fleet:u,lifecycle:l}),await Cn.run(e,{rows:v}),K.warnIfSaturated({fleet:u,lifecycle:l,thresholds:f,frozen:h})}s(Nn,"superviseTick");function V(e){return e===void 0||e==="reconcile"}s(V,"roleRunsLanes");function A(e){return e===void 0||e==="api"}s(A,"roleServesRequests");const Mn=66e4;function Gn(e){const l=new Ir().registerAll(xr(()=>null).filter(n=>n.pattern==="/healthz")),u=s((n,d)=>{const y=(n.url??"/").split("?")[0];if((n.method??"GET").toUpperCase()==="GET"&&y==="/healthz"){l.handle(n,d,null,{class:"person"});return}d.writeHead(404,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({error:{code:"not_found",message:"this process serves only /healthz",origin:"runtime"}}))},"handler"),f=Pe();k(f)&&_e(f);const v=J(u),a=new Promise((n,d)=>{v.once("error",d),v.listen(f,()=>{v.off("error",d),be(f,384),n()})});let h,g=null;const p=e.tcp??ke()??se("user").api.tcp;if(p!==void 0&&p!==""){const n=/^(.*):(\d+)$/.exec(p.trim());if(n===null||Number(n[2])>65535)throw new Error(`invalid reconcile probe TCP address: ${p}`);const d=J(u);d.on("error",y=>m({event:"api.server.failed",level:"error",error:y})),d.listen(Number(n[2]),n[1]===""?"0.0.0.0":n[1],()=>{g=`${n[1]===""?"0.0.0.0":n[1]}:${n[2]}`}),h=d}let c=!1;return{ready:a,tcpAddress:s(()=>g,"tcpAddress"),async close(n={}){if(!c){c=!0,await Promise.all([Te(v,new Set,n.graceMs),h===void 0?Promise.resolve():Te(h,new Set,n.graceMs)]);try{k(f)&&_e(f)}catch{}}}}}s(Gn,"createProbeServer");const On="daemon is draining for shutdown and admits no new work";async function Fn(e){ye(Ee(),{recursive:!0,mode:493}),process.platform==="linux"&&be(Ee(),493);const l=Pe();if(k(l))throw new Error(`layout refusal cannot bind occupied socket: ${l}`);const u=J((p,c)=>{if(p.method==="GET"&&p.url==="/healthz"){c.writeHead(200,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}c.writeHead(503,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((p,c)=>{u.once("error",c),u.listen(l,()=>{u.off("error",c),p()})});let f;const v=e.tcp??ke();if(v){const p=/^(.*):(\d+)$/.exec(v);if(!p||Number(p[2])>65535)throw new Error(`invalid refusal TCP address: ${v}`);const c=J(u.listeners("request")[0]);await new Promise((n,d)=>{c.once("error",d),c.listen(Number(p[2]),p[1],()=>{c.off("error",d),n()})}),f=c}je();let a;const h=s(()=>(a??=(async()=>{u.closeAllConnections(),f?.closeAllConnections(),await Promise.all([u,f].filter(p=>p!==void 0).map(p=>new Promise((c,n)=>p.close(d=>d?n(d):c())))),Ue(process.pid),process.off("SIGINT",g),process.off("SIGTERM",g)})(),a),"cleanup"),g=s(()=>{h().then(()=>process.exit(0),p=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(p)}
2
+ `),process.exit(1)})},"onSignal");return process.on("SIGINT",g),process.on("SIGTERM",g),h}s(Fn,"serveLayoutRefusal");async function Bn(e={}){if(e.role==="machine")return(await import("./machine-daemon.js")).runMachineDaemon();if(_r())return Fn(e);yr();const l=s(t=>{process.stderr.write(`[crtrd] ${t}
3
+ `)},"logPostgres"),u=!!process.env.CRTR_TEST_PG_URL,f=Gt(e.role);Wt(V(e.role));const v=s(async()=>f?await Mt(Re(16).toString("hex")):{claimed:!0,claim:{pid:process.pid,pid_identity:"",token:Re(16).toString("hex")}},"claimOwnership"),{database:a,ownership:h}=u?{database:{url:await Ft()},ownership:await v()}:await Ut(async()=>({database:await Ht({log:l,startLockHeld:!0}),ownership:await v()}));if(!h.claimed){if(h.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${h.incumbentPid??"?"})
4
+ `);else{const t=[h.incumbentPid!==void 0?`pid ${h.incumbentPid}`:void 0,h.verdict!==void 0?`verdict ${h.verdict}`:void 0].filter(w=>w!==void 0),o=t.length>0?` (${t.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${h.reason}${o}
5
+ `),h.reason==="own_identity_indeterminate"&&process.stderr.write("[crtrd] cannot read its own process identity. crouter needs /proc on Linux, or the `ps` command elsewhere (Debian/Ubuntu: apt-get install procps).\n"),(h.reason==="own_identity_indeterminate"||h.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const g=h.claim;let p=null,c=null,n=null,d,y="";try{f&&await fn(g.token);for(const r of kr())process.stderr.write(`[crtrd] ${r}
6
+ `);for(const r of await br())process.stderr.write(`[crtrd] ${r}
7
+ `);await Me(),await Bt(a.url,l);const t=e.role===void 0&&!await ln();let o=null;t&&(cn({kind:"user",root:Be()}),o=dn(Be())),e.role===void 0&&mn(o??{profiles:[],defaults:{},settings:{},state:{}}),await F.listen(a.url);const w=s(r=>{Fe(r).catch(i=>m({level:"error",event:"daemon.settings.reload_failed",error:i}))},"reloadPerson");if(d=await F.subscribe(r=>{Oe().includes(r)&&w(r)},{kinds:["settings"],onListenStart:s(()=>{for(const r of Oe())w(r)},"onListenStart")}),e.role!==void 0&&Ar(),e.role!==void 0){let r;try{r=Vt()}catch(P){m({level:"error",event:"daemon.packages.snapshot_failed",error:P})}const i=await Ge(async P=>(await De(P),r===void 0?void 0:await Kt(P,r,"release")));for(const P of i?.invalid??[])process.stderr.write(`[crtrd] package file is not a document: ${P.path}: ${P.error}
8
+ `)}else{const r=await Ge(async i=>(await De(i),await Jt(i)));for(const i of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${i.message}
9
+ `);for(const i of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${i.path}: ${i.error}
10
+ `);for(const i of r.quarantined)process.stderr.write(`[crtrd] plugin "${i.name}" has a damaged ${i.file} (${i.reason}); ${i.movedTo!==void 0?`moved to ${i.movedTo}`:"left in place and skipped"}
11
+ `);for(const i of r.kinds.refused)process.stderr.write(`[crtrd] plugin "${i.plugin}" kind ${i.kind} not registered: ${i.message}
12
+ `);for(const i of r.kinds.invalid)process.stderr.write(`[crtrd] plugin "${i.plugin}" declares invalid object kinds or scopes; no kinds registered and no app token: ${i.error}
13
+ `)}if(y=await At(),Nt(y),e.role===void 0&&(p=await Nr(),p!==null)){if(Gr(p.id),await sn(p.id),process.platform==="darwin"){const{readConfig:r,updateConfig:i}=await import("../core/config.js");if(r("user").paths?.user_files===void 0){const{homedir:P}=await import("node:os");await i("user",Se=>{Se.paths??={},Se.paths.user_files??=P()})}}c=await Mr(),c.joinedFrom!==null&&await Fe(c.person),await tr(),n=await Or()}if(process.platform==="linux"&&k(T)&&(Sr(),await $({operation:"users.sync",users:await wr()})),f){await lt(g.token);const r=await en();Object.values(r).some(i=>i>0)&&process.stderr.write(`[crtrd] node files copied into rows: ${JSON.stringify(r)}
14
+ `)}}catch(t){await F.close();try{if(f){const{released:o}=await Ne(g);if(!o)throw new Error("daemon ownership claim was not released")}await le()}catch(o){throw new AggregateError([t,o],"daemon startup failed and cleanup also failed")}throw t}let b=!0,Y,B=Promise.resolve(),Q=!1,H,X,Z,D;const j=new Set;let ee=!1,pe=!1,E,C,re,z=!1,U,N,M,G,te,ne,oe;const qe=Xr();let I,S={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},L="initial startup activation",We=null;function Je(){return S.phase==="ready"?null:{phase:S.phase,message:S.message,blockerPaths:S.blockerPaths}}s(Je,"startupBlock");function R(t){j.add(t),t.finally(()=>{j.delete(t)}).catch(()=>{})}s(R,"registerDetached");const fe={acceptsDetachedWork:s(()=>b,"acceptsDetachedWork"),registerDetached:R};V(e.role)&&await Yt(fe,Me);async function Ke(){try{b=!1,qt.close(),X?.(),X=void 0,Z?.(),d?.(),Z=void 0,ne?.(),ne=void 0,await F.close(),H!==void 0&&(clearInterval(H),H=void 0),M!==void 0&&(clearInterval(M),M=void 0),oe?.(),oe=void 0;let t;do t=B,await t;while(t!==B);for(;j.size>0;)await Promise.allSettled([...j]);if(D!==void 0&&(f&&await hn(D),await D.exitsSettled(),D.dispose()),re!==void 0&&await re.close(),C!==void 0&&!z&&(z=!0,await C.close()),te?.(),te=void 0,G!==void 0){const o=G;G=void 0,await o.stop()}if(N!==void 0){const o=N;N=void 0,await o.close()}if(U!==void 0){const o=U;U=void 0,await o.close()}if(ee||(Ue(process.pid),ee=!0),ee&&!pe){if(f){const{released:o}=await Ne(g);if(!o)throw new Error("daemon ownership claim was not released")}pe=!0,await le()}}finally{Dt(),process.off("SIGINT",we),process.off("SIGTERM",ve),process.off("exit",ge)}}s(Ke,"cleanupAttempt");const q=1e3;let ue=!1;function Ve(){return ue?{graceMs:q}:(ue=!0,_.fresh(()=>{m({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:q}})}),setTimeout(()=>{Ye()},q),{graceMs:q})}s(Ve,"requestHandover");async function Ye(){try{await x()}catch(t){const o=t instanceof Error?t.stack??t.message:String(t);process.stderr.write(`[crtrd] handover cleanup failed:
14
15
  ${o}
15
- `),process.exit(1)}try{process.platform==="linux"&&k(x)&&(await L({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await Ct();const r=await Lt({waitForJoinLock:!0});_.fresh(()=>{p({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:r.pid??r.existing_pid??null,spawned:r.started}})})}catch(r){_.fresh(()=>{p({level:"error",event:"daemon.handover.successor_failed",error:r})});const o=r instanceof Error?r.message:String(r);process.stderr.write(`[crtrd] handover successor failed to start: ${o}
16
- `),process.exit(1)}process.exit(0)}s(Ke,"performHandover");function I(){if(P!==void 0)return P;const r=We();return P=r,r.then(()=>{P===r&&(P=void 0)},()=>{P===r&&(P=void 0)}),r}s(I,"requestCleanup");async function Ve(){S={phase:"initializing",message:Gn,blockerPaths:[]},D!==void 0&&!z&&(z=!0,await D.close({graceMs:Nn}))}s(Ve,"drainApi");async function we(r){try{r==="SIGTERM"&&e.role==="api"&&await Ve(),await I(),await Ut({claimed:s(async()=>{try{return f&&await Ot()}finally{await le()}},"claimed")}),process.exit(0)}catch(o){process.exitCode=1;const h=o instanceof Error?o.stack??`${o.name}: ${o.message}`:String(o);process.stderr.write(`[crtrd] ${r} cleanup failed:
17
- ${h}
18
- `),process.exit(1)}}s(we,"handleSignal");function he(){we("SIGINT")}s(he,"onSigint");function ve(){we("SIGTERM")}s(ve,"onSigterm");function ge(){I().catch(()=>{})}s(ge,"onExit");async function ie(r){b&&(B=B.then(r).then(()=>{},o=>{_.fresh(()=>{p({level:"error",event:"daemon.lane_job.failed",error:o})})}))}s(ie,"enqueue");async function W(){!b||Q||(ze.check()&&E&&(p({level:"info",event:"daemon.resume.detected"}),R(E().catch(()=>{}))),Q=!0,await ie(async()=>{if(Q=!1,!!b)try{u||await zt({log:l}),await An(Date.now(),fe)}catch(r){_.fresh(()=>{p({level:"error",event:"daemon.tick.failed",error:r})})}}))}s(W,"enqueueTick");let G=null;async function Ye(){if(G!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${G instanceof Error?G.message:String(G)}`};if(S.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(S.phase!=="prepared"&&S.phase!=="recovering")throw{status:409,code:"not_prepared",message:S.message};const r=S.phase==="prepared";try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(o){throw G=o,{status:500,code:"admission_failed",message:`daemon admission failed: ${o instanceof Error?o.message:String(o)}`}}}s(Ye,"admitStartup");async function Qe(r){if(C!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${C})`};C="repair";try{const o=await on({dryRun:r.dryRun});if(r.dryRun||o.pending||S.phase!=="blocked")return{result:o,resumed:!1};if(e.prepare)return S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:o,resumed:!1};try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},{result:o,resumed:!0}}catch(h){const i=h instanceof Error?h.message:String(h);return setTimeout(()=>{I().catch(()=>{})},1e3),{result:o,resumed:!1,resumeError:i}}}finally{C=null}}s(Qe,"repairMigrations");async function Xe(){Y=e.intervalMs??Qr;const r=g.token;T=new Xt({epoch:r,enqueue:ie}),It(T),S={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{p({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:Y}})});const o=y;_.fresh(()=>{p({level:"info",event:"daemon.install_id.resolved",fields:{install_id:o}})});const h=await Cr(o);if(_.fresh(()=>{p({level:"info",event:"daemon.environment.registered",fields:{environment_id:h.environmentId,created:h.created}})}),_.fresh(()=>{let i;try{i=Yr()}catch{return}i!==null&&p({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:i.slice(0,2048)}})}),ut(),e.role!==void 0&&!process.env.CRTR_DIRECTORY_URL)throw new Error("CRTR_DIRECTORY_URL must be set on a cloud role (--role api|reconcile): it names the directory this deployment mints tokens against");if(e.role!==void 0&&Lr(),!V(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Vr(),await Wr(),await Jr(Date.now()),await Kr(Date.now())}),await _.fresh(async()=>{const{reconcile:i,migrated:t}=await $t(ct);i.changed&&p({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:i.cleared.length,same_boot_proven:i.sameBootProven}}),t.length>0&&p({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:t.length}})}),await _.fresh(async()=>{for(const i of await Ie())i.status!=="active"||i.pi_pid!=null||i.frozen_at!=null||i.respawn_not_before!=null||(await xe(i.node_id,new Date().toISOString()),p({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:i.node_id}))}),await _.fresh(async()=>{await Rt();for(const i of en){const t=await i.apply();t.changed&&p({level:"info",event:"daemon.boot_migration.applied",fields:{migration:i.id,...t.summary}})}}),R(Ur()),E){const i=s(()=>{R(E().catch(()=>{})),R(nr().then(t=>M?.observe(t)).then(()=>{},t=>{p({level:"warn",event:"daemon.peer.status_failed",error:t})}))},"refresh");R(zr().then(({completion:t})=>t).catch(t=>{p({level:"error",event:"daemon.grants.sweep_failed",error:t})})),i(),N=setInterval(i,jr*1e3),N.unref(),oe=tr({joined:!0,register:R})}await ie(async()=>{await Qt(),await Yt()}),H=setInterval(()=>{W().catch(i=>p({level:"error",event:"daemon.tick.failed",error:i}))},Y),X=await kt(()=>{W().catch(i=>p({level:"error",event:"daemon.tick.failed",error:i}))}),Z=await F.subscribe(()=>{W().catch(i=>p({level:"error",event:"daemon.tick.failed",error:i}))},{kinds:["spend_limits"]}),await W(),e.role===void 0&&import("../commands/sys/import/move.js").then(({settleMoveAtDaemonStart:i})=>i(()=>!b,t=>p({level:"warn",event:"daemon.move.settle_failed",error:t}))).catch(i=>p({level:"warn",event:"daemon.move.settle_failed",error:i}))}s(Xe,"completeStartup");function ae(){return Ue??=Xe().catch(r=>{throw S={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}s(ae,"resumeStartup");try{process.on("SIGINT",he),process.on("SIGTERM",ve),process.on("exit",ge),rn(),m!==null&&p({level:"info",event:"daemon.person.resolved",fields:{person_id:m.id,source:m.source}}),n!==null&&p({level:"info",event:"daemon.permissions.boot",fields:{...n}}),c!==null&&p({level:"info",event:"daemon.person.retired",fields:{person_id:c.person,joined_from:c.joinedFrom,retired:c.retired,columns:c.columns}}),$(e.role)?U=await mr():pr(dr());const r=g.token;Tt({epoch:r,requestHandover:Je,registerDetached:R,startupBlock:qe,admitStartup:Ye,repairMigrations:Qe}),Be(),D=$(e.role)?Pr({tcp:e.tcp}):Mn(e),await D.ready;const o=lr()??se("user").document_port;if($(e.role)){const i=xr(o,Tr());try{await i.ready,re=i}catch(t){p({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:o,error:t instanceof Error?t.message:String(t)}})}}const h=se("user").runtime;if(h?.issuer&&(E=Hr(h.issuer,R),h.unsandboxed===!0&&(M=or({syncGrants:E}))),$(e.role)&&(te=await Fr()),ne=await Br({serves:$(e.role),runsLanes:V(e.role)}),h?.unsandboxed===!0&&h.listener!==void 0&&p({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),$(e.role)&&h!==void 0&&h.listener!==void 0&&h.unsandboxed!==!0&&(A=await Dr(h,async()=>await qr(h.issuer.replace(/\/$/,"")),E),await A.ready),e.role===void 0)try{await tn()}catch(i){if(C=null,i instanceof nn)return S={phase:"blocked",message:i.message,blockerPaths:i.blockerPaths},I;throw i}process.platform==="linux"&&k(x)&&(vr(),await hr("app:terminal"));try{e.prepare?S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await ae(),S={phase:"ready",message:"",blockerPaths:[]})}finally{C=null}return I}catch(r){try{await I()}catch(o){throw new AggregateError([r,o],"daemon startup failed and cleanup also failed")}throw r}}s(Fn,"runDaemon");var Ni=Fn;export{Nn as API_DRAIN_GRACE_MS,Oi as brokerCommandDeclaresCanvasHome,me as brokerCommandEpoch,Ni as default,V as roleRunsLanes,$ as roleServesRequests,Fn as runDaemon,An as superviseTick,un as teardownFleet};
16
+ `),process.exit(1)}try{process.platform==="linux"&&k(T)&&(await $({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await Ct();const t=await Lt({waitForJoinLock:!0});_.fresh(()=>{m({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:t.pid??t.existing_pid??null,spawned:t.started}})})}catch(t){_.fresh(()=>{m({level:"error",event:"daemon.handover.successor_failed",error:t})});const o=t instanceof Error?t.message:String(t);process.stderr.write(`[crtrd] handover successor failed to start: ${o}
17
+ `),process.exit(1)}process.exit(0)}s(Ye,"performHandover");function x(){if(E!==void 0)return E;const t=Ke();return E=t,t.then(()=>{E===t&&(E=void 0)},()=>{E===t&&(E=void 0)}),t}s(x,"requestCleanup");async function Qe(){S={phase:"initializing",message:On,blockerPaths:[]},C!==void 0&&!z&&(z=!0,await C.close({graceMs:Mn}))}s(Qe,"drainApi");async function he(t){try{t==="SIGTERM"&&e.role==="api"&&await Qe(),await x(),await zt({claimed:s(async()=>{try{return f&&await Ot()}finally{await le()}},"claimed")}),process.exit(0)}catch(o){process.exitCode=1;const w=o instanceof Error?o.stack??`${o.name}: ${o.message}`:String(o);process.stderr.write(`[crtrd] ${t} cleanup failed:
18
+ ${w}
19
+ `),process.exit(1)}}s(he,"handleSignal");function we(){he("SIGINT")}s(we,"onSigint");function ve(){he("SIGTERM")}s(ve,"onSigterm");function ge(){x().catch(()=>{})}s(ge,"onExit");async function ie(t){b&&(B=B.then(t).then(()=>{},o=>{_.fresh(()=>{m({level:"error",event:"daemon.lane_job.failed",error:o})})}))}s(ie,"enqueue");async function W(){!b||Q||(qe.check()&&I&&(m({level:"info",event:"daemon.resume.detected"}),R(I().catch(()=>{}))),Q=!0,await ie(async()=>{if(Q=!1,!!b)try{u||await jt({log:l}),await Nn(Date.now(),fe)}catch(t){_.fresh(()=>{m({level:"error",event:"daemon.tick.failed",error:t})})}}))}s(W,"enqueueTick");let O=null;async function Xe(){if(O!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${O instanceof Error?O.message:String(O)}`};if(S.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(S.phase!=="prepared"&&S.phase!=="recovering")throw{status:409,code:"not_prepared",message:S.message};const t=S.phase==="prepared";try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},t?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(o){throw O=o,{status:500,code:"admission_failed",message:`daemon admission failed: ${o instanceof Error?o.message:String(o)}`}}}s(Xe,"admitStartup");async function Ze(t){if(L!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${L})`};L="repair";try{const o=await an({dryRun:t.dryRun});if(t.dryRun||o.pending||S.phase!=="blocked")return{result:o,resumed:!1};if(e.prepare)return S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:o,resumed:!1};try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},{result:o,resumed:!0}}catch(w){const r=w instanceof Error?w.message:String(w);return setTimeout(()=>{x().catch(()=>{})},1e3),{result:o,resumed:!1,resumeError:r}}}finally{L=null}}s(Ze,"repairMigrations");async function er(){Y=e.intervalMs??Qr;const t=g.token;D=new Zt({epoch:t,enqueue:ie}),It(D),S={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{m({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:Y}})});const o=y;_.fresh(()=>{m({level:"info",event:"daemon.install_id.resolved",fields:{install_id:o}})});const w=await Lr(o);if(_.fresh(()=>{m({level:"info",event:"daemon.environment.registered",fields:{environment_id:w.environmentId,created:w.created}})}),_.fresh(()=>{let r;try{r=Yr()}catch{return}r!==null&&m({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:r.slice(0,2048)}})}),ut(),e.role!==void 0&&!process.env.CRTR_DIRECTORY_URL)throw new Error("CRTR_DIRECTORY_URL must be set on a cloud role (--role api|reconcile): it names the directory this deployment mints tokens against");if(e.role!==void 0&&$r(),!V(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Vr(),await Wr(),await Jr(Date.now()),await Kr(Date.now())}),await _.fresh(async()=>{const{reconcile:r,migrated:i}=await $t(ct);r.changed&&m({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:r.cleared.length,same_boot_proven:r.sameBootProven}}),i.length>0&&m({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:i.length}})}),await _.fresh(async()=>{for(const r of await Ie())r.status!=="active"||r.pi_pid!=null||r.frozen_at!=null||r.respawn_not_before!=null||(await xe(r.node_id,new Date().toISOString()),m({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:r.node_id}))}),await _.fresh(async()=>{await Rt();for(const r of rn){const i=await r.apply();i.changed&&m({level:"info",event:"daemon.boot_migration.applied",fields:{migration:r.id,...i.summary}})}}),R(Ur()),I){const r=s(()=>{R(I().catch(()=>{})),R(or().then(i=>G?.observe(i)).then(()=>{},i=>{m({level:"warn",event:"daemon.peer.status_failed",error:i})}))},"refresh");R(zr().then(({completion:i})=>i).catch(i=>{m({level:"error",event:"daemon.grants.sweep_failed",error:i})})),r(),M=setInterval(r,jr*1e3),M.unref(),oe=nr({joined:!0,register:R})}await ie(async()=>{await Xt(),await Qt()}),H=setInterval(()=>{W().catch(r=>m({level:"error",event:"daemon.tick.failed",error:r}))},Y),X=await kt(()=>{W().catch(r=>m({level:"error",event:"daemon.tick.failed",error:r}))}),Z=await F.subscribe(()=>{W().catch(r=>m({level:"error",event:"daemon.tick.failed",error:r}))},{kinds:["spend_limits"]}),await W(),e.role===void 0&&import("../commands/sys/import/move.js").then(({settleMoveAtDaemonStart:r})=>r(()=>!b,i=>m({level:"warn",event:"daemon.move.settle_failed",error:i}))).catch(r=>m({level:"warn",event:"daemon.move.settle_failed",error:r}))}s(er,"completeStartup");function ae(){return We??=er().catch(t=>{throw S={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},t})}s(ae,"resumeStartup");try{process.on("SIGINT",we),process.on("SIGTERM",ve),process.on("exit",ge),tn(),p!==null&&m({level:"info",event:"daemon.person.resolved",fields:{person_id:p.id,source:p.source}}),n!==null&&m({level:"info",event:"daemon.permissions.boot",fields:{...n}}),c!==null&&m({level:"info",event:"daemon.person.retired",fields:{person_id:c.person,joined_from:c.joinedFrom,retired:c.retired,columns:c.columns}}),A(e.role)?U=await pr():fr(mr());const t=g.token;Tt({epoch:t,requestHandover:Ve,registerDetached:R,startupBlock:Je,admitStartup:Xe,repairMigrations:Ze}),je(),C=A(e.role)?Er({tcp:e.tcp}):Gn(e),await C.ready;const o=dr()??se("user").document_port;if(A(e.role)){const r=Tr(o,Dr());try{await r.ready,re=r}catch(i){m({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:o,error:i instanceof Error?i.message:String(i)}})}}const w=se("user").runtime;if(w?.issuer&&(I=Hr(w.issuer,R),w.unsandboxed===!0&&(G=ir({syncGrants:I}))),A(e.role)&&(te=await Fr()),ne=await Br({serves:A(e.role),runsLanes:V(e.role)}),w?.unsandboxed===!0&&w.listener!==void 0&&m({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),A(e.role)&&w!==void 0&&w.listener!==void 0&&w.unsandboxed!==!0&&(N=await Cr(w,async()=>await qr(w.issuer.replace(/\/$/,"")),I),await N.ready),e.role===void 0)try{await nn()}catch(r){if(L=null,r instanceof on)return S={phase:"blocked",message:r.message,blockerPaths:r.blockerPaths},x;throw r}process.platform==="linux"&&k(T)&&(gr(),await vr("app:terminal"));try{e.prepare?S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await ae(),S={phase:"ready",message:"",blockerPaths:[]})}finally{L=null}return x}catch(t){try{await x()}catch(o){throw new AggregateError([t,o],"daemon startup failed and cleanup also failed")}throw t}}s(Bn,"runDaemon");var Gi=Bn;export{Mn as API_DRAIN_GRACE_MS,Bi as brokerCommandDeclaresCanvasHome,me as brokerCommandEpoch,Gi as default,V as roleRunsLanes,A as roleServesRequests,Bn as runDaemon,Nn as superviseTick,hn as teardownFleet};
@@ -1,10 +1,10 @@
1
- var w=Object.defineProperty;var o=(e,t)=>w(e,"name",{value:t,configurable:!0});import{formatInboxRefInstruction as l}from"./generated-context.js";const f=12,$=1e3,y=1e3;function A(e){return(e===void 0?null:/^([a-z0-9-]+)\/reports\/[^/]+$/.exec(e))?.[1]}o(A,"reportRefNodeId");function j(e){let t=e,r=!1;const i=t.split(`
2
- `);return i.length>f&&(t=i.slice(0,f).join(`
3
- `),r=!0),t.length>$&&(t=t.slice(0,$),r=!0),{text:t.trimEnd(),clipped:r}}o(j,"clipBody");function x(e){const t=typeof e.data?.body=="string"?String(e.data.body).trim():"";return t===""||t===e.label?"":t}o(x,"inlineBody");function v(e){const t=e.data?.push;return typeof t=="object"&&t!==null&&typeof t.event=="string"?t:null}o(v,"pushOf");function u(e){const t=e.owner_handle??e.owner;return t==null?e.name:`${t}/${e.name}`}o(u,"objectRef");function _(e){return e.type==="document"?`[[${u(e)}]]`:e.type==="job"?`job ${e.id} (\`${e.name}\`)`:e.type==="node"?`node ${e.name} (${e.id})${e.machine?` on ${e.machine}`:""}`:`${e.type} ${e.name}`}o(_,"objectText");function k(e,t){return t.actor===null?"the runtime":e.from_name===void 0||e.from_name===t.actor?t.actor:`${e.from_name} (${t.actor})`}o(k,"actorText");function m(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}o(m,"list");function I(e,t){const r=_(t.object),i=k(e,t),n=t.attrs,a=t.object.type==="document"?` Read it with \`crtr canvas read ${u(t.object)}\`.`:"";switch(t.event){case"created":return t.object.type==="node"?`${i} created ${r}${typeof n.kind=="string"?`, kind ${n.kind}`:""}.`:`${i} created ${r}.${a}`;case"read":return`${i} read ${r}.`;case"watched":return`${i} started watching ${r}.`;case"deleted":return`${i} deleted ${r}.`;case"edited":{const s=m(n.authors),c=m(n.rationales),d=typeof n.from_revision=="number"&&typeof n.revision=="number"&&n.revision-n.from_revision>1?`revisions ${n.from_revision+1}\u2013${n.revision}`:typeof n.revision=="number"?`revision ${n.revision}`:"a new revision",b=s.length===0?i:s.join(", "),g=c.length===0?"":` Rationale: ${c.join("; ")}.`,h=n.needs_merge===!0?" Two edits were made from the same revision; read it and edit it to merge them.":"",p=` You get this because you read or wrote it; if it no longer concerns your work, stop with \`crtr canvas unwatch ${u(t.object)}\`.`;return`${b} edited ${r} (${d}).${g}${h}${a}${p}`}case"messaged":return`${i} messaged ${r}.`;case"sent":return`${i} sent a message as ${r}.`;case"configured":return`${i} changed the settings of ${r}${typeof n.changed=="string"?`: ${n.changed}`:""}.`;case"exited":return`${r[0].toUpperCase()}${r.slice(1)} exited with code ${String(n["exit-code"])}. Output: ${String(n["output-key"])}`;case"silent":{const s=typeof n.files=="string"?n.files:"";return`${r[0].toUpperCase()}${r.slice(1)} has been silent for ${String(n["silent-for"])}: its processes used almost no CPU and none of the files they hold open for writing changed. It may be hung. Watched: ${s===""?"the job log only":s}. Inspect those files; stop it with \`crtr node bash kill ${t.object.id}\`; or, if it is meant to sit idle, stop these messages with \`crtr node bash quiet ${t.object.id}\`.`}case"killed":{const s=t.actor===null?"":` by ${i}`,c=typeof n.reason=="string"?` (${n.reason})`:"",d=n.reason==="deadline"?` It was canceled at its deadline; claim it with \`crtr node bash extend ${t.object.id} --for <duration>\` next time.`:"";return`${r[0].toUpperCase()}${r.slice(1)} was killed${s}${c}.${d} Output: ${String(n["output-key"])}`}default:return e.label}}o(I,"renderPush");function C(e,t){if(t!==null&&t.length<y&&e.ref!==void 0)return`${t.trimEnd()}
1
+ var y=Object.defineProperty;var i=(e,t)=>y(e,"name",{value:t,configurable:!0});import{formatInboxRefInstruction as l}from"./generated-context.js";const f=12,u=1e3,j=1e3;function E(e){return(e===void 0?null:/^([a-z0-9-]+)\/reports\/[^/]+$/.exec(e))?.[1]}i(E,"reportRefNodeId");function x(e){let t=e,r=!1;const o=t.split(`
2
+ `);return o.length>f&&(t=o.slice(0,f).join(`
3
+ `),r=!0),t.length>u&&(t=t.slice(0,u),r=!0),{text:t.trimEnd(),clipped:r}}i(x,"clipBody");function v(e){const t=typeof e.data?.body=="string"?String(e.data.body).trim():"";return t===""||t===e.label?"":t}i(v,"inlineBody");function _(e){const t=e.data?.push;return typeof t=="object"&&t!==null&&typeof t.event=="string"?t:null}i(_,"pushOf");function $(e){const t=e.owner_handle??e.owner;return t==null?e.name:`${t}/${e.name}`}i($,"objectRef");function I(e){return e.type==="document"?`[[${$(e)}]]`:e.type==="job"?`job ${e.id} (\`${e.name}\`)`:e.type==="node"?`node ${e.name} (${e.id})${e.machine?` on ${e.machine}`:""}`:`${e.type} ${e.name}`}i(I,"objectText");function m(e){return`crtr node bash log ${e.id}${e.owner===null||e.owner===void 0?"":` --node ${e.owner}`}`}i(m,"jobLogCommand");function R(e,t){return t.actor===null?"the runtime":e.from_name===void 0||e.from_name===t.actor?t.actor:`${e.from_name} (${t.actor})`}i(R,"actorText");function b(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}i(b,"list");function k(e,t){const r=I(t.object),o=R(e,t),n=t.attrs,c=t.object.type==="document"?` Read it with \`crtr canvas read ${$(t.object)}\`.`:"";switch(t.event){case"created":return t.object.type==="node"?`${o} created ${r}${typeof n.kind=="string"?`, kind ${n.kind}`:""}.`:`${o} created ${r}.${c}`;case"read":return`${o} read ${r}.`;case"watched":return`${o} started watching ${r}.`;case"deleted":return`${o} deleted ${r}.`;case"edited":{const s=b(n.authors),a=b(n.rationales),d=typeof n.from_revision=="number"&&typeof n.revision=="number"&&n.revision-n.from_revision>1?`revisions ${n.from_revision+1}\u2013${n.revision}`:typeof n.revision=="number"?`revision ${n.revision}`:"a new revision",g=s.length===0?o:s.join(", "),h=a.length===0?"":` Rationale: ${a.join("; ")}.`,p=n.needs_merge===!0?" Two edits were made from the same revision; read it and edit it to merge them.":"",w=` You get this because you read or wrote it; if it no longer concerns your work, stop with \`crtr canvas unwatch ${$(t.object)}\`.`;return`${g} edited ${r} (${d}).${h}${p}${c}${w}`}case"messaged":return`${o} messaged ${r}.`;case"sent":return`${o} sent a message as ${r}.`;case"configured":return`${o} changed the settings of ${r}${typeof n.changed=="string"?`: ${n.changed}`:""}.`;case"exited":return`${r[0].toUpperCase()}${r.slice(1)} exited with code ${String(n["exit-code"])}. Output: \`${m(t.object)}\``;case"silent":{const s=typeof n.files=="string"?n.files:"";return`${r[0].toUpperCase()}${r.slice(1)} has been silent for ${String(n["silent-for"])}: its processes used almost no CPU and none of the files they hold open for writing changed. It may be hung. Watched: ${s===""?"the job log only":s}. Inspect those files; stop it with \`crtr node bash kill ${t.object.id}\`; or, if it is meant to sit idle, stop these messages with \`crtr node bash quiet ${t.object.id}\`.`}case"killed":{const s=t.actor===null?"":` by ${o}`,a=typeof n.reason=="string"?` (${n.reason})`:"",d=n.reason==="deadline"?` It was canceled at its deadline; claim it with \`crtr node bash extend ${t.object.id} --for <duration>\` next time.`:"";return`${r[0].toUpperCase()}${r.slice(1)} was killed${s}${a}.${d} Output: \`${m(t.object)}\``}default:return e.label}}i(k,"renderPush");function O(e,t){if(t!==null&&t.length<j&&e.ref!==void 0)return`${t.trimEnd()}
4
4
 
5
- ${l(e.ref)}`;const r=x(e);if(r===""){const a=v(e);return a!==null&&e.ref===void 0?I(e,a):e.ref===void 0?e.label:`${e.label}
5
+ ${l(e.ref)}`;const r=v(e);if(r===""){const c=_(e);return c!==null&&e.ref===void 0?k(e,c):e.ref===void 0?e.label:`${e.label}
6
6
 
7
- ${l(e.ref)}`}const{text:i,clipped:n}=j(r);return e.ref!==void 0?`${i}
7
+ ${l(e.ref)}`}const{text:o,clipped:n}=x(r);return e.ref!==void 0?`${o}
8
8
 
9
- ${l(e.ref)}`:n?`${i}
10
- \u2026 (body clipped)`:i}o(C,"renderEntryBody");export{y as INLINE_REPORT_MAX_CHARS,j as clipBody,x as inlineBody,C as renderEntryBody,A as reportRefNodeId};
9
+ ${l(e.ref)}`:n?`${o}
10
+ \u2026 (body clipped)`:o}i(O,"renderEntryBody");export{j as INLINE_REPORT_MAX_CHARS,x as clipBody,v as inlineBody,O as renderEntryBody,E as reportRefNodeId};
@@ -7,6 +7,10 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
+ ## 0.3.585
11
+
12
+ `GET /v1/nodes/{id}/jobs/{jobId}/output` reads a background bash job's stored output, last 256 KiB by default (`max_bytes` up to 4 MiB, or `tail_lines`), from the blob store, so it works after the job's sandbox is deleted. It answers `job_not_found` for a job the node does not own and an empty `output` for a job that has written nothing. `CrtrClient.readBashJobOutput` calls it. Nothing existing changes.
13
+
10
14
  ## 0.3.578
11
15
 
12
16
  `runs.message` now steers a running root turn by default: the agent reads it at its next step. Pass `{ steer: false }` to wait for the current turn to end and start a separate turn. `start_turn: false` remains deferred and cannot use `steer: true`. When a later message joins a turn, `runs.reply` stops yielding text for the earlier message at that boundary, but still waits for the turn's completion. An app on an older SDK gets steering as soon as the runtime upgrades, because it cannot send `steer: false`; its `runs.reply` then streams the answer to a joined later message as part of the earlier reply. Upgrade the SDK to get the `RunReply` boundary and the opt-out.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.584",
3
+ "version": "0.3.586",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -145,7 +145,7 @@
145
145
  },
146
146
  "license": "UNLICENSED",
147
147
  "dependencies": {
148
- "@north-light/identity": "0.3.584",
148
+ "@north-light/identity": "0.3.586",
149
149
  "@earendil-works/chord": "1.1.0",
150
150
  "@earendil-works/pi-agent-core": "1.1.0",
151
151
  "@earendil-works/pi-ai": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.584",
3
+ "version": "0.3.586",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.584",
3
+ "version": "0.3.586",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.584",
9
+ "version": "0.3.586",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -28,7 +28,7 @@
28
28
  "@milkdown/preset-gfm": "^7.22.3",
29
29
  "@milkdown/prose": "^7.22.3",
30
30
  "@milkdown/utils": "^7.22.3",
31
- "@north-light/identity": "0.3.584",
31
+ "@north-light/identity": "0.3.586",
32
32
  "cron-parser": "^5.6.0",
33
33
  "esbuild": "^0.27.7",
34
34
  "jose": "^6.2.12",
@@ -11956,17 +11956,17 @@
11956
11956
  },
11957
11957
  "packages/crouter-api": {
11958
11958
  "name": "@north-light/api",
11959
- "version": "0.3.584",
11959
+ "version": "0.3.586",
11960
11960
  "license": "UNLICENSED"
11961
11961
  },
11962
11962
  "packages/crouter-env-docker": {
11963
11963
  "name": "@north-light/env-docker",
11964
- "version": "0.3.584",
11964
+ "version": "0.3.586",
11965
11965
  "license": "UNLICENSED"
11966
11966
  },
11967
11967
  "packages/crouter-identity": {
11968
11968
  "name": "@north-light/identity",
11969
- "version": "0.3.584",
11969
+ "version": "0.3.586",
11970
11970
  "license": "UNLICENSED",
11971
11971
  "dependencies": {
11972
11972
  "jose": "^6.2.1"
@@ -11974,21 +11974,21 @@
11974
11974
  },
11975
11975
  "packages/crouter-plugin": {
11976
11976
  "name": "@north-light/plugin",
11977
- "version": "0.3.584",
11977
+ "version": "0.3.586",
11978
11978
  "license": "UNLICENSED",
11979
11979
  "dependencies": {
11980
- "@north-light/api": "0.3.584",
11981
- "@north-light/identity": "0.3.584"
11980
+ "@north-light/api": "0.3.586",
11981
+ "@north-light/identity": "0.3.586"
11982
11982
  }
11983
11983
  },
11984
11984
  "packages/crouter-sdk": {
11985
11985
  "name": "@north-light/sdk",
11986
- "version": "0.3.584",
11986
+ "version": "0.3.586",
11987
11987
  "license": "UNLICENSED",
11988
11988
  "dependencies": {
11989
- "@north-light/api": "0.3.584",
11990
- "@north-light/identity": "0.3.584",
11991
- "@north-light/plugin": "0.3.584",
11989
+ "@north-light/api": "0.3.586",
11990
+ "@north-light/identity": "0.3.586",
11991
+ "@north-light/plugin": "0.3.586",
11992
11992
  "jose": "^6.2.1"
11993
11993
  },
11994
11994
  "bin": {