@north-light/cli 0.3.589 → 0.3.590

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 (73) hide show
  1. package/dist/api/client.d.ts +4 -1
  2. package/dist/api/client.js +1 -1
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/docs.d.ts +5 -0
  6. package/dist/api/dto/settings.d.ts +21 -0
  7. package/dist/build-root.d.ts +2 -0
  8. package/dist/build-root.js +1 -1
  9. package/dist/cli.js +8 -8
  10. package/dist/clients/attach/viewer.js +468 -468
  11. package/dist/commands/pkg/app-installs.d.ts +53 -0
  12. package/dist/commands/pkg/app-installs.js +2 -0
  13. package/dist/commands/pkg/market-inspect.js +1 -1
  14. package/dist/commands/pkg/market-manage.js +1 -1
  15. package/dist/commands/pkg/plugin-inspect.js +1 -1
  16. package/dist/commands/pkg/plugin-manage.js +13 -13
  17. package/dist/core/canvas/schema-pg/011-package-revision.sql +12 -0
  18. package/dist/core/canvas/schema-version.d.ts +1 -1
  19. package/dist/core/canvas/schema-version.js +1 -1
  20. package/dist/core/config.d.ts +1 -0
  21. package/dist/core/config.js +1 -1
  22. package/dist/core/graph/names.js +8 -8
  23. package/dist/core/graph/package-docs.d.ts +6 -15
  24. package/dist/core/graph/package-docs.js +8 -6
  25. package/dist/core/graph/package-publish.d.ts +35 -5
  26. package/dist/core/graph/package-publish.js +3 -3
  27. package/dist/core/graph/package-reconcile.d.ts +20 -1
  28. package/dist/core/graph/package-reconcile.js +3 -1
  29. package/dist/core/import/export/dump.js +4 -3
  30. package/dist/core/import/load/stores.js +2 -2
  31. package/dist/core/installed-plugins.js +1 -1
  32. package/dist/core/packages/directory-sync.d.ts +41 -0
  33. package/dist/core/packages/directory-sync.js +6 -0
  34. package/dist/core/packages/eligibility.d.ts +16 -0
  35. package/dist/core/packages/eligibility.js +4 -0
  36. package/dist/core/packages/launch-kinds.d.ts +6 -0
  37. package/dist/core/packages/launch-kinds.js +2 -0
  38. package/dist/core/packages/source-url.d.ts +3 -0
  39. package/dist/core/packages/source-url.js +1 -0
  40. package/dist/core/permissions/ceiling.d.ts +9 -2
  41. package/dist/core/permissions/ceiling.js +11 -12
  42. package/dist/core/permissions/evaluator.js +2 -2
  43. package/dist/core/runtime/launch-config-worker.js +1 -1
  44. package/dist/core/runtime/launch-target.d.ts +6 -2
  45. package/dist/core/runtime/launch-target.js +1 -1
  46. package/dist/core/runtime/launch.d.ts +8 -1
  47. package/dist/core/runtime/launch.js +2 -2
  48. package/dist/core/runtime/promote.js +1 -1
  49. package/dist/core/runtime/recycle.js +1 -1
  50. package/dist/core/runtime/reset.js +1 -1
  51. package/dist/core/runtime/spawn.js +2 -2
  52. package/dist/core/runtime/warm-pool.js +1 -1
  53. package/dist/core/scoped-state/legacy-profiles.js +1 -1
  54. package/dist/core/scoped-state/migrate-app-installs.d.ts +13 -0
  55. package/dist/core/scoped-state/migrate-app-installs.js +1 -0
  56. package/dist/core/scoped-state/person-rows.js +4 -6
  57. package/dist/core/scoped-state/person-store.d.ts +23 -0
  58. package/dist/core/scoped-state/person-store.js +1 -1
  59. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  60. package/dist/daemon/api/handlers/execution-start.js +2 -2
  61. package/dist/daemon/api/handlers/nodes.js +1 -1
  62. package/dist/daemon/api/handlers/package-docs.d.ts +1 -1
  63. package/dist/daemon/api/handlers/package-docs.js +1 -1
  64. package/dist/daemon/api/handlers/settings.d.ts +4 -1
  65. package/dist/daemon/api/handlers/settings.js +1 -1
  66. package/dist/daemon/crtrd.js +19 -19
  67. package/package.json +2 -2
  68. package/packages/crouter-identity/package.json +1 -1
  69. package/runtime.lock.json +13 -13
  70. package/dist/core/graph/package-kinds.d.ts +0 -22
  71. package/dist/core/graph/package-kinds.js +0 -1
  72. package/dist/core/scoped-state/materialized-plugins.d.ts +0 -20
  73. package/dist/core/scoped-state/materialized-plugins.js +0 -1
