@north-light/cli 0.3.532 → 0.3.533
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/client.d.ts +6 -3
- package/dist/api/client.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +2 -0
- package/dist/api/dto/crons.d.ts +2 -0
- package/dist/builtin-memory/crouter-sdk/release-notes.md +8 -0
- package/dist/builtin-memory/northlight-apps/providers/README.md +2 -0
- package/dist/builtin-memory/northlight-apps/providers/sms.md +2 -0
- package/dist/clients/attach/chrome/inbox-strip.d.ts +6 -1
- package/dist/clients/attach/chrome/inbox-strip.js +1 -1
- package/dist/clients/attach/chrome/roster.js +1 -1
- package/dist/clients/attach/session/chrome-refresh.d.ts +12 -3
- package/dist/clients/attach/session/chrome-refresh.js +1 -1
- package/dist/clients/attach/session/document-links.js +1 -1
- package/dist/clients/attach/viewer.js +586 -587
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/node/inspect.js +6 -6
- package/dist/commands/sys/context/expose.js +2 -2
- package/dist/commands/sys/db.d.ts +1 -0
- package/dist/commands/sys/db.js +1 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/bash-guard.js +9 -3
- package/dist/core/canvas/canvas.d.ts +12 -2
- package/dist/core/canvas/canvas.js +23 -20
- package/dist/core/canvas/daemon-actions.d.ts +0 -3
- package/dist/core/canvas/daemon-actions.js +7 -24
- package/dist/core/canvas/daemon-owner.d.ts +3 -0
- package/dist/core/canvas/daemon-owner.js +1 -6
- package/dist/core/canvas/db.d.ts +28 -20
- package/dist/core/canvas/db.js +4 -3
- package/dist/core/canvas/deliveries.d.ts +5 -0
- package/dist/core/canvas/deliveries.js +25 -30
- package/dist/core/canvas/export-sqlite.d.ts +14 -0
- package/dist/core/canvas/export-sqlite.js +3 -0
- package/dist/core/canvas/import-sqlite.d.ts +44 -0
- package/dist/core/canvas/import-sqlite.js +7 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/outcome-actions.js +4 -4
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg.sql +1022 -0
- package/dist/core/canvas/schema-version.d.ts +4 -0
- package/dist/core/canvas/schema-version.js +1 -0
- package/dist/core/canvas/sessions.js +3 -3
- package/dist/core/canvas/structured-requests.js +2 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/waits.js +1 -1
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/graph/access.js +7 -7
- package/dist/core/graph/custom.js +10 -10
- package/dist/core/graph/deletion.js +6 -6
- package/dist/core/graph/documents.d.ts +1 -1
- package/dist/core/graph/documents.js +9 -9
- package/dist/core/graph/edges.d.ts +3 -3
- package/dist/core/graph/edges.js +3 -1
- package/dist/core/graph/events.js +7 -7
- package/dist/core/graph/exposures.d.ts +8 -8
- package/dist/core/graph/jobs.d.ts +1 -1
- package/dist/core/graph/jobs.js +2 -2
- package/dist/core/graph/kinds/custom.js +1 -1
- package/dist/core/graph/kinds/document.js +4 -4
- package/dist/core/graph/kinds/dto.js +1 -1
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/kinds/kind.d.ts +2 -2
- package/dist/core/graph/kinds/kind.js +1 -1
- package/dist/core/graph/kinds/live-read.d.ts +5 -0
- package/dist/core/graph/kinds/live-read.js +1 -0
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/kinds/owner.js +2 -2
- package/dist/core/graph/names.js +3 -3
- package/dist/core/graph/objects.d.ts +5 -5
- package/dist/core/graph/objects.js +10 -10
- package/dist/core/graph/package-docs.js +6 -5
- package/dist/core/graph/reader.d.ts +1 -1
- package/dist/core/graph/reader.js +2 -2
- package/dist/core/graph/receivers.js +4 -5
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/repos.js +3 -3
- package/dist/core/graph/repo-sync/sync.js +1 -1
- package/dist/core/graph/rules.d.ts +3 -4
- package/dist/core/graph/rules.js +3 -3
- package/dist/core/graph/spaces/app.js +1 -1
- package/dist/core/graph/spaces/index.d.ts +1 -1
- package/dist/core/graph/spaces/index.js +1 -1
- package/dist/core/graph/spaces/own-memory.js +1 -1
- package/dist/core/graph/spaces/person.js +3 -3
- package/dist/core/graph/spaces/repo.d.ts +1 -1
- package/dist/core/graph/spaces/repo.js +1 -1
- package/dist/core/graph/types.d.ts +4 -3
- package/dist/core/graph/watches.d.ts +2 -2
- package/dist/core/graph/watches.js +17 -17
- package/dist/core/human/page-schema.js +5 -4
- package/dist/core/human/requests.d.ts +1 -1
- package/dist/core/human/requests.js +20 -23
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/providers/receipts.js +3 -2
- package/dist/core/review/comments.js +5 -4
- package/dist/core/runs/activity.js +4 -5
- package/dist/core/runs/confinement.d.ts +1 -1
- package/dist/core/runs/confinement.js +2 -2
- package/dist/core/runs/events.d.ts +1 -1
- package/dist/core/runs/events.js +5 -5
- package/dist/core/runs/operations.js +6 -4
- package/dist/core/runtime/close.d.ts +3 -0
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/host.d.ts +5 -1
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/ledger.js +3 -3
- package/dist/core/runtime/lifecycle.d.ts +9 -0
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/nodes.d.ts +1 -1
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/spaces/stop.d.ts +1 -0
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/statements.d.ts +17 -0
- package/dist/core/statements.js +2 -0
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +5 -5
- package/dist/core/substrate/delivery/listings.js +1 -1
- package/dist/core/substrate/delivery/match.d.ts +2 -2
- package/dist/core/substrate/delivery/match.js +1 -1
- package/dist/core/substrate/delivery/plan.js +3 -3
- package/dist/core/substrate/delivery/render-boot.js +5 -5
- package/dist/core/substrate/delivery/render-event.js +6 -6
- package/dist/core/usage/ledger.js +8 -8
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/custom-objects.js +3 -3
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/memory.js +7 -7
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +14 -6
- package/dist/daemon/broker-signals/bus.js +1 -10
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.js +12 -11
- package/dist/daemon/due.js +1 -1
- package/dist/daemon/export-sqlite-run.d.ts +1 -0
- package/dist/daemon/export-sqlite-run.js +4 -0
- package/dist/daemon/fleet.d.ts +1 -0
- package/dist/daemon/fleet.js +3 -3
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/manage.d.ts +10 -0
- package/dist/daemon/manage.js +3 -2
- package/dist/daemon/postgres/binary.d.ts +17 -0
- package/dist/daemon/postgres/binary.js +2 -0
- package/dist/daemon/postgres/cluster.d.ts +37 -0
- package/dist/daemon/postgres/cluster.js +6 -0
- package/dist/daemon/postgres/index.d.ts +2 -0
- package/dist/daemon/postgres/index.js +1 -0
- package/dist/daemon/postgres/pins.d.ts +7 -0
- package/dist/daemon/postgres/pins.js +1 -0
- package/dist/daemon/postgres/supervisor.d.ts +95 -0
- package/dist/daemon/postgres/supervisor.js +2 -0
- package/dist/daemon/reconcilers/bash-deadline.js +2 -2
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +7 -3
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -6
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -8
- package/dist/daemon/runs/observer.js +5 -4
- package/dist/migrations/004-canvas-documents/index.js +1 -1
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/envelope-merge.d.ts +3 -2
- package/dist/pi-extensions/envelope-merge.js +9 -8
- package/dist/shared/env.d.ts +3 -0
- package/dist/shared/env.js +2 -2
- package/docs/apps/providers/README.md +2 -0
- package/docs/apps/providers/sms.md +2 -0
- package/docs/public-api.md +11 -2
- package/docs/sdk/release-notes.md +8 -0
- package/package.json +6 -6
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -26
- package/scripts/install-runtime.mjs +53 -3
- package/scripts/lib/isolation-env.mjs +3 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var R=Object.defineProperty;var o=(t,r)=>R(t,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{chownSync as v,chmodSync as A,existsSync as C,lstatSync as T,mkdirSync as B,rmSync as F,writeFileSync as H}from"node:fs";import{userInfo as G}from"node:os";import{join as i}from"node:path";import{withExclusiveDirectoryLockAsync as M}from"../../core/exclusive-lock.js";import{runtimeRoot as y}from"../../core/layout.js";import{ensurePostgresBinaries as f}from"./binary.js";import{MAX_SOCKET_PATH_BYTES as g,POSTGRES_PORT as D,assertNotRoot as k,clusterInitialized as O,initCluster as p,probe as m,socketUrl as P,startPostmaster as S,stopPostmaster as w,tcpUrl as z}from"./cluster.js";const h=o(()=>{},"noLog");function u(){return process.env.CRTR_DATABASE_URL||null}o(u,"externalDatabaseUrl");function l(t=y()){const r=i(t,"pg"),s=`.s.PGSQL.${D}`,e=Buffer.byteLength(i(r,s))<=g,a=e?r:`/tmp/crtr-pg-${_("sha256").update(t).digest("hex").slice(0,8)}`;if(!e&&Buffer.byteLength(i(a,s))>g)throw new Error(`socket path ${i(a,s)} is too long`);return{dir:r,dataDir:i(r,"data"),lockPath:i(r,"start.lock"),socketDirFile:i(r,"socket-dir"),logFile:i(r,"postgres.log"),socketDir:a}}o(l,"postgresPaths");function x(){return G().username}o(x,"osUser");function U(t=y()){return u()??P(x(),l(t).socketDir)}o(U,"resolveDatabaseUrl");function d(t){B(t,{recursive:!0,mode:448});const r=T(t);if(!r.isDirectory()||r.isSymbolicLink())throw new Error(`${t} is not a directory`);if(typeof process.getuid=="function"&&r.uid!==process.getuid())throw new Error(`${t} is owned by uid ${r.uid}, not this process; refusing to put the Postgres socket there`);(r.mode&63)!==0&&A(t,448)}o(d,"ensurePrivateDir");async function I(t={}){const r=t.log??h,s=u();if(s!==null)return{url:s,started:!1};k("crtrd cannot start its database");const e=l(t.root),a=U(t.root);if(await m(a)===null)return{url:a,started:!1};const n=await f(r);return d(e.dir),e.socketDir!==e.dir&&d(e.socketDir),(t.startLockHeld===!0?c=>c():c=>$(c,t.root))(async()=>{if(await m(a)===null)return{url:a,started:!1};const c={dataDir:e.dataDir,socketDir:e.socketDir,maxConnections:20};if(!O(e.dataDir)){const L=Date.now();p(n,c,x(),"peer"),r(`postgres cluster initialized in ${Date.now()-L} ms`)}H(e.socketDirFile,`${e.socketDir}
|
|
2
|
+
`);const E=Date.now();return await S(n,c,a,e.logFile),r(`postgres started in ${Date.now()-E} ms`),{url:a,started:!0}})}o(I,"ensurePostgres");async function $(t,r){if(u()!==null)return t();const s=l(r);return d(s.dir),M(s.lockPath,t,{timeoutMs:45e3,staleMs:45e3,timeoutError:o(()=>new Error(`timed out waiting for another process to start or stop Postgres (lock ${s.lockPath})`),"timeoutError")})}o($,"withPostgresStartLock");let b=0;async function Z(t={}){const r=U(t.root);if(u()!==null||await m(r,2e3)===null)return{url:r,started:!1};const s=Date.now();if(s-b<6e4)throw new Error(`Postgres stopped answering twice within a minute; see ${l(t.root).logFile}`);(t.log??h)("postgres did not answer the 2 s health probe; restarting it unless it answers now");const e=await I(t);return e.started&&(b=s),e}o(Z,"ensurePostgresHealthy");async function tt(t){if(u()!==null)return!1;const r=l(t.root);return C(i(r.dataDir,"postmaster.pid"))?$(async()=>await t.claimed()?!1:(w(await f(),{dataDir:r.dataDir}),!0),t.root):!1}o(tt,"stopPostgres");async function rt(t){const r=t.log??h;t.asUser===void 0&&k("a scratch Postgres cluster");const s=await f(r);if(d(t.dir),t.asUser&&v(t.dir,t.asUser.uid,t.asUser.gid),Buffer.byteLength(i(t.dir,`.s.PGSQL.${t.tcp?.port??D}`))>g)throw new Error(`scratch directory ${t.dir} is too long for a Postgres socket path`);const e={dataDir:i(t.dir,"data"),socketDir:t.dir,maxConnections:t.maxConnections??100,...t.tcp?{tcp:t.tcp}:{},...t.asUser?{asUser:t.asUser}:{}},a=P("crtr",t.dir,t.tcp?.port);try{p(s,e,"crtr","trust"),await S(s,e,a,i(t.dir,"postgres.log"))}catch(n){try{w(s,e)}catch{}throw n}return{url:a,tcpUrl:t.tcp?z("crtr",t.tcp.host,t.tcp.port):null,dir:t.dir,stop:o(async(n={})=>{w(s,e),n.remove!==!1&&F(t.dir,{recursive:!0,force:!0})},"stop")}}o(rt,"startScratchCluster");export{I as ensurePostgres,Z as ensurePostgresHealthy,u as externalDatabaseUrl,l as postgresPaths,U as resolveDatabaseUrl,rt as startScratchCluster,tt as stopPostgres,$ as withPostgresStartLock};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
WHERE j.status = 'running' AND o.deleted_at IS NULL`).all();for(const{object:e,job_dir:r}of a){const i=b(r,"job.exit");if(!n(i)||n(b(r,"job.stop")))continue;const o=Number(m(i,"utf8").trim());Number.isSafeInteger(o)&&await
|
|
1
|
+
var u=Object.defineProperty;var f=(l,t)=>u(l,"name",{value:t,configurable:!0});import{existsSync as n,readFileSync as m,readdirSync as j,statSync as _}from"node:fs";import{join as b}from"node:path";import{bashJobPaths as y,bashJobsDir as w,expiredAutoBackgroundBashJobs as S,stopBackgroundBashJob as x}from"../../core/bash-jobs.js";import{killBashJobObject as N,recordBashJobObject as E}from"../../core/spaces/stop.js";import{withCanvasWrite as h}from"../../core/canvas/db.js";import{finishJob as v}from"../../core/graph/jobs.js";import{getById as p}from"../../core/graph/objects.js";import{isSafeNodeId as c}from"../../core/canvas/paths.js";import{contextDir as A}from"../../core/canvas/node-agent-paths.js";import{emitEvent as s}from"../../core/events/emit.js";import{operationIdContext as d}from"../../core/events/operation-id.js";import{isProfilePaused as g}from"../../core/profiles/manifest.js";const B=5*1e3;class V{static{f(this,"BashDeadlineReconciler")}lastScanAt=Number.NEGATIVE_INFINITY;startedAt=Date.now();async run(t,a){if(await this.publishExits(),!(t-this.lastScanAt<B)){this.lastScanAt=t;for(const e of a.rows){if(e.status==="dead"||g(e.profile_id))continue;const r=await A(e.node_id);let i;try{await this.adoptUnrecorded(e.node_id,r),i=S(r,t)}catch(o){d.fresh(()=>{s({level:"error",event:"bash_deadline.scan_failed",...c(e.node_id)?{node_id:e.node_id}:{},error:o})});continue}for(const o of i)await this.cancel(e.node_id,r,o.jobId)}}}async publishExits(){try{await h(async t=>{const a=await t.prepare(`SELECT j.object, j.job_dir FROM jobs j JOIN objects o ON o.id = j.object
|
|
2
|
+
WHERE j.status = 'running' AND o.deleted_at IS NULL`).all();for(const{object:e,job_dir:r}of a){const i=b(r,"job.exit");if(!n(i)||n(b(r,"job.stop")))continue;const o=Number(m(i,"utf8").trim());Number.isSafeInteger(o)&&await v(t,await p(t,e),{exitCode:o})}})}catch(t){d.fresh(()=>s({level:"error",event:"bash_completion.delivery_failed",error:t}))}}async adoptUnrecorded(t,a){let e;try{e=j(w(a))}catch{return}await h(async r=>{for(const i of e){if(await p(r,i)!==null)continue;const o=y(a,i);!n(o.jobBg)||!n(o.cmdSh)||n(o.jobExit)&&_(o.jobExit).mtimeMs<this.startedAt||await E(t,i,{command:m(o.cmdSh,"utf8"),jobDir:o.dir,logPath:o.jobLog})}})}async cancel(t,a,e){(await x(a,e,!1,t)).kind==="stopped"&&await d.fresh(async()=>{try{s({level:"info",event:"bash_deadline.canceled",...c(t)?{node_id:t}:{},fields:{job_id:e}}),await N(e,async()=>null,"deadline")}catch(i){s({level:"error",event:"bash_deadline.notice_failed",...c(t)?{node_id:t}:{},error:i,fields:{job_id:e}})}})}}export{V as BashDeadlineReconciler};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var g=Object.defineProperty;var c=(e,t)=>g(e,"name",{value:t,configurable:!0});import{randomUUID as D}from"node:crypto";import{claimPushDelivery as h,duePushDeliveries as j,messageBodyForDelivery as N,pushDeliveryClaimIsCurrent as O,settleDelivery as d}from"../../core/canvas/deliveries.js";import{deliveryBackoffMs as f}from"../../core/canvas/delivery-contract.js";import{openDb as p}from"../../core/canvas/db.js";import{pushLineFor as u}from"../../core/graph/custom.js";import{postReceiverUrl as b}from"../../core/graph/receiver-url.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as m}from"../../core/events/operation-id.js";import{runDelivery as w,DELIVERY_TIMEOUT_MS as E}from"../delivery/run-delivery.js";const v=D();async function o(e,t,a){await d(e.deliveryId,e.attempts,t,{state:"permanent_failed",failure:{kind:"spawn_error",message:a}},Date.now())}c(o,"failed");async function T(e,t){const a=await(await p()).prepare(`SELECT o.type, o.name, c.receiver_json, c.payload_json, m.object_id, i.external_id AS app,
|
|
2
2
|
d.message_id, owner.type AS owner_type, parent.external_id AS parent_app
|
|
3
3
|
FROM deliveries d JOIN objects o ON o.id = d.destination_id
|
|
4
|
-
JOIN custom_objects c ON c.object = o.
|
|
5
|
-
LEFT JOIN objects owner ON owner.
|
|
4
|
+
JOIN custom_objects c ON c.object = o.id JOIN messages m ON m.message_id = d.message_id
|
|
5
|
+
LEFT JOIN objects owner ON owner.id = o.owner
|
|
6
6
|
LEFT JOIN identities i ON i.object = o.owner AND i.scheme = 'app'
|
|
7
7
|
LEFT JOIN identities parent ON parent.object = owner.owner AND parent.scheme = 'app'
|
|
8
8
|
WHERE d.delivery_id = ?`).get(e.deliveryId);if(!a||!a.receiver_json){await o(e,t,`delivery ${e.deliveryId} has no supported receiver`);return}const i=JSON.parse(a.receiver_json);if(!await O(e,t)){await d(e.deliveryId,e.attempts,t,{state:"acknowledged"},Date.now());return}if(typeof i=="object"&&typeof i.url=="string"&&a.type!=="action"){const n=await u(await p(),e.deliveryId);if(!n){await o(e,t,`delivery ${e.deliveryId} has no event document`);return}try{const r=await b(i.url,JSON.stringify(n),{"Content-Type":"application/json","X-Crtr-Delivery":e.deliveryId,"X-Crtr-Event":a.message_id},E);r>=200&&r<300?await d(e.deliveryId,e.attempts,t,{state:"acknowledged"},Date.now()):r>=300&&r<400?await o(e,t,`url receiver returned HTTP ${r}; redirects are not followed \u2014 register the final URL`):r>=400&&r<500&&r!==408&&r!==429?await o(e,t,`url receiver returned HTTP ${r}`):await d(e.deliveryId,e.attempts,t,{state:"pending",nextAttemptAt:Date.now()+f(e.attempts),failure:{kind:"spawn_error",message:`url receiver returned HTTP ${r}`}},Date.now())}catch(r){await d(e.deliveryId,e.attempts,t,{state:"pending",nextAttemptAt:Date.now()+f(e.attempts),failure:{kind:"spawn_error",message:String(r)}},Date.now())}return}if(typeof i!="object"||!Array.isArray(i.argv)||typeof i.cwd!="string"){await o(e,t,`delivery ${e.deliveryId} has an invalid argv receiver`);return}if(a.type==="action"){if(typeof i.name!="string"||!a.object_id){await o(e,t,`delivery ${e.deliveryId} has an invalid argv receiver`);return}const n=await N(e.deliveryId);if(n===null){await o(e,t,`delivery ${e.deliveryId} has no message body`);return}const{push:r,...y}=n,I={...y,action:{name:i.name,payload:a.payload_json===null?null:JSON.parse(a.payload_json)}};await w({argv:i.argv,cwd:i.cwd,document:I,attempt:e.attempts,nodeId:a.object_id,...a.app?{app:a.app}:{}},async _=>{await d(e.deliveryId,e.attempts,t,_,Date.now())});return}const s=await u(await p(),e.deliveryId);if(!s){await o(e,t,`delivery ${e.deliveryId} has no event document`);return}await w({argv:i.argv,cwd:i.cwd,document:s,attempt:e.attempts,app:a.app??a.parent_app??"app:terminal",custom:{deliveryId:e.deliveryId,messageId:a.message_id}},async n=>{await d(e.deliveryId,e.attempts,t,n,Date.now())})}c(T,"deliverExternal");class P{static{c(this,"DeliveryLaneReconciler")}async run(t,a){if(!a.lifecycle.acceptsDetachedWork())return;let i;try{i=await j(t)}catch(s){m.fresh(()=>l({level:"error",event:"delivery.scan_failed",error:s}));return}for(const s of i)try{const n=await h(s.deliveryId,t,v);if(n===null)continue;a.lifecycle.registerDetached(T(n,v).catch(r=>{m.fresh(()=>l({level:"error",event:"delivery.failed",error:r,fields:{delivery_id:n.deliveryId}}))}))}catch(n){m.fresh(()=>l({level:"error",event:"delivery.claim_failed",error:n,fields:{delivery_id:s.deliveryId}}))}}}export{P as DeliveryLaneReconciler,v as deliveryDaemonInstanceId};
|
|
@@ -6,7 +6,7 @@ import type { FleetRegistry } from '../../../core/runtime/fleet.js';
|
|
|
6
6
|
* `policy` re-enacts the dead-row policy table (which relaunches through
|
|
7
7
|
* `reviveNode`); `idle-release` runs the stuck-delivery episode rules before
|
|
8
8
|
* relaunching. */
|
|
9
|
-
export type ThawEnactment = 'thaw' | 'policy' | 'idle-release';
|
|
9
|
+
export type ThawEnactment = 'thaw' | 'policy' | 'idle-release' | 'reopen';
|
|
10
10
|
export interface ThawCandidate {
|
|
11
11
|
row: NodeRow;
|
|
12
12
|
enact: ThawEnactment;
|
|
@@ -33,8 +33,8 @@ export interface FrozenCounts {
|
|
|
33
33
|
* anything, so it must not keep outranking the mail it stalled behind. A row
|
|
34
34
|
* that never launched at all has spent nothing and stays tier 1. */
|
|
35
35
|
export declare function thawTier(row: NodeRow, pendingWake: boolean): ThawTier;
|
|
36
|
-
/** Thaw order
|
|
37
|
-
* `frozen_at` has not waited at all and sorts last
|
|
36
|
+
/** Thaw order is first-come-first-served: longest-frozen first, whatever the tier (the tier only
|
|
37
|
+
* splits the saturation counts). A candidate with no `frozen_at` has not waited at all and sorts last. */
|
|
38
38
|
export declare function compareThaw(a: ThawEntry, b: ThawEntry): number;
|
|
39
39
|
export declare class FreezeLaneReconciler {
|
|
40
40
|
private readonly relaunchState;
|
|
@@ -43,6 +43,10 @@ export declare class FreezeLaneReconciler {
|
|
|
43
43
|
endEpisode(nodeId: string): void;
|
|
44
44
|
run(now: number, ctx: FreezeLaneContext): Promise<FrozenCounts>;
|
|
45
45
|
private enact;
|
|
46
|
+
/** A parked resident owed wake mail: the message-delivery reopen (resident, latch check, `revive`
|
|
47
|
+
* transition), then the one launcher. A capacity freeze leaves the row `active` with its frozen mark,
|
|
48
|
+
* and a lost launch leaves it a stranded launch the tick relaunches, so the mail is never dropped. */
|
|
49
|
+
private enactReopen;
|
|
46
50
|
private enactThaw;
|
|
47
51
|
private enactIdleRelease;
|
|
48
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var E=Object.defineProperty;var d=(
|
|
1
|
+
var E=Object.defineProperty;var d=(o,t)=>E(o,"name",{value:t,configurable:!0});import{clearFrozen as _,getNode as h,getRow as y}from"../../../core/canvas/index.js";import{fullName as g}from"../../../core/canvas/labels.js";import{isSafeNodeId as s}from"../../../core/canvas/paths.js";import{emitEvent as l}from"../../../core/events/emit.js";import{operationIdContext as z}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as R}from"../../../core/canvas/deliveries.js";import{publishNotice as A}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{commitReopenResident as S}from"../../../core/runtime/reopen.js";import{reviveNode as f}from"../../../core/runtime/revive.js";import{hasPendingWake as w}from"../live-obligation.js";import{readInterruptedTurn as k}from"../../../core/canvas/recovery.js";import{mapAsync as L}from"../../../core/async-array.js";const m=6,M=10*6e4,C=2e4;function I(o,t){if(t)return 2;const a=o.launched_at;if(a==null)return 1;const e=o.last_settled_at;return e==null?2:Date.parse(e)>Date.parse(a)?1:2}d(I,"thawTier");function N(o,t){const a=o.row.frozen_at,e=t.row.frozen_at;return a==null?e==null?0:1:e==null?-1:Date.parse(a)-Date.parse(e)}d(N,"compareThaw");class j{static{d(this,"FreezeLaneReconciler")}relaunchState=new Map;endEpisode(t){this.relaunchState.delete(t)}async run(t,a){const e=await L(a.candidates,async r=>({...r,tier:I(r.row,await w(r.row.node_id))}));e.sort(N);const n={stalled:0,waitingOnMail:0};for(const r of e)await z.fresh(()=>this.enact(t,r,a.fleet))==="frozen"&&(r.tier===1?n.stalled+=1:n.waitingOnMail+=1);return n}async enact(t,a,e){const n=a.row.node_id;try{return a.enact==="thaw"?await this.enactThaw(a.row):a.enact==="reopen"?await this.enactReopen(a.row):a.enact==="idle-release"?await this.enactIdleRelease(t,a.row):(await e.applyDeadRowPolicy(n),e.has(n)?"launched":(await y(n))?.frozen_at!=null?"frozen":"skipped")}catch(r){return l({level:"error",event:"node.lifecycle.enact_failed",...s(n)?{node_id:n}:{},error:r,fields:{...s(n)?{}:{affected_node_id:n},enact:a.enact}}),"skipped"}}async enactReopen(t){return await S(t.node_id),(await f(t.node_id,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":"launched"}async enactThaw(t){const a=(await k(t.node_id))?.interrupted===!0;if(!a&&t.lifecycle==="resident"&&(await h(t.node_id))?.pi_session_id!=null&&!await w(t.node_id))return await u(t.node_id,"release"),await _(t.node_id),"skipped";try{return(await f(t.node_id,{resume:!0,capacity:"freeze",recovery:!0,...a?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(e){const n=await h(t.node_id);throw n!==null&&(n.status==="active"||n.status==="idle")&&(await u(t.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}),await _(t.node_id)),e}}async enactIdleRelease(t,a){const e=a.node_id,n=await R(e),r=this.relaunchState.get(e),c=r===void 0||r.acknowledgedCount!==n,i=c?0:r.attempts;if(i>=m)return this.relaunchState.delete(e),l({level:"warn",event:"broker.idle_release.exhausted",...s(e)?{node_id:e}:{},fields:{...s(e)?{}:{affected_node_id:e},attempts:i,max_attempts:m}}),await u(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:i}}}),await A(e,"notice.crash",`Child crashed \u2014 ${g(a)} (${e}) failed to relaunch after ${i} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e}),"skipped";const p=c?void 0:r?.lastAttempt,v=Math.min(C*2**i,M);return p!==void 0&&t-p<v?"skipped":(await f(e,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":(this.relaunchState.set(e,{acknowledgedCount:n,attempts:i+1,lastAttempt:t}),l({level:"info",event:"broker.revive.idle_release",...s(e)?{node_id:e}:{},attempt:i+1,fields:{...s(e)?{}:{affected_node_id:e},attempts:i+1,max_attempts:m}}),"launched")}}export{j as FreezeLaneReconciler,N as compareThaw,I as thawTier};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var y=Object.defineProperty;var f=(r,t)=>y(r,"name",{value:t,configurable:!0});import{clearFrozen as p,endLiveExecution as o,getNode as P}from"../../../core/canvas/index.js";import{isSafeNodeId as k}from"../../../core/canvas/paths.js";import{recordedPidLiveness as u}from"../../../core/canvas/pid.js";import{emitEvent as c}from"../../../core/events/emit.js";import{operationIdContext as v}from"../../../core/events/operation-id.js";import{readInterruptedTurn as L}from"../../../core/canvas/recovery.js";import{isProfilePaused as l}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as m}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as h}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as R,isParkedResident as z}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as I}from"../../fleet.js";import{applyParkEvent as E,hasPendingWake as M,parkEvent as g}from"../live-obligation.js";import{FreezeLaneReconciler as N}from"./freeze-lane.js";import{isInBackoff as _}from"./respawn-policy.js";import{handleTerminatingRow as b}from"./terminating.js";import{wantsExecution as C}from"./wants-execution.js";function D(r){return r.status==="done"||r.status==="canceled"||r.status==="dead"}f(D,"isTerminal");const F=12e4;function T(r,t){const e=Math.max(...[r.created,r.launched_at].map(a=>a==null?0:Date.parse(a)||0));return e>0&&t-e<F}f(T,"isLaunchInFlight");class ${static{f(this,"NodeLifecycleReconciler")}freezeLane=new N;async run(t,e){const a=[];for(const n of e.rows)await v.fresh(async()=>{try{await this.classifyRow(t,n,e,a)}catch(i){const s=n.node_id;c({level:"error",event:"node.lifecycle.classify_failed",...k(s)?{node_id:s}:{fields:{affected_node_id:s}},error:i})}});return this.freezeLane.run(t,{fleet:e.fleet,candidates:a})}async classifyRow(t,e,a,n){const i=e.node_id;if(D(e)){if(b(e,a.fleet.has(i)))return;if(z(e)&&!a.fleet.has(i)&&!l(e.profile_id)&&!m(i)&&!_(e,t)&&await h(i)){n.push({row:e,enact:"reopen"});return}e.pi_pid!=null&&u(e.pi_pid,e.pi_pid_identity)==="dead"&&await o(i,{reason:"observed-dead"}),e.frozen_at!=null&&(e.final_report!=null?await p(i):n.push({row:e,enact:"thaw"}));return}if(a.fleet.has(i)){l(e.profile_id)?a.fleet.interruptForProfilePause(i):await this.thawMark(e);return}if(l(e.profile_id)){this.freezeLane.endEpisode(i);return}if(m(i))return;const s=e.pi_pid!=null&&u(e.pi_pid,e.pi_pid_identity)==="dead";if(s&&!a.fleet.hasProfilePauseInterruption(i)&&await o(i,{reason:"observed-dead"}),!await C(e)){await this.thawMark(e),await this.settleParked(e);return}if(_(e,t))return;if(e.status==="idle"&&R(e)&&await h(i)){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){n.push({row:e,enact:"thaw"});return}if(a.fleet.isClaimed(i)||T(e,t))return;c({level:"warn",event:"node.lifecycle.stranded_launch",node_id:i}),n.push({row:e,enact:"thaw"});return}if(!s)return;const d=I(await P(i),(await L(i))?.interrupted===!0,await M(i));if(d==="respawn-fresh"||d==="respawn-cycle"||d==="respawn-resume"){n.push({row:e,enact:"policy"});return}await a.fleet.applyDeadRowPolicy(i),await this.thawMark(e)}async thawMark(t){t.frozen_at!=null&&await p(t.node_id)}async settleParked(t){if(t.status!=="idle")return;this.freezeLane.endEpisode(t.node_id);const e=await g(t.node_id,t.lifecycle);e!=="release"&&await E(t.node_id,e)}}export{F as LAUNCH_GRACE_MS,$ as NodeLifecycleReconciler,T as isLaunchInFlight};
|
|
@@ -4,9 +4,6 @@ export declare const DEAD_REAP_GRACE_MS: number;
|
|
|
4
4
|
export declare const RETENTION_SWEEP_INTERVAL_MS: number;
|
|
5
5
|
export declare const RETENTION_TTL_DAYS = 14;
|
|
6
6
|
export declare const CONTEXT_STRIP_GRACE_MS: number;
|
|
7
|
-
/** A separate daemon-owned SQLite connection checkpoints without holding the API's
|
|
8
|
-
* event loop. A busy reader or another writer is not a reason to block service. */
|
|
9
|
-
export declare function checkpointCanvasWal(path: string): Promise<boolean>;
|
|
10
7
|
export interface StorageMaintenanceContext {
|
|
11
8
|
/** Carries the managed-worktree sweep's detached Git work off this tick. */
|
|
12
9
|
lifecycle: DetachedWorkLifecycle;
|
|
@@ -22,8 +19,6 @@ export declare class StorageMaintenanceReconciler {
|
|
|
22
19
|
private lastRunExpiryAt;
|
|
23
20
|
private lastRunEventPassAt;
|
|
24
21
|
private runEventCursor;
|
|
25
|
-
private lastWalCheckpointAt;
|
|
26
|
-
private walCheckpointInFlight;
|
|
27
22
|
private lastAnalyzeAt;
|
|
28
23
|
private lastRetentionSweepAt;
|
|
29
24
|
private lastContextStripAt;
|
|
@@ -37,7 +32,6 @@ export declare class StorageMaintenanceReconciler {
|
|
|
37
32
|
run(now: number, ctx: StorageMaintenanceContext): Promise<void>;
|
|
38
33
|
/** Ask the launcher for one purge of every app's cache folder: at boot, then at most hourly. It is off the due lanes (a sleeping runtime is never woken for it) and skipped where no launcher exists. */
|
|
39
34
|
private scheduleCachePass;
|
|
40
|
-
private scheduleWalCheckpoint;
|
|
41
35
|
/** Milliseconds since the node's last activity ({@link lastActivityMs}). */
|
|
42
36
|
private msSinceTerminalActivity;
|
|
43
37
|
/** Delete terminal nodes quiet for {@link RETENTION_TTL_DAYS}, at most once per
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
var I=Object.defineProperty;var
|
|
2
|
-
import { parentPort, workerData } from 'node:worker_threads';
|
|
3
|
-
const db = new DatabaseSync(workerData);
|
|
4
|
-
try {
|
|
5
|
-
db.exec('PRAGMA busy_timeout = 250');
|
|
6
|
-
const rows = db.prepare('PRAGMA wal_checkpoint(TRUNCATE)').all();
|
|
7
|
-
parentPort.postMessage(rows[0]?.busy === 0);
|
|
8
|
-
} finally { db.close(); }`,{eval:!0,workerData:f});let a=!1;const l=u(d=>{a||(a=!0,clearTimeout(s),r(d))},"finish"),s=setTimeout(()=>{n.terminate(),l(!1)},3e3);n.once("message",l),n.once("error",d=>{a||(a=!0,clearTimeout(s),e(d))}),n.once("exit",()=>l(!1))})}u(re,"checkpointCanvasWal");class Te{static{u(this,"StorageMaintenanceReconciler")}lastSpareSweepAt=Number.NEGATIVE_INFINITY;lastCreateRequestSweepAt=Number.NEGATIVE_INFINITY;lastRunExpiryAt=Number.NEGATIVE_INFINITY;lastRunEventPassAt=Number.NEGATIVE_INFINITY;runEventCursor=0;lastWalCheckpointAt=Number.NEGATIVE_INFINITY;walCheckpointInFlight=!1;lastAnalyzeAt=Number.NEGATIVE_INFINITY;lastRetentionSweepAt=Number.NEGATIVE_INFINITY;lastContextStripAt=Number.NEGATIVE_INFINITY;contextStripInFlight=!1;focusGcInFlight=!1;lastCachePassAt=null;cachePassInFlight=!1;worktreeSweep=new V;groveInstanceSweep=new M;async run(t,r){if(await this.reapDeadResidue(t),this.scheduleFocusGc(r),await this.gcWarmPool(t),await this.gcCreateRequests(t),t-this.lastRunEventPassAt>=J){this.lastRunEventPassAt=t;try{await Y(t);const e=await L(t,this.runEventCursor);this.runEventCursor=e.cursor}catch(e){console.warn(`run event maintenance failed: ${String(e)}`)}}if(t-this.lastRunExpiryAt>=60*6e4){try{await z(t)}catch(e){console.warn(`memory-read log prune failed: ${String(e)}`)}this.lastRunExpiryAt=t}t-this.lastAnalyzeAt>=1440*6e4&&(await(await q()).exec("ANALYZE"),this.lastAnalyzeAt=t),await this.sweepRetention(t,r),this.scheduleCachePass(t,r),this.scheduleContextStrip(t,r),this.scheduleWalCheckpoint(t,r),this.worktreeSweep.run(t,r),this.groveInstanceSweep.run(t,r)}scheduleCachePass(t,r){this.cachePassInFlight||!$(this.lastCachePassAt,t)||process.platform!=="linux"||!H(U)||r.lifecycle.acceptsDetachedWork()&&(this.lastCachePassAt=t,this.cachePassInFlight=!0,r.lifecycle.registerDetached(K({operation:"cache.purge"}).then(()=>{}).catch(e=>{o.fresh(()=>{i({level:"warn",event:"app.cache.pass_failed",error:e})})}).then(()=>{this.cachePassInFlight=!1})))}scheduleWalCheckpoint(t,r){this.walCheckpointInFlight||t-this.lastWalCheckpointAt<ee||r.lifecycle.acceptsDetachedWork()&&(this.lastWalCheckpointAt=t,this.walCheckpointInFlight=!0,r.lifecycle.registerDetached(re(O()).catch(e=>{console.warn(`canvas WAL checkpoint failed: ${String(e)}`)}).then(()=>{this.walCheckpointInFlight=!1})))}msSinceTerminalActivity(t,r){const e=h(t);return e===0?Number.POSITIVE_INFINITY:r-e}async sweepRetention(t,r){t-this.lastRetentionSweepAt<m||r.lifecycle.acceptsDetachedWork()&&(this.lastRetentionSweepAt=t,await o.fresh(async()=>{try{const e=await P({ttlDays:Z,held:await _(r.fleet),removeDirs:u(n=>{r.lifecycle.registerDetached(Promise.all(n.map(a=>E(a,{recursive:!0,force:!0}))).then(()=>{}).catch(a=>{o.fresh(()=>{i({level:"error",event:"canvas.retention.failed",error:a})})}))},"removeDirs")});e.pruned.length>0&&i({level:"info",event:"canvas.retention.pruned",outcome:"succeeded",fields:{pruned_count:e.pruned.length}})}catch(e){i({level:"error",event:"canvas.retention.failed",error:e})}}))}scheduleContextStrip(t,r){if(this.contextStripInFlight||t-this.lastContextStripAt<m||!r.lifecycle.acceptsDetachedWork())return;this.lastContextStripAt=t,this.contextStripInFlight=!0;const e=this.stripFinishedContexts(t,r).finally(()=>{this.contextStripInFlight=!1});r.lifecycle.registerDetached(e)}async stripFinishedContexts(t,r){const e=await _(r.fleet),n=u(async s=>s!==null&&["done","canceled","dead"].includes(s.status)&&(s.pi_pid??null)===null&&(s.frozen_at??null)===null&&!x(s)&&h(s)<t-j&&!await e(s.node_id),"eligible");let a=0,l=0;try{for(const s of await g({status:["done","canceled","dead"]})){if(!c(s.node_id)||!await n(s))continue;const d=await D(s.node_id);if(d!==null&&d>=h(s)||!await n(await T(s.node_id)))continue;let p;try{p=await k(s.node_id)}catch(v){o.fresh(()=>{i({level:"warn",event:"canvas.context_strip.node_failed",error:v,fields:{node_id:s.node_id}})});continue}p.removed.length>0&&(a+=1,l+=p.bytes)}}catch(s){o.fresh(()=>{i({level:"error",event:"canvas.context_strip.failed",error:s})})}a>0&&o.fresh(()=>{i({level:"info",event:"canvas.context_strip.completed",outcome:"succeeded",fields:{node_count:a,bytes:l}})})}async reapDeadResidue(t){let r;try{r=await C()}catch(e){o.fresh(()=>{i({level:"error",event:"residue.reap_scan.failed",error:e})});return}for(const e of r){try{if(this.msSinceTerminalActivity(e,t)<B)continue}catch(n){o.fresh(()=>{i({level:"error",event:"residue.reap.failed",...c(e.node_id)?{node_id:e.node_id}:{},error:n,fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})});continue}await o.fresh(async()=>{try{i({level:"info",event:"residue.reaped",...c(e.node_id)?{node_id:e.node_id}:{},fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}}),await W(e.node_id)}catch(n){i({level:"error",event:"residue.reap.failed",...c(e.node_id)?{node_id:e.node_id}:{},error:n,fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})}})}}scheduleFocusGc(t){if(this.focusGcInFlight||!t.lifecycle.acceptsDetachedWork())return;this.focusGcInFlight=!0;const r=this.gcStaleFocuses().finally(()=>{this.focusGcInFlight=!1});t.lifecycle.registerDetached(r)}async gcStaleFocuses(){let t;try{t=await N()}catch(e){o.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(t.length===0)return;let r;try{r=await b()}catch(e){o.fresh(()=>{i({level:"error",event:"focus.gc.failed",error:e})});return}if(r!==null)for(const e of t){if(e.pane===null||r.has(e.pane))continue;if(!await o.fresh(async()=>{try{return(await S(e.focus_id))?.pane!==e.pane||(i({level:"info",event:"focus.gc.removed",...c(e.node_id)?{node_id:e.node_id}:{},fields:{focus_id:e.focus_id,focus_node_id:e.node_id,pane:e.pane}}),await w(e.focus_id)),!0}catch(a){return i({level:"error",event:"focus.gc.failed",error:a}),!1}}))return}}async gcCreateRequests(t){t-this.lastCreateRequestSweepAt<X||(this.lastCreateRequestSweepAt=t,await o.fresh(async()=>{const r=await F(t),e=await R(t);e>0&&i({level:"info",event:"canvas.idempotency_keys.reaped",outcome:"succeeded",fields:{reaped_count:e}}),r>0&&i({level:"info",event:"canvas.create_requests.reaped",outcome:"succeeded",fields:{reaped_count:r}})}))}async gcWarmPool(t){t-this.lastSpareSweepAt<Q||(this.lastSpareSweepAt=t,await o.fresh(async()=>{const r=await G();r.length>0&&i({level:"info",event:"warm_pool.spares_reaped",outcome:"succeeded",fields:{reaped_count:r.length}})}))}}export{j as CONTEXT_STRIP_GRACE_MS,B as DEAD_REAP_GRACE_MS,m as RETENTION_SWEEP_INTERVAL_MS,Z as RETENTION_TTL_DAYS,Te as StorageMaintenanceReconciler,re as checkpointCanvasWal};
|
|
1
|
+
var I=Object.defineProperty;var l=(f,t)=>I(f,"name",{value:t,configurable:!0});import{rm as E}from"node:fs/promises";import{closeFocusRow as y,getFocusById as S,listFocuses as A,listNodes as N}from"../../core/canvas/index.js";import{pruneExpiredIdempotencyKeys as w}from"../../core/runs/operations.js";import{getNode as R,lastActivityMs as u,listTerminalPlacementResidue as g,pruneExpiredCreateRequests as T,pruneNodes as C}from"../../core/canvas/canvas.js";import{lastContextStripMs as F,stripContextDir as x}from"../../core/canvas/context-strip.js";import{isAppRun as P}from"../../core/canvas/app-run.js";import{isSafeNodeId as c}from"../../core/canvas/paths.js";import{emitEvent as s}from"../../core/events/emit.js";import{operationIdContext as n}from"../../core/events/operation-id.js";import{listLivePanesAsync as D,tearDownNode as G}from"../../core/runtime/placement.js";import{reapStaleSpares as V}from"../../core/runtime/warm-pool.js";import{GroveInstanceSweepReconciler as b}from"./grove-instance-sweep.js";import{ManagedWorktreeSweepReconciler as M}from"./managed-worktree-sweep.js";import{compactRunEvents as W,expireRunEvents as Y}from"../../core/runs/events.js";import{openDb as k}from"../../core/canvas/db.js";import{retentionHold as _}from"./live-obligation.js";import{pruneMemoryReads as q}from"../../core/canvas/memory-reads.js";import{existsSync as L}from"node:fs";import{launcherRequest as O}from"../../launcher/client.js";import{LAUNCHER_SOCKET as z}from"../../launcher/spec.js";import{cachePassDue as U}from"../../launcher/limits/policy.js";const H=10*6e4,K=60*1e3,$=60*1e3,m=5*6e4,B=14,Q=1440*6e4,X=2e3;class Ee{static{l(this,"StorageMaintenanceReconciler")}lastSpareSweepAt=Number.NEGATIVE_INFINITY;lastCreateRequestSweepAt=Number.NEGATIVE_INFINITY;lastRunExpiryAt=Number.NEGATIVE_INFINITY;lastRunEventPassAt=Number.NEGATIVE_INFINITY;runEventCursor=0;lastAnalyzeAt=Number.NEGATIVE_INFINITY;lastRetentionSweepAt=Number.NEGATIVE_INFINITY;lastContextStripAt=Number.NEGATIVE_INFINITY;contextStripInFlight=!1;focusGcInFlight=!1;lastCachePassAt=null;cachePassInFlight=!1;worktreeSweep=new M;groveInstanceSweep=new b;async run(t,r){if(await this.reapDeadResidue(t),this.scheduleFocusGc(r),await this.gcWarmPool(t),await this.gcCreateRequests(t),t-this.lastRunEventPassAt>=X){this.lastRunEventPassAt=t;try{await Y(t);const e=await W(t,this.runEventCursor);this.runEventCursor=e.cursor}catch(e){console.warn(`run event maintenance failed: ${String(e)}`)}}if(t-this.lastRunExpiryAt>=60*6e4){try{await q(t)}catch(e){console.warn(`memory-read log prune failed: ${String(e)}`)}this.lastRunExpiryAt=t}t-this.lastAnalyzeAt>=1440*6e4&&(await(await k()).exec("ANALYZE"),this.lastAnalyzeAt=t),await this.sweepRetention(t,r),this.scheduleCachePass(t,r),this.scheduleContextStrip(t,r),this.worktreeSweep.run(t,r),this.groveInstanceSweep.run(t,r)}scheduleCachePass(t,r){this.cachePassInFlight||!U(this.lastCachePassAt,t)||process.platform!=="linux"||!L(z)||r.lifecycle.acceptsDetachedWork()&&(this.lastCachePassAt=t,this.cachePassInFlight=!0,r.lifecycle.registerDetached(O({operation:"cache.purge"}).then(()=>{}).catch(e=>{n.fresh(()=>{s({level:"warn",event:"app.cache.pass_failed",error:e})})}).then(()=>{this.cachePassInFlight=!1})))}msSinceTerminalActivity(t,r){const e=u(t);return e===0?Number.POSITIVE_INFINITY:r-e}async sweepRetention(t,r){t-this.lastRetentionSweepAt<m||r.lifecycle.acceptsDetachedWork()&&(this.lastRetentionSweepAt=t,await n.fresh(async()=>{try{const e=await C({ttlDays:B,held:await _(r.fleet),removeDirs:l(a=>{r.lifecycle.registerDetached(Promise.all(a.map(o=>E(o,{recursive:!0,force:!0}))).then(()=>{}).catch(o=>{n.fresh(()=>{s({level:"error",event:"canvas.retention.failed",error:o})})}))},"removeDirs")});e.pruned.length>0&&s({level:"info",event:"canvas.retention.pruned",outcome:"succeeded",fields:{pruned_count:e.pruned.length}})}catch(e){s({level:"error",event:"canvas.retention.failed",error:e})}}))}scheduleContextStrip(t,r){if(this.contextStripInFlight||t-this.lastContextStripAt<m||!r.lifecycle.acceptsDetachedWork())return;this.lastContextStripAt=t,this.contextStripInFlight=!0;const e=this.stripFinishedContexts(t,r).finally(()=>{this.contextStripInFlight=!1});r.lifecycle.registerDetached(e)}async stripFinishedContexts(t,r){const e=await _(r.fleet),a=l(async i=>i!==null&&["done","canceled","dead"].includes(i.status)&&(i.pi_pid??null)===null&&(i.frozen_at??null)===null&&!P(i)&&u(i)<t-Q&&!await e(i.node_id),"eligible");let o=0,p=0;try{for(const i of await N({status:["done","canceled","dead"]})){if(!c(i.node_id)||!await a(i))continue;const h=await F(i.node_id);if(h!==null&&h>=u(i)||!await a(await R(i.node_id)))continue;let d;try{d=await x(i.node_id)}catch(v){n.fresh(()=>{s({level:"warn",event:"canvas.context_strip.node_failed",error:v,fields:{node_id:i.node_id}})});continue}d.removed.length>0&&(o+=1,p+=d.bytes)}}catch(i){n.fresh(()=>{s({level:"error",event:"canvas.context_strip.failed",error:i})})}o>0&&n.fresh(()=>{s({level:"info",event:"canvas.context_strip.completed",outcome:"succeeded",fields:{node_count:o,bytes:p}})})}async reapDeadResidue(t){let r;try{r=await g()}catch(e){n.fresh(()=>{s({level:"error",event:"residue.reap_scan.failed",error:e})});return}for(const e of r){try{if(this.msSinceTerminalActivity(e,t)<H)continue}catch(a){n.fresh(()=>{s({level:"error",event:"residue.reap.failed",...c(e.node_id)?{node_id:e.node_id}:{},error:a,fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})});continue}await n.fresh(async()=>{try{s({level:"info",event:"residue.reaped",...c(e.node_id)?{node_id:e.node_id}:{},fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}}),await G(e.node_id)}catch(a){s({level:"error",event:"residue.reap.failed",...c(e.node_id)?{node_id:e.node_id}:{},error:a,fields:{...c(e.node_id)?{}:{affected_node_id:e.node_id},pane:e.pane,window:e.window,tmux_session:e.tmux_session}})}})}}scheduleFocusGc(t){if(this.focusGcInFlight||!t.lifecycle.acceptsDetachedWork())return;this.focusGcInFlight=!0;const r=this.gcStaleFocuses().finally(()=>{this.focusGcInFlight=!1});t.lifecycle.registerDetached(r)}async gcStaleFocuses(){let t;try{t=await A()}catch(e){n.fresh(()=>{s({level:"error",event:"focus.gc.failed",error:e})});return}if(t.length===0)return;let r;try{r=await D()}catch(e){n.fresh(()=>{s({level:"error",event:"focus.gc.failed",error:e})});return}if(r!==null)for(const e of t){if(e.pane===null||r.has(e.pane))continue;if(!await n.fresh(async()=>{try{return(await S(e.focus_id))?.pane!==e.pane||(s({level:"info",event:"focus.gc.removed",...c(e.node_id)?{node_id:e.node_id}:{},fields:{focus_id:e.focus_id,focus_node_id:e.node_id,pane:e.pane}}),await y(e.focus_id)),!0}catch(o){return s({level:"error",event:"focus.gc.failed",error:o}),!1}}))return}}async gcCreateRequests(t){t-this.lastCreateRequestSweepAt<$||(this.lastCreateRequestSweepAt=t,await n.fresh(async()=>{const r=await T(t),e=await w(t);e>0&&s({level:"info",event:"canvas.idempotency_keys.reaped",outcome:"succeeded",fields:{reaped_count:e}}),r>0&&s({level:"info",event:"canvas.create_requests.reaped",outcome:"succeeded",fields:{reaped_count:r}})}))}async gcWarmPool(t){t-this.lastSpareSweepAt<K||(this.lastSpareSweepAt=t,await n.fresh(async()=>{const r=await V();r.length>0&&s({level:"info",event:"warm_pool.spares_reaped",outcome:"succeeded",fields:{reaped_count:r.length}})}))}}export{Q as CONTEXT_STRIP_GRACE_MS,H as DEAD_REAP_GRACE_MS,m as RETENTION_SWEEP_INTERVAL_MS,B as RETENTION_TTL_DAYS,Ee as StorageMaintenanceReconciler};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
var k=Object.defineProperty;var r=(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
AND
|
|
1
|
+
var k=Object.defineProperty;var r=(s,t)=>k(s,"name",{value:t,configurable:!0});import{randomUUID as y}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as m}from"../../core/canvas/canvas.js";import{BrokerClient as D,SocketTransport as I}from"../../core/broker-client/client.js";import{emitRunEvent as p,emitRunSettlement as E}from"../../core/runs/events.js";import{cancelOpenQuestions as T}from"../../core/runs/questions.js";import{emitEvent as h}from"../../core/events/emit.js";import{toRunOutcomeDTO as N}from"../api/map.js";import{readOutputResult as R}from"../../core/runtime/structured-output.js";const A=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),u=new Map,b=250;class g{static{r(this,"RunObserver")}nodeId;runId;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;polling;frames=Promise.resolve();constructor(t,i,n,e){this.nodeId=t,this.runId=i,this.status=n,this.outcomeRevision=e,this.timer=setInterval(()=>{this.pollOrClose()},250),this.timer.unref(),u.set(t,this)}static async start(t,i){const n=await l(),e=await n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===i?"node.settled":"child.settled"),o=await n.prepare("SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t),d=new g(t,i,o?JSON.parse(o.body_json).status:void 0,e?JSON.parse(e.body_json).outcome.revision:void 0);return await d.poll(),d}async pollOrClose(){try{await this.poll()}catch(t){this.close(),h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:t})}}poll(){return this.polling===void 0&&(this.polling=this.pollOnce().finally(()=>{this.polling=void 0})),this.polling}async pollOnce(){const t=await m(this.nodeId);if(!t||t.run_id!==this.runId||!await S(this.runId)){this.close();return}this.piPid=t.pi_pid??null;const i=t.pi_pid===null?"dormant":t.status;this.status!==i&&await p(this.runId,this.nodeId,"node.status.changed",{status:i,reason:t.intent??null}),this.status=i;const n=N(t);if(n&&n.revision!==this.outcomeRevision&&Date.now()-Date.parse(n.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const e=await(await l()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const o of e)await w(o.node_id,this.runId),await u.get(o.node_id)?.poll()}if(this.outcomeRevision=n.revision,this.nodeId===this.runId){const e=n.kind==="result"?R(this.nodeId,t.grantee):void 0;await E(this.runId,this.nodeId,"node.settled",{outcome:n,usage:JSON.parse(t.usage_json??A),...e===void 0?{}:{result:e}})}else await E(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:n});if(t.grantee&&t.grantee!=="app:terminal"){const e=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};T(e,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(o=>h({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:o}))}}t.pi_pid===null?this.close():await this.connect()}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&this.piPid!==null?this.assistantStartSequence:null}get openBlock(){return this.assistantMessageStartSequence===null?null:this.block}async connect(){if(this.client||this.closed)return;const t=new D(this.nodeId,{transport:new I(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:y(),attends:!1}));const i=r(async n=>{if(!(this.closed||this.client!==t)){if(n.type==="message_start"&&n.message.role==="assistant"&&(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",this.assistantStartSequence=(await(await l()).prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId)).event_cursor),n.type==="message_update"&&n.message.role==="assistant"&&this.openAssistant){const e=n.message.content;if(!Array.isArray(e))return;const o=e.at(-1);o&&typeof o=="object"&&"type"in o&&(o.type==="toolCall"?this.block={kind:"tool_call",name:"name"in o&&typeof o.name=="string"?o.name:""}:(o.type==="text"||o.type==="thinking")&&(this.block={kind:o.type}));const d=e.filter(a=>a?.type==="thinking").map(a=>a.thinking).join(""),c=e.filter(a=>a?.type==="text").map(a=>a.text).join(""),v=d.startsWith(this.thinking)?d.slice(this.thinking.length):d,O=c.startsWith(this.output)?c.slice(this.output.length):c;this.thinking=d,this.output=c,this.pendingThinking+=v,this.pendingOutput+=O,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>{this.flushDeltas().catch(a=>h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:a}))},b),this.flushTimer.unref())}n.type==="message_end"&&n.message.role==="assistant"&&(await this.flushDeltas(),this.openAssistant=!1,this.block=null)}},"handleFrame");t.on("frame",n=>{this.frames=this.frames.then(()=>i(n)).catch(e=>{this.close(),h({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:e})})}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null)}),t.connect()}async flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const t=this.pendingThinking,i=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!t&&!i)return;if(await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}t&&await p(this.runId,this.nodeId,"node.thinking.delta",{delta:t}),i&&await p(this.runId,this.nodeId,"node.output_text.delta",{delta:i})}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){this.closed=!0,this.discardDeltas(),clearInterval(this.timer),u.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function P(s){return u.get(s)?.assistantMessageStartSequence??null}r(P,"openAssistantMessageStartSequence");function Y(s){return u.get(s)?.openBlock??null}r(Y,"openAssistantBlock");async function S(s){return await(await l()).prepare("SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(s,s)!==void 0}r(S,"runRootExists");const f=new Map;async function w(s,t){const i=f.get(s);if(i)return i;if(u.has(s))return;const n=L(s,t).finally(()=>f.delete(s));return f.set(s,n),n}r(w,"ensureRunObserver");async function L(s,t){if(await S(t)){if(s!==t){const i=await m(s);!await(await l()).prepare("SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,s)&&i&&Date.now()-Date.parse(i.created)<720*60*6e4&&await p(t,s,"child.started",{child_node_id:s,kind:i.kind})}await g.start(s,t)}}r(L,"startRunObserver");async function G(){const s=new Date(Date.now()-2592e6).toISOString(),t=await(await l()).prepare(`SELECT n.node_id, n.run_id, n.pi_pid, COALESCE(n.outcome_revision, 1) AS revision, e.body_json
|
|
2
|
+
FROM node_rows n
|
|
3
|
+
LEFT JOIN run_events e ON n.pi_pid IS NULL AND e.run_id = n.run_id AND e.node_id = n.node_id
|
|
4
|
+
AND e.type = CASE WHEN n.node_id = n.run_id THEN 'node.settled' ELSE 'child.settled' END
|
|
5
|
+
WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ? AND n.outcome_reason != 'parked'))`).all(s),i=new Map;for(const e of t){const o=i.get(e.node_id)??{node_id:e.node_id,run_id:e.run_id,reported:!1};e.body_json!==null&&JSON.parse(e.body_json).outcome?.revision===e.revision&&(o.reported=!0),i.set(e.node_id,o)}const n=[...i.values()].filter(e=>!e.reported);for(const e of n)try{await w(e.node_id,e.run_id),_.delete(e.node_id)}catch(o){M(e.node_id,o)}}r(G,"pollRunObservers");const _=new Map;function M(s,t){const i=t instanceof Error?t.message:String(t);_.get(s)!==i&&(_.set(s,i),h({level:"error",event:"daemon.runs.observer_failed",node_id:s,error:t}))}r(M,"reportObserverFailure");export{w as ensureRunObserver,Y as openAssistantBlock,P as openAssistantMessageStartSequence,G as pollRunObservers};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
var R=Object.defineProperty;var p=(e,n)=>R(e,"name",{value:n,configurable:!0});import{existsSync as y}from"node:fs";import{join as l}from"node:path";import{openDb as m,withCanvasWrite as g}from"../../core/canvas/db.js";import{nodeAgentDir as k,nodeRecordDir as S,onDiskMigrationMarkerPath as C}from"../../core/canvas/paths.js";import{identifyCheckout as j}from"../../core/graph/repo-sync/identity.js";import{profileSpace as I,userRoot as b}from"../../core/layout.js";import{commitConvertedProjectCaps as E,listLegacyProjectCaps as P,listStoredProfiles as x}from"../../core/scoped-state/profiles.js";import{userStore as L}from"../../core/scoped-state/paths.js";import{userScopeRoot as f}from"../../core/scope.js";import{applyPlan as M,readImportRecord as w,storePlanBodies as _}from"./apply.js";import{readLegacyCorpus as v,readMarkerIds as D}from"./legacy/discover.js";import{planImport as O}from"./plan.js";const F=p(()=>({stores:[],counts:{},rewrites:[],droppedFields:[],skipped:[],resolutions:[]}),"emptyReport");async function A(){const e=f(),n=x(e),t=P(e),c=L(e).path,i=n.map(({profileId:r,manifest:a})=>{const s=a.grantee??"app:terminal",d=new Map(t.filter(o=>o.profileId===r).map(o=>[o.path,o.memory]));return{id:r,name:a.name,app:s,memory:I(s,r).dir,projects:a.projects.map(o=>o.path),raw:{projects:a.projects.map(o=>d.has(o.path)?{path:o.path,memory:d.get(o.path)}:{path:o.path})},manifestPath:`${c}#${r}`}}),u=await(await m()).prepareUncached("SELECT node_id, cwd, grantee FROM node_rows ORDER BY created").all(),h=u.map(r=>{const a=r.grantee==="user:local"?"app:terminal":r.grantee,s=a?.startsWith("app:")?k(r.node_id,a):null,d=s!==null&&(y(l(s,"context"))||y(l(s,"reports")))?s:S(r.node_id);return{id:r.node_id,dir:d}});return{roots:{userMemory:l(b(),"memory"),profiles:i,nodeCwds:[...new Set(u.map(r=>r.cwd))],nodes:h},stored:n}}p(A,"legacyRoots");async function N(){const{roots:e,stored:n}=await A(),t=v(e),c=await(await m()).prepareUncached(`SELECT o.type, o.name AS handle, i.external_id AS externalId FROM objects o
|
|
2
|
-
LEFT JOIN identities i ON i.object = o.
|
|
2
|
+
LEFT JOIN identities i ON i.object = o.id WHERE o.type IN ('person','app','repo','profile')`).all();return O(t,{roots:e,markerIds:D(C()),repoIdentity:j,existingOwners:c,storedProfiles:n.map(i=>({id:i.profileId,deliveryLimits:{...i.manifest.delivery_limits??{}}}))})}p(N,"plan");async function V(){return await w(await m())!==null}p(V,"canvasImportDone");async function X(e){const n=await w(await m());if(n!==null)return{report:e.dryRun?n:F(),blockers:[],dryRun:e.dryRun,pending:!1};const t=await N();if(e.dryRun||t.blockers.length>0)return{report:t.report,blockers:t.blockers,dryRun:e.dryRun,pending:!0};const c=_(t);return E(f(),t.profileLimits),await g(async i=>await M(i,t,c)),{report:t.report,blockers:[],dryRun:!1,pending:!1}}p(X,"runCanvasImport");export{V as canvasImportDone,X as runCanvasImport};
|
|
@@ -15,6 +15,7 @@ interface ContentBlockLike {
|
|
|
15
15
|
}
|
|
16
16
|
interface ToolResultEventLike {
|
|
17
17
|
toolName: string;
|
|
18
|
+
toolCallId?: string;
|
|
18
19
|
isError?: boolean;
|
|
19
20
|
/** The tool's resolved input. For `read` it carries the file path under
|
|
20
21
|
* `path` (or the legacy `file_path`); for `bash`, the command string under
|
|
@@ -34,6 +35,7 @@ type ToolResultResultLike = {
|
|
|
34
35
|
* call's synthesized error result, carrying arbitrary-length text. */
|
|
35
36
|
interface ToolCallEventLike {
|
|
36
37
|
toolName: string;
|
|
38
|
+
toolCallId?: string;
|
|
37
39
|
input?: unknown;
|
|
38
40
|
}
|
|
39
41
|
type ToolCallResultLike = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g=Object.defineProperty;var d=(o,e)=>g(o,"name",{value:e,configurable:!0});import{envNodeId as C}from"../shared/env.js";import{homedir as I}from"node:os";import{join as N,resolve as T}from"node:path";import{brokerDelivery as m}from"../core/runtime/broker/daemon-ops.js";import{bashFileReads as E}from"../core/shell-file-reads.js";import{ApiError as O}from"../api/errors.js";import{emitEvent as R}from"../core/events/emit.js";import{autoLoadedContextInner as x,mergeAutoLoadedContext as y}from"./envelope-merge.js";const L=`
|
|
2
2
|
|
|
3
|
-
Guidelines:`;function
|
|
4
|
-
`)}
|
|
5
|
-
`);function
|
|
3
|
+
Guidelines:`;function b(o){const e=o?.command;return typeof e=="string"&&e.trim()!==""?e:null}d(b,"bashCommandOf");function D(o){return["HELD \u2014 nothing ran.","","Your bash command was NOT executed. It matched memory you had not yet read, and that memory is below.","","Read it, then re-issue your WHOLE command unchanged \u2014 every clause of it, including any heredoc, redirect, or `$(\u2026)` that built its input, because none of that ran either. The re-issue executes: this memory is now in your transcript, so there is nothing left to deliver and nothing left to hold.","",o].join(`
|
|
4
|
+
`)}d(D,"heldReason");const j="This command already ran; its output is above. The memory below is for reading \u2014 it is not a hold, so do not re-issue the command.",k=["HELD \u2014 nothing ran.","","Your bash command was NOT executed. Another command in this same message was held against memory you had not read, and that memory was returned with it.","","Read it, then re-issue your WHOLE command unchanged. The re-issue executes."].join(`
|
|
5
|
+
`);function A(o){const e=C();if(e===void 0||e.trim()==="")return;o.on("before_agent_start",async t=>{const a=(await m(e,{activity:"system-prompt"})).content;if(a==="")return;const i=t.systemPrompt.indexOf(L);return i===-1?{systemPrompt:`${t.systemPrompt}
|
|
6
6
|
|
|
7
|
-
${
|
|
7
|
+
${a}`}:{systemPrompt:`${t.systemPrompt.slice(0,i)}
|
|
8
8
|
|
|
9
|
-
${
|
|
9
|
+
${a}${t.systemPrompt.slice(i)}`}});let r=!1;o.on("turn_end",()=>{r=!1,c.clear()});const c=new Map;o.on("session_compact",async()=>{await m(e,{activity:"compact"}),r=!1}),o.on("tool_call",async t=>{if(t.toolName!=="bash")return;const a=b(t.input);if(a===null)return;if(r)return{block:!0,reason:k};const i=performance.now(),l=(await m(e,{activity:"pre-command",subject:a})).content;if(t.toolCallId!==void 0&&c.set(t.toolCallId,performance.now()-i),l!=="")return r=!0,t.toolCallId!==void 0&&c.delete(t.toolCallId),{block:!0,reason:D(l)}}),o.on("tool_result",async(t,a)=>{const i=t.toolCallId===void 0?void 0:c.get(t.toolCallId);if(t.toolCallId!==void 0&&c.delete(t.toolCallId),t.isError===!0){t.toolName==="bash"&&i!==void 0&&w(i,0,0,0);return}const l=typeof a?.cwd=="string"&&a.cwd!==""?a.cwd:process.cwd(),u=[],h=d(s=>{if(s==="")return;const n=x(s);if(n===null)throw new Error("substrate renderer returned an invalid auto-loaded context block");u.push(n)},"collect");if(t.toolName==="read"){const s=t.input,n=s?.path??s?.file_path;if(n===void 0||n==="")return;const f=n.startsWith("~")?N(I(),n.slice(1)):n;h((await m(e,{activity:"file-read",subject:T(l,f)})).content)}else if(t.toolName==="bash"){const s=b(t.input);if(s===null)return;const n=performance.now();h((await m(e,{activity:"command",subject:s})).content);const f=performance.now()-n;let p=0;for(const _ of E(s,l,{contextDir:process.env.CRTR_CONTEXT_DIR}))h(await H(e,_)),p++;w(i,f,p,performance.now()-n-f)}else return;if(u.length!==0)return t.toolName==="bash"?{content:y(u,t.content,"after",j)}:{content:y(u,t.content,"before")}})}d(A,"registerCanvasDocSubstrate");function w(o,e,r,c){try{const t=(o??0)+e+c;R({event:"broker.bash.daemon_round_trip",level:"info",duration_ms:Math.round(t*1e3)/1e3,fields:{pre_command_ms:o===void 0?null:Math.round(o*1e3)/1e3,command_ms:Math.round(e*1e3)/1e3,file_reads:r,file_read_ms:Math.round(c*1e3)/1e3}})}catch{}}d(w,"emitRoundTrip");async function H(o,e){try{return(await m(o,{activity:"file-read",subject:e})).content}catch(r){if(r instanceof O&&r.code==="scope_missing")return"";throw r}}d(H,"fileReadDelivery");var X=A;export{X as default,A as registerCanvasDocSubstrate};
|
|
@@ -8,6 +8,7 @@ type TextBlock = {
|
|
|
8
8
|
};
|
|
9
9
|
/** Return the normalized contents of an auto-loaded-context envelope. */
|
|
10
10
|
export declare function autoLoadedContextInner(text: string): string | null;
|
|
11
|
-
/** Merge fresh items into the one auto-loaded-context envelope in a tool result.
|
|
12
|
-
|
|
11
|
+
/** Merge fresh items into the one auto-loaded-context envelope in a tool result.
|
|
12
|
+
* `lead`, when given, is one line of copy placed directly ahead of the envelope. */
|
|
13
|
+
export declare function mergeAutoLoadedContext<T extends ContentBlock>(items: readonly string[], content: T[], placement?: 'before' | 'after', lead?: string): Array<T | TextBlock>;
|
|
13
14
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
var
|
|
2
|
-
`),x=n.map(t=>t.trim()).filter(t=>t!==""&&!
|
|
3
|
-
`),
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
${
|
|
8
|
-
|
|
1
|
+
var g=Object.defineProperty;var o=(n,e)=>g(n,"name",{value:e,configurable:!0});const r=/<auto-loaded-context(?:\s[^>]*)?>\n([\s\S]*?)\n<\/auto-loaded-context>/;function h(n){const e=n.match(r)?.[1]?.trim();return e===void 0||e===""?null:e}o(h,"autoLoadedContextInner");function T(n,e,f="before",i=""){const c=e.map(t=>t.text??"").join(`
|
|
2
|
+
`),x=n.map(t=>t.trim()).filter(t=>t!==""&&!c.includes(t));if(x.length===0)return e;const d=x.join(`
|
|
3
|
+
`),a=i===""?"":`${i}
|
|
4
|
+
`,u=e.findIndex(t=>typeof t.text=="string"&&r.test(t.text));if(u===-1){const t={type:"text",text:`${a}<auto-loaded-context>
|
|
5
|
+
${d}
|
|
6
|
+
</auto-loaded-context>`};return f==="after"?[...e,t]:[t,...e]}return e.map((t,l)=>l!==u||typeof t.text!="string"?t:{...t,text:t.text.replace(r,(m,p)=>{const s=p.trim();return`${a}<auto-loaded-context>
|
|
7
|
+
${d}${s===""?"":`
|
|
8
|
+
${s}`}
|
|
9
|
+
</auto-loaded-context>`})})}o(T,"mergeAutoLoadedContext");export{h as autoLoadedContextInner,T as mergeAutoLoadedContext};
|
package/dist/shared/env.d.ts
CHANGED
|
@@ -110,6 +110,9 @@ export declare function envMaxLiveBrokers(): number | undefined;
|
|
|
110
110
|
/** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
|
|
111
111
|
* over `readConfig('user').brokerThresholds.warning` when set. */
|
|
112
112
|
export declare function envWarnLiveBrokers(): number | undefined;
|
|
113
|
+
/** Test-only override (`CRTR_TEST_NODE_SOCKET_WINDOW_MS`) of how long a command inside a node waits for the broker's
|
|
114
|
+
* relay socket to come back; gated by `envNoDaemonAutostart()` at the call site, so a real node always waits out a restart. */
|
|
115
|
+
export declare function envTestNodeSocketWindowMs(): number | undefined;
|
|
113
116
|
/** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
|
|
114
117
|
* gated by `envNoDaemonAutostart()` at the call site; no production default. */
|
|
115
118
|
export declare function envTestUnattendedParkMs(): number | undefined;
|
package/dist/shared/env.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var p=Object.defineProperty;var n=(e,r)=>p(e,"name",{value:r,configurable:!0});import{lstatSync as f,readFileSync as c,readdirSync as
|
|
2
|
-
`).map(o=>o.split(" ")[4])),t=
|
|
1
|
+
var p=Object.defineProperty;var n=(e,r)=>p(e,"name",{value:r,configurable:!0});import{lstatSync as f,readFileSync as c,readdirSync as T}from"node:fs";import{join as i}from"node:path";import{covers as _}from"@north-light/identity";function W(){return process.env.CRTR_NODE_ID}n(W,"envNodeId");function d(e){for(const r of["broker-launch.json","cron-launch.json"]){const t=i(e,r);if(f(t,{throwIfNoEntry:!1})?.isFile())return t}}n(d,"launchSnapshotFile");function E(){if(process.platform==="linux")try{const e="/run/crtr/nodes",r=new Set(c("/proc/self/mountinfo","utf8").split(`
|
|
2
|
+
`).map(o=>o.split(" ")[4])),t=T(e,{withFileTypes:!0}).filter(o=>o.isDirectory()&&/^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/.test(o.name)&&r.has(i(e,o.name))&&d(i(e,o.name))!==void 0);return t.length===1?t[0].name:void 0}catch{return}}n(E,"sandboxCliNodeId");function F(){return E()!==void 0}n(F,"isSandboxedNode");function h(){return process.env.CRTR_GRANTEE}n(h,"envGrantee");const v="CRTR_INBOX_BETWEEN_TURNS";function H(){return process.env[v]==="1"}n(H,"envInboxBetweenTurns");const C="CRTR_SCOPES_FILE";function K(){const e=process.env[C];if(e!==void 0&&e!==""){const t=JSON.parse(c(e,"utf8"));if(!Array.isArray(t)||t.some(o=>typeof o!="string"))throw new Error(`invalid scopes file ${e}`);return t}const r=process.env.CRTR_SCOPES;return r===void 0?null:r===""?[]:r.split(",")}n(K,"envScopes");function G(e,r){return e==null?!0:a(e,r)}n(G,"scopeAllowed");function a(e,r){return e.includes(r)?(_(r,r),!0):e.some(t=>_(t,r))}n(a,"coveredByAny");function b(){return process.env.CRTR_EXECUTION_ID}n(b,"envExecutionId");function k(){return process.env.CRTR_PROFILE_ID}n(k,"envProfileId");function y(){return process.env.CRTR_NODE_CWD}n(y,"envNodeCwd");function w(){return process.env.CRTR_MODEL_INTENT}n(w,"envModelIntent");function g(){return process.env.CRTR_MODEL_EXACT==="1"}n(g,"envModelExact");function V(){return process.env.CRTR_HOME}n(V,"envHomeOverride");function X(){return process.env.CRTR_RUNTIME_HOME}n(X,"envRuntimeHomeOverride");function s(e,r){if(e===void 0)return r;const t=Number(e);return Number.isFinite(t)&&t>0?t:r}n(s,"parsePositiveMs");const A=5*6e4;function j(){return s(process.env.CRTR_STREAM_WATCHDOG_MS,A)}n(j,"envStreamWatchdogMs");const S=800;function Y(){return s(process.env.CRTR_WATCHER_TICK_MS,S)}n(Y,"envWatcherTickMs");const N=6e4;function $(){return s(process.env.CRTR_WATCHER_BACKSTOP_MS,N)}n($,"envWatcherBackstopMs");const M=1e3;function z(){return s(process.env.CRTR_WATCHER_DEBOUNCE_MS,M)}n(z,"envWatcherDebounceMs");const x=6e4;function Z(){return s(process.env.CRTR_RECAP_IDLE_MS,x)}n(Z,"envRecapIdleMs");function J(){const e=process.env.CRTR_RECAP_MODEL;return e!==void 0&&e.trim()!==""?e.trim():void 0}n(J,"envRecapModelOverride");const D=300*1e3;function q(){return s(process.env.CRTR_BASH_VALVE_MS,D)}n(q,"envBashValveMs");const O=60*1e3;function Q(){return s(process.env.CRTR_BASH_AUTO_BG_DEADLINE_MS,O)}n(Q,"envBashAutoBgDeadlineMs");function ee(){const e=process.env.CRTR_PIDFILE;return e!==void 0&&e!==""?e:void 0}n(ee,"envPidfileOverride");const m="@earendil-works/pi-coding-agent";function ne(){return process.env.CRTR_BROKER_ENGINE??m}n(ne,"envBrokerEngine");function re(){return process.env.CRTR_PI_BINARY}n(re,"envPiBinaryOverride");function te(){return process.env.CRTR_NO_DAEMON_AUTOSTART==="1"}n(te,"envNoDaemonAutostart");function oe(){const e=process.env.CRTR_DOCUMENT_PORT;if(e===void 0||!/^\d+$/.test(e))return;const r=Number(e);return r<=65535?r:void 0}n(oe,"envDocumentPort");function se(){return process.env.CRTRD_TCP}n(se,"envCrtrdTcp");function ue(){const e=process.env.CRTRD_TOKEN;return e!==void 0&&e!==""?e:void 0}n(ue,"envCrtrdToken");function ie(){return process.env.CRTR_NO_EXPORTS==="1"}n(ie,"envNoExports");function ce(){return process.env.CRTR_DEBUG==="1"}n(ce,"envDebug");function R(e){if(e===void 0||e==="")return;const r=Number(e);return Number.isSafeInteger(r)&&r>=1?r:void 0}n(R,"parsePositiveInteger");function _e(){return R(process.env.CRTR_MAX_LIVE_BROKERS)}n(_e,"envMaxLiveBrokers");function Re(){return R(process.env.CRTR_WARN_LIVE_BROKERS)}n(Re,"envWarnLiveBrokers");function u(e){if(e===void 0)return;const r=Number(e);return Number.isFinite(r)&&r>0?r:void 0}n(u,"parsePositiveMsNoDefault");function pe(){return u(process.env.CRTR_TEST_NODE_SOCKET_WINDOW_MS)}n(pe,"envTestNodeSocketWindowMs");function fe(){return u(process.env.CRTR_TEST_UNATTENDED_PARK_MS)}n(fe,"envTestUnattendedParkMs");function Te(){return u(process.env.CRTR_UNATTENDED_PARK_MS)}n(Te,"envUnattendedParkMs");function I(){return u(process.env.CRTR_TEST_PARK_SUMMARY_GRACE_MS)}n(I,"envTestParkSummaryGraceMs");const l=5*6e4;function de(){return I()??l}n(de,"parkSummaryGraceMs");export{v as INBOX_BETWEEN_TURNS_ENV,C as SCOPES_FILE_ENV,a as coveredByAny,Q as envBashAutoBgDeadlineMs,q as envBashValveMs,ne as envBrokerEngine,se as envCrtrdTcp,ue as envCrtrdToken,ce as envDebug,oe as envDocumentPort,b as envExecutionId,h as envGrantee,V as envHomeOverride,H as envInboxBetweenTurns,_e as envMaxLiveBrokers,g as envModelExact,w as envModelIntent,te as envNoDaemonAutostart,ie as envNoExports,y as envNodeCwd,W as envNodeId,re as envPiBinaryOverride,ee as envPidfileOverride,k as envProfileId,Z as envRecapIdleMs,J as envRecapModelOverride,X as envRuntimeHomeOverride,K as envScopes,j as envStreamWatchdogMs,pe as envTestNodeSocketWindowMs,I as envTestParkSummaryGraceMs,fe as envTestUnattendedParkMs,Te as envUnattendedParkMs,Re as envWarnLiveBrokers,$ as envWatcherBackstopMs,z as envWatcherDebounceMs,Y as envWatcherTickMs,F as isSandboxedNode,d as launchSnapshotFile,de as parkSummaryGraceMs,E as sandboxCliNodeId,G as scopeAllowed};
|
|
@@ -15,6 +15,8 @@ A provider is a service the person's runtime calls for your app. Your app asks t
|
|
|
15
15
|
| `context` | Ask about the person from their memory, and look up public profiles | `context:<group>` | [Context](/docs/providers/context) |
|
|
16
16
|
| `device` | The person's Mac: browser, files, Messages and shell | `device:<group>` | [Device](/docs/providers/device) |
|
|
17
17
|
|
|
18
|
+
> **Want your app to have its own number and text its users?** The `sms` provider texts only the signed-in person's own phone. For your own number, use Comms: [the Comms guide for coding agents](https://comms.northlight.ai/llms.txt), and the SDK [`@north-light/comms`](https://www.npmjs.com/package/@north-light/comms) on npm.
|
|
19
|
+
|
|
18
20
|
## Where names come from
|
|
19
21
|
|
|
20
22
|
- **Scope strings** come from the console's **What it asks for → Add permissions** list. A scope is `<provider id>:<group>`. Do not guess them.
|
|
@@ -5,6 +5,8 @@ description: Text the signed-in person's own verified phone from your app with t
|
|
|
5
5
|
|
|
6
6
|
# Texting (sms)
|
|
7
7
|
|
|
8
|
+
> **Want your app to have its own number and text its users?** The `sms` provider cannot: it texts only the signed-in person's own phone. Use Comms instead: [the Comms guide for coding agents](https://comms.northlight.ai/llms.txt) covers fake mode, testers and production, and the SDK is [`@north-light/comms`](https://www.npmjs.com/package/@north-light/comms) on npm.
|
|
9
|
+
|
|
8
10
|
The `sms` provider sends a text from Northlight's number to the verified phone of the person who signed in to your app. It has no recipient argument, so an app cannot text anyone else.
|
|
9
11
|
|
|
10
12
|
## Scopes
|
package/docs/public-api.md
CHANGED
|
@@ -44,7 +44,8 @@ comment-organized); this table is the map, not the inventory:
|
|
|
44
44
|
the underlying storage file.
|
|
45
45
|
- **Canvas reads** — `getNode`, `listNodes`, `nodeDir`, `asksForNodes`,
|
|
46
46
|
`asksAcrossCanvas`, `readTelemetry`, `readContextTokens` (+ their types).
|
|
47
|
-
Read-only queries against the
|
|
47
|
+
Read-only queries against the node graph, which lives in the daemon's
|
|
48
|
+
supervised local Postgres.
|
|
48
49
|
- **Broker client** — `ViewSocketClient`, `BrokerUnavailableError`. A typed
|
|
49
50
|
client for a node's `view.sock`. A consumer that would rather not depend on
|
|
50
51
|
this class can speak the frame protocol directly over the socket path
|
|
@@ -76,9 +77,17 @@ comment-organized); this table is the map, not the inventory:
|
|
|
76
77
|
A consumer that runs alongside crtr (a separate process, a separate repo)
|
|
77
78
|
also has a CLI/socket/schema surface to depend on instead of an import:
|
|
78
79
|
`crtr sys version`, `crtr node message send`, the broker `view.sock`
|
|
79
|
-
`reload_auth` subset, and the
|
|
80
|
+
`reload_auth` subset, and the `/v1` socket API. Each of those is versioned
|
|
80
81
|
by the CLI's own `sys version` output rather than by a document here.
|
|
81
82
|
|
|
83
|
+
The canvas is a supervised local Postgres owned by `crtrd`, not a file. The
|
|
84
|
+
old `runtime/canvas.db` is no longer maintained: the first boot of a Postgres
|
|
85
|
+
generation imports it and renames it `canvas.db.imported`. A sibling process
|
|
86
|
+
reads the canvas through `/v1` or the root barrel's canvas reads above, never
|
|
87
|
+
through the database itself. `crtr sys db export-sqlite` writes a `canvas.db`
|
|
88
|
+
for rolling back to a SQLite generation; it is a one-time snapshot taken
|
|
89
|
+
with the daemon stopped, not a live file to read.
|
|
90
|
+
|
|
82
91
|
## Packaging
|
|
83
92
|
|
|
84
93
|
`docs/` is listed in `package.json#files`, so this note ships inside the
|
|
@@ -7,6 +7,14 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
|
|
|
7
7
|
|
|
8
8
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
9
9
|
|
|
10
|
+
## 0.3.533
|
|
11
|
+
|
|
12
|
+
Three reads take optional narrowing. Additive: no request or response an existing app sends or reads changes.
|
|
13
|
+
|
|
14
|
+
- `GET /v1/canvas/roster` node rows carry an optional `description`. A runtime that predates the field omits it.
|
|
15
|
+
- `GET /v1/crons` accepts `created_by=<node id>` and returns only the crons that node armed. An empty value is 400 `invalid_request`. An older runtime ignores the parameter and returns every cron, so filter on `created_by` yourself if you may talk to one.
|
|
16
|
+
- `GET /v1/human/inbox/history` accepts `state=pending|resolved|canceled|passive` and returns only page tickets in that state. Any other value is 400 `invalid_request`. An older runtime ignores the parameter and returns every state.
|
|
17
|
+
|
|
10
18
|
## 0.3.527
|
|
11
19
|
|
|
12
20
|
`POST /v1/nodes/:id/jobs/start` accepts a job prepared as already backgrounded. Additive: no request or response an existing app sends or reads changes.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.533",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -116,12 +116,12 @@
|
|
|
116
116
|
"dev": "tsx --conditions=crtr-src src/cli.ts",
|
|
117
117
|
"link": "npm link",
|
|
118
118
|
"prepublishOnly": "npm run build",
|
|
119
|
-
"test": "CRTR_NO_DAEMON_AUTOSTART=1 node --conditions=crtr-src --import tsx/esm --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.max(4, require(`node:os`).availableParallelism() - 1)') --test-timeout=10000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'src/**/__tests__/*.test.ts'",
|
|
120
|
-
"test:integration": "npm run build:sdk && CRTR_NO_DAEMON_AUTOSTART=1 node --conditions=crtr-src --import tsx/esm --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(8, Math.max(2, require(`node:os`).availableParallelism() - 1))') --test-timeout=60000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'src/**/__tests__/integration/*.test.ts' 'packages/crouter-sdk/src/**/__tests__/integration/*.test.ts' 'packages/crouter-plugin/src/**/__tests__/integration/*.test.ts'",
|
|
119
|
+
"test": "CRTR_NO_DAEMON_AUTOSTART=1 node scripts/test-lane.mjs -- node --conditions=crtr-src --import tsx/esm --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.max(4, require(`node:os`).availableParallelism() - 1)') --test-timeout=10000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'src/**/__tests__/*.test.ts'",
|
|
120
|
+
"test:integration": "npm run build:sdk && CRTR_NO_DAEMON_AUTOSTART=1 node scripts/test-lane.mjs -- node --conditions=crtr-src --import tsx/esm --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(8, Math.max(2, require(`node:os`).availableParallelism() - 1))') --test-timeout=60000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'src/**/__tests__/integration/*.test.ts' 'packages/crouter-sdk/src/**/__tests__/integration/*.test.ts' 'packages/crouter-plugin/src/**/__tests__/integration/*.test.ts'",
|
|
121
121
|
"test:seam": "npm run build && npm run test:seam:built",
|
|
122
122
|
"test:sdk": "npm run build:api && npm run build:identity && node --conditions=crtr-src --import tsx/esm --test --test-timeout=60000 'packages/crouter-sdk/src/__tests__/*.test.ts' 'packages/crouter-sdk/src/__tests__/integration/*.test.ts'",
|
|
123
123
|
"test:sdk:pg": "node -e \"if (!process.env.TEST_DATABASE_URL) { console.error('test:sdk:pg needs TEST_DATABASE_URL (a disposable PostgreSQL), e.g. docker run --rm -d -e POSTGRES_PASSWORD=pw -p 127.0.0.1:55432:5432 postgres:18-alpine; TEST_DATABASE_URL=postgres://postgres:pw@127.0.0.1:55432/postgres'); process.exit(1) }\" && node --conditions=crtr-src --import tsx/esm --test --test-timeout=60000 'packages/crouter-sdk/src/**/__tests__/**/*.pg.test.ts'",
|
|
124
|
-
"test:seam:built": "CRTR_NO_DAEMON_AUTOSTART=1 node --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(4, Math.max(2, require(`node:os`).availableParallelism() - 2))') --test-timeout=180000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'dist/**/__tests__/seam/*.test.js'",
|
|
124
|
+
"test:seam:built": "CRTR_NO_DAEMON_AUTOSTART=1 node scripts/test-lane.mjs -- node --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(4, Math.max(2, require(`node:os`).availableParallelism() - 2))') --test-timeout=180000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'dist/**/__tests__/seam/*.test.js'",
|
|
125
125
|
"test:all": "npm test && npm run test:integration && npm run test:seam",
|
|
126
126
|
"test:isolated": "node scripts/test-isolated.mjs",
|
|
127
127
|
"build:identity": "tsc -p packages/crouter-identity/tsconfig.json"
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
},
|
|
141
141
|
"license": "UNLICENSED",
|
|
142
142
|
"dependencies": {
|
|
143
|
-
"@north-light/identity": "0.3.
|
|
143
|
+
"@north-light/identity": "0.3.533",
|
|
144
144
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
145
145
|
"@earendil-works/pi-ai": "1.1.0",
|
|
146
146
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
@@ -155,6 +155,7 @@
|
|
|
155
155
|
"esbuild": "^0.27.7",
|
|
156
156
|
"jose": "^6.2.12",
|
|
157
157
|
"marked": "18.0.11",
|
|
158
|
+
"pg": "^8.23.1",
|
|
158
159
|
"proper-lockfile": "4.1.2",
|
|
159
160
|
"remark-gfm": "^4.0.1",
|
|
160
161
|
"remark-parse": "^11.0.0",
|
|
@@ -173,7 +174,6 @@
|
|
|
173
174
|
"@types/proper-lockfile": "^4.1.4",
|
|
174
175
|
"@types/ws": "^8.18.1",
|
|
175
176
|
"mermaid": "11.17.2",
|
|
176
|
-
"pg": "^8.23.1",
|
|
177
177
|
"tsx": "^4.0.0"
|
|
178
178
|
}
|
|
179
179
|
}
|