@north-light/cli 0.3.591 → 0.3.593
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/imports.d.ts +6 -0
- package/dist/cli.js +7 -7
- package/dist/clients/attach/viewer.js +429 -429
- package/dist/commands/pkg/market-inspect.js +1 -1
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-inspect.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +6 -6
- package/dist/core/import/load/prepare.js +5 -5
- package/dist/core/import/load/publish-plugins.d.ts +10 -0
- package/dist/core/import/load/publish-plugins.js +1 -0
- package/dist/core/import/load/run.js +2 -2
- package/dist/core/import/load/stores.d.ts +8 -1
- package/dist/core/import/load/stores.js +2 -2
- package/dist/core/packages/directory-sync.d.ts +2 -0
- package/dist/core/packages/directory-sync.js +3 -3
- package/dist/daemon/api/handlers/imports.js +1 -1
- package/dist/daemon/crtrd.js +12 -12
- package/dist/daemon/manage.d.ts +10 -3
- package/dist/daemon/manage.js +3 -3
- package/dist/daemon/reconcilers/node-lifecycle/tick.d.ts +5 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/shared/env.d.ts +4 -0
- package/dist/shared/env.js +2 -2
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var a=(t,n)=>k(t,"name",{value:n,configurable:!0});import{randomBytes as E}from"node:crypto";import{ApiError as o}from"../../../api/errors.js";import{blobStore as
|
|
1
|
+
var k=Object.defineProperty;var a=(t,n)=>k(t,"name",{value:n,configurable:!0});import{randomBytes as E}from"node:crypto";import{ApiError as o}from"../../../api/errors.js";import{blobStore as f}from"../../../core/blobs/index.js";import{presignPutUrl as $,r2ConfigFromEnv as v}from"../../../core/blobs/r2.js";import{openDb as c}from"../../../core/canvas/db.js";import{bundleKeys as m}from"../../../core/import/bundle/layout.js";import{putStore as O,StoreBodyError as T,STORE_NAMES as R}from"../../../core/import/load/stores.js";import{rollbackRun as D}from"../../../core/import/load/rollback.js";import{crtrVersion as w}from"../../../shared/crtr-version.js";import{importTokenFor as N}from"../import-auth.js";const h=3600;function y(t){if(t.principal.class!=="person"||t.principal.sub===void 0)throw new o(403,"person_only","an import is made by a signed-in person");return t.principal.sub}a(y,"personOf");async function _(t,n=!1){const e=t.params.run_id??"",r=await(await c()).prepare("SELECT * FROM import_runs WHERE run_id = ?").get(e),s=t.principal;if(s.class==="import"){if(s.run===null&&!n)throw new o(403,"permission_error","the service credential starts and reads runs; the import token uploads and loads");if(r===void 0||(s.run===null?r.source_kind!=="hosted":s.run!==r.run_id))throw new o(404,"import_not_found",`no import run ${e}`);if(s.run!==null&&!n&&r.state!=="uploading"&&r.state!=="loading")throw new o(403,"import_token_expired",`import run ${r.run_id} is ${r.state}: its import token no longer works`);return r}if(r===void 0||r.person!==y(t))throw new o(404,"import_not_found",`no import run ${e}`);return r}a(_,"ownRun");function A(t,n,e){const r=t.principal;if(r.class!=="import")return y(t);if(r.run!==null)throw new o(403,"permission_error","an import token reaches only its own run");const s=n.person;if(typeof s!="string"||!/^user:.+/.test(s))throw new o(400,"invalid_body","person (user:<id>) is required");if(e!=="hosted")throw new o(400,"invalid_body","the service credential starts hosted runs only: source_kind must be hosted");return s}a(A,"startPerson");const g=a(t=>{if(t===null||typeof t!="object"||Array.isArray(t))throw new o(400,"invalid_body","the body must be a JSON object");return t},"objectBody");async function j(t){const n=g(t.body),e=A(t,n,n.source_kind),r=n.source_install_id,s=n.source_kind,u=n.release;if(typeof r!="string"||r===""||s!=="machine"&&s!=="hosted"||typeof u!="string")throw new o(400,"invalid_body","source_install_id, source_kind (machine | hosted) and release are required");if(u!==w())throw new o(409,"release_mismatch",`the source runs ${u}, the control plane accepts ${w()}`);const p=await c();let i=await p.prepare("SELECT run_id, state FROM import_runs WHERE source_install_id = ? AND state IN ('uploading', 'loading', 'committed', 'done')").get(r);if(i?.state==="uploading"){const S={step:"uploading",code:"superseded",message:`a new import run was started for install ${r} before this one asked for the load`};await p.prepare("UPDATE import_runs SET state = 'failed', failure_json = ?, finished_at = ? WHERE run_id = ? AND state = 'uploading'").run(JSON.stringify(S),new Date().toISOString(),i.run_id),i=await p.prepare("SELECT run_id, state FROM import_runs WHERE source_install_id = ? AND state IN ('uploading', 'loading', 'committed', 'done')").get(r)}if(i?.state==="done")throw new o(409,"already_imported",`install ${r} was imported by run ${i.run_id}`);if(i!==void 0)throw new o(409,"import_running",`install ${r} has an open run ${i.run_id} (${i.state})`);const d=`imp_${E(8).toString("hex")}`;await p.prepare("INSERT INTO import_runs (run_id, source_install_id, source_kind, person, release, state, created_at) VALUES (?, ?, ?, ?, ?, 'uploading', ?)").run(d,r,s,e,u,new Date().toISOString());const l=t.principal.class==="import"?N(d):null;return{status:201,body:{run_id:d,upload:{rows_prefix:m.prefix(d),url_template:`POST /v1/imports/${d}/upload-urls {"keys":[...]}`},...l===null?{}:{import_token:l}}}}a(j,"handleStart");async function P(t){const n=await _(t);if(n.state!=="uploading")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);const e=g(t.body).keys;if(!Array.isArray(e)||e.some(i=>typeof i!="string"))throw new o(400,"invalid_body","keys must be a list of blob keys");const r=m.prefix(n.run_id);for(const i of e)if(!(i.startsWith(r)&&!i.startsWith(`${r}stores/`)&&i!==m.manifest(n.run_id))||i.split("/").some(l=>l===""||l==="."||l===".."))throw new o(400,"invalid_key",`${i} is not a key this run may upload`);const s=v();if(s===null)throw new o(501,"upload_not_supported","this control plane keeps blobs in a directory: there is no URL to upload to");const u={};for(const i of e)u[i]=$(s,i,h);return{status:200,body:{urls:u,expires_at:new Date(Date.now()+h*1e3).toISOString()}}}a(P,"handleUploadUrls");async function I(t){const n=await _(t);if(n.state!=="uploading")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);const e=t.params.name;if(!R.includes(e))throw new o(404,"unknown_store",`no file store ${e}`);try{await O(await f(),n.run_id,e,t.body)}catch(r){throw r instanceof T?new o(400,"invalid_body",r.message):r}return{status:204}}a(I,"handleStore");async function U(t){const n=await _(t),e=await c();if(n.state==="uploading"){if(await(await f()).get(m.source(n.run_id))===null)throw new o(409,"bundle_invalid","source.json is not uploaded");await e.prepare("UPDATE import_runs SET state = 'loading', step = 'queued', loaded_at = ? WHERE run_id = ? AND state = 'uploading'").run(new Date().toISOString(),n.run_id)}else if(n.state!=="loading"&&n.state!=="committed"&&n.state!=="done")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);return{status:202,body:await b(n.run_id)}}a(U,"handleLoad");async function b(t){const n=await(await c()).prepare("SELECT * FROM import_runs WHERE run_id = ?").get(t),e=n.counts_json===null?{}:JSON.parse(n.counts_json),{unresolved_plugins:r,refused_plugins:s,...u}=e;return{run_id:n.run_id,source_install_id:n.source_install_id,source_kind:n.source_kind,person:n.person,release:n.release,state:n.state,step:n.step,counts:u,verify:n.verify_json===null?null:JSON.parse(n.verify_json),failure:n.failure_json===null?null:JSON.parse(n.failure_json),unresolved_plugins:r??[],refused_plugins:s??[],created:n.created_at,loaded:n.loaded_at,finished:n.finished_at}}a(b,"runDto");async function L(t){const n=await _(t,!0);return{status:200,body:await b(n.run_id)}}a(L,"handleGet");async function W(t){const n=await _(t),e=await D(n.run_id,await f());if(!e.rolled_back)throw new o(409,"rollback_has_dependents",`later rows depend on import run ${n.run_id}`,e.dependents);return{status:200,body:e}}a(W,"handleRollback");const X=[{method:"POST",pattern:"/v1/imports",handler:j},{method:"POST",pattern:"/v1/imports/:run_id/upload-urls",handler:P},{method:"PUT",pattern:"/v1/imports/:run_id/stores/:name",handler:I},{method:"POST",pattern:"/v1/imports/:run_id/load",handler:U},{method:"GET",pattern:"/v1/imports/:run_id",handler:L},{method:"POST",pattern:"/v1/imports/:run_id/rollback",handler:W}];export{X as importRoutes};
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
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(
|
|
3
|
-
`)},"logPostgres"),u=!!process.env.CRTR_TEST_PG_URL,f=
|
|
1
|
+
var or=Object.defineProperty;var a=(e,l)=>or(e,"name",{value:l,configurable:!0});import{applyBootSettings as ir}from"./boot-settings.js";import{startPeerOutbox as ar}from"./peer/outbox.js";import{reportMachineStatus as sr}from"../core/peer/directory.js";import{createPeerRelay as cr}from"./peer/relay-service.js";import{writeFileSync as lr,readFileSync as dr,rmSync as mr,mkdirSync as ke,existsSync as R,unlinkSync as Re,chmodSync as Pe}from"node:fs";import{createServer as V}from"node:http";import{dirname as pr}from"node:path";import{envCrtrdTcp as Ee,envDocumentPort as fr}from"../shared/env.js";import{openCanvasConversationStore as ur,serveCanvasConversationStore as wr}from"../core/canvas/sessions.js";import{installConversationStore as hr}from"../core/conversation-store/index.js";import{pollRunObservers as vr}from"./runs/observer.js";import{randomBytes as Ie}from"node:crypto";import{apiSocketPath as xe,crtrHome as gr}from"../core/canvas/paths.js";import{activeAppUsers as Sr}from"../core/spaces/users.js";import{ensureAppSpace as yr,ensureUserFiles as _r}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 br}from"./launcher-events.js";import{initializeEmptyLayout as kr,layoutNeedsMigration as Rr,socketDir as Te}from"../core/layout.js";import{migrateLooseKeys as Pr}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as Er}from"../core/profiles/relocate.js";import{getNode as Ir,listNodesForSupervision as De,listParkedResidentsWithWakeMail as xr,setFrozen as Ce}from"../core/canvas/index.js";import{createApiServer as Tr,closeServer as Le}from"./api/server.js";import{Router as Dr}from"./api/router.js";import{healthRoutes as Cr}from"./api/handlers/health.js";import{createDocumentListener as Lr}from"./api/document-listener.js";import{documentSecret as $r}from"./api/document-secret.js";import{createAppListener as Ar}from"./api/app-listener.js";import{registerMachineEnvironment as Nr}from"../core/environments.js";import{registerBlaxelRunnerFromEnv as Mr}from"../core/secrets/blaxel-register.js";import{markCloudRole as Gr,resolvePerson as Or,retireLocalPerson as Fr,setPersonId as Br}from"../core/canvas/person.js";import{backfillNodeApps as $e,runPermissionsBoot as Hr}from"../core/permissions/boot.js";import{startRunNotices as jr}from"./run-notices.js";import{startGrantEffects as zr}from"./reconcilers/grant-effects.js";import{syncPackages as Ur}from"../core/packages/directory-sync.js";import{createGrantSync as qr,GRANT_SYNC_INTERVAL_S as Ae}from"../core/grants/sync.js";import{sweepSandboxes as Wr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as Jr}from"./cron/run-socket.js";import{hasSyncedGrants as Kr}from"../core/grants/mirror.js";import{readConfig as le}from"../core/config.js";import{reconcileUndeliveredTickets as Vr}from"./human/sweep.js";import{resetHandedOffDeliveries as Yr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as Qr}from"../core/canvas/daemon-actions.js";import{sweepReviews as Xr}from"./review/sweep.js";import{pidfilePath as de}from"./pidfile.js";import{rendererWarning as Zr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as et}from"./supervise-cadence.js";import{createResumeDetector as rt}from"./resume-detector.js";import{setFatalFaultAnnouncer as tt}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as nt}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as ot}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as it}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as at}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as st}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as ct}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as lt}from"./reconcilers/action-lane.js";import{endLiveExecution as dt,migrateLegacyExecutionIdentities as mt}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as pt}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as ft}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as ut}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as wt}from"./reconcilers/storage-due-work.js";import{PurgeDueWorkReconciler as ht}from"./reconcilers/purge-due-work.js";import{assertLedgerEnv as vt}from"../core/ledger/rates.js";import{LedgerSandboxReconciler as gt}from"./reconcilers/ledger-sandbox.js";import{LedgerStorageReconciler as St}from"./reconcilers/ledger-storage.js";import{LedgerR2Reconciler as yt}from"./reconcilers/ledger-r2.js";import{ImportLaneReconciler as _t}from"./reconcilers/import-lane.js";import{BashDeadlineReconciler as bt}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as kt}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Rt}from"./reconcilers/structured-request-lane.js";import{RecipeImageReconciler as Pt,subscribeImageBuilt as Et}from"./reconcilers/recipe-image.js";import{reconcileStructuredRequestSidecars as It}from"./structured-requests/boot.js";import{captureLivenessSnapshot as Ne,capturePidCommand as xt,captureTeardownSnapshot as Me,isPidAlive as Tt,isAnyPidAlive as Ge,killProcessTreePids as Oe}from"../core/canvas/pid.js";import{bindFleet as Dt,boundFleet as Ct}from"../core/runtime/fleet.js";import{bindDaemonControl as Lt,clearDaemonControl as $t}from"./control.js";import{execDaemon as At,spawnDaemon as Nt}from"./manage.js";import{reconcileAndMigrateBoot as Mt}from"../core/canvas/boot.js";import{resolveInstallId as Gt}from"../core/canvas/install-id.js";import{setInstallId as Ot}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ft,daemonOwnershipApplies as Bt,daemonOwnershipClaimed as Ht,releaseDaemonOwnership as Fe}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as jt,closeAllDbs as me,openDb as Be,withCanvasWrite as pe}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as zt}from"../core/canvas/import-sqlite.js";import{ensurePostgres as Ut,ensurePostgresHealthy as qt,stopPostgres as Wt,withPostgresStartLock as Jt}from"./postgres/index.js";import{brokerSignalBus as H}from"./broker-signals/bus.js";import{brokerSignalStreams as Kt}from"./api/handlers/broker-signals.js";import{setRequestsStartRunObservers as Vt}from"./api/handlers/broker-ops.js";import{reconcilePackages as Yt}from"../core/graph/package-reconcile.js";import{migrateAppInstalls as Qt}from"../core/scoped-state/migrate-app-installs.js";import{publish as Xt,readBuiltinSnapshot as Zt}from"../core/graph/package-publish.js";import{startRepoSync as en}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as rn,reapStaleSpares as tn}from"../core/runtime/warm-pool.js";import{DaemonFleet as nn}from"./fleet.js";import{copyNodeFilesToRows as on}from"../core/runtime/first-boot-rows.js";import{BOOT_MIGRATIONS as an}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 sn}from"../core/events/source.js";import{activateCanvasImport as cn,MigrationBlockedError as ln,runForcedCanvasImport as dn}from"../migrations/activation.js";import{adoptInstallPerson as mn,convertLegacyScopedStore as pn,personStoresCopied as fn}from"../core/scoped-state/migrate.js";import{readLegacyUserSnapshot as un}from"../core/scoped-state/legacy-profiles.js";import{heldPersons as He,installPreludeSnapshot as wn}from"../core/scoped-state/person-store.js";import{loadPersonSettings as je}from"../core/scoped-state/person-rows.js";import{userScopeRoot as ze}from"../core/scope.js";import{brokerCommandDeclaresCanvasHome as fe}from"../core/runtime/broker-ownership.js";import{brokerCommandDeclaresCanvasHome as Wi}from"../core/runtime/broker-ownership.js";function ue(e){return/ --epoch (\S+) /.exec(e)?.[1]??null}a(ue,"brokerCommandEpoch");const hn=5e3,Ue=150;async function vn(e){const l=Ne();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=gr(),f=[];for(const[n,d]of l.processes){const y=d.command;if(d.zombie||!y.includes("broker-cli.js")||!fe(y,u)||ue(y)===e)continue;const P=y.trim().split(/\s+/).at(-1)??"";P===""||P.endsWith("broker-cli.js")||f.push({pid:n,nodeId:P})}let v=0;const s=[];for(const n of f){const d=xt(n.pid);if(d===null||!d.includes("broker-cli.js")||!fe(d,u)||ue(d)===e||d.trim().split(/\s+/).at(-1)!==n.nodeId)continue;const y=Me(n.pid,null);if(!y.reused){try{process.platform==="linux"&&R(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()+hn;for(;Date.now()<w&&s.some(n=>Ge(n.snap.tree.length>0?n.snap.tree:[n.pid]));)await new Promise(n=>setTimeout(n,Ue));let g=0;for(const n of s){const d=n.snap.tree.length>0?n.snap.tree:[n.pid];Ge(d)&&(process.platform==="linux"&&R(T)?await A({operation:"stop",pid:n.pid}):Oe(d,"SIGKILL",n.snap.identities),g++)}g>0&&await new Promise(n=>setTimeout(n,Ue));const p=Ne();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")||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(", ")}`);m({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:f.length,sigtermed:v,sigkilled:g}})}a(vn,"reapPriorEpochBrokers");const gn=5e3;async function Sn(e){const l=Array.from(e.entries());if(l.length===0)return;for(const[s]of l){const w=(await Ir(s))?.status;(w==="active"||w==="idle")&&await Ce(s,new Date().toISOString())}const u=l.map(([,s])=>({pid:s.pid,snap:Me(s.pid,null),exited:s.handle.exited}));for(const s of u)if(!s.snap.reused)try{process.platform==="linux"&&R(T)?await A({operation:"stop",pid:s.pid}):process.kill(s.pid,"SIGTERM")}catch{}const f=new Promise(s=>{setTimeout(s,gn).unref()});await Promise.allSettled(u.map(s=>Promise.race([s.exited.then(()=>{}),f])));const v=[];for(const s of u)Tt(s.pid)&&(process.platform==="linux"&&R(T)?await A({operation:"stop",pid:s.pid}):Oe(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 dt(s,{reason:"daemon-teardown"});m({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:u.length,sigkilled:v.length}})}a(Sn,"teardownFleet");function qe(){ke(pr(de()),{recursive:!0}),lr(de(),String(process.pid),"utf8")}a(qe,"writePidfile");function We(e){return typeof e=="object"&&e!==null&&e.code==="ENOENT"}a(We,"isMissingPathError");function Je(e){const l=de();let u;try{u=dr(l,"utf8")}catch(f){if(We(f))return;throw f}if(u.trim()!==String(e))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${e})`);try{mr(l)}catch(f){if(We(f))return;throw f}}a(Je,"removeOwnedPidfileMirror");const yn={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(e=>{e.catch(()=>{})},"registerDetached")},Y=new nt;tt(e=>Y.handleFatalFault(e,!1));const _n=new ot,bn=new it,kn=new at,Rn=new st,Pn=new ct,En=new lt,In=new ft,xn=new ut,Tn=new wt,Dn=new ht,Cn=new gt,Ln=new St,$n=new yt,An=new _t,Nn=new bt,Mn=new kt,Gn=new Rt,On=new Pt;async function Fn(e=Date.now(),l=yn){const u=Ct(),f=await Y.runFleetPreamble(u);let v,s;try{const g=await De();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 xr()).filter(c=>!p.has(c.node_id)))}catch(g){m({level:"error",event:"canvas.node_list.failed",error:g});return}await Y.run(e,{rows:v,fleet:u,lifecycle:l}),await _n.run(e,{rows:v});const w=await bn.run(e,{rows:[...v,...s],fleet:u});await kn.run(e),await Gn.run(e),await On.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}),await xn.run(e,{lifecycle:l,fleet:u}),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}),An.run(e,{lifecycle:l}),await vr(),Mn.run(e,{fleet:u,lifecycle:l}),await Nn.run(e,{rows:v}),Y.warnIfSaturated({fleet:u,lifecycle:l,thresholds:f,frozen:w})}a(Fn,"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 Bn=66e4;function Hn(e){const l=new Dr().registerAll(Cr(()=>null).filter(n=>n.pattern==="/healthz")),u=a((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=xe();R(f)&&Re(f);const v=V(u),s=new Promise((n,d)=>{v.once("error",d),v.listen(f,()=>{v.off("error",d),Pe(f,384),n()})});let w,g=null;const p=e.tcp??Ee()??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 d=V(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]}`}),w=d}let c=!1;return{ready:s,tcpAddress:a(()=>g,"tcpAddress"),async close(n={}){if(!c){c=!0,await Promise.all([Le(v,new Set,n.graceMs),w===void 0?Promise.resolve():Le(w,new Set,n.graceMs)]);try{R(f)&&Re(f)}catch{}}}}}a(Hn,"createProbeServer");const jn="daemon is draining for shutdown and admits no new work";async function zn(e){ke(Te(),{recursive:!0,mode:493}),process.platform==="linux"&&Pe(Te(),493);const l=xe();if(R(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??Ee();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,d)=>{c.once("error",d),c.listen(Number(p[2]),p[1],()=>{c.off("error",d),n()})}),f=c}qe();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(d=>d?n(d):c())))),Je(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(zn,"serveLayoutRefusal");async function Un(e={}){if(e.role==="machine")return(await import("./machine-daemon.js")).runMachineDaemon();if(Rr())return zn(e);kr();const l=a(t=>{process.stderr.write(`[crtrd] ${t}
|
|
3
|
+
`)},"logPostgres"),u=!!process.env.CRTR_TEST_PG_URL,f=Bt(e.role);Vt(Q(e.role));const v=a(async()=>f?await Ft(Ie(16).toString("hex")):{claimed:!0,claim:{pid:process.pid,pid_identity:"",token:Ie(16).toString("hex")}},"claimOwnership"),{database:s,ownership:w}=u?{database:{url:await jt()},ownership:await v()}:await Jt(async()=>({database:await Ut({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 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,
|
|
6
|
-
`);for(const r of await
|
|
7
|
-
`);await
|
|
8
|
-
`)}else{const r=await pe(async o=>(await
|
|
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,d=null,y,P="";try{f&&await vn(g.token);for(const r of Er())process.stderr.write(`[crtrd] ${r}
|
|
6
|
+
`);for(const r of await Pr())process.stderr.write(`[crtrd] ${r}
|
|
7
|
+
`);await Be(),await zt(s.url,l);const t=e.role===void 0&&!await fn();let i=null;t&&(pn({kind:"user",root:ze()}),i=un(ze())),e.role===void 0&&wn(i??{profiles:[],defaults:{},settings:{},state:{},apps:{}}),await H.listen(s.url);const h=a(r=>{je(r).catch(o=>m({level:"error",event:"daemon.settings.reload_failed",error:o}))},"reloadPerson");if(y=await H.subscribe(r=>{He().includes(r)&&h(r)},{kinds:["settings"],onListenStart:a(()=>{for(const r of He())h(r)},"onListenStart")}),e.role!==void 0&&Gr(),e.role!==void 0){let r;try{r=Zt()}catch(b){m({level:"error",event:"daemon.packages.snapshot_failed",error:b})}const o=await pe(async b=>(await $e(b),r===void 0?void 0:await Xt(b,r,"release")));d=await pe(async b=>await Qt(b));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 $e(o),await Yt(o)));for(const o of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${o.message}
|
|
9
9
|
`);for(const o of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${o.path}: ${o.error}
|
|
10
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
11
|
`);for(const o of r.kinds.refused)process.stderr.write(`[crtrd] plugin "${o.plugin}" kind ${o.kind} not registered: ${o.message}
|
|
12
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(
|
|
14
|
-
`)}}catch(t){await H.close();try{if(f){const{released:i}=await
|
|
13
|
+
`)}if(P=await Gt(),Ot(P),e.role===void 0&&(p=await Or(),p!==null)){if(Br(p.id),await mn(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:b}=await import("node:os");await o("user",be=>{be.paths??={},be.paths.user_files??=b()})}}c=await Fr(),c.joinedFrom!==null&&await je(c.person),await ir(),n=await Hr()}if(process.platform==="linux"&&R(T)&&(br(),await A({operation:"users.sync",users:await Sr()})),f){await pt(g.token);const r=await on();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 Fe(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 D=!0,X,j=Promise.resolve(),Z=!1,z,ee,re,C;const U=new Set;let te=!1,we=!1,E,L,ne,q=!1,W,M,G,O,F,oe,ie,ae;const Ke=rt();let I,S={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},$="initial startup activation",Ve=null;function Ye(){return S.phase==="ready"?null:{phase:S.phase,message:S.message,blockerPaths:S.blockerPaths}}a(Ye,"startupBlock");function k(t){U.add(t),t.finally(()=>{U.delete(t)}).catch(()=>{})}a(k,"registerDetached");const he={acceptsDetachedWork:a(()=>D,"acceptsDetachedWork"),registerDetached:k};Q(e.role)&&await en(he,Be);async function Qe(){try{D=!1,Kt.close(),ee?.(),ee=void 0,re?.(),y?.(),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(C!==void 0&&(f&&await Sn(C),await C.exitsSettled(),C.dispose()),ne!==void 0&&await ne.close(),L!==void 0&&!q&&(q=!0,await L.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||(Je(process.pid),te=!0),te&&!we){if(f){const{released:i}=await Fe(g);if(!i)throw new Error("daemon ownership claim was not released")}we=!0,await me()}}finally{$t(),process.off("SIGINT",Se),process.off("SIGTERM",ye),process.off("exit",_e)}}a(Qe,"cleanupAttempt");const J=1e3;let ve=!1;function Xe(){return ve?{graceMs:J}:(ve=!0,_.fresh(()=>{m({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:J}})}),setTimeout(()=>{Ze()},J),{graceMs:J})}a(Xe,"requestHandover");async function Ze(){try{await x()}catch(t){const i=t instanceof Error?t.stack??t.message:String(t);process.stderr.write(`[crtrd] handover cleanup failed:
|
|
15
15
|
${i}
|
|
16
|
-
`),process.exit(1)}try{process.platform==="linux"&&
|
|
17
|
-
`),process.exit(1)}process.exit(0)}a(
|
|
16
|
+
`),process.exit(1)}try{process.platform==="linux"&&R(T)&&(await A({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await At();const t=await Nt({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 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(Ze,"performHandover");function x(){if(E!==void 0)return E;const t=Qe();return E=t,t.then(()=>{E===t&&(E=void 0)},()=>{E===t&&(E=void 0)}),t}a(x,"requestCleanup");async function er(){S={phase:"initializing",message:jn,blockerPaths:[]},L!==void 0&&!q&&(q=!0,await L.close({graceMs:Bn}))}a(er,"drainApi");async function ge(t){try{t==="SIGTERM"&&e.role==="api"&&await er(),await x(),await Wt({claimed:a(async()=>{try{return f&&await Ht()}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
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){
|
|
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){D&&(j=j.then(t).then(()=>{},i=>{_.fresh(()=>{m({level:"error",event:"daemon.lane_job.failed",error:i})})}))}a(se,"enqueue");async function K(){!D||Z||(Ke.check()&&I&&(m({level:"info",event:"daemon.resume.detected"}),k(I().catch(()=>{}))),Z=!0,await se(async()=>{if(Z=!1,!!D)try{u||await qt({log:l}),await Fn(Date.now(),he)}catch(t){_.fresh(()=>{m({level:"error",event:"daemon.tick.failed",error:t})})}}))}a(K,"enqueueTick");let B=null;async function rr(){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(rr,"admitStartup");async function tr(t){if($!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${$})`};$="repair";try{const i=await dn({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{$=null}}a(tr,"repairMigrations");async function nr(){X=e.intervalMs??et;const t=g.token;C=new nn({epoch:t,enqueue:se}),Dt(C),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:X}})});const i=P;_.fresh(()=>{m({level:"info",event:"daemon.install_id.resolved",fields:{install_id:i}})});const h=await Nr(i);if(_.fresh(()=>{m({level:"info",event:"daemon.environment.registered",fields:{environment_id:h.environmentId,created:h.created}})}),_.fresh(()=>{let r;try{r=Zr()}catch{return}r!==null&&m({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:r.slice(0,2048)}})}),vt(),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&&Mr(),!Q(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Xr(),await Vr(),await Yr(Date.now()),await Qr(Date.now())}),await _.fresh(async()=>{const{reconcile:r,migrated:o}=await Mt(mt);r.changed&&m({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:r.cleared.length,same_boot_proven:r.sameBootProven}}),o.length>0&&m({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:o.length}})}),await _.fresh(async()=>{for(const r of await De())r.status!=="active"||r.pi_pid!=null||r.frozen_at!=null||r.respawn_not_before!=null||(await Ce(r.node_id,new Date().toISOString()),m({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:r.node_id}))}),await _.fresh(async()=>{await It();for(const r of an){const o=await r.apply();o.changed&&m({level:"info",event:"daemon.boot_migration.applied",fields:{migration:r.id,...o.summary}})}}),k(Jr()),I){const r=a(()=>{k(I().catch(()=>{})),k(sr().then(o=>F?.observe(o)).then(()=>{},o=>{m({level:"warn",event:"daemon.peer.status_failed",error:o})}))},"refresh");k(Wr().then(({completion:o})=>o).catch(o=>{m({level:"error",event:"daemon.grants.sweep_failed",error:o})})),r(),G=setInterval(r,Ae*1e3),G.unref(),ae=ar({joined:!0,register:k})}await se(async()=>{await tn(),await rn()}),z=setInterval(()=>{K().catch(r=>m({level:"error",event:"daemon.tick.failed",error:r}))},X),ee=await Et(()=>{K().catch(r=>m({level:"error",event:"daemon.tick.failed",error:r}))}),re=await H.subscribe(()=>{K().catch(r=>m({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(()=>!D,o=>m({level:"warn",event:"daemon.move.settle_failed",error:o}))).catch(r=>m({level:"warn",event:"daemon.move.settle_failed",error:r}))}a(nr,"completeStartup");function ce(){return Ve??=nr().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),sn(),p!==null&&m({level:"info",event:"daemon.person.resolved",fields:{person_id:p.id,source:p.source}}),d!==null&&!d.alreadyDone&&m({level:"info",event:"daemon.packages.install_migration_done",fields:{moved:d.moved,discarded:d.discarded,people:d.people}}),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}}),N(e.role)?W=await wr():hr(ur());const t=g.token;Lt({epoch:t,requestHandover:Xe,registerDetached:k,startupBlock:Ye,admitStartup:rr,repairMigrations:tr}),qe(),L=N(e.role)?Tr({tcp:e.tcp}):Hn(e),await L.ready;const i=fr()??le("user").document_port;if(N(e.role)){const r=Lr(i,$r());try{await r.ready,ne=r}catch(o){m({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=qr(h.issuer,k),h.unsandboxed===!0&&(F=cr({syncGrants:I}))),e.role==="api"){const r=a(()=>k(Ur().catch(o=>{m({level:"error",event:"daemon.packages.sync_failed",error:o})})),"packageTick");r(),O=setInterval(r,Ae*1e3),O.unref()}if(N(e.role)&&(oe=await jr()),ie=await zr({serves:N(e.role),runsLanes:Q(e.role)}),h?.unsandboxed===!0&&h.listener!==void 0&&m({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 Ar(h,async()=>await Kr(h.issuer.replace(/\/$/,"")),I),await M.ready),e.role===void 0)try{await cn()}catch(r){if($=null,r instanceof ln)return S={phase:"blocked",message:r.message,blockerPaths:r.blockerPaths},x;throw r}process.platform==="linux"&&R(T)&&(_r(),await yr("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{$=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(Un,"runDaemon");var zi=Un;export{Bn as API_DRAIN_GRACE_MS,Wi as brokerCommandDeclaresCanvasHome,ue as brokerCommandEpoch,zi as default,Q as roleRunsLanes,N as roleServesRequests,Un as runDaemon,Fn as superviseTick,Sn as teardownFleet};
|
package/dist/daemon/manage.d.ts
CHANGED
|
@@ -122,6 +122,11 @@ export declare class DaemonExitedBeforeReadyError extends Error {
|
|
|
122
122
|
readonly stderrTail: string;
|
|
123
123
|
constructor(message: string, stderrTail: string);
|
|
124
124
|
}
|
|
125
|
+
/** The daemon's launch command could not be resolved, so no child was ever
|
|
126
|
+
* started — a standing failure that waiting longer cannot fix. */
|
|
127
|
+
export declare class DaemonLaunchError extends Error {
|
|
128
|
+
constructor(cause: unknown);
|
|
129
|
+
}
|
|
125
130
|
/** A live daemon has bound its repair socket but cannot serve normal work
|
|
126
131
|
* until its corpus migration succeeds. */
|
|
127
132
|
export declare class DaemonStartupBlockedError extends Error {
|
|
@@ -200,7 +205,8 @@ export interface EnsureDaemonDeps {
|
|
|
200
205
|
spawnDaemon?: () => Promise<SpawnDaemonResult>;
|
|
201
206
|
now?: () => number;
|
|
202
207
|
}
|
|
203
|
-
/** Why the daemon this process autostarted died before becoming ready, or
|
|
208
|
+
/** Why the daemon this process autostarted died before becoming ready, or why
|
|
209
|
+
* its launch command could not be resolved (no daemon was started), or
|
|
204
210
|
* undefined while it is starting, running, or exited cleanly (a clean exit may
|
|
205
211
|
* be a lost singleton race, so only a non-zero/signal exit counts). A client
|
|
206
212
|
* waiting for that daemon polls this so a startup failure ends the wait now
|
|
@@ -210,6 +216,7 @@ export declare function daemonAutostartStartupFailure(): string | undefined;
|
|
|
210
216
|
* autostart is suppressed for this invocation, while `crtr sys join` holds
|
|
211
217
|
* the join lock (see core/directory/join-lock.ts), while an attempt is in flight,
|
|
212
218
|
* or while backing off from a recent failure.
|
|
213
|
-
*
|
|
214
|
-
*
|
|
219
|
+
* Does not throw: a spawn error is recorded, and a launch or early-exit failure
|
|
220
|
+
* is reported through `daemonAutostartStartupFailure()` so a waiting client
|
|
221
|
+
* fails with it. */
|
|
215
222
|
export declare function ensureDaemon(deps?: EnsureDaemonDeps): void;
|
package/dist/daemon/manage.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).at(-1)??"";return JSON.parse(s)}o(R,"runDaemonEntry");function
|
|
3
|
-
${r}`),this.name="DaemonExitedBeforeReadyError",this.stderrTail=r}}class v extends Error{static{o(this,"DaemonStartupBlockedError")}constructor(t,r){super(`daemon ${t} is running but normal startup is blocked: ${r}`),this.name="DaemonStartupBlockedError"}}class F extends Error{static{o(this,"DaemonNotPreparedError")}constructor(t,r){super(r===void 0?`daemon ${t} is serving but did not report the prepared startup phase`:`daemon ${t} reported startup phase ${r}, not prepared`),this.name="DaemonNotPreparedError"}}async function
|
|
1
|
+
var q=Object.defineProperty;var o=(e,t)=>q(e,"name",{value:t,configurable:!0});import{spawn as B,execFileSync as V}from"node:child_process";import{createRequire as Q}from"node:module";import{dirname as k,join as E}from"node:path";import{fileURLToPath as Z,pathToFileURL as I}from"node:url";import{existsSync as H,lstatSync as ee,mkdirSync as te,openSync as U,closeSync as j,fstatSync as K,readSync as re}from"node:fs";import{crtrHome as g}from"../core/canvas/paths.js";import{listProcessTable as ne}from"../core/canvas/pid.js";import{bindDaemonEventSource as oe,eventSource as ae}from"../core/events/source.js";import{hostExecPath as O}from"../core/runtime/branded-host.js";import{isDaemonRunning as ie,readPidfile as D,isPidAlive as f}from"./pidfile.js";import{DAEMON_STARTUP_WINDOW_MS as G}from"./startup-policy.js";import{exclusiveLockOwnerPid as se}from"../core/exclusive-lock.js";import{onDiskMigrationLockPath as ce}from"../core/canvas/paths.js";import{envNoDaemonAutostart as ue}from"../shared/env.js";import{awaitJoinLockRelease as le,joinInProgress as de,joinInProgressError as pe,joinLockHolder as fe}from"../core/directory/join-lock.js";import{waitForDaemonAvailability as me}from"../api/index.js";import{localClient as he}from"../api/node-transport.js";const we=["CRTR_NODE_ID","CRTR_KIND","CRTR_MODE","CRTR_LIFECYCLE","CRTR_NODE_CWD","CRTR_CONTEXT_DIR","CRTR_CYCLES","CRTR_PROFILE_ID","CRTR_PARENT_NODE_ID","CRTR_FRONT_DOOR","TMUX","TMUX_PANE","CRTR_BROKER_ENGINE","CRTR_PI_BINARY","NODE_OPTIONS"];function M(){const e={...process.env};for(const t of we)delete e[t];return e}o(M,"sanitizedDaemonEnv");function _e(){for(let e=k(Z(import.meta.url));;e=k(e)){if(H(E(e,"bin","runtime-generation-manifest.mjs")))return e;if(k(e)===e)throw new Error(`cannot locate the crouter generation root from ${import.meta.url}`)}}o(_e,"generationRoot");async function A(){const e=_e(),t=I(E(e,"bin","runtime-generation-manifest.mjs")).href,{runtimeHome:r}=await import(t);try{ee(E(r(),"selected"))}catch(s){if(s.code!=="ENOENT")throw s;return["--conditions","crtr-src","--import",I(Q(import.meta.url).resolve("tsx/esm")).href,E(e,"src","daemon","crtrd-cli.ts")]}const n=I(E(e,"bin","runtime-selector.mjs")).href,{tryResolveRuntime:a}=await import(n),c=a("daemon");if(!c.ok)throw new Error(`cannot resolve the selected runtime generation's daemon entry: ${c.error}`);return[c.runtime.entryPath]}o(A,"resolveDaemonLaunch");function Ee(e,t){return e.includes(` --canvas-home ${t} `)||e.endsWith(` --canvas-home ${t}`)}o(Ee,"daemonCommandDeclaresCanvasHome");function De(){const e=ne();if(e===null)return[];const t=g(),r=[];for(const{pid:n,command:a}of e)a.includes("daemon/crtrd")&&Ee(a,t)&&n!==process.pid&&r.push(n);return r}o(De,"findDaemonPids");function xe(e){const t=De().filter(n=>n!==e);for(const n of t)try{process.kill(n,"SIGTERM")}catch{}if(t.length===0)return t;const r=Date.now()+2e3;for(;Date.now()<r&&t.some(n=>f(n));)V("sleep",["0.1"]);for(const n of t)if(f(n))try{process.kill(n,"SIGKILL")}catch{}return t}o(xe,"sweepStrayDaemons");async function Qe(){const e=process.execve;if(e===void 0)throw new Error(`this Node.js ${process.version} runtime cannot replace PID 1 with the successor daemon`);const t=O(),r=await A();return e(t,[t,...r,"--canvas-home",g()],M())}o(Qe,"execDaemon");async function R(e){const t=await A(),r=B(O(),[...t,...e],{stdio:["ignore","pipe","pipe"],env:M()});let n="",a="";r.stdout.setEncoding("utf8").on("data",u=>{n+=u}),r.stderr.setEncoding("utf8").on("data",u=>{a+=u});const c=await new Promise((u,m)=>{r.once("error",m),r.once("close",p=>u(p))});if(c!==0)throw new Error(a.trim()||`the ${e[0]} process exited with code ${c}`);const s=n.trim().split(`
|
|
2
|
+
`).at(-1)??"";return JSON.parse(s)}o(R,"runDaemonEntry");function Ze(){return R(["export-sqlite"])}o(Ze,"runDaemonExportSqlite");function et(e,t){return R(["import-dump",e,t])}o(et,"runDaemonImportDump");function tt(e){return R(["import-dump",e,"bodies"])}o(tt,"runDaemonBodiesDump");function rt(){return R(["import-dump","","install-id"])}o(rt,"runDaemonInstallId");const ye=3*6e4,z=2e4,N=10,P=1e3;async function L(e=P){const t=Math.min(e,P);return he({autostart:!1,timeoutMs:t}).probeHealthz(t)}o(L,"probeDaemonHealth");function ge(e){const t=e instanceof Error?e.message:String(e);if(typeof e!="object"||e===null)return t;const r=e.code,n=e.cause,a=typeof r=="string"?r:n?.code;return typeof a=="string"&&!t.includes(a)?`${t}: ${a}`:t}o(ge,"probeErrorMessage");async function J(e=P){const t=await L(e);if(t.startup_phase==="blocked"){const r=D()??process.pid;throw new v(r,t.startup_blocked??"daemon startup is blocked")}if(!t.ok)throw new Error(t.startup_blocked??"crtrd health check reported not ready")}o(J,"probeDaemonServing");async function nt(){try{return await J(),!0}catch{return!1}}o(nt,"isDaemonServing");function $(e){return new Promise(t=>{setTimeout(t,e)})}o($,"sleepMs");class C extends Error{static{o(this,"DaemonExitedBeforeReadyError")}stderrTail;constructor(t,r){super(r===""?t:`${t}
|
|
3
|
+
${r}`),this.name="DaemonExitedBeforeReadyError",this.stderrTail=r}}class Y extends Error{static{o(this,"DaemonLaunchError")}constructor(t){super(t instanceof Error?t.message:String(t),{cause:t}),this.name="DaemonLaunchError"}}class v extends Error{static{o(this,"DaemonStartupBlockedError")}constructor(t,r){super(`daemon ${t} is running but normal startup is blocked: ${r}`),this.name="DaemonStartupBlockedError"}}class F extends Error{static{o(this,"DaemonNotPreparedError")}constructor(t,r){super(r===void 0?`daemon ${t} is serving but did not report the prepared startup phase`:`daemon ${t} reported startup phase ${r}, not prepared`),this.name="DaemonNotPreparedError"}}async function Se(e,t=G,r={},n="ready"){const a=r.readPidfile??D,c=r.isPidAlive??f,s=r.childExited,u=r.isDaemonServing,m=r.probeDaemonServing??(async w=>{if(u!==void 0){if(await u())return;throw new Error("crtrd health check reported not ready")}await J(w)}),p=r.probeDaemonHealth??L,x=r.sleepMs??$,y=r.now??Date.now;let i=null,l=null;return await me({windowMs:t,pollIntervalMs:N,now:y,sleep:x,retry:o(w=>w!==l,"retry"),probe:o(async w=>{const h=a();if(h===null||!c(h)){const d=s?.();throw d!=null&&(d.signal!==null?l=new C(`daemon ${e} exited before becoming ready (by ${d.signal})`,r.childStderrTail?.()??""):d.code!==0&&(l=new C(`daemon ${e} exited before becoming ready (with exit code ${d.code??"?"})`,r.childStderrTail?.()??"")),l!==null)?l:new Error(`daemon ${e} has no live pidfile owner`)}if(n==="ready"){try{await m(w)}catch(d){throw d instanceof v&&(l=d),d}i=h;return}const _=await p(w);if(_.startup_phase==="prepared"){i=h;return}throw _.startup_phase==="blocked"?(l=new v(h,_.startup_blocked??"on-disk migration is blocked"),l):_.startup_phase==="ready"?(l=new F(h,_.startup_phase),l):new Error(`daemon ${h} is ${_.startup_phase??"not reporting a startup phase"}; waiting for prepared`)},"probe")}),i===e?null:i}o(Se,"verifyDaemonStartup");async function Re(e,t=z,r={}){const n=r.readPidfile??D,a=r.isPidAlive??f,c=r.sleepMs??$,s=r.now??Date.now,u=s()+t;for(;s()<=u;){if(!a(e)&&n()!==e)return;await c(N)}throw new Error(`daemon ${e} did not exit and release its pidfile within ${t}ms`)}o(Re,"waitForDaemonExit");const ve=2e3,Te=5e3;async function X(e,t=z,r={}){const n=r.isPidAlive??f,a=r.sleepMs??$,c=r.now??Date.now;try{process.kill(e,"SIGTERM")}catch{}try{return await Re(e,t,r),"terminated"}catch{}try{process.kill(e,"SIGKILL")}catch{}const s=c()+ve;for(;c()<=s;){if(!n(e))return"killed";await a(N)}throw new Error(`daemon ${e} survived both SIGTERM and SIGKILL`)}o(X,"stopDaemonProcess");async function ot(){const e=D(),t=e!==null&&f(e),r=t&&await X(e)==="killed",n=xe(null);return{stopped:t||n.length>0,...t?{pid:e}:{},strays_killed:n,force_killed:r}}o(ot,"stopAllDaemons");function be(e,t,r=2048){let n;try{n=U(e,"r");const{size:a}=K(n),c=Math.max(t,a-r),s=a-c;if(s<=0)return"";const u=Buffer.alloc(s);return re(n,u,0,s,c),u.toString("utf8").trim()}catch{return""}finally{if(n!==void 0)try{j(n)}catch{}}}o(be,"readLogTailFrom");async function ke(e={}){if(process.platform==="linux"&&H("/run/crtr/launcher.sock")&&!f(D()??-1))throw new Error("crtrd is managed by the root launcher; it cannot self-daemonize");const t=e.targetPhase??"ready",r=D();if(r!==null&&f(r))try{const i=await L();if(t==="prepared"){if(i.startup_phase==="prepared")return{started:!1,existing_pid:r,startup_phase:i.startup_phase};throw new F(r,i.startup_phase)}return i.ok?{started:!1,existing_pid:r,...i.startup_phase===void 0?{}:{startup_phase:i.startup_phase}}:{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:i.startup_blocked??"crtrd health check reported not ready",...i.startup_phase===void 0?{}:{startup_phase:i.startup_phase}}}catch(i){if(i instanceof F)throw i;return{started:!1,existing_pid:r,running:!0,serving:!1,probe_error:ge(i)}}te(g(),{recursive:!0});const n=await A().catch(i=>{throw new Y(i)});e.waitForJoinLock===!0&&await le(ye);const a=fe();if(a!==null&&a!==process.pid&&e.ignoreJoinLock!==!0)throw pe(a);const c=E(g(),"crtrd.err"),s=U(c,"a"),u=(()=>{try{return K(s).size}catch{return 0}})();ae()===void 0&&oe();const m=B(O(),[...n,"--canvas-home",g(),...t==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",s,s],env:M()});j(s);const p=m.pid;if(p===void 0)throw new Error("daemon spawn did not return a pid");let x=null;m.once("exit",(i,l)=>{x={code:i,signal:l}}),m.unref();let y;try{y=await Se(p,G,{childExited:o(()=>x,"childExited"),childStderrTail:o(()=>be(c,u),"childStderrTail")},t)}catch(i){const l=se(ce())===p;if(x===null&&!l&&!(i instanceof v))try{await X(p,Te)}catch{}throw i}return y!==null?{started:!1,existing_pid:y,startup_phase:t}:{started:!0,pid:p,startup_phase:t}}o(ke,"spawnDaemon");function Ie(){return ue()||process.argv.includes("--no-autostart")}o(Ie,"autostartDisabled");const Oe=5e3,Me=6e4;let W=!1,S,T=0,b=0;function Ae(e){return Math.min(Oe*2**(e-1),Me)}o(Ae,"autostartBackoffMs");function Ne(){S=void 0,T=0,b=0}o(Ne,"resetDaemonAutostart");function at(){return S}o(at,"daemonAutostartStartupFailure");function it(e={}){const t=e.isDaemonRunning??ie,r=e.spawnDaemon??ke,n=e.now??Date.now;if(!Ie()&&!de()&&!W&&!(n()<b)){if(t()){Ne();return}S=void 0,W=!0,r().then(()=>{S=void 0,T=0,b=0},a=>{(a instanceof C||a instanceof Y)&&(S=a.message),T+=1,b=n()+Ae(T)}).finally(()=>{W=!1})}}o(it,"ensureDaemon");export{we as DAEMON_ENV_STRIP_KEYS,C as DaemonExitedBeforeReadyError,Y as DaemonLaunchError,F as DaemonNotPreparedError,v as DaemonStartupBlockedError,Ie as autostartDisabled,at as daemonAutostartStartupFailure,Ee as daemonCommandDeclaresCanvasHome,it as ensureDaemon,Qe as execDaemon,De as findDaemonPids,nt as isDaemonServing,L as probeDaemonHealth,J as probeDaemonServing,ge as probeErrorMessage,Ne as resetDaemonAutostart,tt as runDaemonBodiesDump,Ze as runDaemonExportSqlite,et as runDaemonImportDump,rt as runDaemonInstallId,M as sanitizedDaemonEnv,ke as spawnDaemon,ot as stopAllDaemons,X as stopDaemonProcess,xe as sweepStrayDaemons,Se as verifyDaemonStartup,Re as waitForDaemonExit};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type NodeRow } from '../../../core/canvas/index.js';
|
|
2
|
+
import { type Execution } from '../../../core/canvas/executions.js';
|
|
2
3
|
import type { FleetRegistry } from '../../../core/runtime/fleet.js';
|
|
3
4
|
import { type FrozenCounts } from './freeze-lane.js';
|
|
4
5
|
export interface NodeLifecycleContext {
|
|
@@ -9,7 +10,10 @@ export interface NodeLifecycleContext {
|
|
|
9
10
|
}
|
|
10
11
|
/** How long an active row with no engine may be a birth in flight rather than stranded. */
|
|
11
12
|
export declare const LAUNCH_GRACE_MS = 120000;
|
|
12
|
-
|
|
13
|
+
/** A birth is in flight while it is younger than the grace and its launch has not already ended. A launch begins its
|
|
14
|
+
* execution before it records `launched_at`, so the node's latest execution is the one this birth made: once it is
|
|
15
|
+
* `exited` (a broker that died `lost`), the launch reached the ledger and failed, and the grace has nothing to protect. */
|
|
16
|
+
export declare function isLaunchInFlight(row: Pick<NodeRow, 'created' | 'launched_at'>, now: number, latest: Pick<Execution, 'state'> | null): boolean;
|
|
13
17
|
export declare class NodeLifecycleReconciler {
|
|
14
18
|
private readonly freezeLane;
|
|
15
19
|
run(now: number, ctx: NodeLifecycleContext): Promise<FrozenCounts>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g=Object.defineProperty;var o=(s,i)=>g(s,"name",{value:i,configurable:!0});import{clearFrozen as P,getNode as z}from"../../../core/canvas/index.js";import{isSafeNodeId as L}from"../../../core/canvas/paths.js";import{recordedPidLiveness as x}from"../../../core/canvas/pid.js";import{endExecution as v,hasAbsorbedProfilePauseStop as N,hasObservedExit as M,latestExecutionForNode as w,liveExecutionForNode as c}from"../../../core/canvas/executions.js";import{emitEvent as I}from"../../../core/events/emit.js";import{operationIdContext as D}from"../../../core/events/operation-id.js";import{readInterruptedTurn as F}from"../../../core/canvas/recovery.js";import{isProfilePaused as d}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as E}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as p}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as A,isParkedResident as C}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as S}from"../../fleet.js";import{applyParkEvent as T,hasPendingWake as U,parkEvent as W}from"../live-obligation.js";import{FreezeLaneReconciler as B}from"./freeze-lane.js";import{isInBackoff as k}from"./respawn-policy.js";import{asNodePerson as G,NodePersonUnresolvedError as R}from"./node-person.js";import{handleTerminatingRow as H}from"./terminating.js";import{wantsExecution as O}from"./wants-execution.js";import{enactRequestedStops as q}from"./requested-stops.js";import{endRemoteExecutionIfGone as j,recoverLaunching as J,wakeResident as K}from"./remote-wake.js";import{isDrained as Q}from"../../drain.js";function V(s){return s.status==="done"||s.status==="canceled"||s.status==="dead"}o(V,"isTerminal");const X=12e4;function Y(s,i,e){const n=Math.max(...[s.created,s.launched_at].map(r=>r==null?0:Date.parse(r)||0));return n>0&&i-n<X&&e?.state!=="exited"}o(Y,"isLaunchInFlight");async function b(s){const i=await c(s);return i!==null&&i.state==="running"&&i.pid!=null&&x(i.pid,i.processIdentity)==="dead"?i:null}o(b,"executionWithDeadPid");class we{static{o(this,"NodeLifecycleReconciler")}freezeLane=new B;async run(i,e){const n=[];await q(i);for(const r of e.rows)await D.fresh(async()=>{try{await G(r,()=>this.classifyRow(i,r,e,n))}catch(t){const l=r.node_id;I({level:t instanceof R?"warn":"error",event:t instanceof R?"node.lifecycle.person_unresolved":"node.lifecycle.classify_failed",...L(l)?{node_id:l}:{fields:{affected_node_id:l}},error:t})}});return await Q()?{stalled:0,waitingOnMail:0}:this.freezeLane.run(i,{fleet:e.fleet,candidates:n})}async classifyRow(i,e,n,r){const t=e.node_id;if(V(e)){if(H(e,await n.fleet.has(t)))return;if(C(e)&&!await n.fleet.has(t)&&!d(e.profile_id)&&!await E(t)&&!k(e,i)&&await p(t)){r.push({row:e,enact:"reopen"});return}if(e.pi_pid!=null){const a=await b(t);a!==null&&await v(a.executionId,{reason:"observed-dead"})}e.frozen_at!=null&&(e.final_report!=null||e.status==="dead"?await P(t):r.push({row:e,enact:"thaw"}));return}if(await n.fleet.has(t)){const a=await c(t);if(a?.runner!==void 0&&a.runner!=="process"&&a.state==="running"&&!d(e.profile_id)&&await p(t)){if(await K(a)==="lost")return}else a?.runner!==void 0&&a.runner!=="process"&&a.state==="running"&&await j(a);if(await n.fleet.has(t)){d(e.profile_id)?await n.fleet.interruptForProfilePause(t):await this.thawMark(e);return}}if(await J(t,i),d(e.profile_id)){await this.freezeLane.endEpisode(t);return}if(await E(t))return;const l=e.pi_pid==null?await w(t):null,f=l!==null&&M(l),m=l!==null&&!f&&N(l),h=e.pi_pid!=null?await b(t):null,_=f||m||h!==null;if(_&&!await n.fleet.hasProfilePauseInterruption(t)){const a=h??l;a!==null&&await v(a.executionId,{reason:"observed-dead"});const y=await c(t);if(y!==null&&y.executionId!==a?.executionId)return}if(!await O(e)){await this.thawMark(e),await this.settleParked(e);return}if(k(e,i))return;if(e.status==="idle"&&A(e)&&await p(t)){r.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null&&(!f||e.frozen_at!=null)&&!m){if(e.respawn_not_before!=null){r.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){r.push({row:e,enact:"thaw"});return}if(await n.fleet.isClaimed(t)||Y(e,i,await w(t)))return;I({level:"warn",event:"node.lifecycle.stranded_launch",node_id:t}),r.push({row:e,enact:"thaw"});return}if(!_)return;const u=S(await z(t),(await F(t))?.interrupted===!0,await U(t));if(u==="respawn-fresh"||u==="respawn-cycle"||u==="respawn-resume"){r.push({row:e,enact:"policy"});return}await n.fleet.applyDeadRowPolicy(t),await this.thawMark(e)}async thawMark(i){i.frozen_at!=null&&await P(i.node_id)}async settleParked(i){if(i.status!=="idle")return;await this.freezeLane.endEpisode(i.node_id);const e=await W(i.node_id,i.lifecycle);e!=="release"&&await T(i.node_id,e)}}export{X as LAUNCH_GRACE_MS,we as NodeLifecycleReconciler,Y as isLaunchInFlight};
|
package/dist/shared/env.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export declare function isSandboxedNode(): boolean;
|
|
|
16
16
|
* descriptions (`GET /v1/providers/tools` through that relay); the relay's node token stays the authority. It is not `isSandboxedNode()`,
|
|
17
17
|
* which gates owner-only commands and launch-snapshot reads on a Linux launcher mount. */
|
|
18
18
|
export declare function providerProjectionOverBrokerRelay(): boolean;
|
|
19
|
+
/** True when this CLI's plugin and marketplace installs are its app's install block on the control plane (`app-plugins.replace` over `/v1`), not
|
|
20
|
+
* directories in a scope: a Linux launcher sandbox (`isSandboxedNode()`) or a fleet node reaching `/v1` through its broker relay
|
|
21
|
+
* (`providerProjectionOverBrokerRelay()`, which has no launcher mount). The `pkg plugin` and `pkg market` leaves choose their path with it. */
|
|
22
|
+
export declare function installsLiveInAppBlock(): boolean;
|
|
19
23
|
/** The app that owns the current node, supplied in its broker launch identity. */
|
|
20
24
|
export declare function envGrantee(): string | undefined;
|
|
21
25
|
/** Set to '1' by `nodeEnv` for an app-started run's brokers, which admit inbox
|
package/dist/shared/env.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var p=Object.defineProperty;var e=(n,r)=>p(n,"name",{value:r,configurable:!0});import{lstatSync as T,readFileSync as c,readdirSync as f}from"node:fs";import{join as i}from"node:path";import{covers as _}from"@north-light/identity";function
|
|
2
|
-
`).map(o=>o.split(" ")[4])),t=f(n,{withFileTypes:!0}).filter(o=>o.isDirectory()&&/^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/.test(o.name)&&r.has(i(n,o.name))&&d(i(n,o.name))!==void 0);return t.length===1?t[0].name:void 0}catch{return}}e(E,"sandboxCliNodeId");function
|
|
1
|
+
var p=Object.defineProperty;var e=(n,r)=>p(n,"name",{value:r,configurable:!0});import{lstatSync as T,readFileSync as c,readdirSync as f}from"node:fs";import{join as i}from"node:path";import{covers as _}from"@north-light/identity";function h(){return process.env.CRTR_NODE_ID}e(h,"envNodeId");function d(n){for(const r of["broker-launch.json","cron-launch.json"]){const t=i(n,r);if(T(t,{throwIfNoEntry:!1})?.isFile())return t}}e(d,"launchSnapshotFile");function E(){if(process.platform==="linux")try{const n="/run/crtr/nodes",r=new Set(c("/proc/self/mountinfo","utf8").split(`
|
|
2
|
+
`).map(o=>o.split(" ")[4])),t=f(n,{withFileTypes:!0}).filter(o=>o.isDirectory()&&/^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/.test(o.name)&&r.has(i(n,o.name))&&d(i(n,o.name))!==void 0);return t.length===1?t[0].name:void 0}catch{return}}e(E,"sandboxCliNodeId");function v(){return E()!==void 0}e(v,"isSandboxedNode");function C(){return/^https?:\/\//.test(process.env.CRTR_API_URL??"")&&(process.env.CRTR_API_SOCKET??"")!==""}e(C,"providerProjectionOverBrokerRelay");function H(){return v()||C()}e(H,"installsLiveInAppBlock");function K(){return process.env.CRTR_GRANTEE}e(K,"envGrantee");const a="CRTR_INBOX_BETWEEN_TURNS";function k(){return process.env[a]==="1"}e(k,"envInboxBetweenTurns");const A="CRTR_SCOPES_FILE";function y(){const n=process.env[A];if(n!==void 0&&n!==""){const t=JSON.parse(c(n,"utf8"));if(!Array.isArray(t)||t.some(o=>typeof o!="string"))throw new Error(`invalid scopes file ${n}`);return t}const r=process.env.CRTR_SCOPES;return r===void 0?null:r===""?[]:r.split(",")}e(y,"envScopes");function G(n,r){return n==null?!0:S(n,r)}e(G,"scopeAllowed");function S(n,r){return n.includes(r)?(_(r,r),!0):n.some(t=>_(t,r))}e(S,"coveredByAny");function b(){return process.env.CRTR_EXECUTION_ID}e(b,"envExecutionId");function w(){return process.env.CRTR_PROFILE_ID}e(w,"envProfileId");function g(){return process.env.CRTR_NODE_CWD}e(g,"envNodeCwd");function V(){return process.env.CRTR_MODEL_INTENT}e(V,"envModelIntent");function X(){return process.env.CRTR_MODEL_EXACT==="1"}e(X,"envModelExact");function j(){return process.env.CRTR_HOME}e(j,"envHomeOverride");function Y(){return process.env.CRTR_RUNTIME_HOME}e(Y,"envRuntimeHomeOverride");function s(n,r){if(n===void 0)return r;const t=Number(n);return Number.isFinite(t)&&t>0?t:r}e(s,"parsePositiveMs");const M=5*6e4;function $(){return s(process.env.CRTR_STREAM_WATCHDOG_MS,M)}e($,"envStreamWatchdogMs");const N=800;function z(){return s(process.env.CRTR_WATCHER_TICK_MS,N)}e(z,"envWatcherTickMs");const x=6e4;function Z(){return s(process.env.CRTR_WATCHER_BACKSTOP_MS,x)}e(Z,"envWatcherBackstopMs");const D=1e3;function J(){return s(process.env.CRTR_WATCHER_DEBOUNCE_MS,D)}e(J,"envWatcherDebounceMs");const O=6e4;function q(){return s(process.env.CRTR_RECAP_IDLE_MS,O)}e(q,"envRecapIdleMs");function Q(){const n=process.env.CRTR_RECAP_MODEL;return n!==void 0&&n.trim()!==""?n.trim():void 0}e(Q,"envRecapModelOverride");const l=300*1e3;function ee(){return s(process.env.CRTR_BASH_VALVE_MS,l)}e(ee,"envBashValveMs");const I=60*1e3;function ne(){return s(process.env.CRTR_BASH_AUTO_BG_DEADLINE_MS,I)}e(ne,"envBashAutoBgDeadlineMs");function re(){const n=process.env.CRTR_PIDFILE;return n!==void 0&&n!==""?n:void 0}e(re,"envPidfileOverride");const m="@earendil-works/pi-coding-agent";function te(){return process.env.CRTR_BROKER_ENGINE??m}e(te,"envBrokerEngine");function oe(){return process.env.CRTR_PI_BINARY}e(oe,"envPiBinaryOverride");function se(){return process.env.CRTR_NO_DAEMON_AUTOSTART==="1"}e(se,"envNoDaemonAutostart");function ue(){const n=process.env.CRTR_DOCUMENT_PORT;if(n===void 0||!/^\d+$/.test(n))return;const r=Number(n);return r<=65535?r:void 0}e(ue,"envDocumentPort");function ie(){return process.env.CRTRD_TCP}e(ie,"envCrtrdTcp");function ce(){const n=process.env.CRTRD_TOKEN;return n!==void 0&&n!==""?n:void 0}e(ce,"envCrtrdToken");function _e(){return process.env.CRTR_NO_EXPORTS==="1"}e(_e,"envNoExports");function Re(){return process.env.CRTR_DEBUG==="1"}e(Re,"envDebug");function R(n){if(n===void 0||n==="")return;const r=Number(n);return Number.isSafeInteger(r)&&r>=1?r:void 0}e(R,"parsePositiveInteger");function pe(){return R(process.env.CRTR_MAX_LIVE_BROKERS)}e(pe,"envMaxLiveBrokers");function Te(){return R(process.env.CRTR_WARN_LIVE_BROKERS)}e(Te,"envWarnLiveBrokers");function u(n){if(n===void 0)return;const r=Number(n);return Number.isFinite(r)&&r>0?r:void 0}e(u,"parsePositiveMsNoDefault");function fe(){return u(process.env.CRTR_TEST_NODE_SOCKET_WINDOW_MS)}e(fe,"envTestNodeSocketWindowMs");function de(){return u(process.env.CRTR_TEST_UNATTENDED_PARK_MS)}e(de,"envTestUnattendedParkMs");function Ee(){return u(process.env.CRTR_UNATTENDED_PARK_MS)}e(Ee,"envUnattendedParkMs");function ve(){return u(process.env.CRTR_BASH_SILENCE_MS)??15*6e4}e(ve,"envBashSilenceMs");function B(){return u(process.env.CRTR_TEST_PARK_SUMMARY_GRACE_MS)}e(B,"envTestParkSummaryGraceMs");const P=5*6e4;function Ce(){return B()??P}e(Ce,"parkSummaryGraceMs");export{a as INBOX_BETWEEN_TURNS_ENV,A as SCOPES_FILE_ENV,S as coveredByAny,ne as envBashAutoBgDeadlineMs,ve as envBashSilenceMs,ee as envBashValveMs,te as envBrokerEngine,ie as envCrtrdTcp,ce as envCrtrdToken,Re as envDebug,ue as envDocumentPort,b as envExecutionId,K as envGrantee,j as envHomeOverride,k as envInboxBetweenTurns,pe as envMaxLiveBrokers,X as envModelExact,V as envModelIntent,se as envNoDaemonAutostart,_e as envNoExports,g as envNodeCwd,h as envNodeId,oe as envPiBinaryOverride,re as envPidfileOverride,w as envProfileId,q as envRecapIdleMs,Q as envRecapModelOverride,Y as envRuntimeHomeOverride,y as envScopes,$ as envStreamWatchdogMs,fe as envTestNodeSocketWindowMs,B as envTestParkSummaryGraceMs,de as envTestUnattendedParkMs,Ee as envUnattendedParkMs,Te as envWarnLiveBrokers,Z as envWatcherBackstopMs,J as envWatcherDebounceMs,z as envWatcherTickMs,H as installsLiveInAppBlock,v as isSandboxedNode,d as launchSnapshotFile,Ce as parkSummaryGraceMs,C as providerProjectionOverBrokerRelay,E as sandboxCliNodeId,G as scopeAllowed};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
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.593",
|
|
11981
|
+
"@north-light/identity": "0.3.593"
|
|
11982
11982
|
}
|
|
11983
11983
|
},
|
|
11984
11984
|
"packages/crouter-sdk": {
|
|
11985
11985
|
"name": "@north-light/sdk",
|
|
11986
|
-
"version": "0.3.
|
|
11986
|
+
"version": "0.3.593",
|
|
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.593",
|
|
11990
|
+
"@north-light/identity": "0.3.593",
|
|
11991
|
+
"@north-light/plugin": "0.3.593",
|
|
11992
11992
|
"jose": "^6.2.1"
|
|
11993
11993
|
},
|
|
11994
11994
|
"bin": {
|