@north-light/cli 0.3.581 → 0.3.582
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/health.d.ts +2 -0
- package/dist/api/error-codes.d.ts +5 -0
- package/dist/api/error-codes.js +1 -1
- package/dist/api/errors.js +1 -1
- package/dist/build-root.d.ts +11 -4
- package/dist/build-root.js +1 -1
- package/dist/cli.js +7 -7
- package/dist/clients/attach/viewer.js +428 -428
- package/dist/commands/api-client.d.ts +5 -0
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/sys/desktop.d.ts +5 -0
- package/dist/commands/sys/desktop.js +1 -0
- package/dist/commands/sys/import/move.d.ts +55 -0
- package/dist/commands/sys/import/move.js +8 -0
- package/dist/commands/sys/import/resume.js +1 -1
- package/dist/commands/sys/import/start.d.ts +3 -4
- package/dist/commands/sys/import/start.js +1 -4
- package/dist/commands/sys/signin.js +2 -2
- package/dist/commands/sys.js +1 -1
- package/dist/core/canvas/pid.d.ts +6 -0
- package/dist/core/canvas/pid.js +5 -5
- package/dist/core/command-plugins/compose.js +1 -1
- package/dist/core/command.d.ts +17 -8
- package/dist/core/command.js +9 -9
- package/dist/core/directory/issuer.d.ts +3 -0
- package/dist/core/directory/issuer.js +1 -1
- package/dist/core/directory/person-credential.d.ts +28 -3
- package/dist/core/directory/person-credential.js +1 -1
- package/dist/core/directory/reach.d.ts +3 -0
- package/dist/core/directory/reach.js +1 -0
- package/dist/core/grants/mirror.d.ts +3 -0
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/graph/bodies-boot-copy.d.ts +16 -2
- package/dist/core/graph/bodies-boot-copy.js +1 -1
- package/dist/core/graph/bodies.d.ts +13 -4
- package/dist/core/graph/bodies.js +1 -1
- package/dist/core/graph/documents.js +10 -10
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/ref-format.d.ts +7 -2
- package/dist/core/graph/repo-sync/ref-format.js +2 -2
- package/dist/core/import/bundle/layout.d.ts +2 -1
- package/dist/core/import/export/cloud.d.ts +4 -2
- package/dist/core/import/export/cloud.js +1 -1
- package/dist/core/import/export/dump.js +3 -3
- package/dist/core/import/load/copy.js +5 -5
- package/dist/core/import/load/rewrite.js +9 -5
- package/dist/core/import/load/stage.js +1 -1
- package/dist/core/import/load/verify.js +8 -7
- package/dist/core/io.js +4 -4
- package/dist/core/northlight/previews.d.ts +22 -0
- package/dist/core/northlight/previews.js +1 -0
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/device.js +1 -1
- package/dist/core/providers/files.d.ts +2 -1
- package/dist/core/providers/files.js +1 -1
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/model-adapter.js +3 -3
- package/dist/core/runtime/broker-ownership.d.ts +1 -0
- package/dist/core/runtime/broker-ownership.js +1 -0
- package/dist/core/runtime/first-run-offer.d.ts +7 -2
- package/dist/core/runtime/first-run-offer.js +10 -2
- package/dist/core/runtime/front-door.js +4 -4
- package/dist/core/runtime/runner/machine/executor.d.ts +7 -1
- package/dist/core/runtime/runner/machine/executor.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/boot-migrations.js +1 -1
- package/dist/daemon/cron/machine-exec.d.ts +6 -0
- package/dist/daemon/cron/machine-exec.js +1 -1
- package/dist/daemon/crtrd.d.ts +1 -1
- package/dist/daemon/crtrd.js +14 -14
- package/dist/daemon/machine-daemon.d.ts +7 -4
- package/dist/daemon/machine-daemon.js +1 -1
- package/dist/daemon/machine-link/config.d.ts +32 -1
- package/dist/daemon/machine-link/config.js +3 -3
- package/dist/daemon/machine-link/move-notify.d.ts +4 -0
- package/dist/daemon/machine-link/move-notify.js +1 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
package/dist/daemon/crtrd.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
var er=Object.defineProperty;var i=(e,c)=>er(e,"name",{value:c,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 b,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 jr,GRANT_SYNC_INTERVAL_S as zr}from"../core/grants/sync.js";import{sweepSandboxes as Hr}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 jt}from"../core/canvas/import-sqlite.js";import{ensurePostgres as zt,ensurePostgresHealthy as Ht,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 u}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";function de(e,c){return e.includes(` --canvas-home ${c} `)}i(de,"brokerCommandDeclaresCanvasHome");function me(e){return/ --epoch (\S+) /.exec(e)?.[1]??null}i(me,"brokerCommandEpoch");const mn=5e3,Fe=150;async function pn(e){const c=De();if(c===null)throw u({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 f=ur(),p=[];for(const[n,d]of c.processes){const y=d.command;if(d.zombie||!y.includes("broker-cli.js")||!de(y,f)||me(y)===e)continue;const k=y.trim().split(/\s+/).at(-1)??"";k===""||k.endsWith("broker-cli.js")||p.push({pid:n,nodeId:k})}let v=0;const a=[];for(const n of p){const d=Pt(n.pid);if(d===null||!d.includes("broker-cli.js")||!de(d,f)||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"&&b(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"&&b(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 u({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 l=[];for(const[n,d]of m.processes){const y=d.command;d.zombie||!y.includes("broker-cli.js")||de(y,f)&&me(y)!==e&&l.push(n)}if(l.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${l.join(", ")}`);u({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:p.length,sigtermed:v,sigkilled:g}})}i(pn,"reapPriorEpochBrokers");const fn=5e3;async function un(e){const c=Array.from(e.entries());if(c.length===0)return;for(const[a]of c){const w=(await kr(a))?.status;(w==="active"||w==="idle")&&await xe(a,new Date().toISOString())}const f=c.map(([,a])=>({pid:a.pid,snap:Ce(a.pid,null),exited:a.handle.exited}));for(const a of f)if(!a.snap.reused)try{process.platform==="linux"&&b(x)?await L({operation:"stop",pid:a.pid}):process.kill(a.pid,"SIGTERM")}catch{}const p=new Promise(a=>{setTimeout(a,fn).unref()});await Promise.allSettled(f.map(a=>Promise.race([a.exited.then(()=>{}),p])));const v=[];for(const a of f)Et(a.pid)&&(process.platform==="linux"&&b(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 c)await st(a,{reason:"daemon-teardown"});u({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:f.length,sigkilled:v.length}})}i(un,"teardownFleet");function Be(){ye(cr(ce()),{recursive:!0}),ir(ce(),String(process.pid),"utf8")}i(Be,"writePidfile");function je(e){return typeof e=="object"&&e!==null&&e.code==="ENOENT"}i(je,"isMissingPathError");function ze(e){const c=ce();let f;try{f=ar(c,"utf8")}catch(p){if(je(p))return;throw p}if(f.trim()!==String(e))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${e})`);try{sr(c)}catch(p){if(je(p))return;throw p}}i(ze,"removeOwnedPidfileMirror");const wn={acceptsDetachedWork:i(()=>!0,"acceptsDetachedWork"),registerDetached:i(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(),c=wn){const f=xt(),p=await K.runFleetPreamble(f);let v,a;try{const g=await Ie();v=g.filter(l=>l.status==="active"||l.status==="idle"),a=g.filter(l=>l.status==="done"||l.status==="canceled"||l.status==="dead");const m=new Set(a.map(l=>l.node_id));a.push(...(await Rr()).filter(l=>!m.has(l.node_id)))}catch(g){u({level:"error",event:"canvas.node_list.failed",error:g});return}await K.run(e,{rows:v,fleet:f,lifecycle:c}),await hn.run(e,{rows:v});const w=await vn.run(e,{rows:[...v,...a],fleet:f});await gn.run(e),await Ln.run(e),await $n.run(e,{lifecycle:c}),await Sn.run(e,{lifecycle:c}),await yn.run(e,{lifecycle:c}),await _n.run(e,{lifecycle:c}),await bn.run(e,{lifecycle:c}),await kn.run(e,{lifecycle:c,fleet:f}),Rn.run(e,{lifecycle:c}),Pn.run(e,{lifecycle:c}),En.run(e,{lifecycle:c}),In.run(e,{lifecycle:c}),xn.run(e,{lifecycle:c}),Tn.run(e,{lifecycle:c}),await fr(),Cn.run(e,{fleet:f,lifecycle:c}),await Dn.run(e,{rows:v}),K.warnIfSaturated({fleet:f,lifecycle:c,thresholds:p,frozen:w})}i(An,"superviseTick");function V(e){return e===void 0||e==="reconcile"}i(V,"roleRunsLanes");function $(e){return e===void 0||e==="api"}i($,"roleServesRequests");const Nn=66e4;function Mn(e){const c=new Er().registerAll(Ir(()=>null).filter(n=>n.pattern==="/healthz")),f=i((n,d)=>{const y=(n.url??"/").split("?")[0];if((n.method??"GET").toUpperCase()==="GET"&&y==="/healthz"){c.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"),p=Pe();b(p)&&_e(p);const v=J(f),a=new Promise((n,d)=>{v.once("error",d),v.listen(p,()=>{v.off("error",d),be(p,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(f);d.on("error",y=>u({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 l=!1;return{ready:a,tcpAddress:i(()=>g,"tcpAddress"),async close(n={}){if(!l){l=!0,await Promise.all([Te(v,new Set,n.graceMs),w===void 0?Promise.resolve():Te(w,new Set,n.graceMs)]);try{b(p)&&_e(p)}catch{}}}}}i(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 c=Pe();if(b(c))throw new Error(`layout refusal cannot bind occupied socket: ${c}`);const f=J((m,l)=>{if(m.method==="GET"&&m.url==="/healthz"){l.writeHead(200,{"content-type":"application/json; charset=utf-8"}),l.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}l.writeHead(503,{"content-type":"application/json; charset=utf-8"}),l.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,l)=>{f.once("error",l),f.listen(c,()=>{f.off("error",l),m()})});let p;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 l=J(f.listeners("request")[0]);await new Promise((n,d)=>{l.once("error",d),l.listen(Number(m[2]),m[1],()=>{l.off("error",d),n()})}),p=l}Be();let a;const w=i(()=>(a??=(async()=>{f.closeAllConnections(),p?.closeAllConnections(),await Promise.all([f,p].filter(m=>m!==void 0).map(m=>new Promise((l,n)=>m.close(d=>d?n(d):l())))),ze(process.pid),process.off("SIGINT",g),process.off("SIGTERM",g)})(),a),"cleanup"),g=i(()=>{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}
|
|
3
|
-
`)},"logPostgres"),
|
|
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
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,
|
|
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
6
|
`);for(const t of await _r())process.stderr.write(`[crtrd] ${t}
|
|
7
|
-
`);await Ne(),await
|
|
8
|
-
`);for(const t of
|
|
9
|
-
`);for(const t of
|
|
10
|
-
`);for(const t of
|
|
11
|
-
`);for(const t of
|
|
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()})}}
|
|
13
|
-
`)}}catch(r){await F.close();try{if(
|
|
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:
|
|
14
14
|
${o}
|
|
15
|
-
`),process.exit(1)}try{process.platform==="linux"&&
|
|
16
|
-
`),process.exit(1)}process.exit(0)}
|
|
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
17
|
${h}
|
|
18
|
-
`),process.exit(1)}}
|
|
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};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { HealthDTO } from '../api/index.js';
|
|
2
2
|
/** `/healthz` of the machine role. The daemon is up and serving whatever the link does, so `ok` stays true (a start waiting for it must not fail on an offline Mac);
|
|
3
|
-
* the link is its own fact, and the phase reads `ready` only while it is up.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
* the link is its own fact, and the phase reads `ready` only while it is up. `signed_in` is false on a computer with no person sign-in, which opens no link
|
|
4
|
+
* and runs nothing. No brokers are reconciled here: this role holds no database. */
|
|
5
|
+
export declare function machineHealth(linkConnected: boolean, signedIn: boolean): HealthDTO;
|
|
6
|
+
/** Start the machine role and return its teardown. Throws when `runtime/machine.json` is missing, or the machine credential is while the person is signed
|
|
7
|
+
* in: a machine role with nothing to link to must not look like a running daemon. With no person sign-in (`crtr sys signout`, or the file gone any other
|
|
8
|
+
* way) it opens no link and stops every broker and running machine cron of this home before it serves `/healthz` (design-crtr-northlight-signin
|
|
9
|
+
* component 5): the control plane's start and wake calls then get `machine_offline`, and nodes wait with their mail for the next sign-in. */
|
|
7
10
|
export declare function runMachineDaemon(): Promise<() => Promise<void>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=Object.defineProperty;var c=(e,n)=>_(e,"name",{value:n,configurable:!0});import{chmodSync as M,existsSync as S,mkdirSync as h,unlinkSync as g,writeFileSync as I,rmSync as v}from"node:fs";import{createServer as k}from"node:http";import{dirname as T}from"node:path";import{apiSocketPath as E}from"../core/canvas/paths.js";import{bindDaemonEventSource as R}from"../core/events/source.js";import{emitEvent as f}from"../core/events/emit.js";import{createMachineExecutor as P,stopAllBrokers as x}from"../core/runtime/runner/machine/executor.js";import{readPersonCredential as C}from"../core/directory/person-credential.js";import{socketDir as F}from"../core/layout.js";import{isDaemonRunning as G,pidfilePath as u,readPidfile as b}from"./pidfile.js";import{cancelMachineCron as N,runMachineCron as D,stopOrphanedMachineCrons as O}from"./cron/machine-exec.js";import{startMachineLink as U}from"./machine-link/client.js";import{deleteMoveRecord as w,readMachineConfig as Y,readMachineCredential as y,readMoveRecord as A,writeMoveRecord as z}from"./machine-link/config.js";import{notifyMoveFinished as H}from"./machine-link/move-notify.js";function j(e,n){return{ok:!0,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,link_connected:e,signed_in:n,startup_phase:e?"ready":"recovering"}}c(j,"machineHealth");async function se(){const e=Y();if(e===void 0)throw new Error("crtrd --role machine needs runtime/machine.json: this install has not been imported as a machine");const n=C()!==void 0;if(n&&y(),G())throw new Error("a crtrd is already running for this home");R(),n||(await x(),await O(),f({level:"info",event:"daemon.machine.signed_out",fields:{environment:e.environmentId}})),h(F(),{recursive:!0,mode:493});const a=E();S(a)&&g(a);let r;const t=k((s,d)=>{const p=(s.method??"GET")==="GET"&&(s.url??"/").split("?")[0]==="/healthz";d.writeHead(p?200:404,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify(p?j(r?.connected()===!0,n):{error:{code:"not_found",message:"a machine-role crtrd serves only /healthz",origin:"runtime"}}))});await new Promise((s,d)=>{t.once("error",d),t.listen(a,()=>{t.off("error",d),M(a,384),s()})}),h(T(u()),{recursive:!0}),I(u(),String(process.pid),"utf8");let i;await L(e.runId,n,()=>i!==void 0);const o=P({apiUrl:e.apiUrl,environmentId:e.environmentId});r=n?U({apiUrl:e.apiUrl,environmentId:e.environmentId,credential:y,handlers:{start:o.start,wake:o.wake,stop:o.stop,status:o.status,delete:o.delete,viewer:o.viewer,"cron.run":D,"cron.cancel":N}}):void 0,f({level:"info",event:"daemon.machine.started",fields:{environment:e.environmentId}});const l=c(()=>i??=(async()=>{r?.stop(),await new Promise(s=>{t.close(()=>s()),t.closeAllConnections()}),b()===process.pid&&(v(a,{force:!0}),v(u(),{force:!0})),process.off("SIGINT",m),process.off("SIGTERM",m)})(),"teardown"),m=c(()=>{l().then(()=>process.exit(0),()=>process.exit(1))},"onSignal");return process.on("SIGINT",m),process.on("SIGTERM",m),l}c(se,"runMachineDaemon");const B=5e3,J=3e5;async function L(e,n,a){let r;try{r=A()}catch(i){f({level:"warn",event:"daemon.machine.move_record_unreadable",fields:{error:i.message}});return}if(r===void 0||r.state==="running"||r.runId!==e)return;if(r.notified||r.notify===null){w();return}if(r.state==="committed"&&(r={...r,state:"activated"},z(r)),!n)return;const t=r;(async()=>{let i=B;for(;;){try{await H(t),w();return}catch(o){f({level:"warn",event:"daemon.machine.move_notify_failed",fields:{node:t.notify??"",error:o.message}})}if(await new Promise(o=>{setTimeout(o,i).unref()}),a())return;i=Math.min(i*2,J)}})()}c(L,"settleFinishedMove");export{j as machineHealth,se as runMachineDaemon};
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { CrtrError } from '../../core/errors.js';
|
|
2
|
+
/** The Northlight account, as the directory names it (`account` of the sign-in poll). */
|
|
3
|
+
export interface NorthlightAccount {
|
|
4
|
+
id: string;
|
|
5
|
+
display: string;
|
|
6
|
+
}
|
|
7
|
+
/** `directoryUrl` is the directory the person signs in against (`crtr sys signin`).
|
|
8
|
+
* `account` is the account the records moved into, kept only to name it when another account signs in; a Mac moved before it existed has none. */
|
|
2
9
|
export interface MachineConfig {
|
|
3
10
|
apiUrl: string;
|
|
4
11
|
environmentId: string;
|
|
5
12
|
runId: string;
|
|
6
13
|
directoryUrl: string;
|
|
14
|
+
account?: NorthlightAccount;
|
|
7
15
|
}
|
|
8
16
|
export declare const machineConfigPath: () => string;
|
|
9
17
|
export declare const machineCredentialPath: () => string;
|
|
@@ -12,3 +20,26 @@ export declare function readMachineConfig(): MachineConfig | undefined;
|
|
|
12
20
|
export declare function writeMachineConfig(config: MachineConfig): void;
|
|
13
21
|
export declare function readMachineCredential(): string;
|
|
14
22
|
export declare function writeMachineCredential(secret: string): void;
|
|
23
|
+
/** A move to Northlight in progress. `running`: the cloud run has not reached `done`, so a failure undoes the move. `committed`: the account holds the
|
|
24
|
+
* records and only the switch-over (machine credential, `machine.json`, restart) is left. `activated`: the machine-role daemon is up, so the switch-over is
|
|
25
|
+
* complete and commands run; the record stays only until `notified` — the asking node's message is stored in the account — is true, then it is deleted. */
|
|
26
|
+
export interface MoveRecord {
|
|
27
|
+
runId: string;
|
|
28
|
+
apiUrl: string;
|
|
29
|
+
directoryUrl: string;
|
|
30
|
+
account: NorthlightAccount;
|
|
31
|
+
notify: string | null;
|
|
32
|
+
state: 'running' | 'committed' | 'activated';
|
|
33
|
+
notified: boolean;
|
|
34
|
+
/** The exporter's process, so a later `crtr sys signin` can tell a running move from one whose exporter was killed. */
|
|
35
|
+
pid: number;
|
|
36
|
+
}
|
|
37
|
+
export declare const moveRecordPath: () => string;
|
|
38
|
+
/** The move record, or undefined when no move is running or unfinished. A present but malformed file throws. */
|
|
39
|
+
export declare function readMoveRecord(): MoveRecord | undefined;
|
|
40
|
+
export declare function writeMoveRecord(record: MoveRecord): void;
|
|
41
|
+
export declare function deleteMoveRecord(): void;
|
|
42
|
+
/** Whether a move's records are in the Northlight account but this computer has not switched over (the record says `committed`). */
|
|
43
|
+
export declare const isMoveCommitted: () => boolean;
|
|
44
|
+
/** The one `move_unfinished` error: every command, `crtr sys import resume` and a move whose switch-over failed answer it alike (exit code USAGE, as `not_signed_in`). */
|
|
45
|
+
export declare const moveUnfinishedError: (reason?: string) => CrtrError;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}e(
|
|
3
|
-
`,{mode:384}),
|
|
1
|
+
var y=Object.defineProperty;var e=(r,t)=>y(r,"name",{value:t,configurable:!0});import{chmodSync as l,existsSync as n,mkdirSync as s,readFileSync as o,rmSync as h,writeFileSync as u}from"node:fs";import{dirname as p,join as i}from"node:path";import{runtimeRoot as f,secretsDir as g}from"../../core/layout.js";import{CrtrError as v}from"../../core/errors.js";import{atomicWriteJson as U}from"../../core/fs-utils.js";import{ExitCode as x}from"../../types.js";const c=e(()=>i(f(),"machine.json"),"machineConfigPath"),m=e(()=>i(g(),"machine-credential"),"machineCredentialPath");function J(){const r=c();if(!n(r))return;const t=JSON.parse(o(r,"utf8"));if(typeof t.apiUrl!="string"||typeof t.environmentId!="string"||typeof t.runId!="string"||typeof t.directoryUrl!="string")throw new Error(`${r} must hold {apiUrl, environmentId, runId, directoryUrl}`);const a=t.account!==void 0&&typeof t.account?.id=="string"&&typeof t.account.display=="string"?{id:t.account.id,display:t.account.display}:void 0;return{apiUrl:t.apiUrl,environmentId:t.environmentId,runId:t.runId,directoryUrl:t.directoryUrl,...a===void 0?{}:{account:a}}}e(J,"readMachineConfig");function N(r){s(p(c()),{recursive:!0}),u(c(),`${JSON.stringify(r,null,2)}
|
|
2
|
+
`)}e(N,"writeMachineConfig");function j(){const r=m();if(!n(r))throw new Error(`no machine credential at ${r}`);return o(r,"utf8").trim()}e(j,"readMachineCredential");function O(r){const t=m();s(p(t),{recursive:!0}),u(t,`${r}
|
|
3
|
+
`,{mode:384}),l(t,384)}e(O,"writeMachineCredential");const d=e(()=>i(f(),"import","move.json"),"moveRecordPath");function w(){const r=d();if(!n(r))return;const t=JSON.parse(o(r,"utf8"));if(typeof t.runId!="string"||typeof t.apiUrl!="string"||typeof t.directoryUrl!="string"||t.state!=="running"&&t.state!=="committed"&&t.state!=="activated"||typeof t.account?.id!="string"||typeof t.account.display!="string")throw new Error(`${r} is not a move record`);return{runId:t.runId,apiUrl:t.apiUrl,directoryUrl:t.directoryUrl,account:{id:t.account.id,display:t.account.display},notify:typeof t.notify=="string"?t.notify:null,state:t.state,notified:t.notified===!0,pid:typeof t.pid=="number"?t.pid:0}}e(w,"readMoveRecord");function P(r){U(d(),r,{mode:384})}e(P,"writeMoveRecord");function b(){h(d(),{force:!0})}e(b,"deleteMoveRecord");const F=e(()=>w()?.state==="committed","isMoveCommitted"),k=e(r=>new v("move_unfinished",`crtr's records are already in your Northlight account, but this computer has not switched over${r===void 0?".":`: ${r}`}`,x.USAGE,{next:"Run `crtr sys signin` to finish."}),"moveUnfinishedError");export{b as deleteMoveRecord,F as isMoveCommitted,c as machineConfigPath,m as machineCredentialPath,d as moveRecordPath,k as moveUnfinishedError,J as readMachineConfig,j as readMachineCredential,w as readMoveRecord,N as writeMachineConfig,O as writeMachineCredential,P as writeMoveRecord};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type MoveRecord } from './config.js';
|
|
2
|
+
/** Tell the node that asked for the move that it finished, through the control plane with the person's bearer (`POST /v1/nodes/:id/messages`): the node
|
|
3
|
+
* now lives in the account, so the message is stored there as mail and wakes it once the machine link is up. Then the record says `notified`. */
|
|
4
|
+
export declare function notifyMoveFinished(move: MoveRecord): Promise<MoveRecord>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var i=Object.defineProperty;var n=(t,r)=>i(t,"name",{value:r,configurable:!0});import{CrtrClient as o}from"../../api/index.js";import{northlightFetch as e}from"../../core/directory/person-credential.js";import{writeMoveRecord as c}from"./config.js";async function l(t){if(t.notified||t.notify===null)return t;await new o({baseUrl:t.apiUrl,fetch:e(t.directoryUrl,t.apiUrl)}).sendMessage(t.notify,{from:null,body:`The move to Northlight finished; crtr on this computer now runs with the account ${t.account.display}. Retry the command that needed the account and carry on.`});const r={...t,notified:!0};return c(r),r}n(l,"notifyMoveFinished");export{l as notifyMoveFinished};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.582",
|
|
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.
|
|
148
|
+
"@north-light/identity": "0.3.582",
|
|
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",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.582",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.582",
|
|
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.
|
|
31
|
+
"@north-light/identity": "0.3.582",
|
|
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.
|
|
11959
|
+
"version": "0.3.582",
|
|
11960
11960
|
"license": "UNLICENSED"
|
|
11961
11961
|
},
|
|
11962
11962
|
"packages/crouter-env-docker": {
|
|
11963
11963
|
"name": "@north-light/env-docker",
|
|
11964
|
-
"version": "0.3.
|
|
11964
|
+
"version": "0.3.582",
|
|
11965
11965
|
"license": "UNLICENSED"
|
|
11966
11966
|
},
|
|
11967
11967
|
"packages/crouter-identity": {
|
|
11968
11968
|
"name": "@north-light/identity",
|
|
11969
|
-
"version": "0.3.
|
|
11969
|
+
"version": "0.3.582",
|
|
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.
|
|
11977
|
+
"version": "0.3.582",
|
|
11978
11978
|
"license": "UNLICENSED",
|
|
11979
11979
|
"dependencies": {
|
|
11980
|
-
"@north-light/api": "0.3.
|
|
11981
|
-
"@north-light/identity": "0.3.
|
|
11980
|
+
"@north-light/api": "0.3.582",
|
|
11981
|
+
"@north-light/identity": "0.3.582"
|
|
11982
11982
|
}
|
|
11983
11983
|
},
|
|
11984
11984
|
"packages/crouter-sdk": {
|
|
11985
11985
|
"name": "@north-light/sdk",
|
|
11986
|
-
"version": "0.3.
|
|
11986
|
+
"version": "0.3.582",
|
|
11987
11987
|
"license": "UNLICENSED",
|
|
11988
11988
|
"dependencies": {
|
|
11989
|
-
"@north-light/api": "0.3.
|
|
11990
|
-
"@north-light/identity": "0.3.
|
|
11991
|
-
"@north-light/plugin": "0.3.
|
|
11989
|
+
"@north-light/api": "0.3.582",
|
|
11990
|
+
"@north-light/identity": "0.3.582",
|
|
11991
|
+
"@north-light/plugin": "0.3.582",
|
|
11992
11992
|
"jose": "^6.2.1"
|
|
11993
11993
|
},
|
|
11994
11994
|
"bin": {
|