@@ -1,19 +1,19 @@
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:
15
- ${o}
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
+ var nr=Object.defineProperty;var a=(e,l)=>nr(e,"name",{value:l,configurable:!0});import{applyBootSettings as or}from"./boot-settings.js";import{startPeerOutbox as ir}from"./peer/outbox.js";import{reportMachineStatus as ar}from"../core/peer/directory.js";import{createPeerRelay as sr}from"./peer/relay-service.js";import{writeFileSync as cr,readFileSync as lr,rmSync as dr,mkdirSync as be,existsSync as P,unlinkSync as ke,chmodSync as Re}from"node:fs";import{createServer as V}from"node:http";import{dirname as mr}from"node:path";import{envCrtrdTcp as Pe,envDocumentPort as pr}from"../shared/env.js";import{openCanvasConversationStore as fr,serveCanvasConversationStore as ur}from"../core/canvas/sessions.js";import{installConversationStore as wr}from"../core/conversation-store/index.js";import{pollRunObservers as hr}from"./runs/observer.js";import{randomBytes as Ee}from"node:crypto";import{apiSocketPath as Ie,crtrHome as vr}from"../core/canvas/paths.js";import{activeAppUsers as gr}from"../core/spaces/users.js";import{ensureAppSpace as Sr,ensureUserFiles as yr}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as T}from"../launcher/spec.js";import{launcherRequest as A}from"../launcher/client.js";import{installLauncherEventSink as _r}from"./launcher-events.js";import{initializeEmptyLayout as br,layoutNeedsMigration as kr,socketDir as xe}from"../core/layout.js";import{migrateLooseKeys as Rr}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as Pr}from"../core/profiles/relocate.js";import{getNode as Er,listNodesForSupervision as Te,listParkedResidentsWithWakeMail as Ir,setFrozen as De}from"../core/canvas/index.js";import{createApiServer as xr,closeServer as Ce}from"./api/server.js";import{Router as Tr}from"./api/router.js";import{healthRoutes as Dr}from"./api/handlers/health.js";import{createDocumentListener as Cr}from"./api/document-listener.js";import{documentSecret as Lr}from"./api/document-secret.js";import{createAppListener as $r}from"./api/app-listener.js";import{registerMachineEnvironment as Ar}from"../core/environments.js";import{registerBlaxelRunnerFromEnv as Nr}from"../core/secrets/blaxel-register.js";import{markCloudRole as Mr,resolvePerson as Gr,retireLocalPerson as Or,setPersonId as Fr}from"../core/canvas/person.js";import{backfillNodeApps as Le,runPermissionsBoot as Br}from"../core/permissions/boot.js";import{startRunNotices as Hr}from"./run-notices.js";import{startGrantEffects as jr}from"./reconcilers/grant-effects.js";import{syncPackages as zr}from"../core/packages/directory-sync.js";import{createGrantSync as Ur,GRANT_SYNC_INTERVAL_S as $e}from"../core/grants/sync.js";import{sweepSandboxes as qr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as Wr}from"./cron/run-socket.js";import{hasSyncedGrants as Jr}from"../core/grants/mirror.js";import{readConfig as le}from"../core/config.js";import{reconcileUndeliveredTickets as Kr}from"./human/sweep.js";import{resetHandedOffDeliveries as Vr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as Yr}from"../core/canvas/daemon-actions.js";import{sweepReviews as Qr}from"./review/sweep.js";import{pidfilePath as de}from"./pidfile.js";import{rendererWarning as Xr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Zr}from"./supervise-cadence.js";import{createResumeDetector as et}from"./resume-detector.js";import{setFatalFaultAnnouncer as rt}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as tt}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as nt}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as ot}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as it}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as at}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as st}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as ct}from"./reconcilers/action-lane.js";import{endLiveExecution as lt,migrateLegacyExecutionIdentities as dt}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as mt}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as pt}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as ft}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as ut}from"./reconcilers/storage-due-work.js";import{PurgeDueWorkReconciler as wt}from"./reconcilers/purge-due-work.js";import{assertLedgerEnv as ht}from"../core/ledger/rates.js";import{LedgerSandboxReconciler as vt}from"./reconcilers/ledger-sandbox.js";import{LedgerStorageReconciler as gt}from"./reconcilers/ledger-storage.js";import{LedgerR2Reconciler as St}from"./reconcilers/ledger-r2.js";import{ImportLaneReconciler as yt}from"./reconcilers/import-lane.js";import{BashDeadlineReconciler as _t}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as bt}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as kt}from"./reconcilers/structured-request-lane.js";import{RecipeImageReconciler as Rt,subscribeImageBuilt as Pt}from"./reconcilers/recipe-image.js";import{reconcileStructuredRequestSidecars as Et}from"./structured-requests/boot.js";import{captureLivenessSnapshot as Ae,capturePidCommand as It,captureTeardownSnapshot as Ne,isPidAlive as xt,isAnyPidAlive as Me,killProcessTreePids as Ge}from"../core/canvas/pid.js";import{bindFleet as Tt,boundFleet as Dt}from"../core/runtime/fleet.js";import{bindDaemonControl as Ct,clearDaemonControl as Lt}from"./control.js";import{execDaemon as $t,spawnDaemon as At}from"./manage.js";import{reconcileAndMigrateBoot as Nt}from"../core/canvas/boot.js";import{resolveInstallId as Mt}from"../core/canvas/install-id.js";import{setInstallId as Gt}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ot,daemonOwnershipApplies as Ft,daemonOwnershipClaimed as Bt,releaseDaemonOwnership as Oe}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as Ht,closeAllDbs as me,openDb as Fe,withCanvasWrite as pe}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as jt}from"../core/canvas/import-sqlite.js";import{ensurePostgres as zt,ensurePostgresHealthy as Ut,stopPostgres as qt,withPostgresStartLock as Wt}from"./postgres/index.js";import{brokerSignalBus as H}from"./broker-signals/bus.js";import{brokerSignalStreams as Jt}from"./api/handlers/broker-signals.js";import{setRequestsStartRunObservers as Kt}from"./api/handlers/broker-ops.js";import{reconcilePackages as Vt}from"../core/graph/package-reconcile.js";import{migrateAppInstalls as Yt}from"../core/scoped-state/migrate-app-installs.js";import{publish as Qt,readBuiltinSnapshot as Xt}from"../core/graph/package-publish.js";import{startRepoSync as Zt}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as en,reapStaleSpares as rn}from"../core/runtime/warm-pool.js";import{DaemonFleet as tn}from"./fleet.js";import{copyNodeFilesToRows as nn}from"../core/runtime/first-boot-rows.js";import{BOOT_MIGRATIONS as on}from"./boot-migrations.js";import{emitEvent as d}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as an}from"../core/events/source.js";import{activateCanvasImport as sn,MigrationBlockedError as cn,runForcedCanvasImport as ln}from"../migrations/activation.js";import{adoptInstallPerson as dn,convertLegacyScopedStore as mn,personStoresCopied as pn}from"../core/scoped-state/migrate.js";import{readLegacyUserSnapshot as fn}from"../core/scoped-state/legacy-profiles.js";import{heldPersons as Be,installPreludeSnapshot as un}from"../core/scoped-state/person-store.js";import{loadPersonSettings as He}from"../core/scoped-state/person-rows.js";import{userScopeRoot as je}from"../core/scope.js";import{brokerCommandDeclaresCanvasHome as fe}from"../core/runtime/broker-ownership.js";import{brokerCommandDeclaresCanvasHome as qi}from"../core/runtime/broker-ownership.js";function ue(e){return/ --epoch (\S+) /.exec(e)?.[1]??null}a(ue,"brokerCommandEpoch");const wn=5e3,ze=150;async function hn(e){const l=Ae();if(l===null)throw d({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=vr(),f=[];for(const[n,m]of l.processes){const y=m.command;if(m.zombie||!y.includes("broker-cli.js")||!fe(y,u)||ue(y)===e)continue;const k=y.trim().split(/\s+/).at(-1)??"";k===""||k.endsWith("broker-cli.js")||f.push({pid:n,nodeId:k})}let v=0;const s=[];for(const n of f){const m=It(n.pid);if(m===null||!m.includes("broker-cli.js")||!fe(m,u)||ue(m)===e||m.trim().split(/\s+/).at(-1)!==n.nodeId)continue;const y=Ne(n.pid,null);if(!y.reused){try{process.platform==="linux"&&P(T)?await A({operation:"stop",pid:n.pid}):process.kill(n.pid,"SIGTERM")}catch{continue}v++,s.push({pid:n.pid,snap:y})}}const w=Date.now()+wn;for(;Date.now()<w&&s.some(n=>Me(n.snap.tree.length>0?n.snap.tree:[n.pid]));)await new Promise(n=>setTimeout(n,ze));let g=0;for(const n of s){const m=n.snap.tree.length>0?n.snap.tree:[n.pid];Me(m)&&(process.platform==="linux"&&P(T)?await A({operation:"stop",pid:n.pid}):Ge(m,"SIGKILL",n.snap.identities),g++)}g>0&&await new Promise(n=>setTimeout(n,ze));const p=Ae();if(p===null)throw d({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,m]of p.processes){const y=m.command;m.zombie||!y.includes("broker-cli.js")||fe(y,u)&&ue(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(", ")}`);d({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:f.length,sigtermed:v,sigkilled:g}})}a(hn,"reapPriorEpochBrokers");const vn=5e3;async function gn(e){const l=Array.from(e.entries());if(l.length===0)return;for(const[s]of l){const w=(await Er(s))?.status;(w==="active"||w==="idle")&&await De(s,new Date().toISOString())}const u=l.map(([,s])=>({pid:s.pid,snap:Ne(s.pid,null),exited:s.handle.exited}));for(const s of u)if(!s.snap.reused)try{process.platform==="linux"&&P(T)?await A({operation:"stop",pid:s.pid}):process.kill(s.pid,"SIGTERM")}catch{}const f=new Promise(s=>{setTimeout(s,vn).unref()});await Promise.allSettled(u.map(s=>Promise.race([s.exited.then(()=>{}),f])));const v=[];for(const s of u)xt(s.pid)&&(process.platform==="linux"&&P(T)?await A({operation:"stop",pid:s.pid}):Ge(s.snap.tree.length>0?s.snap.tree:[s.pid],"SIGKILL",s.snap.identities),v.push(s));await Promise.all(v.map(s=>s.exited));for(const[s]of l)await lt(s,{reason:"daemon-teardown"});d({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:u.length,sigkilled:v.length}})}a(gn,"teardownFleet");function Ue(){be(mr(de()),{recursive:!0}),cr(de(),String(process.pid),"utf8")}a(Ue,"writePidfile");function qe(e){return typeof e=="object"&&e!==null&&e.code==="ENOENT"}a(qe,"isMissingPathError");function We(e){const l=de();let u;try{u=lr(l,"utf8")}catch(f){if(qe(f))return;throw f}if(u.trim()!==String(e))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${e})`);try{dr(l)}catch(f){if(qe(f))return;throw f}}a(We,"removeOwnedPidfileMirror");const Sn={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(e=>{e.catch(()=>{})},"registerDetached")},Y=new tt;rt(e=>Y.handleFatalFault(e,!1));const yn=new nt,_n=new ot,bn=new it,kn=new at,Rn=new st,Pn=new ct,En=new pt,In=new ft,xn=new ut,Tn=new wt,Dn=new vt,Cn=new gt,Ln=new St,$n=new yt,An=new _t,Nn=new bt,Mn=new kt,Gn=new Rt;async function On(e=Date.now(),l=Sn){const u=Dt(),f=await Y.runFleetPreamble(u);let v,s;try{const g=await Te();v=g.filter(c=>c.status==="active"||c.status==="idle"),s=g.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead");const p=new Set(s.map(c=>c.node_id));s.push(...(await Ir()).filter(c=>!p.has(c.node_id)))}catch(g){d({level:"error",event:"canvas.node_list.failed",error:g});return}await Y.run(e,{rows:v,fleet:u,lifecycle:l}),await yn.run(e,{rows:v});const w=await _n.run(e,{rows:[...v,...s],fleet:u});await bn.run(e),await Mn.run(e),await Gn.run(e,{lifecycle:l}),await kn.run(e,{lifecycle:l}),await Rn.run(e,{lifecycle:l}),await Pn.run(e,{lifecycle:l}),await En.run(e,{lifecycle:l}),await In.run(e,{lifecycle:l,fleet:u}),xn.run(e,{lifecycle:l}),Tn.run(e,{lifecycle:l}),Dn.run(e,{lifecycle:l}),Cn.run(e,{lifecycle:l}),Ln.run(e,{lifecycle:l}),$n.run(e,{lifecycle:l}),await hr(),Nn.run(e,{fleet:u,lifecycle:l}),await An.run(e,{rows:v}),Y.warnIfSaturated({fleet:u,lifecycle:l,thresholds:f,frozen:w})}a(On,"superviseTick");function Q(e){return e===void 0||e==="reconcile"}a(Q,"roleRunsLanes");function N(e){return e===void 0||e==="api"}a(N,"roleServesRequests");const Fn=66e4;function Bn(e){const l=new Tr().registerAll(Dr(()=>null).filter(n=>n.pattern==="/healthz")),u=a((n,m)=>{const y=(n.url??"/").split("?")[0];if((n.method??"GET").toUpperCase()==="GET"&&y==="/healthz"){l.handle(n,m,null,{class:"person"});return}m.writeHead(404,{"content-type":"application/json; charset=utf-8"}),m.end(JSON.stringify({error:{code:"not_found",message:"this process serves only /healthz",origin:"runtime"}}))},"handler"),f=Ie();P(f)&&ke(f);const v=V(u),s=new Promise((n,m)=>{v.once("error",m),v.listen(f,()=>{v.off("error",m),Re(f,384),n()})});let w,g=null;const p=e.tcp??Pe()??le("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 m=V(u);m.on("error",y=>d({event:"api.server.failed",level:"error",error:y})),m.listen(Number(n[2]),n[1]===""?"0.0.0.0":n[1],()=>{g=`${n[1]===""?"0.0.0.0":n[1]}:${n[2]}`}),w=m}let c=!1;return{ready:s,tcpAddress:a(()=>g,"tcpAddress"),async close(n={}){if(!c){c=!0,await Promise.all([Ce(v,new Set,n.graceMs),w===void 0?Promise.resolve():Ce(w,new Set,n.graceMs)]);try{P(f)&&ke(f)}catch{}}}}}a(Bn,"createProbeServer");const Hn="daemon is draining for shutdown and admits no new work";async function jn(e){be(xe(),{recursive:!0,mode:493}),process.platform==="linux"&&Re(xe(),493);const l=Ie();if(P(l))throw new Error(`layout refusal cannot bind occupied socket: ${l}`);const u=V((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??Pe();if(v){const p=/^(.*):(\d+)$/.exec(v);if(!p||Number(p[2])>65535)throw new Error(`invalid refusal TCP address: ${v}`);const c=V(u.listeners("request")[0]);await new Promise((n,m)=>{c.once("error",m),c.listen(Number(p[2]),p[1],()=>{c.off("error",m),n()})}),f=c}Ue();let s;const w=a(()=>(s??=(async()=>{u.closeAllConnections(),f?.closeAllConnections(),await Promise.all([u,f].filter(p=>p!==void 0).map(p=>new Promise((c,n)=>p.close(m=>m?n(m):c())))),We(process.pid),process.off("SIGINT",g),process.off("SIGTERM",g)})(),s),"cleanup"),g=a(()=>{w().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),w}a(jn,"serveLayoutRefusal");async function zn(e={}){if(e.role==="machine")return(await import("./machine-daemon.js")).runMachineDaemon();if(kr())return jn(e);br();const l=a(t=>{process.stderr.write(`[crtrd] ${t}
3
+ `)},"logPostgres"),u=!!process.env.CRTR_TEST_PG_URL,f=Ft(e.role);Kt(Q(e.role));const v=a(async()=>f?await Ot(Ee(16).toString("hex")):{claimed:!0,claim:{pid:process.pid,pid_identity:"",token:Ee(16).toString("hex")}},"claimOwnership"),{database:s,ownership:w}=u?{database:{url:await Ht()},ownership:await v()}:await Wt(async()=>({database:await zt({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 t=[w.incumbentPid!==void 0?`pid ${w.incumbentPid}`:void 0,w.verdict!==void 0?`verdict ${w.verdict}`:void 0].filter(h=>h!==void 0),i=t.length>0?` (${t.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${w.reason}${i}
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 p=null,c=null,n=null,m,y="";try{f&&await hn(g.token);for(const r of Pr())process.stderr.write(`[crtrd] ${r}
6
+ `);for(const r of await Rr())process.stderr.write(`[crtrd] ${r}
7
+ `);await Fe(),await jt(s.url,l);const t=e.role===void 0&&!await pn();let i=null;t&&(mn({kind:"user",root:je()}),i=fn(je())),e.role===void 0&&un(i??{profiles:[],defaults:{},settings:{},state:{},apps:{}}),await H.listen(s.url);const h=a(r=>{He(r).catch(o=>d({level:"error",event:"daemon.settings.reload_failed",error:o}))},"reloadPerson");if(m=await H.subscribe(r=>{Be().includes(r)&&h(r)},{kinds:["settings"],onListenStart:a(()=>{for(const r of Be())h(r)},"onListenStart")}),e.role!==void 0&&Mr(),e.role!==void 0){let r;try{r=Xt()}catch(b){d({level:"error",event:"daemon.packages.snapshot_failed",error:b})}const o=await pe(async b=>(await Le(b),r===void 0?void 0:await Qt(b,r,"release"))),$=await pe(async b=>await Yt(b));$.alreadyDone||d({level:"info",event:"daemon.packages.install_migration_done",fields:{moved:$.moved,discarded:$.discarded,people:$.people}});for(const b of o?.invalid??[])process.stderr.write(`[crtrd] package file is not a document: ${b.path}: ${b.error}
8
+ `)}else{const r=await pe(async o=>(await Le(o),await Vt(o)));for(const o of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${o.message}
9
+ `);for(const o of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${o.path}: ${o.error}
10
+ `);for(const o of r.quarantined)process.stderr.write(`[crtrd] plugin "${o.name}" has a damaged ${o.file} (${o.reason}); ${o.movedTo!==void 0?`moved to ${o.movedTo}`:"left in place and skipped"}
11
+ `);for(const o of r.kinds.refused)process.stderr.write(`[crtrd] plugin "${o.plugin}" kind ${o.kind} not registered: ${o.message}
12
+ `);for(const o of r.kinds.invalid)process.stderr.write(`[crtrd] plugin "${o.plugin}" declares invalid object kinds or scopes; no kinds registered and no app token: ${o.error}
13
+ `)}if(y=await Mt(),Gt(y),e.role===void 0&&(p=await Gr(),p!==null)){if(Fr(p.id),await dn(p.id),process.platform==="darwin"){const{readConfig:r,updateConfig:o}=await import("../core/config.js");if(r("user").paths?.user_files===void 0){const{homedir:$}=await import("node:os");await o("user",b=>{b.paths??={},b.paths.user_files??=$()})}}c=await Or(),c.joinedFrom!==null&&await He(c.person),await or(),n=await Br()}if(process.platform==="linux"&&P(T)&&(_r(),await A({operation:"users.sync",users:await gr()})),f){await mt(g.token);const r=await nn();Object.values(r).some(o=>o>0)&&process.stderr.write(`[crtrd] node files copied into rows: ${JSON.stringify(r)}
14
+ `)}}catch(t){await H.close();try{if(f){const{released:i}=await Oe(g);if(!i)throw new Error("daemon ownership claim was not released")}await me()}catch(i){throw new AggregateError([t,i],"daemon startup failed and cleanup also failed")}throw t}let k=!0,X,j=Promise.resolve(),Z=!1,z,ee,re,D;const U=new Set;let te=!1,we=!1,E,C,ne,q=!1,W,M,G,O,F,oe,ie,ae;const Je=et();let I,S={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},L="initial startup activation",Ke=null;function Ve(){return S.phase==="ready"?null:{phase:S.phase,message:S.message,blockerPaths:S.blockerPaths}}a(Ve,"startupBlock");function R(t){U.add(t),t.finally(()=>{U.delete(t)}).catch(()=>{})}a(R,"registerDetached");const he={acceptsDetachedWork:a(()=>k,"acceptsDetachedWork"),registerDetached:R};Q(e.role)&&await Zt(he,Fe);async function Ye(){try{k=!1,Jt.close(),ee?.(),ee=void 0,re?.(),m?.(),re=void 0,ie?.(),ie=void 0,await H.close(),z!==void 0&&(clearInterval(z),z=void 0),G!==void 0&&(clearInterval(G),G=void 0),O!==void 0&&(clearInterval(O),O=void 0),ae?.(),ae=void 0;let t;do t=j,await t;while(t!==j);for(;U.size>0;)await Promise.allSettled([...U]);if(D!==void 0&&(f&&await gn(D),await D.exitsSettled(),D.dispose()),ne!==void 0&&await ne.close(),C!==void 0&&!q&&(q=!0,await C.close()),oe?.(),oe=void 0,F!==void 0){const i=F;F=void 0,await i.stop()}if(M!==void 0){const i=M;M=void 0,await i.close()}if(W!==void 0){const i=W;W=void 0,await i.close()}if(te||(We(process.pid),te=!0),te&&!we){if(f){const{released:i}=await Oe(g);if(!i)throw new Error("daemon ownership claim was not released")}we=!0,await me()}}finally{Lt(),process.off("SIGINT",Se),process.off("SIGTERM",ye),process.off("exit",_e)}}a(Ye,"cleanupAttempt");const J=1e3;let ve=!1;function Qe(){return ve?{graceMs:J}:(ve=!0,_.fresh(()=>{d({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:J}})}),setTimeout(()=>{Xe()},J),{graceMs:J})}a(Qe,"requestHandover");async function Xe(){try{await x()}catch(t){const i=t instanceof Error?t.stack??t.message:String(t);process.stderr.write(`[crtrd] handover cleanup failed:
15
+ ${i}
16
+ `),process.exit(1)}try{process.platform==="linux"&&P(T)&&(await A({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await $t();const t=await At({waitForJoinLock:!0});_.fresh(()=>{d({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(()=>{d({level:"error",event:"daemon.handover.successor_failed",error:t})});const i=t instanceof Error?t.message:String(t);process.stderr.write(`[crtrd] handover successor failed to start: ${i}
17
+ `),process.exit(1)}process.exit(0)}a(Xe,"performHandover");function x(){if(E!==void 0)return E;const t=Ye();return E=t,t.then(()=>{E===t&&(E=void 0)},()=>{E===t&&(E=void 0)}),t}a(x,"requestCleanup");async function Ze(){S={phase:"initializing",message:Hn,blockerPaths:[]},C!==void 0&&!q&&(q=!0,await C.close({graceMs:Fn}))}a(Ze,"drainApi");async function ge(t){try{t==="SIGTERM"&&e.role==="api"&&await Ze(),await x(),await qt({claimed:a(async()=>{try{return f&&await Bt()}finally{await me()}},"claimed")}),process.exit(0)}catch(i){process.exitCode=1;const h=i instanceof Error?i.stack??`${i.name}: ${i.message}`:String(i);process.stderr.write(`[crtrd] ${t} cleanup failed:
18
+ ${h}
19
+ `),process.exit(1)}}a(ge,"handleSignal");function Se(){ge("SIGINT")}a(Se,"onSigint");function ye(){ge("SIGTERM")}a(ye,"onSigterm");function _e(){x().catch(()=>{})}a(_e,"onExit");async function se(t){k&&(j=j.then(t).then(()=>{},i=>{_.fresh(()=>{d({level:"error",event:"daemon.lane_job.failed",error:i})})}))}a(se,"enqueue");async function K(){!k||Z||(Je.check()&&I&&(d({level:"info",event:"daemon.resume.detected"}),R(I().catch(()=>{}))),Z=!0,await se(async()=>{if(Z=!1,!!k)try{u||await Ut({log:l}),await On(Date.now(),he)}catch(t){_.fresh(()=>{d({level:"error",event:"daemon.tick.failed",error:t})})}}))}a(K,"enqueueTick");let B=null;async function er(){if(B!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${B instanceof Error?B.message:String(B)}`};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 ce(),S={phase:"ready",message:"",blockerPaths:[]},t?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(i){throw B=i,{status:500,code:"admission_failed",message:`daemon admission failed: ${i instanceof Error?i.message:String(i)}`}}}a(er,"admitStartup");async function rr(t){if(L!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${L})`};L="repair";try{const i=await ln({dryRun:t.dryRun});if(t.dryRun||i.pending||S.phase!=="blocked")return{result:i,resumed:!1};if(e.prepare)return S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:i,resumed:!1};try{return await ce(),S={phase:"ready",message:"",blockerPaths:[]},{result:i,resumed:!0}}catch(h){const r=h instanceof Error?h.message:String(h);return setTimeout(()=>{x().catch(()=>{})},1e3),{result:i,resumed:!1,resumeError:r}}}finally{L=null}}a(rr,"repairMigrations");async function tr(){X=e.intervalMs??Zr;const t=g.token;D=new tn({epoch:t,enqueue:se}),Tt(D),S={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{d({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:X}})});const i=y;_.fresh(()=>{d({level:"info",event:"daemon.install_id.resolved",fields:{install_id:i}})});const h=await Ar(i);if(_.fresh(()=>{d({level:"info",event:"daemon.environment.registered",fields:{environment_id:h.environmentId,created:h.created}})}),_.fresh(()=>{let r;try{r=Xr()}catch{return}r!==null&&d({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:r.slice(0,2048)}})}),ht(),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&&Nr(),!Q(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Qr(),await Kr(),await Vr(Date.now()),await Yr(Date.now())}),await _.fresh(async()=>{const{reconcile:r,migrated:o}=await Nt(dt);r.changed&&d({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:r.cleared.length,same_boot_proven:r.sameBootProven}}),o.length>0&&d({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:o.length}})}),await _.fresh(async()=>{for(const r of await Te())r.status!=="active"||r.pi_pid!=null||r.frozen_at!=null||r.respawn_not_before!=null||(await De(r.node_id,new Date().toISOString()),d({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:r.node_id}))}),await _.fresh(async()=>{await Et();for(const r of on){const o=await r.apply();o.changed&&d({level:"info",event:"daemon.boot_migration.applied",fields:{migration:r.id,...o.summary}})}}),R(Wr()),I){const r=a(()=>{R(I().catch(()=>{})),R(ar().then(o=>F?.observe(o)).then(()=>{},o=>{d({level:"warn",event:"daemon.peer.status_failed",error:o})}))},"refresh");R(qr().then(({completion:o})=>o).catch(o=>{d({level:"error",event:"daemon.grants.sweep_failed",error:o})})),r(),G=setInterval(r,$e*1e3),G.unref(),ae=ir({joined:!0,register:R})}await se(async()=>{await rn(),await en()}),z=setInterval(()=>{K().catch(r=>d({level:"error",event:"daemon.tick.failed",error:r}))},X),ee=await Pt(()=>{K().catch(r=>d({level:"error",event:"daemon.tick.failed",error:r}))}),re=await H.subscribe(()=>{K().catch(r=>d({level:"error",event:"daemon.tick.failed",error:r}))},{kinds:["spend_limits"]}),await K(),e.role===void 0&&import("../commands/sys/import/move.js").then(({settleMoveAtDaemonStart:r})=>r(()=>!k,o=>d({level:"warn",event:"daemon.move.settle_failed",error:o}))).catch(r=>d({level:"warn",event:"daemon.move.settle_failed",error:r}))}a(tr,"completeStartup");function ce(){return Ke??=tr().catch(t=>{throw S={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},t})}a(ce,"resumeStartup");try{process.on("SIGINT",Se),process.on("SIGTERM",ye),process.on("exit",_e),an(),p!==null&&d({level:"info",event:"daemon.person.resolved",fields:{person_id:p.id,source:p.source}}),n!==null&&d({level:"info",event:"daemon.permissions.boot",fields:{...n}}),c!==null&&d({level:"info",event:"daemon.person.retired",fields:{person_id:c.person,joined_from:c.joinedFrom,retired:c.retired,columns:c.columns}}),N(e.role)?W=await ur():wr(fr());const t=g.token;Ct({epoch:t,requestHandover:Qe,registerDetached:R,startupBlock:Ve,admitStartup:er,repairMigrations:rr}),Ue(),C=N(e.role)?xr({tcp:e.tcp}):Bn(e),await C.ready;const i=pr()??le("user").document_port;if(N(e.role)){const r=Cr(i,Lr());try{await r.ready,ne=r}catch(o){d({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:i,error:o instanceof Error?o.message:String(o)}})}}const h=le("user").runtime;if(h?.issuer&&(I=Ur(h.issuer,R),h.unsandboxed===!0&&(F=sr({syncGrants:I}))),e.role==="api"){const r=a(()=>R(zr().catch(o=>{d({level:"error",event:"daemon.packages.sync_failed",error:o})})),"packageTick");r(),O=setInterval(r,$e*1e3),O.unref()}if(N(e.role)&&(oe=await Hr()),ie=await jr({serves:N(e.role),runsLanes:Q(e.role)}),h?.unsandboxed===!0&&h.listener!==void 0&&d({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),N(e.role)&&h!==void 0&&h.listener!==void 0&&h.unsandboxed!==!0&&(M=await $r(h,async()=>await Jr(h.issuer.replace(/\/$/,"")),I),await M.ready),e.role===void 0)try{await sn()}catch(r){if(L=null,r instanceof cn)return S={phase:"blocked",message:r.message,blockerPaths:r.blockerPaths},x;throw r}process.platform==="linux"&&P(T)&&(yr(),await Sr("app:terminal"));try{e.prepare?S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await ce(),S={phase:"ready",message:"",blockerPaths:[]})}finally{L=null}return x}catch(t){try{await x()}catch(i){throw new AggregateError([t,i],"daemon startup failed and cleanup also failed")}throw t}}a(zn,"runDaemon");var ji=zn;export{Fn as API_DRAIN_GRACE_MS,qi as brokerCommandDeclaresCanvasHome,ue as brokerCommandEpoch,ji as default,Q as roleRunsLanes,N as roleServesRequests,zn as runDaemon,On as superviseTick,gn as teardownFleet};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.589",
3
+ "version": "0.3.590",
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.589",
148
+ "@north-light/identity": "0.3.590",
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.589",
3
+ "version": "0.3.590",
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.589",
3
+ "version": "0.3.590",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.589",
9
+ "version": "0.3.590",
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.589",
31
+ "@north-light/identity": "0.3.590",
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.589",
11959
+ "version": "0.3.590",
11960
11960
  "license": "UNLICENSED"
11961
11961
  },
11962
11962
  "packages/crouter-env-docker": {
11963
11963
  "name": "@north-light/env-docker",
11964
- "version": "0.3.589",
11964
+ "version": "0.3.590",
11965
11965
  "license": "UNLICENSED"
11966
11966
  },
11967
11967
  "packages/crouter-identity": {
11968
11968
  "name": "@north-light/identity",
11969
- "version": "0.3.589",
11969
+ "version": "0.3.590",
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.589",
11977
+ "version": "0.3.590",
11978
11978
  "license": "UNLICENSED",
11979
11979
  "dependencies": {
11980
- "@north-light/api": "0.3.589",
11981
- "@north-light/identity": "0.3.589"
11980
+ "@north-light/api": "0.3.590",
11981
+ "@north-light/identity": "0.3.590"
11982
11982
  }
11983
11983
  },
11984
11984
  "packages/crouter-sdk": {
11985
11985
  "name": "@north-light/sdk",
11986
- "version": "0.3.589",
11986
+ "version": "0.3.590",
11987
11987
  "license": "UNLICENSED",
11988
11988
  "dependencies": {
11989
- "@north-light/api": "0.3.589",
11990
- "@north-light/identity": "0.3.589",
11991
- "@north-light/plugin": "0.3.589",
11989
+ "@north-light/api": "0.3.590",
11990
+ "@north-light/identity": "0.3.590",
11991
+ "@north-light/plugin": "0.3.590",
11992
11992
  "jose": "^6.2.1"
11993
11993
  },
11994
11994
  "bin": {
@@ -1,22 +0,0 @@
1
- import type { CanvasDb } from '../canvas/db.js';
2
- export interface KindsReport {
3
- /** every kind a valid plugin declares that now has its row, and what upserting it did */
4
- applied: Array<{
5
- plugin: string;
6
- kind: string;
7
- outcome: 'inserted' | 'updated' | 'unchanged';
8
- }>;
9
- /** kinds another owner holds; the plugin's other kinds still applied */
10
- refused: Array<{
11
- plugin: string;
12
- kind: string;
13
- code: 'kind_owned';
14
- message: string;
15
- }>;
16
- /** enabled plugins whose manifest or commands are invalid (no kind update, no token); a provider bundle's kinds reconcile without a token, and plugins whose app handle another owner holds */
17
- invalid: Array<{
18
- plugin: string;
19
- error: string;
20
- }>;
21
- }
22
- export declare function reconcilePackageKinds(db: CanvasDb): Promise<KindsReport>;
@@ -1 +0,0 @@
1
- var u=Object.defineProperty;var d=(o,i)=>u(o,"name",{value:i,configurable:!0});import{CrtrError as p}from"../errors.js";import{invalidAppPlugins as l,kindPlugins as f}from"../plugin-app.js";import{upsertKind as g}from"./custom.js";import{ensureOwner as w}from"./objects.js";async function j(o){const i={applied:[],refused:[],invalid:l().map(e=>({plugin:e.plugin.name,error:e.error}))},t=new Set;for(const e of f()){const s=Object.entries(e.manifest.object_kinds??{});if(s.length===0)continue;let c;try{c=await w(o,"app","app",`app:${e.name}`,e.name)}catch(n){if(!(n instanceof p)||n.code!=="conflict")throw n;i.invalid.push({plugin:e.name,error:n.message});continue}for(const[n,a]of s)try{const r=await g(o,{name:n,owner:c,description:a.description,events:a.events,read:a.read===void 0?null:{command:a.read.command},source:"manifest"});if(r.outcome==="skipped")continue;t.add(n),i.applied.push({plugin:e.name,kind:n,outcome:r.outcome})}catch(r){if(!(r instanceof p)||r.code!=="kind_owned")throw r;i.refused.push({plugin:e.name,kind:n,code:"kind_owned",message:r.message})}}const m=await o.prepare("SELECT name FROM object_kinds WHERE source = 'manifest' AND declared = 1").all();for(const{name:e}of m)t.has(e)||await o.prepare("UPDATE object_kinds SET declared = 0 WHERE name = ?").run(e);return i}d(j,"reconcilePackageKinds");export{j as reconcilePackageKinds};
@@ -1,20 +0,0 @@
1
- /** One enabled plugin row of the person's user scope, with its marketplace's url and ref. */
2
- export interface PluginInstall {
3
- name: string;
4
- version: string | null;
5
- sourcePath: string | null;
6
- marketplace: {
7
- name: string;
8
- url: string | null;
9
- ref: string | null;
10
- } | null;
11
- /** A directory provider bundle (`isProviderBundleRow`): a provider call installs it into this process's own plugin directory, so there is nothing to fetch. */
12
- providerBundle: boolean;
13
- }
14
- /** The directory holding this person's materialized plugins as `<dir>/<plugin name>`; undefined when none were materialized. */
15
- export declare function materializedPluginsDir(person: string): string | undefined;
16
- /** Install `installs` for `person` at `revision` into this process's plugin cache, once per (person, revision). When a plugin cannot
17
- * be installed — a source on another machine, a marketplace that does not list it, a failed clone — the failure is held for that person
18
- * and thrown by the next read of their plugins (`materializedPluginsDir`), so a request that never reads plugins, such as the one that
19
- * fixes the settings, still works; the next load retries. */
20
- export declare function materializePlugins(person: string, revision: number, installs: readonly PluginInstall[]): Promise<void>;
@@ -1 +0,0 @@
1
- var z=Object.defineProperty;var u=(e,r)=>z(e,"name",{value:r,configurable:!0});import{cpSync as S,existsSync as d,mkdirSync as b,renameSync as M,rmSync as w}from"node:fs";import{tmpdir as v}from"node:os";import{isAbsolute as $,join as l,relative as A,resolve as P}from"node:path";import{CrtrError as c}from"../errors.js";import{gitAsync as x}from"../git.js";import{readMarketplaceManifest as D}from"../manifest.js";const m=new Map,h=new Map;function Z(e){const r=m.get(e);if(r!==void 0&&"failure"in r)throw r.failure;return r?.dir}u(Z,"materializedPluginsDir");function y(e){return l(v(),"crtr-plugin-cache",e.replace(/[^A-Za-z0-9._-]/g,"_"))}u(y,"cacheRoot");async function _(e,r,o,n){const t=await x(["clone","--depth","1",...r?["--branch",r]:[],e,o]);if(t.status!==0)throw new c("plugin_install_failed",`${n}: git clone ${e} failed: ${t.stderr.trim()}`)}u(_,"cloneInto");async function R(e,r){const o=new Map;b(l(e,"plugins"),{recursive:!0});for(const n of r){if(n.sourcePath!==null)throw new c("plugin_source_unreachable",`${n.name}: its source is ${n.sourcePath} on the machine that registered it, which the control plane cannot read`);const t=n.marketplace;if(n.providerBundle)continue;if(t===null)throw new c("plugin_source_unreachable",`${n.name}: it names neither a marketplace nor a path`);if(t.url===null||t.url==="")throw new c("plugin_source_unreachable",`${n.name}: its marketplace ${t.name} has no url`);const s=`${t.url}\0${t.ref??""}`;let a=o.get(s);a===void 0&&(a=l(e,"marketplaces",String(o.size)),await _(t.url,t.ref,a,`${n.name}: marketplace ${t.name}`),o.set(s,a));const i=D(a)?.plugins.find(k=>k.name===n.name);if(i===void 0)throw new c("plugin_install_failed",`${n.name}: marketplace ${t.name} (${t.url}) does not list it`);const f=l(e,"plugins",n.name);if($(i.source)||/^[a-z][a-z0-9+.-]*:|^git@/i.test(i.source)||i.source.endsWith(".git")){await _(i.source,null,f,n.name);continue}const p=P(a,i.source),g=A(a,p);if(g.startsWith("..")||$(g))throw new c("plugin_install_failed",`${n.name}: its source ${i.source} leaves the marketplace`);if(!d(p))throw new c("plugin_install_failed",`${n.name}: its source ${i.source} is not in marketplace ${t.name}`);S(p,f,{recursive:!0})}w(l(e,"marketplaces"),{recursive:!0,force:!0})}u(R,"installAll");async function q(e,r,o){const n=m.get(e);if(n?.revision===r&&!("failure"in n))return;const t=l(y(e),String(r)),s=`${e}\0${r}`;let a=h.get(s);a===void 0&&(a=(async()=>{if(!d(l(t,"plugins"))){const i=l(y(e),`${r}.${process.pid}.${Date.now()}`);try{await R(i,o);try{M(i,t)}catch(f){if(!d(l(t,"plugins")))throw f}}finally{w(i,{recursive:!0,force:!0})}}return l(t,"plugins")})().finally(()=>h.delete(s)),h.set(s,a));try{m.set(e,{revision:r,dir:await a})}catch(i){if(!(i instanceof c))throw i;m.set(e,{revision:r,failure:i})}}u(q,"materializePlugins");export{q as materializePlugins,Z as materializedPluginsDir};