@north-light/cli 0.3.579 → 0.3.581
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 -1
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/execution-start.d.ts +14 -0
- package/dist/api/dto/health.d.ts +20 -0
- package/dist/api/dto/imports.d.ts +142 -0
- package/dist/api/dto/imports.js +0 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +2 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +2 -2
- package/dist/clients/attach/session/connection.d.ts +3 -1
- package/dist/clients/attach/session/connection.js +1 -1
- package/dist/clients/attach/viewer.js +510 -510
- package/dist/commands/api-client.d.ts +7 -4
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/sys/daemon.js +1 -1
- package/dist/commands/sys/import/resume.d.ts +1 -0
- package/dist/commands/sys/import/resume.js +1 -0
- package/dist/commands/sys/import/start.d.ts +5 -0
- package/dist/commands/sys/import/start.js +4 -0
- package/dist/commands/sys/join.d.ts +2 -0
- package/dist/commands/sys/join.js +1 -1
- package/dist/commands/sys/machine/rotate.d.ts +1 -0
- package/dist/commands/sys/machine/rotate.js +1 -0
- package/dist/commands/sys/signin.d.ts +7 -0
- package/dist/commands/sys/signin.js +2 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/blobs/r2.d.ts +4 -0
- package/dist/core/blobs/r2.js +7 -4
- package/dist/core/canvas/daemon-owner.d.ts +1 -1
- package/dist/core/canvas/executions.d.ts +1 -1
- package/dist/core/canvas/export-sqlite.js +1 -1
- package/dist/core/canvas/node-tokens.d.ts +2 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/schema-pg/009-bodies.sql +10 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/directory/person-credential.d.ts +36 -0
- package/dist/core/directory/person-credential.js +1 -0
- package/dist/core/feed/feed.js +3 -3
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/graph/access.d.ts +1 -1
- package/dist/core/graph/bodies-boot-copy.d.ts +14 -0
- package/dist/core/graph/bodies-boot-copy.js +1 -0
- package/dist/core/graph/bodies.d.ts +13 -6
- package/dist/core/graph/bodies.js +1 -1
- package/dist/core/graph/deletion.d.ts +4 -1
- package/dist/core/graph/deletion.js +3 -3
- package/dist/core/graph/documents.d.ts +4 -0
- package/dist/core/graph/documents.js +10 -10
- package/dist/core/graph/objects.js +11 -11
- package/dist/core/graph/package-docs.js +5 -5
- package/dist/core/graph/reader.js +2 -2
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/ref-format.d.ts +0 -1
- package/dist/core/graph/repo-sync/ref-format.js +2 -2
- package/dist/core/import/bundle/blob-keys.d.ts +10 -0
- package/dist/core/import/bundle/blob-keys.js +1 -0
- package/dist/core/import/bundle/layout.d.ts +89 -0
- package/dist/core/import/bundle/layout.js +5 -0
- package/dist/core/import/export/archive.d.ts +11 -0
- package/dist/core/import/export/archive.js +1 -0
- package/dist/core/import/export/cloud.d.ts +21 -0
- package/dist/core/import/export/cloud.js +1 -0
- package/dist/core/import/export/dump.d.ts +34 -0
- package/dist/core/import/export/dump.js +3 -0
- package/dist/core/import/export/files.d.ts +22 -0
- package/dist/core/import/export/files.js +1 -0
- package/dist/core/import/export/inline.d.ts +3 -0
- package/dist/core/import/export/inline.js +1 -0
- package/dist/core/import/export/source.d.ts +2 -0
- package/dist/core/import/export/source.js +1 -0
- package/dist/core/import/export/stores.d.ts +9 -0
- package/dist/core/import/export/stores.js +1 -0
- package/dist/core/import/load/bind.d.ts +19 -0
- package/dist/core/import/load/bind.js +15 -0
- package/dist/core/import/load/blobs.d.ts +10 -0
- package/dist/core/import/load/blobs.js +1 -0
- package/dist/core/import/load/catalog.d.ts +32 -0
- package/dist/core/import/load/catalog.js +9 -0
- package/dist/core/import/load/copy.d.ts +26 -0
- package/dist/core/import/load/copy.js +6 -0
- package/dist/core/import/load/path-map.d.ts +7 -0
- package/dist/core/import/load/path-map.js +1 -0
- package/dist/core/import/load/prepare.d.ts +37 -0
- package/dist/core/import/load/prepare.js +10 -0
- package/dist/core/import/load/rewrite.d.ts +39 -0
- package/dist/core/import/load/rewrite.js +9 -0
- package/dist/core/import/load/rollback.d.ts +3 -0
- package/dist/core/import/load/rollback.js +6 -0
- package/dist/core/import/load/run.d.ts +22 -0
- package/dist/core/import/load/run.js +3 -0
- package/dist/core/import/load/stage.d.ts +15 -0
- package/dist/core/import/load/stage.js +1 -0
- package/dist/core/import/load/stores.d.ts +24 -0
- package/dist/core/import/load/stores.js +2 -0
- package/dist/core/import/load/verify.d.ts +4 -0
- package/dist/core/import/load/verify.js +11 -0
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/revive.d.ts +5 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/roadmap.js +3 -3
- package/dist/core/runtime/runner/blaxel/runner.js +3 -3
- package/dist/core/runtime/runner/index.d.ts +1 -0
- package/dist/core/runtime/runner/index.js +1 -1
- package/dist/core/runtime/runner/machine/call.d.ts +8 -0
- package/dist/core/runtime/runner/machine/call.js +3 -0
- package/dist/core/runtime/runner/machine/environment.d.ts +1 -0
- package/dist/core/runtime/runner/machine/environment.js +1 -0
- package/dist/core/runtime/runner/machine/executor.d.ts +23 -0
- package/dist/core/runtime/runner/machine/executor.js +1 -0
- package/dist/core/runtime/runner/machine/machine-executor.test.d.ts +1 -0
- package/dist/core/runtime/runner/machine/machine-executor.test.js +4 -0
- package/dist/core/runtime/runner/machine/ops.d.ts +127 -0
- package/dist/core/runtime/runner/machine/ops.js +1 -0
- package/dist/core/runtime/runner/machine/runner.d.ts +12 -0
- package/dist/core/runtime/runner/machine/runner.js +1 -0
- package/dist/core/runtime/runner/types.d.ts +7 -1
- package/dist/core/runtime/warm-pool.d.ts +2 -0
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/secrets/env-rows.d.ts +1 -0
- package/dist/core/secrets/env-rows.js +1 -1
- package/dist/core/storage/purge.d.ts +6 -0
- package/dist/core/storage/purge.js +4 -0
- package/dist/core/subscription-state.d.ts +1 -0
- package/dist/core/subscription-state.js +1 -1
- package/dist/core/substrate/delivery/corpus.d.ts +2 -0
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +3 -3
- package/dist/core/substrate/delivery/render-boot.js +25 -25
- package/dist/core/substrate/delivery/render-event.d.ts +1 -1
- package/dist/core/substrate/delivery/render-event.js +4 -4
- package/dist/core/substrate/delivery/types.d.ts +2 -2
- package/dist/daemon/api/bridge.js +3 -3
- package/dist/daemon/api/document-listener.js +4 -4
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/execution-start.js +2 -2
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/imports.d.ts +2 -0
- package/dist/daemon/api/handlers/imports.js +1 -0
- package/dist/daemon/api/handlers/machine-credential.d.ts +2 -0
- package/dist/daemon/api/handlers/machine-credential.js +1 -0
- package/dist/daemon/api/handlers/memory.js +4 -4
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/reports.js +4 -4
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/import-auth.d.ts +6 -0
- package/dist/daemon/api/import-auth.js +1 -0
- package/dist/daemon/api/operations.d.ts +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +7 -1
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/boot-migrations.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +3 -2
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/cron/armed-context.d.ts +1 -0
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/closed.d.ts +31 -0
- package/dist/daemon/cron/closed.js +1 -0
- package/dist/daemon/cron/ended.js +2 -2
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/machine-exec.d.ts +5 -0
- package/dist/daemon/cron/machine-exec.js +1 -0
- package/dist/daemon/cron/machine-fire.d.ts +26 -0
- package/dist/daemon/cron/machine-fire.js +1 -0
- package/dist/daemon/cron/recurrence.d.ts +14 -0
- package/dist/daemon/cron/recurrence.js +1 -0
- package/dist/daemon/cron/run-token.d.ts +7 -0
- package/dist/daemon/cron/run-token.js +1 -0
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +2 -2
- package/dist/daemon/crtrd.js +10 -10
- package/dist/daemon/drain.d.ts +25 -0
- package/dist/daemon/drain.js +9 -0
- package/dist/daemon/due-sources.d.ts +1 -1
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.js +8 -8
- package/dist/daemon/fleet.js +5 -5
- package/dist/daemon/import-dump-run.d.ts +1 -0
- package/dist/daemon/import-dump-run.js +5 -0
- package/dist/daemon/machine-daemon.d.ts +7 -0
- package/dist/daemon/machine-daemon.js +1 -0
- package/dist/daemon/machine-link/client.d.ts +29 -0
- package/dist/daemon/machine-link/client.js +1 -0
- package/dist/daemon/machine-link/config.d.ts +14 -0
- package/dist/daemon/machine-link/config.js +3 -0
- package/dist/daemon/machine-link/credential.d.ts +7 -0
- package/dist/daemon/machine-link/credential.js +2 -0
- package/dist/daemon/machine-link/forward.d.ts +16 -0
- package/dist/daemon/machine-link/forward.js +1 -0
- package/dist/daemon/machine-link/frames.d.ts +49 -0
- package/dist/daemon/machine-link/frames.js +1 -0
- package/dist/daemon/machine-link/holder.d.ts +73 -0
- package/dist/daemon/machine-link/holder.js +9 -0
- package/dist/daemon/manage.d.ts +19 -3
- package/dist/daemon/manage.js +3 -3
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/import-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/import-lane.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +3 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/purge-due-work.d.ts +13 -0
- package/dist/daemon/reconcilers/purge-due-work.js +1 -0
- package/dist/daemon/reconcilers/row-claim.d.ts +1 -0
- package/dist/daemon/reconcilers/row-claim.js +2 -2
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/runs/observer.js +3 -3
- package/dist/migrations/004-canvas-documents/apply.d.ts +2 -4
- package/dist/migrations/004-canvas-documents/apply.js +1 -1
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/sandbox-start.mjs +185 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var j=Object.defineProperty;var d=(n,e)=>j(n,"name",{value:e,configurable:!0});import{substitutePerson as S}from"../../canvas/person.js";import{withCanvasWrite as h}from"../../canvas/db.js";import{ImportLaneError as $}from"./stage.js";import{q as u}from"./catalog.js";const w=[["rules","owner"],["messages","object_id"],["messages","actor_id"],["custom_objects","registered_by"],["nodes","app"],["nodes","profile_id"],["revisions","acting_app"],["relations","resource_id"],["relations","subject_id"],["crons","profile"],["profiles","environment_id"]],I=[["nodes","grant_id"],["crons","grant_id"]],L={identities:"object",documents:"object",jobs:"object",custom_objects:"object",context_sessions:"node",rules:"object"},M=["app","person","profile","repo"];function D(n){const e=new Map,E=d((i,o)=>{e.has(i)||e.set(i,new Set),e.get(i).add(o)},"add");for(const i of n.foreignKeys)i.parent==="objects"&&i.columns.length===1&&E(i.table,i.columns[0]);for(const[i,o]of w)E(i,o);return e}d(D,"objectIdColumns");const T=d((n,e)=>`${u(n)}.${u(e)}`,"sq"),p=d(async(n,e,...E)=>Number((await n.prepareUncached(e).run(...E)).changes),"run"),f=d(async(n,e,...E)=>await n.prepareUncached(e).all(...E),"rows");async function U(n){n.sourcePerson!==n.targetPerson&&await h(async e=>{await e.exec(`SET LOCAL search_path TO ${u(n.schema)}`),await S(e,n.sourcePerson,n.targetPerson)})}d(U,"rewritePerson");async function A(n,e,E,i,o){return E===null?void 0:(await n.prepareUncached(`SELECT id FROM ${T(e,"grants")} WHERE runtime = ? AND sub = ? AND grantee = ?`).get(E,i,o))?.id}d(A,"findFleetGrant");function C(n){return new $("id_map","grant_missing",`no grant in the target for: ${n.slice(0,10).join(", ")}; approve the app, then rerun`,{grantees:[...n]})}d(C,"grantMissing");async function x(n){const{db:e,schema:E,target:i}=n,o=d(t=>T(E,t),"S"),r=d(t=>T(i,t),"T"),m={object:new Map,grant:new Map,kind:new Map},N=n.targetPerson.replace(/^user:/,"");for(const t of M){const c=t==="person"?"t.external_id = ?":t==="app"?"?::text IS NOT NULL":`EXISTS (SELECT 1 FROM ${r("relations")} r WHERE r.resource_type = 'crtr/object' AND r.resource_id = tobj.id AND r.relation = 'acts_for' AND r.subject_type = 'user' AND r.subject_id = ?)`,b=await f(e,`SELECT i.object AS src, t.object AS dst FROM ${o("identities")} i
|
|
2
|
+
JOIN ${o("objects")} so ON so.id = i.object AND so.type = ?
|
|
3
|
+
JOIN ${r("identities")} t ON t.scheme = i.scheme AND t.external_id = i.external_id
|
|
4
|
+
JOIN ${r("objects")} tobj ON tobj.id = t.object AND tobj.type = so.type
|
|
5
|
+
WHERE ${c}`,t,t==="person"?n.targetPerson:N);for(const{src:R,dst:_}of b)R!==_&&m.object.set(R,_)}const O=await f(e,`SELECT o.id, o.owner, o.name FROM ${o("objects")} o JOIN ${o("documents")} d ON d.object = o.id WHERE d.source_path IS NOT NULL`);for(const t of O){const c=await e.prepareUncached(`SELECT o.id FROM ${r("objects")} o JOIN ${r("documents")} d ON d.object = o.id
|
|
6
|
+
WHERE o.owner = ? AND o.name = ? AND o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).get(m.object.get(t.owner)??t.owner,t.name);if(c!==void 0){m.object.set(t.id,c.id);continue}const b=n.shippedBodies[t.id];if(b===void 0)throw new $("id_map","bundle_invalid",`shipped document ${t.name} (${t.id}) has no counterpart in the target and source.json has no body for it`);await p(e,`UPDATE ${o("documents")} SET source_path = NULL WHERE object = ?`,t.id),await p(e,`UPDATE ${o("revisions")} r SET body_hash = ? WHERE r.document = ? AND NOT EXISTS (SELECT 1 FROM ${o("revision_parents")} p WHERE p.parent = r.rev_id)`,b,t.id)}const s=await f(e,`SELECT id, sub, grantee FROM ${o("grants")} ORDER BY id`),a=[];for(const t of s){const c=await A(e,i,n.fleetRuntime,t.sub,t.grantee);c===void 0?a.push(t.grantee):m.grant.set(t.id,c)}if(a.length>0)throw C(a);await e.exec(`CREATE TABLE ${o("_idmap")} (kind text NOT NULL, source text NOT NULL, target text NOT NULL, PRIMARY KEY (kind, source))`);for(const[t,c]of[["object",m.object],["grant",m.grant]])for(const[b,R]of c)await p(e,`INSERT INTO ${o("_idmap")} (kind, source, target) VALUES (?, ?, ?)`,t,b,R);const l=`(SELECT source FROM ${o("_idmap")} WHERE kind = 'object')`;for(const[t,c]of Object.entries(L))await p(e,`DELETE FROM ${o(t)} WHERE ${c} IN ${l}`);await p(e,`DELETE FROM ${o("revision_parents")} WHERE child IN (SELECT rev_id FROM ${o("revisions")} WHERE document IN ${l})`),await p(e,`DELETE FROM ${o("revisions")} WHERE document IN ${l}`);for(const[t,c]of D(n.catalog))if(n.catalog.tables.has(t))for(const b of c)await g(e,o(t),b,"object",o("_idmap"));for(const[t,c]of I)await g(e,o(t),c,"grant",o("_idmap"));await p(e,`UPDATE ${o("daemon_actions")} d SET adapter_json = jsonb_set(d.adapter_json::jsonb, '{principal,grant_id}', to_jsonb(m.target))::text
|
|
7
|
+
FROM ${o("_idmap")} m WHERE m.kind = 'grant' AND d.adapter_json::jsonb ->> 'adapter' = 'cron_spawn' AND d.adapter_json::jsonb #>> '{principal,grant_id}' = m.source`),await p(e,`DELETE FROM ${o("objects")} WHERE id IN ${l}`);for(const{name:t}of await f(e,`SELECT k.name FROM ${o("object_kinds")} k WHERE EXISTS (SELECT 1 FROM ${r("object_kinds")} t WHERE t.name = k.name)`))m.kind.set(t,t);return await p(e,`DELETE FROM ${o("object_kinds")} k WHERE EXISTS (SELECT 1 FROM ${r("object_kinds")} t WHERE t.name = k.name)`),m}d(x,"rewriteIds");async function g(n,e,E,i,o){await p(n,`UPDATE ${e} t SET ${u(E)} = m.target FROM ${o} m WHERE m.kind = ? AND t.${u(E)} = m.source`,i)}d(g,"remap");async function v(n){const{db:e,schema:E,target:i,catalog:o}=n,r=d(s=>T(E,s),"S"),m={},N=d((s,a)=>{a>0&&(m[s]=(m[s]??0)+a)},"count");await e.exec(`CREATE TABLE ${r("_dropped")} (tbl text NOT NULL, key text NOT NULL, PRIMARY KEY (tbl, key))`);const O=`(SELECT id FROM ${r("objects")} WHERE home_machine IS NOT NULL)`;await p(e,`INSERT INTO ${r("_dropped")} SELECT 'objects', id FROM ${r("objects")} WHERE home_machine IS NOT NULL`);for(const[s,a]of Object.entries(L))N(s,await p(e,`DELETE FROM ${r(s)} WHERE ${a} IN ${O}`));for(N("objects",await p(e,`DELETE FROM ${r("objects")} WHERE home_machine IS NOT NULL`));;){let s=0;for(const a of o.foreignKeys){if(a.columns.length!==1||a.parentColumns.length!==1||!n.catalog.tables.has(a.table))continue;const l=o.tables.get(a.table),t=u(a.columns[0]),c=l.primaryKey.length===1?u(l.primaryKey[0]):null;c!==null&&await p(e,`INSERT INTO ${r("_dropped")} SELECT ?, ${c}::text FROM ${r(a.table)} WHERE ${t} IN (SELECT key FROM ${r("_dropped")} WHERE tbl = ?) ON CONFLICT DO NOTHING`,a.table,a.parent);const b=await p(e,`DELETE FROM ${r(a.table)} WHERE ${t} IN (SELECT key FROM ${r("_dropped")} WHERE tbl = ?)`,a.parent);N(a.table,b),s+=b}if(s===0)break}for(const s of o.foreignKeys){if(s.columns.length!==1||!o.tables.has(s.table))continue;const a=u(s.columns[0]),l=u(s.parentColumns[0]),t=await f(e,`SELECT DISTINCT c.${a}::text AS value FROM ${r(s.table)} c
|
|
8
|
+
WHERE c.${a} IS NOT NULL AND NOT EXISTS (SELECT 1 FROM ${r(s.parent)} p WHERE p.${l} = c.${a})
|
|
9
|
+
AND NOT EXISTS (SELECT 1 FROM ${T(i,s.parent)} p WHERE p.${l} = c.${a}) LIMIT 10`);if(t.length>0)throw new $("drop","bundle_invalid",`${s.table}.${s.columns[0]} names rows that exist nowhere: ${t.map(c=>c.value).join(", ")}`,{table:s.table,column:s.columns[0],values:t.map(c=>c.value)})}return m}d(v,"dropStubRows");export{w as OBJECT_ID_COLUMNS,v as dropStubRows,A as findFleetGrant,C as grantMissing,D as objectIdColumns,x as rewriteIds,U as rewritePerson};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var y=Object.defineProperty;var m=(n,l)=>y(n,"name",{value:l,configurable:!0});import{openDb as C,withCanvasWrite as D}from"../../canvas/db.js";import{bundleKeys as A}from"../bundle/layout.js";import{q as r,readCatalog as $,rowKey as T,topologicalOrder as h}from"./catalog.js";import{decodeKeys as M}from"./copy.js";import{OBJECT_ID_COLUMNS as W}from"./rewrite.js";import{targetSchema as g}from"./stage.js";class O extends Error{static{m(this,"Refused")}}async function B(n,l){const _=await C(),c=await _.prepare("SELECT source_install_id, source_kind, state, created_at FROM import_runs WHERE run_id = ?").get(n);if(c===void 0)throw new Error(`no import run ${n}`);if(c.state!=="done"&&c.state!=="committed"&&c.state!=="failed")throw new Error(`import run ${n} is ${c.state}, not rollbackable`);const N=(await _.prepare("SELECT blob_key FROM import_node_files WHERE blob_key LIKE ?").all(`imports/${n}/node-files/%`)).map(t=>t.blob_key),E={run_id:n,rolled_back:!1,dependents:{},deleted:{}};try{await D(async t=>{const i=await g(t),L=(await t.prepareUncached("SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND table_type = 'BASE TABLE'").all(i)).map(e=>e.table_name),d=await $(t,i,L);d.tables.get("env_vars").primaryKey=["person","owner_kind","owner_id","name"],await t.exec("CREATE TEMP TABLE _rb (tbl text NOT NULL, k jsonb NOT NULL) ON COMMIT DROP");const R=await t.prepare("SELECT table_name, inserted_keys FROM import_manifest WHERE run_id = ?").all(n);for(const{table_name:e,inserted_keys:o}of R){const a=M(o);for(let s=0;s<a.length;s+=5e3)await t.prepare("INSERT INTO _rb SELECT ?, e FROM jsonb_array_elements(?::jsonb) e").run(e,JSON.stringify(a.slice(s,s+5e3)))}const b=new Set(R.map(e=>e.table_name)),u=m((e,o,a)=>`jsonb_build_array(${o.map(s=>`${a}.${r(s)}::text`).join(", ")})`,"keyOf");for(const e of d.foreignKeys){const o=d.tables.get(e.parent),a=d.tables.get(e.table);if(e.table==="import_node_files"||!b.has(e.parent)||o===void 0||a===void 0||e.parentColumns.join()!==o.primaryKey.join())continue;const s=b.has(e.table)?`AND NOT EXISTS (SELECT 1 FROM _rb o WHERE o.tbl = '${e.table}' AND o.k = ${u(e.table,T(a),"c")})`:"",p=Number((await t.prepareUncached(`SELECT count(*) AS n FROM ${r(i)}.${r(e.table)} c WHERE ${e.columns.map(k=>`c.${r(k)} IS NOT NULL`).join(" AND ")}
|
|
2
|
+
AND ${u(e.parent,e.columns,"c")} IN (SELECT k FROM _rb WHERE tbl = '${e.parent}') ${s}`).get()).n);p>0&&(E.dependents[e.table]=(E.dependents[e.table]??0)+p)}for(const[e,o]of W){const a=d.tables.get(e);if(a===void 0||!a.columns.includes(o)||a.primaryKey.length===0)continue;const s=b.has(e)?`AND NOT EXISTS (SELECT 1 FROM _rb o WHERE o.tbl = '${e}' AND o.k = ${u(e,a.primaryKey,"c")})`:"",p=Number((await t.prepareUncached(`SELECT count(*) AS n FROM ${r(i)}.${r(e)} c WHERE c.${r(o)} IN (SELECT k ->> 0 FROM _rb WHERE tbl = 'objects') ${s}`).get()).n);p>0&&(E.dependents[`${e}.${o}`]=p)}const f=Number((await t.prepare("SELECT count(*) AS n FROM import_runs WHERE source_install_id = ? AND run_id <> ? AND created_at > ? AND (state IN ('loading', 'committed', 'done') OR (state = 'failed' AND committed_at IS NOT NULL))").get(c.source_install_id,n,c.created_at)).n);f>0&&(E.dependents.import_runs=f);const S=Number((await t.prepare("SELECT count(*) AS n FROM import_id_map m WHERE m.run_id <> ? AND m.kind = 'object' AND m.target_value IN (SELECT k ->> 0 FROM _rb WHERE tbl = 'objects')").get(n)).n);if(S>0&&(E.dependents.import_id_map=S),Object.keys(E.dependents).length>0)throw new O;const w=(await t.prepareUncached(`SELECT DISTINCT r.document FROM ${r(i)}.revisions r WHERE jsonb_build_array(r.rev_id) IN (SELECT k FROM _rb WHERE tbl = 'revisions')
|
|
3
|
+
AND NOT EXISTS (SELECT 1 FROM _rb o WHERE o.tbl = 'objects' AND o.k = jsonb_build_array(r.document))`).all()).map(e=>e.document);for(const e of h(d,[...b]).reverse()){const o=d.tables.get(e);if(o===void 0)continue;const a=await t.prepareUncached(`DELETE FROM ${r(i)}.${r(e)} t WHERE ${u(e,T(o),"t")} IN (SELECT k FROM _rb WHERE tbl = '${e}')`).run();E.deleted[e]=a.changes}for(const e of w)await t.prepareUncached(`UPDATE ${r(i)}.documents d SET
|
|
4
|
+
heads_key = COALESCE((SELECT string_agg(r.rev_id, ',' ORDER BY r.rev_id) FROM ${r(i)}.revisions r WHERE r.document = d.object AND NOT EXISTS (SELECT 1 FROM ${r(i)}.revision_parents p WHERE p.parent = r.rev_id)), ''),
|
|
5
|
+
revision = COALESCE((SELECT max(r.number) FROM ${r(i)}.revisions r WHERE r.document = d.object AND NOT EXISTS (SELECT 1 FROM ${r(i)}.revision_parents p WHERE p.parent = r.rev_id)), 0)
|
|
6
|
+
WHERE d.object = ?`).run(e);await t.prepareUncached("DELETE FROM import_key_map km WHERE km.source_install_id = ? AND EXISTS (SELECT 1 FROM _rb r WHERE r.tbl = km.table_name AND r.k = jsonb_build_array(km.target_key))").run(c.source_install_id),await t.prepare("DELETE FROM import_id_map WHERE run_id = ?").run(n),await t.prepare("DELETE FROM import_manifest WHERE run_id = ?").run(n),await t.prepare("UPDATE import_runs SET state = 'rolled_back', step = 'rolled_back', finished_at = ? WHERE run_id = ?").run(new Date().toISOString(),n),await F(t,c)})}catch(t){if(t instanceof O)return E;throw t}await l.delete(A.manifest(n));for(const t of N)await l.delete(t);return E.rolled_back=!0,E}m(B,"rollbackRun");async function F(n,l){if(l.source_kind!=="machine")return;const _=await n.prepare("SELECT object FROM environments WHERE machine_id = ? AND kind = 'machine'").get(l.source_install_id);_!==void 0&&await n.prepare("UPDATE machine_credentials SET revoked_at = ? WHERE environment = ? AND revoked_at IS NULL").run(new Date().toISOString(),_.object)}m(F,"revokeFor");export{B as rollbackRun};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type BlobStore } from '../../blobs/index.js';
|
|
2
|
+
import { type RowClaim } from '../../../daemon/reconcilers/row-claim.js';
|
|
3
|
+
export interface RunRow {
|
|
4
|
+
run_id: string;
|
|
5
|
+
source_install_id: string;
|
|
6
|
+
source_kind: 'machine' | 'hosted';
|
|
7
|
+
person: string;
|
|
8
|
+
release: string;
|
|
9
|
+
state: string;
|
|
10
|
+
loaded_at?: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface RunOptions {
|
|
13
|
+
blobs?: BlobStore;
|
|
14
|
+
/** The control plane's fleet runtime principal, the key of the directory's grants (`CRTR_RUNTIME`). */
|
|
15
|
+
fleetRuntime?: string | null;
|
|
16
|
+
/** Test hook: called when a step is reached, before it runs. A throw there is that step failing. */
|
|
17
|
+
atStep?: (step: string) => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/** How long a loading run waits for the directory to copy the person's grants onto the fleet runtime before it fails `grant_missing` (design-import-fleet-grants G10). */
|
|
20
|
+
export declare const GRANT_WAIT_MS: number;
|
|
21
|
+
/** Process one claimed run. Never throws: the outcome is the row's state. */
|
|
22
|
+
export declare function processRun(row: RunRow, claim: RowClaim, options?: RunOptions): Promise<void>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var J=Object.defineProperty;var u=(e,s)=>J(e,"name",{value:s,configurable:!0});import{zstdCompressSync as q}from"node:zlib";import{blobStore as G}from"../../blobs/index.js";import{openDb as E,withCanvasWrite as $}from"../../canvas/db.js";import{insertImportedRevisions as z}from"../../graph/documents.js";import{getById as Q}from"../../graph/objects.js";import{bundleKeys as y,decodeRows as V,rowKeys as Y,SEQ_TABLES as X}from"../bundle/layout.js";import{readCatalog as Z}from"./catalog.js";import{copyRows as x,decodeKeys as I,encodeKeys as A}from"./copy.js";import{pruneStaged as ee,precheck as te,renameClashingProfiles as ae,rewritePaths as ne,rewriteRequestPaths as ie,takeRepoSyncedDocuments as se}from"./prepare.js";import{boundSub as re,checkSourcePerson as oe,checkStagedBlobKeys as de,checkStagedPersons as ce,checkStagedReferences as pe,checkStagedRequestKeys as ue}from"./bind.js";import{deleteRunBlobs as fe,moveRunBlobs as me}from"./blobs.js";import{dropStubRows as le,findFleetGrant as _e,grantMissing as we,rewriteIds as ge,rewritePerson as be}from"./rewrite.js";import{dropStaging as M,ImportLaneError as g,stage as he,stagingSchema as Ee,targetSchema as ye}from"./stage.js";import{verifyRun as Se}from"./verify.js";import{sandboxPathMap as ve,writeNodeFiles as Re}from"./path-map.js";import{allStoreKeys as Oe,writeStores as Te}from"./stores.js";import{COPIED_TABLES as ke}from"../bundle/layout.js";import{ClaimLostError as Pe}from"../../../daemon/reconcilers/row-claim.js";const je=10*6e4,S=u(()=>new Date().toISOString(),"now"),N=u(async(e,s)=>{await(await E()).prepare("UPDATE import_runs SET step = ? WHERE run_id = ?").run(s,e)},"setStep");async function De(e,s){const n=await e.get(y.source(s));if(n===null)throw new g("stage","bundle_invalid","source.json is missing");return JSON.parse(n.toString("utf8"))}u(De,"readSource");async function Ie(e,s,n,r,i,d){const a=await e.get(y.rows(n.run_id,"grants")),f=a===null?[]:V(a),m=[];for(const t of f){const c=re(t.sub,r,n.person,"grants.sub");await _e(s,i,d,c,t.grantee)===void 0&&m.push(t.grantee)}if(m.length===0)return!0;if(n.loaded_at===void 0||n.loaded_at===null)throw new g("stage","import_failed","a loading run has no loaded_at");if(Date.now()-Date.parse(n.loaded_at)>=je)throw we(m);return!1}u(Ie,"grantsReady");async function tt(e,s,n={}){const r=n.blobs??await G(),i=await E(),d=Ee(e.run_id),a=u(async t=>{await s.assertOwned(),await N(e.run_id,t),await n.atStep?.(t)},"at");let f=e.state==="committed";const m=[];try{const t=await De(r,e.run_id);if(e.source_kind==="machine"&&t.installId!==e.source_install_id)throw new g("stage","bundle_invalid",`source.json names install ${t.installId}, the run is for ${e.source_install_id}`);t.installId=e.source_install_id;const c=await ye(i),b=[...ke],w=await Z(i,c,[...b,"grants"]);if(!f){const l={},O=[],T=n.fleetRuntime??process.env.CRTR_RUNTIME??null;if(await oe(i,c,t.person,e.person),!await Ie(r,i,e,t.person,c,T)){await s.assertOwned(),await N(e.run_id,"waiting_for_grants");return}await a("stage");const W=await he(i,e.run_id,t.counts,o=>Y(e.run_id,o,t),o=>r.get(o));for(const[o,p]of Object.entries(W))l[o]={staged:p,inserted:0,mapped:0,dropped:0};const _={db:i,schema:d,target:c,catalog:w,sourcePerson:t.person,targetPerson:e.person,fleetRuntime:T,shippedBodies:t.shippedBodies??{}};await a("bind-staged");for(const[o,p]of Object.entries(await ce(_)))v(l,o,p);await de(_),await a("rewrite-person"),await be(_),await a("prune");const B=await ee(i,d,w,t),k=t.kind==="hosted"?ve(t.pathPrefixes??[]):[];await a("rewrite-paths"),await ne(i,d,k),await ie(i,d),await ue(_),await ae(i,d,c,t.installId,e.person),await a("rewrite-ids");const P=await ge(_);await a("drop");const L=await se(i,d,c),H=await le(_);for(const[o,p]of Object.entries({...B}))v(l,o,p);for(const[o,p]of Object.entries(H))v(l,o,p);await pe(_),await a("pre-check");const K=new Map([["messages",["seq"]],...X.map(o=>[o,["seq"]])]);await te(i,d,c,w,b,new Set,K),await a("blobs"),await me(i,d,r,e.run_id,m),await a("copy"),await $(async o=>{await s.assertOwned();const p=await x({db:o,runId:e.run_id,schema:d,target:c,catalog:w,source:t,person:e.person,idMap:P,pathMap:k}),j=await Ne(o,e.run_id,L);j>0&&(p.inserted.revisions=(p.inserted.revisions??0)+j),await Re(o,d,e.run_id,t);const D=await Te({db:o,blobs:r,runId:e.run_id,person:e.person,objectMap:P.object});for(const[U,F]of Object.entries(D.inserted))p.inserted[U]=F.length;return O.push(...D.unresolvedPlugins),await o.prepare("UPDATE import_runs SET counts_json = ?, loaded_at = COALESCE(loaded_at, ?) WHERE run_id = ?").run(JSON.stringify({...Me(l,p),unresolved_plugins:O}),S(),e.run_id),p}),f=!0,await n.atStep?.("committed")}await a("verify");const h=await Se(i,e.run_id,d,c,w,t.installId);if(await i.prepare("UPDATE import_runs SET verify_json = ? WHERE run_id = ?").run(JSON.stringify(h),e.run_id),!h.ok)throw new g("verify","verify_failed","the committed rows differ from the staged rows or an invariant failed",{differences:h.differences,invariants:h.invariants});await a("manifest");const R=y.manifest(e.run_id);await r.put(R,await Ce(e.run_id)),await M(i,e.run_id);for(const l of Oe(e.run_id))await r.delete(l);await fe(r,e.run_id),await i.prepare("UPDATE import_runs SET state = 'done', step = 'done', manifest_key = ?, finished_at = ? WHERE run_id = ?").run(R,S(),e.run_id)}catch(t){if(t instanceof Pe)throw t;const c=Ae(t);if(await M(i,e.run_id).catch(()=>{}),!f)for(const b of m)await r.delete(b).catch(()=>{});await i.prepare("UPDATE import_runs SET state = 'failed', failure_json = ?, finished_at = ? WHERE run_id = ?").run(JSON.stringify(c),S(),e.run_id)}}u(tt,"processRun");function Ae(e){if(e instanceof g)return{step:e.step,code:e.code,message:e.message,...e.detail===void 0?{}:{detail:e.detail}};const s=e.code;return{step:"unknown",code:typeof s=="string"?s:"import_failed",message:e instanceof Error?e.message:String(e)}}u(Ae,"failureOf");function v(e,s,n){(e[s]??={staged:0,inserted:0,mapped:0,dropped:0}).dropped+=n}u(v,"addDropped");function Me(e,s){for(const[n,r]of Object.entries(s.inserted))(e[n]??={staged:0,inserted:0,mapped:0,dropped:0}).inserted=r;for(const[n,r]of Object.entries(s.mapped))(e[n]??={staged:0,inserted:0,mapped:0,dropped:0}).mapped=r;return e}u(Me,"withInserted");async function Ne(e,s,n){const r=new Set((await e.prepareUncached("SELECT rev_id FROM revisions WHERE rev_id IN (SELECT jsonb_array_elements_text(?::jsonb))").all(JSON.stringify(n.map(a=>a.rev_id)))).map(a=>a.rev_id)),i=n.filter(a=>!r.has(a.rev_id)),d=new Map;for(const a of n)d.set(a.document,[...d.get(a.document)??[],a]);for(const[a,f]of d){const m=await Q(e,a);m!==null&&await z(e,m,f.map(t=>({rev_id:t.rev_id,parents:t.parents,body_hash:t.body_hash,rationale:t.rationale,created_at:t.created_at})))}return await C(e,s,"revisions",i.map(a=>[a.rev_id])),await C(e,s,"revision_parents",i.flatMap(a=>a.parents.map(f=>[a.rev_id,f]))),i.length}u(Ne,"arrive");async function C(e,s,n,r){if(r.length===0)return;const i=await e.prepare("SELECT inserted_keys FROM import_manifest WHERE run_id = ? AND table_name = ?").get(s,n);i===void 0?await e.prepare("INSERT INTO import_manifest (run_id, table_name, inserted_keys) VALUES (?, ?, ?)").run(s,n,A(r)):await e.prepare("UPDATE import_manifest SET inserted_keys = ? WHERE run_id = ? AND table_name = ?").run(A([...I(i.inserted_keys),...r]),s,n)}u(C,"appendManifest");async function Ce(e){const n=await(await E()).prepare("SELECT table_name, inserted_keys FROM import_manifest WHERE run_id = ? ORDER BY table_name").all(e);return q(Buffer.from(n.map(r=>JSON.stringify({table:r.table_name,keys:I(r.inserted_keys)})).join(`
|
|
2
|
+
`)+`
|
|
3
|
+
`))}u(Ce,"manifestFile");export{je as GRANT_WAIT_MS,tt as processRun};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
/** Tables `substitutePerson` and `rebuildTotalsFor` read or write that the bundle does not dump: staged empty. */
|
|
3
|
+
export declare const EMPTY_STAGED_TABLES: readonly ["node_tokens", "charge_chunks", "charge_totals", "profile_defaults", "scope_settings", "scope_bookkeeping", "scope_marketplaces", "scope_plugins", "person_settings", "model_accounts", "model_account_cooldowns", "model_api_keys", "model_settings", "model_sign_in_flows", "env_vars"];
|
|
4
|
+
export declare const stagingSchema: (run: string) => string;
|
|
5
|
+
/** The target schema's name (the transaction's current schema). */
|
|
6
|
+
export declare function targetSchema(db: CanvasDb): Promise<string>;
|
|
7
|
+
export declare function dropStaging(db: CanvasDb, run: string): Promise<void>;
|
|
8
|
+
/** Create the staging schema and load every row file. `rowKeys(table)` names the table's row files (one file, or the parts of `bodies`) and `get` reads one from R2. */
|
|
9
|
+
export declare function stage(db: CanvasDb, run: string, counts: Record<string, number>, rowKeys: (table: string) => string[], get: (key: string) => Promise<Buffer | null>): Promise<Record<string, number>>;
|
|
10
|
+
export declare class ImportLaneError extends Error {
|
|
11
|
+
readonly step: string;
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly detail?: Record<string, unknown> | undefined;
|
|
14
|
+
constructor(step: string, code: string, message: string, detail?: Record<string, unknown> | undefined);
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var m=Object.defineProperty;var s=(e,n)=>m(e,"name",{value:n,configurable:!0});import{DUMPED_TABLES as S,rowLines as L}from"../bundle/layout.js";const T=["node_tokens","charge_chunks","charge_totals","profile_defaults","scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins","person_settings","model_accounts","model_account_cooldowns","model_api_keys","model_settings","model_sign_in_flows","env_vars"],A=16*1024*1024,C=2e3,d=s(e=>`import_${e.replace(/[^A-Za-z0-9_]/g,"_")}`,"stagingSchema"),o=s(e=>`"${e.replace(/"/g,'""')}"`,"q");async function I(e){return(await e.prepare("SELECT current_schema() AS s").get()).s}s(I,"targetSchema");async function x(e,n){await e.exec(`DROP SCHEMA IF EXISTS ${o(d(n))} CASCADE`)}s(x,"dropStaging");async function N(e,n,r,p,_){const i=d(n),$=await I(e);await x(e,n),await e.exec(`CREATE SCHEMA ${o(i)}`);const h={};for(const t of[...S,...T])await e.exec(`CREATE UNLOGGED TABLE ${o(i)}.${o(t)} (LIKE ${o($)}.${o(t)} INCLUDING DEFAULTS)`);for(const t of S){let c=0;for(const g of p(t)){const w=await _(g);if(w===null){if((r[t]??0)!==0)throw f(`row file ${g} is missing`);continue}let a=[],E=0;const u=s(async()=>{a.length!==0&&(await e.prepareUncached(`INSERT INTO ${o(i)}.${o(t)} SELECT * FROM json_populate_recordset(NULL::${o(i)}.${o(t)}, ?::json)`).run(`[${a.join(",")}]`),c+=a.length,a=[],E=0)},"insert");for await(const l of L(w)){if(!l.startsWith("{"))throw f(`row file ${g} has a line that is not a JSON object`);a.length>0&&(a.length>=C||E+l.length>A)&&await u(),a.push(l),E+=l.length}await u()}if(c!==(r[t]??0))throw f(`row file for ${t} has ${c} rows; source.json says ${r[t]??0}`);h[t]=c}return h}s(N,"stage");class y extends Error{static{s(this,"ImportLaneError")}step;code;detail;constructor(n,r,p,_){super(p),this.step=n,this.code=r,this.detail=_}}function f(e){return new y("stage","bundle_invalid",e)}s(f,"bundleInvalid");export{T as EMPTY_STAGED_TABLES,y as ImportLaneError,x as dropStaging,N as stage,d as stagingSchema,I as targetSchema};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BlobStore } from '../../blobs/index.js';
|
|
2
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
3
|
+
import type { ImportStoreNameDTO } from '../../../api/dto/imports.js';
|
|
4
|
+
export declare const STORE_NAMES: readonly ImportStoreNameDTO[];
|
|
5
|
+
export declare const storeKey: (run: string, name: ImportStoreNameDTO) => string;
|
|
6
|
+
/** Seal one uploaded body under the target key and store it. The plaintext lives only in this call. */
|
|
7
|
+
export declare function putStore(blobs: BlobStore, run: string, name: ImportStoreNameDTO, body: unknown): Promise<void>;
|
|
8
|
+
export declare class StoreBodyError extends Error {
|
|
9
|
+
}
|
|
10
|
+
/** Every store's blob key under a run, for deletion once the run is done. */
|
|
11
|
+
export declare const allStoreKeys: (run: string) => string[];
|
|
12
|
+
export interface StoreInput {
|
|
13
|
+
db: CanvasDb;
|
|
14
|
+
blobs: BlobStore;
|
|
15
|
+
runId: string;
|
|
16
|
+
person: string;
|
|
17
|
+
objectMap: ReadonlyMap<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface StoreResult {
|
|
20
|
+
inserted: Record<string, string[][]>;
|
|
21
|
+
unresolvedPlugins: string[];
|
|
22
|
+
}
|
|
23
|
+
/** Must run inside the copy transaction (after the profile rows exist). */
|
|
24
|
+
export declare function writeStores(input: StoreInput): Promise<StoreResult>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var R=Object.defineProperty;var l=(s,o)=>R(s,"name",{value:o,configurable:!0});import{loadSecretsKey as g,open as U,seal as I}from"../../secrets/index.js";import{insertAccount as j,upsertModelCooldown as $}from"../../subscription-state.js";import{validateEnvVarName as C,isReservedEnvName as D}from"../../env-name.js";import{encodeKeys as V}from"./copy.js";const x=["auth","credentials","env","settings","plugins"],O=l((s,o)=>`imports/${s}/stores/${o}.sealed`,"storeKey"),h=l((s,o)=>`import_store|${s}|${o}`,"aadOf");async function B(s,o,i,r){if(r===null||typeof r!="object"||Array.isArray(r))throw new F(`the ${i} store must be a JSON object`);const{sealed:t,keyId:_}=I(JSON.stringify(r),g(),h(o,i));await s.put(O(o,i),Buffer.concat([Buffer.from(`${_}
|
|
2
|
+
`),t]))}l(B,"putStore");class F extends Error{static{l(this,"StoreBodyError")}}async function E(s,o,i){const r=await s.get(O(o,i));if(r===null)return null;const t=r.indexOf(10);return JSON.parse(U(r.subarray(t+1),r.subarray(0,t).toString("utf8"),g(),h(o,i)))}l(E,"readStore");const H=l(s=>x.map(o=>O(s,o)),"allStoreKeys");async function G(s){const{db:o,blobs:i,runId:r,person:t}=s,_=l(e=>s.objectMap.get(e)??e,"mapId"),f=l(e=>e.startsWith("profile:")?`profile:${_(e.slice(8))}`:e,"mapOwner"),m={},N=[],v=l((e,n)=>{(m[e]??=[]).push(n)},"record"),p=l(async(e,n,a,c)=>{await o.prepareUncached(`${n} ON CONFLICT DO NOTHING RETURNING 1 AS ok`).get(...a)!==void 0&&v(e,c)},"insert"),y=g(),k=new Date().toISOString(),d=await E(i,r,"credentials");if(d!==null){for(const e of d.accounts)if(await o.prepare("SELECT 1 FROM model_accounts WHERE person = ? AND provider_id = ? AND (id = ? OR label_key = ?)").get(t,e.provider,e.id,e.labelKey)===void 0){await j(o,t,e.provider,{providerId:e.provider,id:e.id,label:e.label,labelKey:e.labelKey,position:e.position,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil,...e.authFailure?{authFailure:e.authFailure}:{}},{refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{},...e.clientId?{clientId:e.clientId}:{}}),v("model_accounts",[t,e.provider,e.id]);for(const a of e.cooldowns)await $(o,t,e.provider,e.id,a.family,a.until,a.at),v("model_account_cooldowns",[t,e.provider,e.id,a.family])}d.rotation!==void 0&&await p("model_settings","INSERT INTO model_settings (person, default_fallback_strength, revert_when_available) VALUES (?, ?, ?)",[t,d.rotation.defaultFallbackStrength,d.rotation.revertWhenAvailable===null?null:d.rotation.revertWhenAvailable?1:0],[t]),d.openaiDeviceId!==void 0&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(d.openaiDeviceId)&&await o.prepare("INSERT INTO model_settings (person, openai_device_id) VALUES (?, ?) ON CONFLICT (person) DO UPDATE SET openai_device_id = COALESCE(model_settings.openai_device_id, EXCLUDED.openai_device_id)").run(t,d.openaiDeviceId.toLowerCase())}const T=await E(i,r,"auth");if(T!==null)for(const[e,n]of Object.entries(T.apiKeys)){const{sealed:a,keyId:c}=I(JSON.stringify(n),y,`model_api_keys|${t}|${e}`);await p("model_api_keys","INSERT INTO model_api_keys (person, provider_id, credential_sealed, key_id, updated_at) VALUES (?, ?, ?, ?, ?)",[t,e,a,c,k],[t,e])}const b=await E(i,r,"env");if(b!==null)for(const[e,n]of Object.entries(b.profiles)){const a=_(e);for(const[c,u]of Object.entries(n)){if(!C(c).isValid||D(c)||typeof u!="string"||u.includes("\0"))continue;const{sealed:A,keyId:L}=I(u,y,`env_vars|${t}|profile|${a}|${c}`);await p("env_vars","INSERT INTO env_vars (person, owner_kind, owner_id, name, value_sealed, key_id, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[t,"profile",a,c,A,L,k],[t,"profile",a,c])}}const w=await E(i,r,"settings");if(w!==null){for(const[e,n]of Object.entries(w.settings))await p("scope_settings","INSERT INTO scope_settings (person, owner_key, raw_json) VALUES (?, ?, ?)",[t,f(e),JSON.stringify(n)],[t,f(e)]);for(const[e,n]of Object.entries(w.state))await p("scope_bookkeeping","INSERT INTO scope_bookkeeping (person, owner_key, last_self_check, active_canvas) VALUES (?, ?, ?, ?)",[t,f(e),n.last_self_check??null,n.activeCanvas??null],[t,f(e)]);for(const[e,n]of Object.entries(w.profileProjects)){const a=_(e);if(await o.prepare("SELECT 1 FROM profile_projects WHERE profile_id = ?").get(a)!==void 0)continue;let c=0;for(const u of n)await p("profile_projects","INSERT INTO profile_projects (profile_id, path, position) VALUES (?, ?, ?)",[a,u,c++],[a,u])}for(const[e,n]of Object.entries(w.defaults))await p("profile_defaults","INSERT INTO profile_defaults (person, directory, profile_id) VALUES (?, ?, ?)",[t,e,_(n)],[t,e])}const S=await E(i,r,"plugins");if(S!==null){for(const e of S.marketplaces)await p("scope_marketplaces","INSERT INTO scope_marketplaces (person, owner_key, name, last_updated, url, ref, installed_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[t,f(e.owner),e.name,e.last_updated??null,e.url??null,e.ref??null,e.installed_at??null],[t,f(e.owner),e.name]);for(const e of S.plugins){if(e.source_path!=null&&(e.source_marketplace??null)===null){N.push(`${e.owner}:${e.name}`);continue}await p("scope_plugins","INSERT INTO scope_plugins (person, owner_key, name, last_updated, etag, checked_at, enabled, source_marketplace, version, source_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[t,f(e.owner),e.name,e.last_updated??null,e.etag??null,e.checked_at??null,e.enabled?1:0,e.source_marketplace??null,e.version??null,e.source_path??null],[t,f(e.owner),e.name])}(m.scope_plugins??[]).length+(m.scope_marketplaces??[]).length>0&&await p("person_settings","INSERT INTO person_settings (person, plugins_revision) VALUES (?, 1)",[t],[t])}for(const[e,n]of Object.entries(m))await o.prepare("INSERT INTO import_manifest (run_id, table_name, inserted_keys) VALUES (?, ?, ?) ON CONFLICT (run_id, table_name) DO UPDATE SET inserted_keys = EXCLUDED.inserted_keys").run(r,e,V(n));return Object.keys(m).length>0&&await o.prepare("SELECT pg_notify('crtr_signal', ?)").get(`settings:${t}`),{inserted:m,unresolvedPlugins:N}}l(G,"writeStores");export{x as STORE_NAMES,F as StoreBodyError,H as allStoreKeys,B as putStore,O as storeKey,G as writeStores};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
import type { ImportVerifyDTO } from '../../../api/dto/imports.js';
|
|
3
|
+
import { type Catalog } from './catalog.js';
|
|
4
|
+
export declare function verifyRun(db: CanvasDb, runId: string, schema: string, target: string, catalog: Catalog, installId: string): Promise<ImportVerifyDTO>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var M=Object.defineProperty;var c=(a,d)=>M(a,"name",{value:d,configurable:!0});import{KEY_MAPPED_TABLES as T}from"../bundle/layout.js";import{q as i,rowKey as F}from"./catalog.js";import{decodeKeys as h}from"./copy.js";const n=c((a,d)=>`${i(a)}.${i(d)}`,"sq"),U={messages:["seq"]},j=["claimed_by","lease_expires_at"];async function x(a,d,t,O,$,y){const _={},u=await a.prepare("SELECT table_name, inserted_keys FROM import_manifest WHERE run_id = ?").all(d);await a.exec(`DROP TABLE IF EXISTS ${i(t)}._m; CREATE TABLE ${i(t)}._m (tbl text NOT NULL, k jsonb NOT NULL)`);for(const{table_name:e,inserted_keys:s}of u){const o=$.tables.get(e);if(o===void 0)continue;const E=h(s);if(E.length===0)continue;await a.prepare(`DELETE FROM ${i(t)}._m WHERE tbl = ?`).run(e);for(let r=0;r<E.length;r+=5e3)await a.prepare(`INSERT INTO ${i(t)}._m SELECT ?, e FROM jsonb_array_elements(?::jsonb) e`).run(e,JSON.stringify(E.slice(r,r+5e3)));const A=[...o.identity,...U[e]??[],...j].map(r=>`'${r.replace(/'/g,"''")}'`).join(", ")||"''",p=c(r=>`to_jsonb(${r}) - ARRAY[${A}]::text[]`,"strip"),m=F(o),D=c(r=>`jsonb_build_array(${m.map(N=>`${r}.${i(N)}::text`).join(", ")})`,"targetKey");let L;if(e in T){const r=T[e];L=`JOIN import_key_map km ON km.source_install_id = '${y.replace(/'/g,"''")}' AND km.table_name = '${e}' AND jsonb_build_array(km.target_key) = m.k
|
|
2
|
+
JOIN ${n(t,e)} s ON s.${i(r)}::text = km.source_key`}else L=`JOIN ${n(t,e)} s ON ${m.map((r,N)=>`s.${i(r)}::text = m.k ->> ${N}`).join(" AND ")}`;const g=e==="revisions"?` AND m.k ->> 0 NOT IN (SELECT rev_id FROM ${n(t,"_arr_revisions")})`:e==="revision_parents"?` AND NOT EXISTS (SELECT 1 FROM ${n(t,"_arr_parents")} a WHERE a.child = m.k ->> 0 AND a.parent = m.k ->> 1)`:"",I=`FROM ${n(t,"_m")} m LEFT JOIN ${n(O,e)} t ON ${D("t")} = m.k ${L.replace("JOIN","LEFT JOIN")} WHERE m.tbl = '${e}'${g}
|
|
3
|
+
AND (t.${i(m[0])} IS NULL OR s.${i(m[0])} IS NULL OR (${p("t")}) <> (${p("s")}))`,f=Number((await a.prepareUncached(`SELECT count(*) AS n ${I}`).get()).n);if(f>0){const r=await a.prepareUncached(`SELECT m.k::text AS k ${I} LIMIT 10`).all();_[e]={count:f,keys:r.map(N=>N.k)}}}for(const[e,s]of[["revisions",`FROM ${n(t,"_m")} m JOIN ${n(t,"_arr_revisions")} a ON a.rev_id = m.k ->> 0 LEFT JOIN revisions t ON t.rev_id = a.rev_id
|
|
4
|
+
WHERE m.tbl = 'revisions' AND (t.rev_id IS NULL OR t.document <> a.document OR t.body_hash <> a.body_hash OR t.rationale IS DISTINCT FROM a.rationale OR t.created_at <> a.created_at)`],["revision_parents",`FROM ${n(t,"_m")} m JOIN ${n(t,"_arr_parents")} a ON a.child = m.k ->> 0 AND a.parent = m.k ->> 1 LEFT JOIN revision_parents t ON t.child = a.child AND t.parent = a.parent
|
|
5
|
+
WHERE m.tbl = 'revision_parents' AND t.child IS NULL`]]){const o=Number((await a.prepareUncached(`SELECT count(*) AS n ${s}`).get()).n);o>0&&(_[`${e}.arrived`]={count:o,keys:[]})}const l={},R=`SELECT source AS key FROM ${n(t,"_idmap")} WHERE kind = 'object'`,k=c(e=>e==="messages"?`(${R})`:`(${R} UNION SELECT key FROM ${n(t,"_dropped")} WHERE tbl = 'objects')`,"droppedFor");let S=!1;for(const{table_name:e}of u){const s=$.tables.get(e);if(s===void 0||S)continue;const o=await a.prepareUncached("SELECT column_name FROM information_schema.columns WHERE table_schema = ? AND table_name = ? AND data_type = 'text'").all(O,e);for(const{column_name:E}of o){if(s.primaryKey.includes(E)&&e==="objects")continue;if(await a.prepareUncached(`SELECT 1 AS found FROM ${n(t,"_m")} m JOIN ${n(O,e)} t ON jsonb_build_array(${s.primaryKey.map(p=>`t.${i(p)}::text`).join(", ")}) = m.k
|
|
6
|
+
WHERE m.tbl = ? AND t.${i(E)} IN ${k(e)} LIMIT 1`).get(e)!==void 0){S=!0,_[`${e}.${E}`]={count:1,keys:["holds a dropped object id"]};break}}}l.no_dropped_id=!S;const C=u.find(e=>e.table_name==="revisions");let b=!0;C!==void 0&&(b=await a.prepare(`SELECT 1 AS missing FROM ${n(t,"_m")} m JOIN revisions r ON r.rev_id = m.k ->> 0 WHERE m.tbl = 'revisions'
|
|
7
|
+
AND NOT EXISTS (SELECT 1 FROM bodies b WHERE b.hash = r.body_hash) LIMIT 1`).get()===void 0),l.revision_bodies_readable=b;const v=await a.prepare(`SELECT 1 AS found FROM (
|
|
8
|
+
SELECT month, payer, funding, COALESCE(sub, '') AS sub, grantee, COALESCE(provider, '') AS provider, COALESCE(SUM(usd), 0) AS usd, COALESCE(SUM(billed_usd), 0) AS billed
|
|
9
|
+
FROM charges WHERE refused IS NULL AND kind <> 'take' AND (month, payer) IN (SELECT DISTINCT month, payer FROM ${n(t,"charges")}) GROUP BY 1, 2, 3, 4, 5, 6) c
|
|
10
|
+
FULL JOIN charge_totals t ON t.month = c.month AND t.payer = c.payer AND t.funding = c.funding AND t.sub = c.sub AND t.grantee = c.grantee AND t.provider = c.provider
|
|
11
|
+
WHERE (COALESCE(t.month, c.month), COALESCE(t.payer, c.payer)) IN (SELECT DISTINCT month, payer FROM ${n(t,"charges")}) AND (c.month IS NULL OR t.month IS NULL OR c.usd <> t.usd OR c.billed <> t.billed_usd) LIMIT 1`).get();return l.charge_totals_equal_recompute=v===void 0,{ok:Object.keys(_).length===0&&Object.values(l).every(Boolean),differences:_,invariants:l}}c(x,"verifyRun");export{x as verifyRun};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var y=Object.defineProperty;var a=(t,n)=>y(t,"name",{value:n,configurable:!0});import{heads as m}from"../graph/documents.js";import{get as p}from"../graph/bodies.js";import{getById as s}from"../graph/objects.js";import{enqueuePeerRow as _}from"./outbox-store.js";import{describeObject as u,stubOf as w}from"./stubs.js";const b=a((t,n)=>`ev:${t}:${n}`,"eventKey");async function g(t,n){const i=typeof n?.pointer=="string"?n.pointer:void 0,e=i===void 0?null:await s(t,i);if(e===null||e.type!=="document"||e.deleted_at!==null)return;const o=(await m(t,e))[0];if(o!==void 0)return await p(t,o.body_hash)}a(g,"reportText");async function j(t,n,i){const e=await t.prepare("SELECT message_id, event, object_id, level, actor_id, body_ref, body_json FROM messages WHERE message_id = ?").get(n);if(e===void 0)throw new Error(`no message ${n}`);const o=await s(t,e.object_id);if(o===null)throw new Error(`no object ${e.object_id}`);const r=e.actor_id===null?null:await s(t,e.actor_id),f=e.body_json===null?{}:JSON.parse(e.body_json),{push:d,bodyRef:v,...c}=f,l=e.body_ref===null?void 0:await g(t,d);return{key:i,message_id:e.message_id,event:e.event,level:e.level,object:await u(t,o),actor:r===null?null:await u(t,r),attrs:d?.attrs??{},...Object.keys(c).length>0?{body:c}:{},...l===void 0?{}:{body_text:l}}}a(j,"payloadFor");const $={bodyOwner:a(()=>null,"bodyOwner"),async enqueue(t,n,i){for(const e of i){const o=await w(t,e.id);if(o===null)continue;const r=b(n.messageId,e.id);await _(t,{peer:o.home_machine,kind:"event",key:r,payload:{...await j(t,n.messageId,r),...e.linked?{linked:!0}:{}}})}}};export{b as eventKey,j as payloadFor,$ as peerReceiver};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var Fe=Object.defineProperty;var n=(t,o)=>Fe(t,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Le,envModelIntent as Be,envNodeCwd as Ue,envNodeId as $e,envProfileId as Ke,envScopes as We,scopeAllowed as Ge}from"../../shared/env.js";import{createServer as je}from"node:net";import{WebSocketServer as qe,createWebSocketStream as Ve}from"ws";import{BROKER_VIEW_PORT as Xe}from"./view-socket.js";import{existsSync as Te,readFileSync as He,unlinkSync as Ee}from"node:fs";import{join as ke}from"node:path";import{randomUUID as A}from"node:crypto";import{mark as Ye}from"../timing.js";import{SUBMIT_RESULT_TOOL as ze}from"./structured-output.js";import{flushConversation as Ce,installSessionManagerStorePatch as Je}from"../conversation-store/index.js";import{getAgentDir as J,ModelRegistry as Qe,ModelRuntime as Ze}from"@earendil-works/pi-coding-agent";import{nodeRunDir as et,viewSocketPath as tt}from"../canvas/paths.js";import{bindBrokerEventSource as nt}from"../events/source.js";import{emitEvent as b,flushBrokerLog as rt}from"../events/emit.js";import{operationIdContext as ot}from"../events/operation-id.js";import{findMissingPackagePaths as it}from"./package-health.js";import{installBrokerConfigSnapshot as st}from"../config.js";import{FRONT_DOOR_ENV as at}from"./front-door.js";import{CANVAS_EXTENSIONS as oe,piInvocationToSdkConfig as dt}from"./launch.js";import{assertEngineVersion as lt,loadBrokerEngine as ct}from"./broker-sdk.js";import{initCrtrTheme as mt}from"./crtr-theme.js";import{resolveBundledPiPackageDir as ut}from"./pi-cli.js";import{captureSessionChatCapabilities as ft}from"./command-surface.js";import{InMemoryCredentialStore as pt}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as gt,refusalRetryAt as vt}from"./broker/model-adapter.js";import{brokerApiUrl as _t,mutateBrokerFault as Q,recordBrokerTurn as xe}from"./broker/daemon-ops.js";import{fetchRunAttachments as ht}from"./broker/attachments-fetch.js";import{modelRequestFromConfig as wt,expandModelCandidates as St,parseModelSpec as bt,unregisteredConcreteModel as yt}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as Rt}from"./stream-watchdog.js";import{probeOnline as Tt}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as Et,cycleAwareMessages as kt,endedByAbort as Ct}from"./session-cycles.js";import{turnErrorOf as xt}from"../llm/refusal.js";import{projectTranscript as At}from"./session-visibility.js";import{currentTurnVisibility as Mt}from"./turn-visibility.js";import{isUnknownModel as ie}from"./model-selection.js";import{BrokerClientRegistry as Pt}from"./broker/client-registry.js";import{ToolGroupTracker as Ot}from"./broker/tool-groups.js";import{TurnReplyTracker as Dt}from"./broker/turn-replies.js";import{onNodeNamed as It}from"./broker/node-named.js";import{FaultRetry as Nt,willDaemonRetry as Ft}from"./broker/fault-retry.js";import{RunTurnEnds as Lt}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Bt}from"./broker/turn-admission.js";import{BROKER_DISPOSE_AND_EXIT as Ut,BROKER_IDLE_TURN_START as $t,BROKER_RUN_TURN_BUSY as Kt,BROKER_RUN_STEER as Wt}from"./broker/held-deferred-inbox.js";import{createRunSteerBridge as Gt}from"./broker/run-steer.js";import{prependRunDeferredMail as jt,settleRunDeferredMail as qt}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Vt}from"./broker/run-turn-queue.js";import{EventProjection as Xt}from"./broker/event-projection.js";import{createFrameDispatchContext as Ht,handleFrame as Yt}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as zt,installAdvertisedCommandInvocationContract as Jt}from"./advertised-command-invocation.js";import{RebindDriver as Qt}from"./broker/rebind.js";import{beginRuntimeTeardown as Zt}from"./broker/extension-abort.js";import{receiveNodeToken as en}from"./broker/node-token.js";import{serveCliRelay as tn}from"./broker/cli-relay.js";import{recordBrokerRelease as nn}from"./lifecycle.js";import{setTurnCauseSource as rn}from"./broker/turn-cause.js";import{decodeKickoffOrigin as on,KICKOFF_ORIGIN_ENV as sn}from"./stamp/protocol.js";import{announceMessageOrigin as an}from"./stamp/channel.js";import{commitBrokerModel as dn,recordConversationWriteFault as Ae}from"./broker/daemon-ops.js";import{bootExtensionState as ln}from"./broker/boot-state.js";import{composerNames as cn}from"./broker/frame-memory-refs.js";import{BROKER_READ_CAPS as mn,FrameOverflowError as un,normalizeSnapshotTail as fn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as Nr,REVIEW_BOUNDARY_NAVIGATION_CODE as Fr}from"./broker/frame-replies.js";function se(t){return new Qe(t.modelRuntime)}n(se,"registryOf");function $(t,o){if(t==null||ie(t))return null;const s=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${t.provider}/${t.id}${s}`}n($,"formatModelSpec");function pn(t,o){const s=$(t,void 0);return s===null?null:`${s}:${o===void 0||o===""?"off":o}`}n(pn,"formatExactModelSpec");const gn=12e4;let Z=null;import{brokerSignalClient as K}from"./broker/signal-stream.js";function vn(){K().stop();const t=Z;if(Z=null,t!==null)try{t.dispose()}catch{}}n(vn,"disposeActiveSession");function _n(t,o){const s=Ge(o,"crtr:act")?void 0:["bash"],f=t!==void 0&&t.length>0?[...new Set([...t,ze])]:t===void 0?void 0:[...t];return{...f!==void 0?{tools:f}:{},...s!==void 0?{excludeTools:s}:{}}}n(_n,"brokerToolOptions");async function Or(t,o=process.hrtime.bigint(),s=new Date().toISOString()){nt(t);const f=await en(),i=await tn(t,f);process.env.CRTR_API_SOCKET=i.path,ot.fresh(()=>{b({level:"info",event:"broker.startup.cli_entry",ts:s,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),b({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let c=null;const d=n((e,r=null)=>{a.has(e)||(a.add(e),Ye(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),b({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:c,model:r}}))},"emitStartupMilestone");process.env[at]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,Je(t);const v=await ct();lt(v.VERSION),c=v.VERSION;const w=et(t),E=ke(w,"broker-launch.json"),S=JSON.parse(He(E,"utf8"));if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");st(S.configSnapshot);const g=dt(S);g.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await cn(t);let R,M;const X=n(e=>{R!==void 0?R(e):M??=e},"onSignal");process.on("SIGTERM",()=>X("SIGTERM")),process.on("SIGINT",()=>X("SIGINT")),process.on("SIGUSR1",()=>{const e=process.env.CRTR_EXECUTION_ID;e!==void 0&&e!==""&&K().start(t,e)});let{session:W,services:P,resuming:de,runtime:G}=await bn(v,g);d("broker.startup.session_built");const k=(await ln(t)).node.review_binding?.review_id,T=Le();Z=W;const L=Tt;try{process.env.PI_PACKAGE_DIR=ut(),mt(P.settingsManager.getTheme(),J(),!1)}catch(e){b({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of it(J()))b({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const j=tt(t),_=new Pt(t),H=new Map,D=new Ot(t,e=>_.broadcast(e)),q=new Dt(t,e=>_.broadcast(e));It(e=>_.broadcast({type:"node_named",...e}));let I=!1,le=!1,Y,z,ce,u,V;const ee=new Lt;let B,me=n(()=>{},"notifyTurnAccepted"),ue=n(()=>{},"resetFrameState");const te=Bt();let fe=n(()=>0,"pendingPromptDispatches"),pe;const N=Vt({runNode:T,session:n(()=>u.session(),"session"),isReplacing:n(()=>u.isReplacing(),"isReplacing"),pendingRebind:n(()=>u.pendingRebind(),"pendingRebind"),isAgentRunActive:n(()=>u.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:n(()=>fe(),"pendingDispatches"),turnAdmission:te,prependDeferred:n(e=>jt(t,e),"prependDeferred"),onError:n(e=>b({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")}),ge=Gt(N.steerable);globalThis[Wt]=ge,rn(()=>u.session());const ve=N.drain;g.firstPrompt!==void 0&&g.firstPrompt!==""&&N.holdForKickoff(),globalThis[$t]=N.start,globalThis[Kt]=N.busy,u=new Qt({nodeId:t,cfg:g,session:W,services:P,runtime:G,registry:_,toolGroups:D,turnReplies:q,runSteer:ge,runNode:T,transcriptMessages:n(e=>ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:n(()=>ce,"uiContext"),faultRetry:n(()=>V,"faultRetry"),projection:n(()=>B,"projection"),setActiveSession:n(e=>{if(Z=e,pe?.(),T||process.env.CRTR_RUN_ID){let r="stop",l,p=!1;pe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",l=void 0,p=!1,ee.started()),h.type==="agent_end"){const m=[...h.messages??[]].reverse().find(U=>U.role==="assistant");m&&(r=m.stopReason,l=Ct(m)?void 0:xt(m,vt(m)),p=m.role==="assistant"&&Ft(m,e.model?.contextWindow))}h.type==="agent_settled"&&(ee.settled(e.sessionManager,{stop_reason:r,...l?{error:l}:{}},p),T&&(Ce().then(()=>qt(t,e)).catch(async m=>{if(String(m?.message).startsWith("conversation_write_failed")){b({level:"error",event:"broker.exited",node_id:t,error:m,fields:{fault:"conversation_write_failed"}}),await Ae(t,m),C("conversation_write_failed",1);return}b({level:"error",event:"broker.run_deferred_mail.settle_failed",error:m})}),queueMicrotask(()=>{u.session()===e&&ve()})))})}},"setActiveSession"),disposeAndExit:n((e,r)=>C(e,r),"disposeAndExit"),onSessionRebind:n(()=>{ue()},"onSessionRebind"),onReplacementIdle:n(()=>{T&&ve()},"onReplacementIdle"),reWelcomeAll:n(()=>ne(),"reWelcomeAll")});const _e=n(async(e,r=!1)=>{const l=u.session(),p=$(l.model,l.thinkingLevel);if(p===null)return null;const h=await dn(t,{spec:p,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(g.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,g.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",g.modelExact=!0)),h.modelOverride},"persistModelChoice"),he=n(async(e=!0,r,l=!1)=>{const p=u.session(),h=$(p.model,p.thinkingLevel),m=e?await _e(r,l):h;_.broadcast({type:"model_changed",model:ie(p.model)?void 0:p.model,spec:m})},"broadcastModelChanged");V=new Nt({nodeId:t,cfg:g,retryProbe:L,currentSession:n(()=>u.session(),"currentSession"),currentServices:n(()=>u.services(),"currentServices"),installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:$,broadcastModelChanged:he,turnAdmission:te,reWelcomeAll:n(()=>ne(),"reWelcomeAll"),...T?{turnEnds:ee}:{}});const we=n(()=>{V.rearmIfStranded().catch(e=>{b({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");K().subscribe("resync",we),K().subscribe("fault-retry",we),B=new Xt({registry:_,faultRetry:V,installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),currentSession:n(()=>u.session(),"currentSession"),notifyTurnAccepted:n(()=>me(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Pe=n(e=>{const r=u.session(),l=ae(r,k),p=fn(e.snapshotTail),h=l===void 0||p===void 0?l:l.slice(-p),m=h?.map(({message:F})=>F)??r.sessionManager.buildSessionContext().messages,U=D.summaries(),Re=h!==void 0&&p!==void 0?hn(m):void 0,Ne=Re===void 0?U:Object.fromEntries(Object.entries(U).filter(([F])=>Re.has(F)));return{messages:m,...h===void 0?{}:{messageIds:h.map(({id:F})=>F)},messageVisibility:h?.map(({visibility:F})=>F)??m.map(()=>"visible"),turnVisibility:Mt(),stats:r.getSessionStats(),state:{model:ie(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{..._.displaySnapshot()},toolGroupSummaries:Ne,turnReplies:q.snapshot(),workingActivity:B.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),Se=n(e=>{const r=e.role==="controller"?H.values().next().value:void 0;_.sendFrame(e,{type:"welcome",snapshot:Pe(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:J()},!0)},"sendWelcome"),Oe=n(e=>{const r=[...H.values()];for(let l=1;l<r.length;l++)_.sendFrame(e,r[l].request)},"replayExtraPendingDialogsTo"),ne=n(()=>{try{const e=u.session();q.seed(ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){b({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}_.forEachHelloed(Se)},"reWelcomeAll"),be=n(async e=>{if(I)return;I=!0;const r=K().latestNode;r!==void 0&&(r.intent==="idle-release"||r.status==="done")&&nn(t,process.env.CRTR_EXECUTION_ID??null),K().stop(),e===0&&await Ce().catch(async l=>{e=1,b({level:"error",event:"broker.exited",node_id:t,error:l,fields:{fault:"conversation_write_failed"}}),await Ae(t,l)}),D.persistPendingSummary(),B.dispose(),vn();try{Y?.close(),z?.close()}catch{}i.close(),_.dispose();try{Te(j)&&Ee(j)}catch{}_.clearAttachState(),await rt(),process.exit(e)},"completeExit"),C=n((e,r=0)=>{if(I)return;const l=e==="shutdown-hook"||e==="shutdown-after-settle";if(l&&D.finishOpenToolGroup(!0),l&&(D.hasSummaryTasks()||q.hasTasks())){if(le)return;le=!0,Promise.allSettled([D.waitForSummaryTasks(),q.waitForTasks()]).finally(()=>be(r));return}be(r)},"disposeAndExit");globalThis[Ut]=C,ce=yn({writable:n(()=>_.writableClients(),"writable"),forward:n((e,r)=>_.sendFrame(e,r),"forward"),pending:H,broadcast:n(e=>_.broadcastUi(e),"broadcast"),onKnownStreamWait:n(e=>B.knownStreamWait(e),"onKnownStreamWait")}),u.setRebindSession(),await u.enqueueRebind(W,P),d("broker.startup.extensions_bound");const x=Ht({nodeId:t,registry:_,toolGroups:D,projection:B,rebind:u,boundaryReviewId:k,pendingDialogs:H,sendWelcome:Se,replayExtraPendingDialogsTo:Oe,reWelcomeAll:ne,disposeAndExit:C,persistModelChoice:_e,broadcastModelChanged:he,registryOf:se,formatModelSpec:$,formatExactModelSpec:pn,turnAdmission:te,memoryInventory:y,runNode:T,onKickoffAdmitted:N.releaseKickoff});me=x.notifyTurnAccepted,ue=x.resetForSession,fe=x.pendingPromptDispatches;const De=2500;let re=!1;const Ie=n(async e=>{if(I||re)return;if(re=!0,u.isAgentRunActive()||u.session().isStreaming||x.pendingPromptDispatches()>0){const l=Date.now()+De;for(;x.pendingPromptDispatches()>0&&!u.session().isStreaming&&Date.now()<l;)await new Promise(p=>setTimeout(p,25));if(u.session().isStreaming){const p=l-Date.now();if(p>0){let h;try{Zt(),await Promise.race([u.session().abort().then(()=>!0,()=>!1),new Promise(U=>{h=setTimeout(()=>U(!1),p)})])&&await xe(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(x.pendingPromptDispatches()>0||u.isAgentRunActive())&&await xe(t,{event:"interrupted"})}C(e)},"abortAndExit");if(R=n(e=>{Ie(e)},"signalTeardown"),M!==void 0){R(M);return}try{Te(j)&&Ee(j)}catch{}const ye=n(e=>{const r=_.create(e);e.on("data",p=>{let h;try{h=r.decoder.push(p)}catch(m){m instanceof un?(_.sendFrame(r,{type:"error",code:"frame_overflow",message:m.message}),_.dropClient(r,`frame overflow: ${m.message}`)):_.dropClient(r,`decoder error: ${String(m)}`);return}for(const m of h)try{Yt(x,r,m)}catch{}});const l=n(()=>{_.removeClient(r)},"drop");e.on("close",l),e.on("error",()=>{})},"serveViewer");Y=je(ye),_t()!==void 0&&(z=new qe({host:"::",port:Xe,path:"/view",maxPayload:mn.maxLineBytes}),z.on("connection",e=>ye(Ve(e))),z.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))})),Y.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))}),Y.listen(j,async()=>{Promise.all([Q(t,{op:"clear",link:"viewer\u2194broker"}),Q(t,{op:"clear",link:"relay\u2194broker"})]).catch(r=>b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await V.recoverOnStartup()}catch(r){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"recovery_startup"}}),C("recovery-startup-failed",1);return}if(!(I||re))if(e==="none"&&g.firstPrompt!==void 0&&g.firstPrompt!==""){const r=on(process.env[sn]);r!==null&&an(g.firstPrompt,r);try{await ht(t)}catch(p){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:p,fields:{operation:"attachments_fetch"}}),C("attachments-fetch-failed",1);return}const l=process.env.CRTR_KICKOFF_MESSAGE_IDS;x.kickoff(g.firstPrompt,l?JSON.parse(l):[])}else N.releaseKickoff()}),_.persistAttachState()}n(Or,"runBroker");function hn(t){const o=new Set;for(const s of t)if(!(s.role!=="assistant"||!Array.isArray(s.content)))for(const f of s.content)f!==null&&typeof f=="object"&&f.type==="toolCall"&&typeof f.id=="string"&&o.add(f.id);return o}n(hn,"toolCallIds");function ae(t,o){const s=t.sessionManager,f=kt(s);return f!==void 0&&zt(f.map(({message:i})=>i)),f===void 0?void 0:At(f,{boundaryReviewId:o,sessionEntries:s.getEntries?.()})}n(ae,"snapshotMessages");function Me(){const t=$e();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}n(Me,"currentBrokerNodeId");async function wn(t,o){const s=wt(o.model,Be(),o.modelExact===!0);if(s===void 0)return;const f=se(t),i={cwd:Ue()??o.cwd,profileId:Ke()},a=await yt(s,f,i);if(a!==void 0)throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const c=await St(s,i.cwd,i.profileId),d=bt(s.spec);for(const v of c){const w=f.find(v.providerId,v.modelId);if(w===void 0)continue;const S=d?.providerId===v.providerId&&d.modelId===v.modelId?d.thinkingLevel??(v.thinkingLevel===void 0?void 0:"off"):v.thinkingLevel;return{model:w,thinkingLevel:S}}if(o.modelExact===!0){const v=c.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${v})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}b({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:c.map(v=>({provider:v.providerId,model:v.modelId,reason:"unregistered"})).slice(0,16)}})}n(wn,"resolveLaunchModel");function Sn(t){let o=!0;return{runtime:new Proxy(t,{get(f,i,a){return o&&i==="getAvailableSnapshot"?()=>[]:o&&i==="getAvailable"?async()=>[]:o&&i==="getModel"?()=>{}:Reflect.get(f,i,a)}}),reveal:n(()=>{o=!1},"reveal")}}n(Sn,"modelLessRegistry");async function bn(t,o){const s=J(),f=n(async S=>{const g=await Ze.create({credentials:new pt,modelsPath:ke(S.agentDir,"models.json")});gt(g);const y=await t.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:g,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:n(O=>({...O,extensions:O.extensions.filter(k=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(k.path))}),"extensionsOverride")}}),R=y.resourceLoader.getExtensions();if(o.extensionPaths.some(O=>oe.includes(O))){const O=new Set(R.extensions.map(T=>T.path)),k=oe.filter(T=>!O.has(T));if(k.length>0){const T=R.errors.filter(L=>oe.includes(L.path)).map(L=>`${L.path}: ${L.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${k.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const M=await wn(y,o),X=M?.model,W=M?.thinkingLevel,P=M===void 0?Sn(y.modelRuntime):void 0,de=P!==void 0?{...y,modelRuntime:P.runtime}:y,G=await t.createAgentSessionFromServices({services:de,sessionManager:S.sessionManager,model:X,thinkingLevel:W,..._n(o.tools,We()),sessionStartEvent:S.sessionStartEvent});return Jt(G.session),ft(G.session),P?.reveal(),{...G,services:y}},"buildForManager"),i=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(i===void 0||i==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const c=!a&&i!==void 0&&i!=="",d=c&&o.newCycle===!0,v=c&&!d;let w;if(a)w=await t.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(v||d){if(w=await t.SessionManager.open(i),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(Et,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=await t.SessionManager.create(o.cwd);if(t.createAgentSessionRuntime!==void 0){const S=n(async y=>{const R=await f({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...R,diagnostics:R.services.diagnostics??[]}},"factory"),g=await t.createAgentSessionRuntime(S,{cwd:o.cwd,agentDir:s,sessionManager:w});return{session:g.session,services:g.services,resuming:v,runtime:g}}const E=await f({cwd:o.cwd,agentDir:s,sessionManager:w});return{session:E.session,services:E.services,resuming:v,runtime:void 0}}n(bn,"buildBrokerSession");function yn(t){const o=n((i,a,c,d)=>{if(d?.signal?.aborted)return Promise.resolve(i);const v=t.writable();return v.length===0?Promise.resolve(i):new Promise(w=>{let E;const S=n(()=>{E!==void 0&&clearTimeout(E),d?.signal?.removeEventListener("abort",g),t.pending.delete(a.id)},"cleanup"),g=n(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},"onAbort");d?.signal?.addEventListener("abort",g,{once:!0});const y=d?.timeout!==void 0?d.timeout:gn;E=setTimeout(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},y),typeof E.unref=="function"&&E.unref(),t.pending.set(a.id,{request:a,resolve:n(R=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(c(R))},"resolve")});for(const R of v)t.forward(R,a)})},"dialogPromise"),s=n(()=>{},"noop");return{[Rt]:t.onKnownStreamWait??(i=>()=>{}),get theme(){const i=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(i==null)throw new Error("Theme not initialized. Call initTheme() first.");return i},select:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:A(),method:"select",title:i,options:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"select"),confirm:n((i,a,c)=>o(!1,{type:"extension_ui_request",id:A(),method:"confirm",title:i,message:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,c),"confirm"),input:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:A(),method:"input",title:i,placeholder:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"input"),editor:n((i,a)=>o(void 0,{type:"extension_ui_request",id:A(),method:"editor",title:i,prefill:a},c=>"cancelled"in c&&c.cancelled?void 0:"value"in c?c.value:void 0),"editor"),setStatus:n((i,a)=>t.broadcast({type:"extension_ui_request",id:A(),method:"setStatus",statusKey:i,statusText:a}),"setStatus"),setWidget:n((i,a,c)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:A(),method:"setWidget",widgetKey:i,widgetLines:a,widgetPlacement:c?.placement})},"setWidget"),setTitle:n(i=>t.broadcast({type:"extension_ui_request",id:A(),method:"setTitle",title:i}),"setTitle"),notify:n((i,a)=>{const c=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:A(),method:"notify",message:i,notifyType:c})},"notify"),onTerminalInput:n(()=>s,"onTerminalInput"),setWorkingMessage:s,setWorkingVisible:s,setWorkingIndicator:s,setHiddenThinkingLabel:s,setFooter:s,setHeader:s,custom:n(()=>Promise.resolve(void 0),"custom"),pasteToEditor:s,setEditorText:s,getEditorText:n(()=>"","getEditorText"),addAutocompleteProvider:s,setEditorComponent:s,getEditorComponent:n(()=>{},"getEditorComponent"),getAllThemes:n(()=>[],"getAllThemes"),getTheme:n(()=>{},"getTheme"),setTheme:s,getToolsExpanded:n(()=>!1,"getToolsExpanded"),setToolsExpanded:s}}n(yn,"makeBrokerUiContext");export{Fr as REVIEW_BOUNDARY_NAVIGATION_CODE,Nr as ReviewBoundaryNavigationError,_n as brokerToolOptions,bn as buildBrokerSession,vn as disposeActiveSession,yn as makeBrokerUiContext,Or as runBroker,ae as snapshotMessages};
|
|
1
|
+
var Fe=Object.defineProperty;var n=(t,o)=>Fe(t,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Le,envModelIntent as Be,envNodeCwd as Ue,envNodeId as $e,envProfileId as We,envScopes as Ke,scopeAllowed as Ge}from"../../shared/env.js";import{createServer as je}from"node:net";import{WebSocketServer as Ve,createWebSocketStream as qe}from"ws";import{BROKER_VIEW_PORT as Xe}from"./view-socket.js";import{existsSync as Te,readFileSync as He,unlinkSync as Ee}from"node:fs";import{join as ke}from"node:path";import{randomUUID as A}from"node:crypto";import{mark as Ye}from"../timing.js";import{SUBMIT_RESULT_TOOL as ze}from"./structured-output.js";import{flushConversation as Ce,installSessionManagerStorePatch as Je}from"../conversation-store/index.js";import{getAgentDir as J,ModelRegistry as Qe,ModelRuntime as Ze}from"@earendil-works/pi-coding-agent";import{nodeRunDir as et,viewSocketPath as tt}from"../canvas/paths.js";import{bindBrokerEventSource as nt}from"../events/source.js";import{emitEvent as b,flushBrokerLog as rt}from"../events/emit.js";import{operationIdContext as ot}from"../events/operation-id.js";import{findMissingPackagePaths as it}from"./package-health.js";import{installBrokerConfigSnapshot as st}from"../config.js";import{FRONT_DOOR_ENV as at}from"./front-door.js";import{CANVAS_EXTENSIONS as oe,piInvocationToSdkConfig as dt}from"./launch.js";import{assertEngineVersion as lt,loadBrokerEngine as ct}from"./broker-sdk.js";import{initCrtrTheme as mt}from"./crtr-theme.js";import{resolveBundledPiPackageDir as ut}from"./pi-cli.js";import{captureSessionChatCapabilities as ft}from"./command-surface.js";import{InMemoryCredentialStore as pt}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as gt,refusalRetryAt as vt}from"./broker/model-adapter.js";import{brokerApiUrl as _t,mutateBrokerFault as Q,recordBrokerTurn as xe}from"./broker/daemon-ops.js";import{fetchRunAttachments as ht}from"./broker/attachments-fetch.js";import{modelRequestFromConfig as wt,expandModelCandidates as St,parseModelSpec as bt,unregisteredConcreteModel as yt}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as Rt}from"./stream-watchdog.js";import{probeOnline as Tt}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as Et,cycleAwareMessages as kt,endedByAbort as Ct}from"./session-cycles.js";import{turnErrorOf as xt}from"../llm/refusal.js";import{projectTranscript as At}from"./session-visibility.js";import{currentTurnVisibility as Mt}from"./turn-visibility.js";import{isUnknownModel as ie}from"./model-selection.js";import{BrokerClientRegistry as Pt}from"./broker/client-registry.js";import{ToolGroupTracker as Ot}from"./broker/tool-groups.js";import{TurnReplyTracker as Dt}from"./broker/turn-replies.js";import{onNodeNamed as It}from"./broker/node-named.js";import{FaultRetry as Nt,willDaemonRetry as Ft}from"./broker/fault-retry.js";import{RunTurnEnds as Lt}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Bt}from"./broker/turn-admission.js";import{BROKER_DISPOSE_AND_EXIT as Ut,BROKER_IDLE_TURN_START as $t,BROKER_RUN_TURN_BUSY as Wt,BROKER_RUN_STEER as Kt}from"./broker/held-deferred-inbox.js";import{createRunSteerBridge as Gt}from"./broker/run-steer.js";import{prependRunDeferredMail as jt,settleRunDeferredMail as Vt}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as qt}from"./broker/run-turn-queue.js";import{EventProjection as Xt}from"./broker/event-projection.js";import{createFrameDispatchContext as Ht,handleFrame as Yt}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as zt,installAdvertisedCommandInvocationContract as Jt}from"./advertised-command-invocation.js";import{RebindDriver as Qt}from"./broker/rebind.js";import{beginRuntimeTeardown as Zt}from"./broker/extension-abort.js";import{receiveNodeToken as en}from"./broker/node-token.js";import{serveCliRelay as tn}from"./broker/cli-relay.js";import{recordBrokerRelease as nn}from"./lifecycle.js";import{setTurnCauseSource as rn}from"./broker/turn-cause.js";import{decodeKickoffOrigin as on,KICKOFF_ORIGIN_ENV as sn}from"./stamp/protocol.js";import{announceMessageOrigin as an}from"./stamp/channel.js";import{commitBrokerModel as dn,recordConversationWriteFault as Ae}from"./broker/daemon-ops.js";import{bootExtensionState as ln}from"./broker/boot-state.js";import{composerNames as cn}from"./broker/frame-memory-refs.js";import{BROKER_READ_CAPS as mn,FrameOverflowError as un,normalizeSnapshotTail as fn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as Nr,REVIEW_BOUNDARY_NAVIGATION_CODE as Fr}from"./broker/frame-replies.js";function se(t){return new Qe(t.modelRuntime)}n(se,"registryOf");function $(t,o){if(t==null||ie(t))return null;const s=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${t.provider}/${t.id}${s}`}n($,"formatModelSpec");function pn(t,o){const s=$(t,void 0);return s===null?null:`${s}:${o===void 0||o===""?"off":o}`}n(pn,"formatExactModelSpec");const gn=12e4;let Z=null;import{brokerSignalClient as W}from"./broker/signal-stream.js";function vn(){W().stop();const t=Z;if(Z=null,t!==null)try{t.dispose()}catch{}}n(vn,"disposeActiveSession");function _n(t,o){const s=Ge(o,"crtr:act")?void 0:["bash"],f=t!==void 0&&t.length>0?[...new Set([...t,ze])]:t===void 0?void 0:[...t];return{...f!==void 0?{tools:f}:{},...s!==void 0?{excludeTools:s}:{}}}n(_n,"brokerToolOptions");async function Or(t,o=process.hrtime.bigint(),s=new Date().toISOString()){nt(t);const f=await en(),i=await tn(t,f);process.env.CRTR_API_SOCKET=i.path,ot.fresh(()=>{b({level:"info",event:"broker.startup.cli_entry",ts:s,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),b({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let c=null;const d=n((e,r=null)=>{a.has(e)||(a.add(e),Ye(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),b({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:c,model:r}}))},"emitStartupMilestone");process.env[at]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,Je(t);const v=await ct();lt(v.VERSION),c=v.VERSION;const w=et(t),E=ke(w,"broker-launch.json"),S=JSON.parse(He(E,"utf8"));if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");st(S.configSnapshot);const g=dt(S);g.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await cn(t);let R,M;const X=n(e=>{R!==void 0?R(e):M??=e},"onSignal");process.on("SIGTERM",()=>X("SIGTERM")),process.on("SIGINT",()=>X("SIGINT")),process.on("SIGUSR1",()=>{const e=process.env.CRTR_EXECUTION_ID;e!==void 0&&e!==""&&W().start(t,e)});let{session:K,services:P,resuming:de,runtime:G}=await bn(v,g);d("broker.startup.session_built");const k=(await ln(t)).node.review_binding?.review_id,T=Le();Z=K;const L=Tt;try{process.env.PI_PACKAGE_DIR=ut(),mt(P.settingsManager.getTheme(),J(),!1)}catch(e){b({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of it(J()))b({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const j=tt(t),_=new Pt(t),H=new Map,D=new Ot(t,e=>_.broadcast(e)),V=new Dt(t,e=>_.broadcast(e));It(e=>_.broadcast({type:"node_named",...e}));let I=!1,le=!1,Y,z,ce,u,q;const ee=new Lt;let B,me=n(()=>{},"notifyTurnAccepted"),ue=n(()=>{},"resetFrameState");const te=Bt();let fe=n(()=>0,"pendingPromptDispatches"),pe;const N=qt({runNode:T,session:n(()=>u.session(),"session"),isReplacing:n(()=>u.isReplacing(),"isReplacing"),pendingRebind:n(()=>u.pendingRebind(),"pendingRebind"),isAgentRunActive:n(()=>u.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:n(()=>fe(),"pendingDispatches"),turnAdmission:te,prependDeferred:n(e=>jt(t,e),"prependDeferred"),onError:n(e=>b({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")}),ge=Gt(N.steerable);globalThis[Kt]=ge,rn(()=>u.session());const ve=N.drain;g.firstPrompt!==void 0&&g.firstPrompt!==""&&N.holdForKickoff(),globalThis[$t]=N.start,globalThis[Wt]=N.busy,u=new Qt({nodeId:t,cfg:g,session:K,services:P,runtime:G,registry:_,toolGroups:D,turnReplies:V,runSteer:ge,runNode:T,transcriptMessages:n(e=>ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:n(()=>ce,"uiContext"),faultRetry:n(()=>q,"faultRetry"),projection:n(()=>B,"projection"),setActiveSession:n(e=>{if(Z=e,pe?.(),T||process.env.CRTR_RUN_ID){let r="stop",l,p=!1;pe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",l=void 0,p=!1,ee.started()),h.type==="agent_end"){const m=[...h.messages??[]].reverse().find(U=>U.role==="assistant");m&&(r=m.stopReason,l=Ct(m)?void 0:xt(m,vt(m)),p=m.role==="assistant"&&Ft(m,e.model?.contextWindow))}h.type==="agent_settled"&&(ee.settled(e.sessionManager,{stop_reason:r,...l?{error:l}:{}},p),T&&(Ce().then(()=>Vt(t,e)).catch(async m=>{if(String(m?.message).startsWith("conversation_write_failed")){b({level:"error",event:"broker.exited",node_id:t,error:m,fields:{fault:"conversation_write_failed"}}),await Ae(t,m),C("conversation_write_failed",1);return}b({level:"error",event:"broker.run_deferred_mail.settle_failed",error:m})}),queueMicrotask(()=>{u.session()===e&&ve()})))})}},"setActiveSession"),disposeAndExit:n((e,r)=>C(e,r),"disposeAndExit"),onSessionRebind:n(()=>{ue()},"onSessionRebind"),onReplacementIdle:n(()=>{T&&ve()},"onReplacementIdle"),reWelcomeAll:n(()=>ne(),"reWelcomeAll")});const _e=n(async(e,r=!1)=>{const l=u.session(),p=$(l.model,l.thinkingLevel);if(p===null)return null;const h=await dn(t,{spec:p,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(g.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,g.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",g.modelExact=!0)),h.modelOverride},"persistModelChoice"),he=n(async(e=!0,r,l=!1)=>{const p=u.session(),h=$(p.model,p.thinkingLevel),m=e?await _e(r,l):h;_.broadcast({type:"model_changed",model:ie(p.model)?void 0:p.model,spec:m})},"broadcastModelChanged");q=new Nt({nodeId:t,cfg:g,retryProbe:L,currentSession:n(()=>u.session(),"currentSession"),currentServices:n(()=>u.services(),"currentServices"),installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:$,broadcastModelChanged:he,turnAdmission:te,reWelcomeAll:n(()=>ne(),"reWelcomeAll"),...T?{turnEnds:ee}:{}});const we=n(()=>{q.rearmIfStranded().catch(e=>{b({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");W().subscribe("resync",we),W().subscribe("fault-retry",we),B=new Xt({registry:_,faultRetry:q,installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),currentSession:n(()=>u.session(),"currentSession"),notifyTurnAccepted:n(()=>me(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Pe=n(e=>{const r=u.session(),l=ae(r,k),p=fn(e.snapshotTail),h=l===void 0||p===void 0?l:l.slice(-p),m=h?.map(({message:F})=>F)??r.sessionManager.buildSessionContext().messages,U=D.summaries(),Re=h!==void 0&&p!==void 0?hn(m):void 0,Ne=Re===void 0?U:Object.fromEntries(Object.entries(U).filter(([F])=>Re.has(F)));return{messages:m,...h===void 0?{}:{messageIds:h.map(({id:F})=>F)},messageVisibility:h?.map(({visibility:F})=>F)??m.map(()=>"visible"),turnVisibility:Mt(),stats:r.getSessionStats(),state:{model:ie(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{..._.displaySnapshot()},toolGroupSummaries:Ne,turnReplies:V.snapshot(),workingActivity:B.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),Se=n(e=>{const r=e.role==="controller"?H.values().next().value:void 0;_.sendFrame(e,{type:"welcome",snapshot:Pe(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:J()},!0)},"sendWelcome"),Oe=n(e=>{const r=[...H.values()];for(let l=1;l<r.length;l++)_.sendFrame(e,r[l].request)},"replayExtraPendingDialogsTo"),ne=n(()=>{try{const e=u.session();V.seed(ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){b({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}_.forEachHelloed(Se)},"reWelcomeAll"),be=n(async e=>{if(I)return;I=!0;const r=W().latestNode;r!==void 0&&(r.intent==="idle-release"||r.status==="done")&&nn(t,process.env.CRTR_EXECUTION_ID??null),W().stop(),e===0&&await Ce().catch(async l=>{e=1,b({level:"error",event:"broker.exited",node_id:t,error:l,fields:{fault:"conversation_write_failed"}}),await Ae(t,l)}),D.persistPendingSummary(),B.dispose(),vn();try{Y?.close(),z?.close()}catch{}i.close(),_.dispose();try{Te(j)&&Ee(j)}catch{}_.clearAttachState(),await rt(),process.exit(e)},"completeExit"),C=n((e,r=0)=>{if(I)return;const l=e==="shutdown-hook"||e==="shutdown-after-settle";if(l&&D.finishOpenToolGroup(!0),l&&(D.hasSummaryTasks()||V.hasTasks())){if(le)return;le=!0,Promise.allSettled([D.waitForSummaryTasks(),V.waitForTasks()]).finally(()=>be(r));return}be(r)},"disposeAndExit");globalThis[Ut]=C,ce=yn({writable:n(()=>_.writableClients(),"writable"),forward:n((e,r)=>_.sendFrame(e,r),"forward"),pending:H,broadcast:n(e=>_.broadcastUi(e),"broadcast"),onKnownStreamWait:n(e=>B.knownStreamWait(e),"onKnownStreamWait")}),u.setRebindSession(),await u.enqueueRebind(K,P),d("broker.startup.extensions_bound");const x=Ht({nodeId:t,registry:_,toolGroups:D,projection:B,rebind:u,boundaryReviewId:k,pendingDialogs:H,sendWelcome:Se,replayExtraPendingDialogsTo:Oe,reWelcomeAll:ne,disposeAndExit:C,persistModelChoice:_e,broadcastModelChanged:he,registryOf:se,formatModelSpec:$,formatExactModelSpec:pn,turnAdmission:te,memoryInventory:y,runNode:T,onKickoffAdmitted:N.releaseKickoff});me=x.notifyTurnAccepted,ue=x.resetForSession,fe=x.pendingPromptDispatches;const De=2500;let re=!1;const Ie=n(async e=>{if(I||re)return;if(re=!0,u.isAgentRunActive()||u.session().isStreaming||x.pendingPromptDispatches()>0){const l=Date.now()+De;for(;x.pendingPromptDispatches()>0&&!u.session().isStreaming&&Date.now()<l;)await new Promise(p=>setTimeout(p,25));if(u.session().isStreaming){const p=l-Date.now();if(p>0){let h;try{Zt(),await Promise.race([u.session().abort().then(()=>!0,()=>!1),new Promise(U=>{h=setTimeout(()=>U(!1),p)})])&&await xe(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(x.pendingPromptDispatches()>0||u.isAgentRunActive())&&await xe(t,{event:"interrupted"})}C(e)},"abortAndExit");if(R=n(e=>{Ie(e)},"signalTeardown"),M!==void 0){R(M);return}try{Te(j)&&Ee(j)}catch{}const ye=n(e=>{const r=_.create(e);e.on("data",p=>{let h;try{h=r.decoder.push(p)}catch(m){m instanceof un?(_.sendFrame(r,{type:"error",code:"frame_overflow",message:m.message}),_.dropClient(r,`frame overflow: ${m.message}`)):_.dropClient(r,`decoder error: ${String(m)}`);return}for(const m of h)try{Yt(x,r,m)}catch{}});const l=n(()=>{_.removeClient(r)},"drop");e.on("close",l),e.on("error",()=>{})},"serveViewer");Y=je(ye),_t()!==void 0&&process.env.CRTR_VIEW_WSS!=="0"&&(z=new Ve({host:"::",port:Xe,path:"/view",maxPayload:mn.maxLineBytes}),z.on("connection",e=>ye(qe(e))),z.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))})),Y.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))}),Y.listen(j,async()=>{Promise.all([Q(t,{op:"clear",link:"viewer\u2194broker"}),Q(t,{op:"clear",link:"relay\u2194broker"})]).catch(r=>b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await q.recoverOnStartup()}catch(r){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"recovery_startup"}}),C("recovery-startup-failed",1);return}if(!(I||re))if(e==="none"&&g.firstPrompt!==void 0&&g.firstPrompt!==""){const r=on(process.env[sn]);r!==null&&an(g.firstPrompt,r);try{await ht(t)}catch(p){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:p,fields:{operation:"attachments_fetch"}}),C("attachments-fetch-failed",1);return}const l=process.env.CRTR_KICKOFF_MESSAGE_IDS;x.kickoff(g.firstPrompt,l?JSON.parse(l):[])}else N.releaseKickoff()}),_.persistAttachState()}n(Or,"runBroker");function hn(t){const o=new Set;for(const s of t)if(!(s.role!=="assistant"||!Array.isArray(s.content)))for(const f of s.content)f!==null&&typeof f=="object"&&f.type==="toolCall"&&typeof f.id=="string"&&o.add(f.id);return o}n(hn,"toolCallIds");function ae(t,o){const s=t.sessionManager,f=kt(s);return f!==void 0&&zt(f.map(({message:i})=>i)),f===void 0?void 0:At(f,{boundaryReviewId:o,sessionEntries:s.getEntries?.()})}n(ae,"snapshotMessages");function Me(){const t=$e();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}n(Me,"currentBrokerNodeId");async function wn(t,o){const s=wt(o.model,Be(),o.modelExact===!0);if(s===void 0)return;const f=se(t),i={cwd:Ue()??o.cwd,profileId:We()},a=await yt(s,f,i);if(a!==void 0)throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const c=await St(s,i.cwd,i.profileId),d=bt(s.spec);for(const v of c){const w=f.find(v.providerId,v.modelId);if(w===void 0)continue;const S=d?.providerId===v.providerId&&d.modelId===v.modelId?d.thinkingLevel??(v.thinkingLevel===void 0?void 0:"off"):v.thinkingLevel;return{model:w,thinkingLevel:S}}if(o.modelExact===!0){const v=c.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${v})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}b({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:c.map(v=>({provider:v.providerId,model:v.modelId,reason:"unregistered"})).slice(0,16)}})}n(wn,"resolveLaunchModel");function Sn(t){let o=!0;return{runtime:new Proxy(t,{get(f,i,a){return o&&i==="getAvailableSnapshot"?()=>[]:o&&i==="getAvailable"?async()=>[]:o&&i==="getModel"?()=>{}:Reflect.get(f,i,a)}}),reveal:n(()=>{o=!1},"reveal")}}n(Sn,"modelLessRegistry");async function bn(t,o){const s=J(),f=n(async S=>{const g=await Ze.create({credentials:new pt,modelsPath:ke(S.agentDir,"models.json")});gt(g);const y=await t.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:g,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:n(O=>({...O,extensions:O.extensions.filter(k=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(k.path))}),"extensionsOverride")}}),R=y.resourceLoader.getExtensions();if(o.extensionPaths.some(O=>oe.includes(O))){const O=new Set(R.extensions.map(T=>T.path)),k=oe.filter(T=>!O.has(T));if(k.length>0){const T=R.errors.filter(L=>oe.includes(L.path)).map(L=>`${L.path}: ${L.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${k.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const M=await wn(y,o),X=M?.model,K=M?.thinkingLevel,P=M===void 0?Sn(y.modelRuntime):void 0,de=P!==void 0?{...y,modelRuntime:P.runtime}:y,G=await t.createAgentSessionFromServices({services:de,sessionManager:S.sessionManager,model:X,thinkingLevel:K,..._n(o.tools,Ke()),sessionStartEvent:S.sessionStartEvent});return Jt(G.session),ft(G.session),P?.reveal(),{...G,services:y}},"buildForManager"),i=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(i===void 0||i==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const c=!a&&i!==void 0&&i!=="",d=c&&o.newCycle===!0,v=c&&!d;let w;if(a)w=await t.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(v||d){if(w=await t.SessionManager.open(i),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(Et,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=await t.SessionManager.create(o.cwd);if(t.createAgentSessionRuntime!==void 0){const S=n(async y=>{const R=await f({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...R,diagnostics:R.services.diagnostics??[]}},"factory"),g=await t.createAgentSessionRuntime(S,{cwd:o.cwd,agentDir:s,sessionManager:w});return{session:g.session,services:g.services,resuming:v,runtime:g}}const E=await f({cwd:o.cwd,agentDir:s,sessionManager:w});return{session:E.session,services:E.services,resuming:v,runtime:void 0}}n(bn,"buildBrokerSession");function yn(t){const o=n((i,a,c,d)=>{if(d?.signal?.aborted)return Promise.resolve(i);const v=t.writable();return v.length===0?Promise.resolve(i):new Promise(w=>{let E;const S=n(()=>{E!==void 0&&clearTimeout(E),d?.signal?.removeEventListener("abort",g),t.pending.delete(a.id)},"cleanup"),g=n(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},"onAbort");d?.signal?.addEventListener("abort",g,{once:!0});const y=d?.timeout!==void 0?d.timeout:gn;E=setTimeout(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},y),typeof E.unref=="function"&&E.unref(),t.pending.set(a.id,{request:a,resolve:n(R=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(c(R))},"resolve")});for(const R of v)t.forward(R,a)})},"dialogPromise"),s=n(()=>{},"noop");return{[Rt]:t.onKnownStreamWait??(i=>()=>{}),get theme(){const i=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(i==null)throw new Error("Theme not initialized. Call initTheme() first.");return i},select:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:A(),method:"select",title:i,options:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"select"),confirm:n((i,a,c)=>o(!1,{type:"extension_ui_request",id:A(),method:"confirm",title:i,message:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,c),"confirm"),input:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:A(),method:"input",title:i,placeholder:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"input"),editor:n((i,a)=>o(void 0,{type:"extension_ui_request",id:A(),method:"editor",title:i,prefill:a},c=>"cancelled"in c&&c.cancelled?void 0:"value"in c?c.value:void 0),"editor"),setStatus:n((i,a)=>t.broadcast({type:"extension_ui_request",id:A(),method:"setStatus",statusKey:i,statusText:a}),"setStatus"),setWidget:n((i,a,c)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:A(),method:"setWidget",widgetKey:i,widgetLines:a,widgetPlacement:c?.placement})},"setWidget"),setTitle:n(i=>t.broadcast({type:"extension_ui_request",id:A(),method:"setTitle",title:i}),"setTitle"),notify:n((i,a)=>{const c=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:A(),method:"notify",message:i,notifyType:c})},"notify"),onTerminalInput:n(()=>s,"onTerminalInput"),setWorkingMessage:s,setWorkingVisible:s,setWorkingIndicator:s,setHiddenThinkingLabel:s,setFooter:s,setHeader:s,custom:n(()=>Promise.resolve(void 0),"custom"),pasteToEditor:s,setEditorText:s,getEditorText:n(()=>"","getEditorText"),addAutocompleteProvider:s,setEditorComponent:s,getEditorComponent:n(()=>{},"getEditorComponent"),getAllThemes:n(()=>[],"getAllThemes"),getTheme:n(()=>{},"getTheme"),setTheme:s,getToolsExpanded:n(()=>!1,"getToolsExpanded"),setToolsExpanded:s}}n(yn,"makeBrokerUiContext");export{Fr as REVIEW_BOUNDARY_NAVIGATION_CODE,Nr as ReviewBoundaryNavigationError,_n as brokerToolOptions,bn as buildBrokerSession,vn as disposeActiveSession,yn as makeBrokerUiContext,Or as runBroker,ae as snapshotMessages};
|
|
@@ -106,6 +106,9 @@ export declare function decideAttachRevive(nodeId: string, opts: Omit<ReviveOpti
|
|
|
106
106
|
* reaped) can never host a launch. Fail loud with a typed, user-visible error naming the path instead
|
|
107
107
|
* of letting `headlessBrokerHost.launch` fail deep inside the crash/doctrine-wake catch, where it would
|
|
108
108
|
* surface as an opaque `internal error` (toErrorBody masks every 5xx). Callers admit work to a node
|
|
109
|
-
* with this before changing any state. Returns the node
|
|
110
|
-
export declare function assertRecordedCwdExists(nodeId: string, meta: NodeMeta): Promise<
|
|
109
|
+
* with this before changing any state. Returns where the node runs: its Blaxel environment (null on a machine) and whether a remote machine hosts it. */
|
|
110
|
+
export declare function assertRecordedCwdExists(nodeId: string, meta: NodeMeta): Promise<{
|
|
111
|
+
blaxelEnvironment: string | null;
|
|
112
|
+
remoteMachine: boolean;
|
|
113
|
+
}>;
|
|
111
114
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var te=Object.defineProperty;var s=(e,r)=>te(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ne}from"./unsandboxed.js";import{existsSync as M}from"node:fs";import{conversationIdFromPath as v,conversationStore as h,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ae}from"node:path";import{findNodeBySessionFile as oe,getNode as $,updateNode as C,beginExecution as se,ExecutionAlreadyLive as le,recordExecutionPid as ce,abortExecution as N,endLiveExecution as ue,unbindSession as U,recordLaunch as fe,setFrozen as we,clearFrozen as G,fullName as de}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as pe}from"../feed/messages.js";import{isParked as W,transition as F}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as A}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as me,drainBearings as ve,hasRetainedReports as _e,readGoal as g,readYieldMessage as ye,RUNTIME_RESTART_CONTINUATION as ke}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ge,KICKOFF_ORIGIN_ENV as be}from"./stamp/protocol.js";import{headlessBrokerHost as Re,brokerLaunchJson as xe}from"./host.js";import{processRunner as Ee}from"./runner/process.js";import{runnerForEnvironment as Se}from"./runner/index.js";import{blaxelEnvironmentOf as j}from"./blaxel-environment.js";import{recordLaunchFailure as $e}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Ce,checkBilledWake as Ne,EnvironmentImagePending as Fe,imageForWake as Ae}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Pe,liveExecutionForNode as Be,setExecutionLaunchJson as Oe}from"../canvas/executions.js";import{appMemoryFull as De,appMemoryTooSmall as Te,boundFleet as V,brokerCapReached as X,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as Le}from"./memory-admission.js";import{beginBootFaultAttempt as ze,clearFault as Me,hasAdmittedTurn as He,readFault as Ue}from"../canvas/recovery.js";import{clearNodeLedger as Y,forkNodeLedger as Ge,noticeChangedWhileDone as Ke}from"./ledger.js";import{forkSourceNode as We,rootOfSpine as Je}from"./nodes.js";import{ApiError as je}from"../../api/errors.js";import{grantSnapshotMissing as Ve}from"../../daemon/readiness.js";import{checkStart as Xe}from"./start-check.js";import{isReviewCompanionBound as Ye}from"../review/companion.js";import{assertProfileActive as qe}from"../profiles/manifest.js";import{isPidAlive as Qe}from"../canvas/pid.js";import{crtrHome as Ze,jobDir as Ie}from"../canvas/paths.js";import{contextDir as er,ensureNodeDirs as rr,nodeAgentDir as ir}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as tr}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as nr}from"../command-hooks/transport/exec-lifecycle.js";async function ar(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await h().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}s(ar,"resumeArgs");async function q(e){const r=v(e);if(r===null)return!1;try{return await h().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}s(q,"conversationExists");async function or(e){const r=v(e);return r===null?!0:(await h().read(r)).entries.some(i=>i.type==="message")}s(or,"sessionHasConversation");async function sr(e){const r=v(e);if(r===null)return!0;const i=(await h().header(r)).header.cwd;return typeof i!="string"||M(i)}s(sr,"sessionCwdExists");async function lr(e,r,i,t){const a=r.pi_session_file;if(!a||!await q(a))return{};const w=await oe(a);return w!==null&&w.node_id!==e&&Qe(w.pi_pid)?{}:t&&!await sr(a)?{}:await ar(r,i)}s(lr,"resumableSessionArgs");async function cr(e){return await J(e)===null&&await ye(e)===null&&!await _e(e)}s(cr,"isUnstartedBirth");async function qr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}s(qr,"hasFreshGroundState");async function Qr(e,r){const i=await Q(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}s(Qr,"reviveNode");async function Zr(e,r,i){return Q(e,{...r,viewerAttach:!0},i)}s(Zr,"decideAttachRevive");async function Q(e,r,i){let t=await $(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await $(e)??t,t.run_id&&(await $(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);qe(t.profile_id),ne(t.grantee);const a=V(),w=t.grantee==="app:terminal"&&await Ve();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&W(t))&&(await Xe(t),await j(t.profile_id??null)!==null&&await Ne(t)),await a.has(e))return await F(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&W(t))return{parked:!0};if(w){if(r.capacity==="refuse")throw new je(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await Z(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const l=await a.reserveSlot(e);let o=null;if(l){try{o=await Le(e)}catch(b){throw a.releaseReservation(e),b}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Te(o);if(!l||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?De(o):X(P().automaticReviveCap,await a.occupancy());return await Z(e,t,o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await fr(e,t,r)}}finally{a.releaseReservation(e)}}s(Q,"decideRevive");async function Z(e,r,i){r.frozen_at==null&&(await we(e,new Date().toISOString()),await ue(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:i}))}s(Z,"freezeForWait");async function ur(e,r){const i=await j(r.profile_id??null);if(i===null&&!M(r.cwd)){const t=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new A({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:t})}return i}s(ur,"assertRecordedCwdExists");async function fr(e,r,i){const t=await ur(e,r);r.host_kind!=="broker"&&(await C(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Ye(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);const w=r.fork_from!=null&&r.pi_session_id==null,l=r.fork_source_file;if(w&&(typeof l!="string"||!ae(l)))throw new A({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const o=w&&typeof l=="string";if(o&&!await q(l))throw new A({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${l}`,next:`Restore ${l}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:b}=P();if(t!==null){const c=await Ae(t);if(c.state==="pending")throw new Fe(t,c.error)}const I=t===null?Ee:Se("blaxel");let f;try{f=await se(e,{daemonEpoch:V().epoch(),cap:b,...t===null?{}:{runner:"blaxel",release:Ce()}})}catch(c){if(c instanceof Pe)throw X(c.cap,c.live);if(c instanceof le)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw c}try{r.cycles=(r.cycles??0)+1,await C(e,{cycles:r.cycles});const R=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,p=o?{}:await lr(e,r,R,t===null),y=p.resumeSessionPath!==void 0,B=y&&p.newCycle===!0,m=y&&!B,O=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await cr(e),x=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await or(p.resumeSessionPath)?(await g(e))?.trim():void 0,D=x!==void 0&&x!=="",ee=o||O||D,T=r.cycle_pending===!0||B;await C(e,{cycle_pending:T}),r.cycle_pending=T,!o&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);let u,d=null;const E=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(o){const n=await g(e),S=v(l);if(S===null)throw new Error(`invalid fork source ${l}`);const ie=(await h().header(await h().fork(S,e))).path;u=_(r,{resumeSessionPath:ie,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=E()),await Ge(e,(await We(l))?.node_id??null)}else if(D)u=_(r,{...p,prompt:x}),d=E();else if(m)u=_(r,{...p,...i.wakeReason==="runtime-restart-abort"?{prompt:ke}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(O){const n=(await g(e))?.trim();u=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=E()),await Y(e)}else{const n=await ve(r,f);u=_(r,{...p,prompt:await me(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(u.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await Y(e)}u.env={...u.env,CRTR_SUBTREE:await Je(e)},d!==null&&(u.env[be]=ge(d)),r.status==="done"&&r.last_settled_at!=null&&await Ke(e,r.last_settled_at),await F(e,r.intent==="refresh"?"refresh-launch":"revive"),(await Ue(e))?.op!=="conversation_write_failed"&&await Me(e,{preserveEpisode:!0});const L=await ze(e);i.recovery!==!0&&i.viewerAttach!==!0&&await pe(e),await rr(e,r.grantee);const re=tr(r.cwd,r.profile_id).plans.get("node:start")??[];await nr(re,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await ir(e),contextDir:await er(e),jobDir:Ie(e)},runtime:{isBirth:ee,canvasHome:Ze(),profile:r.profile_id??null}}),u.env={...u.env,CRTR_EXECUTION_ID:f};const z=await xe(e,u,r.cwd);await Oe(f,z);let k;try{const n=await Be(e);if(k=await I.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await F(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await he(e,"notice.crash",`Child crashed \u2014 ${de(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
1
|
+
var le=Object.defineProperty;var s=(e,r)=>le(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ce}from"./unsandboxed.js";import{existsSync as U}from"node:fs";import{conversationIdFromPath as _,conversationStore as h,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ue}from"node:path";import{findNodeBySessionFile as fe,getNode as R,updateNode as N,beginExecution as we,ExecutionAlreadyLive as me,recordExecutionPid as de,abortExecution as F,endLiveExecution as he,unbindSession as G,recordLaunch as pe,setFrozen as ve,clearFrozen as K,fullName as _e}from"../canvas/index.js";import{emitEvent as W}from"../events/emit.js";import{consumeDeadlineOnWake as ye}from"../feed/messages.js";import{isParked as J,transition as A}from"./lifecycle.js";import{publishNotice as ke}from"./close.js";import{InputError as O}from"../io.js";import{buildPiArgv as y}from"./launch.js";import{buildReviveKickoff as ge,drainBearings as be,hasRetainedReports as Re,readGoal as E,readYieldMessage as Ee,RUNTIME_RESTART_CONTINUATION as xe}from"./kickoff.js";import{readRoadmap as j}from"./roadmap.js";import{encodeKickoffOrigin as Se,KICKOFF_ORIGIN_ENV as Ce}from"./stamp/protocol.js";import{headlessBrokerHost as $e,brokerLaunchJson as Ne}from"./host.js";import{isCloudRole as Fe}from"../canvas/person.js";import{asNodePerson as Ae}from"../../daemon/reconcilers/node-lifecycle/node-person.js";import{processRunner as Oe}from"./runner/process.js";import{runnerForEnvironment as V}from"./runner/index.js";import{MachineLaunchUncertainError as Pe,MachineOfflineError as Be}from"./runner/machine/ops.js";import{blaxelEnvironmentOf as X}from"./blaxel-environment.js";import{recordLaunchFailure as De}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Y,remoteMachineEnvironmentOf as Me,checkBilledWake as Te,EnvironmentImagePending as Le,imageForWake as ze}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Ue,liveExecutionForNode as He,setExecutionLaunchJson as Ge}from"../canvas/executions.js";import{isDrained as Ke}from"../../daemon/drain.js";import{appMemoryFull as We,appMemoryTooSmall as Je,boundFleet as q,brokerCapReached as Q,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as je}from"./memory-admission.js";import{beginBootFaultAttempt as Ve,clearFault as Xe,hasAdmittedTurn as Ye,readFault as qe}from"../canvas/recovery.js";import{clearNodeLedger as Z,forkNodeLedger as Qe,noticeChangedWhileDone as Ze}from"./ledger.js";import{forkSourceNode as Ie,rootOfSpine as er}from"./nodes.js";import{ApiError as rr}from"../../api/errors.js";import{grantSnapshotMissing as ir}from"../../daemon/readiness.js";import{checkStart as tr}from"./start-check.js";import{isReviewCompanionBound as nr}from"../review/companion.js";import{assertProfileActive as ar}from"../profiles/manifest.js";import{isPidAlive as or}from"../canvas/pid.js";import{crtrHome as sr,jobDir as lr}from"../canvas/paths.js";import{contextDir as cr,ensureNodeDirs as ur,nodeAgentDir as fr}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as wr}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as mr}from"../command-hooks/transport/exec-lifecycle.js";async function dr(e,r){const i=e.pi_session_file,t=i?_(i):null;if(t===null)return{};try{const a=await h().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}s(dr,"resumeArgs");async function I(e){const r=_(e);if(r===null)return!1;try{return await h().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}s(I,"conversationExists");async function hr(e){const r=_(e);return r===null?!0:(await h().read(r)).entries.some(i=>i.type==="message")}s(hr,"sessionHasConversation");async function pr(e){const r=_(e);if(r===null)return!0;const i=(await h().header(r)).header.cwd;return typeof i!="string"||U(i)}s(pr,"sessionCwdExists");async function vr(e,r,i,t){const a=r.pi_session_file;if(!a||!await I(a))return{};const u=await fe(a);return u!==null&&u.node_id!==e&&or(u.pi_pid)?{}:t&&!await pr(a)?{}:await dr(r,i)}s(vr,"resumableSessionArgs");async function _r(e){return await j(e)===null&&await Ee(e)===null&&!await Re(e)}s(_r,"isUnstartedBirth");async function ci(e){const r=await E(e);if(r!==null&&r.trim()!=="")return!0;const i=await j(e);return i!==null&&i.trim()!==""}s(ci,"hasFreshGroundState");async function ui(e,r){const i=await ee(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}s(ui,"reviveNode");async function fi(e,r,i){return ee(e,{...r,viewerAttach:!0},i)}s(fi,"decideAttachRevive");async function ee(e,r,i){const t=Fe()?await R(e):null;return t===null?await re(e,r,i):await Ae({node_id:e,sub:t.sub??null,profile_id:t.profile_id??null},()=>re(e,r,i))}s(ee,"decideRevive");async function re(e,r,i){let t=await R(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await R(e)??t,t.run_id&&(await R(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);ar(t.profile_id),ce(t.grantee);const a=q(),u=t.grantee==="app:terminal"&&await ir();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&J(t))&&(await tr(t),await X(t.profile_id??null)!==null&&await Te(t)),await a.has(e))return await A(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&J(t))return{parked:!0};if(u){if(r.capacity==="refuse")throw new rr(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await ie(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const k=await Ke();if(k&&r.capacity==="refuse")throw new Error(`the daemon is drained for an import; ${e} cannot start until it ends`);const p=!k&&await a.reserveSlot(e);let o=null;if(p){try{o=await je(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Je(o);if(!p||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?We(o):Q(P().automaticReviveCap,await a.occupancy());return await ie(e,t,k?{reason:"drain"}:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await kr(e,t,r)}}finally{a.releaseReservation(e)}}s(re,"decideReviveAsCaller");async function ie(e,r,i){r.frozen_at==null&&(await ve(e,new Date().toISOString()),await he(e,{reason:"frozen"}),W({level:"info",event:"broker.frozen",node_id:e,fields:i}))}s(ie,"freezeForWait");async function yr(e,r){const i=await X(r.profile_id??null),t=await Me(r.profile_id??null)!==null;if(!(i!==null||t)&&!U(r.cwd)){const u=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new O({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:u})}return{blaxelEnvironment:i,remoteMachine:t}}s(yr,"assertRecordedCwdExists");async function kr(e,r,i){const{blaxelEnvironment:t,remoteMachine:a}=await yr(e,r),u=t!==null||a;r.host_kind!=="broker"&&(await N(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await nr(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);const p=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(p&&(typeof o!="string"||!ue(o)))throw new O({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=p&&typeof o=="string";if(w&&!await I(o))throw new O({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:te}=P();if(t!==null){const l=await ze(t);if(l.state==="pending")throw new Le(t,l.error)}const ne=t!==null?V("blaxel"):a?V("machine"):Oe;let f;try{f=await we(e,{daemonEpoch:q().epoch(),cap:te,...t!==null?{runner:"blaxel",release:Y()}:a?{runner:"machine",release:Y()}:{}})}catch(l){if(l instanceof Ue)throw Q(l.cap,l.live);if(l instanceof me)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw l}try{r.cycles=(r.cycles??0)+1,await N(e,{cycles:r.cycles});const x=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,d=w?{}:await vr(e,r,x,!u),g=d.resumeSessionPath!==void 0,B=g&&d.newCycle===!0,v=g&&!B,D=!g&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await _r(e),S=v&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await Ye(e)&&!await hr(d.resumeSessionPath)?(await E(e))?.trim():void 0,M=S!==void 0&&S!=="",ae=w||D||M,T=r.cycle_pending===!0||B;await N(e,{cycle_pending:T}),r.cycle_pending=T,!w&&!g&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);let c,m=null;const C=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await E(e),$=_(o);if($===null)throw new Error(`invalid fork source ${o}`);const se=(await h().header(await h().fork($,e))).path;c=y(r,{resumeSessionPath:se,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(m=C()),await Qe(e,(await Ie(o))?.node_id??null)}else if(M)c=y(r,{...d,prompt:S}),m=C();else if(v)c=y(r,{...d,...i.wakeReason==="runtime-restart-abort"?{prompt:xe}:{}}),i.wakeReason==="runtime-restart-abort"&&(m={type:"runtime",kind:"restart-continuation"});else if(D){const n=(await E(e))?.trim();c=y(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(m=C()),await Z(e)}else{const n=await be(r,f);c=y(r,{...d,prompt:await ge(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),m=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await Z(e)}c.env={...c.env,CRTR_SUBTREE:await er(e)},m!==null&&(c.env[Ce]=Se(m)),r.status==="done"&&r.last_settled_at!=null&&await Ze(e,r.last_settled_at),await A(e,r.intent==="refresh"?"refresh-launch":"revive"),(await qe(e))?.op!=="conversation_write_failed"&&await Xe(e,{preserveEpisode:!0});const L=await Ve(e);i.recovery!==!0&&i.viewerAttach!==!0&&await ye(e),await ur(e,r.grantee);const oe=wr(r.cwd,r.profile_id).plans.get("node:start")??[];await mr(oe,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await fr(e),contextDir:await cr(e),jobDir:lr(e)},runtime:{isBirth:ae,canvasHome:sr(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:f};const z=await Ne(e,c,r.cwd);await Ge(f,z);let b;try{const n=await He(e);if(b=await ne.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:v}),!u&&b.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){if(n instanceof Be)throw n;try{await A(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await ke(e,"notice.crash",`Child crashed \u2014 ${_e(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
2
2
|
|
|
3
|
-
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await
|
|
3
|
+
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await F(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await pe(e,new Date().toISOString()),u)return await K(e),{window:null,session:r.tmux_session??null,resumed:v,faultExplanation:L.explanation,outcome:"launched"};if(await de(f,e,b.pid)==="shutdown")throw await F(f,{reason:"superseded"}),$e.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await K(e),{window:null,session:r.tmux_session??null,resumed:v,launch:b,faultExplanation:L.explanation,outcome:"launched"}}catch(l){throw l instanceof Pe||(await F(f,{reason:"launch_failed"}),await De(f,l).catch(x=>{W({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:x})})),l}}s(kr,"launchRevive");export{yr as assertRecordedCwdExists,fi as decideAttachRevive,ci as hasFreshGroundState,dr as resumeArgs,ui as reviveNode};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).map(n=>n.trim()).find(n=>n!=="")??g}
|
|
1
|
+
var u=Object.defineProperty;var a=(t,e)=>u(t,"name",{value:e,configurable:!0});import{openDb as s,withCanvasWrite as l}from"../canvas/db.js";import{findMany as d}from"../graph/bodies.js";import{heads as c,writeDocument as m}from"../graph/documents.js";import{asRuntimeWriter as p}from"../permissions/ceiling.js";import{getById as f,liveDocumentNamed as w,nodeObject as h}from"../graph/objects.js";import{readerForNode as y}from"../graph/reader.js";const o="roadmap",g="To understand this node's long-term task and current plan, read this.";function x(t){return t?.split(`
|
|
2
|
+
`).map(n=>n.trim()).find(n=>n!=="")??g}a(x,"roadmapPreview");function O(t){return`${t}/${o}`}a(O,"roadmapRef");async function i(t,e){const n=await f(t,e);return n===null||n.type!=="node"?null:await w(t,n.id,o)}a(i,"roadmapObject");async function P(t){return await i(await s(),t)!==null}a(P,"hasRoadmap");async function _(t){const e=await s(),n=await i(e,t);if(n===null)return null;const r=(await c(e,n))[0];return r===void 0?null:(await d(e,[r.body_hash])).get(r.body_hash)??null}a(_,"readRoadmap");function R(t){return`# Roadmap
|
|
3
3
|
|
|
4
4
|
## Goal
|
|
5
5
|
${t.goal?.trim()||"(the goal you now own)"}
|
|
@@ -12,4 +12,4 @@ ${t.exitCriteria?.trim()||'(what "done" looks like)'}
|
|
|
12
12
|
|
|
13
13
|
## Working set
|
|
14
14
|
(links to the documents the work depends on now, one per line)
|
|
15
|
-
`}
|
|
15
|
+
`}a(R,"scaffold");async function k(t,e,n={}){if(await i(t,e)!==null)return null;const r=R(n);return await m(t,p(await y(t,e,async()=>[])),{owner:await h(t,e),name:o,kind:"knowledge",preview:x(n.goal),privacy:"public",rules:[{on:"boot",deliver:"content"}]},r),r}a(k,"seedRoadmap");async function $(t,e={}){return await l(async n=>await k(n,t,e)!==null)}a($,"ensureRoadmap");export{o as ROADMAP_NAME,g as ROADMAP_PREVIEW,$ as ensureRoadmap,P as hasRoadmap,_ as readRoadmap,x as roadmapPreview,O as roadmapRef,k as seedRoadmap};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var g=Object.defineProperty;var
|
|
2
|
-
${
|
|
3
|
-
${
|
|
1
|
+
var g=Object.defineProperty;var i=(r,a)=>g(r,"name",{value:a,configurable:!0});import{openDb as k}from"../../../canvas/db.js";import{mintExecutionToken as I}from"../../../canvas/node-tokens.js";import{BlaxelApiError as T,isWorkloadUnavailable as x}from"./client.js";const m=4180,u="view",C="node /opt/crtr/current/scripts/sandbox-start.mjs --wake",S=3,N=/^crtr-sandbox-start: failed (\S+)/m,f=i(r=>`broker-${r}`,"brokerProcessName"),E=i(r=>r.sandboxName??`${r.nodeId}-${r.attempt}`,"sandboxNameFor");async function y(r){return(await(await k()).prepare("SELECT DISTINCT sandbox_name FROM executions WHERE node_id = ? AND sandbox_name IS NOT NULL").all(r)).map(l=>l.sandbox_name)}i(y,"defaultSandboxNames");function P(r){const a=`${r.logs}
|
|
2
|
+
${r.stderr}
|
|
3
|
+
${r.stdout}`;return{state:"failed",reason:N.exec(a)?.[1]??"start_failed",code:r.exitCode}}i(P,"failureOf");function h(r){const{client:a}=r,l=(r.stopGraceS??10)*1e3,b=new Map;async function d(t){return await a.getSandbox(E(t))}return i(d,"sandboxOf"),{kind:"blaxel",async start(t){const n=await r.launchContext(t),e=E(t),o=await a.createSandbox({name:e,image:n.image,memoryMb:n.memoryMb,ports:[{name:u,target:m}]}),s=f(t.executionId);if((await a.getProcess(o,s))?.status==="running")return{pid:null,exited:null};await a.ensurePreview(e,u,m);const w=await(r.mintToken??(p=>I(p.executionId,p.nodeId)))(t),R={...n.secrets,CRTR_API_URL:n.apiUrl,CRTR_EXECUTION_ID:t.executionId,CRTR_NODE_TOKEN:w,CRTR_RELEASE:t.release,CRTR_RELEASE_URL:n.releaseUrl,CRTR_RELEASE_SHA256:n.releaseSha256};return await a.startProcess(o,{name:s,command:r.bootstrap(),env:R,waitForCompletion:!1}),{pid:null,exited:null}},async wake(t){const n=await d(t);if(n===null)return"no_broker";try{const e=await a.exec(n,`wake-${t.executionId}-${Date.now()}`,`${C} ${t.executionId}`,30);if(e.exitCode===0)return"signalled";if(e.exitCode===S)return"no_broker";throw new Error(`wake of ${t.executionId} failed (exit ${e.exitCode}): ${(e.stderr||e.logs).slice(0,300)}`)}catch(e){if(x(e))return"no_broker";throw e}},async stop(t,n){try{const e=await d(t);if(e===null)return{confirmed:!0};const o=f(t.executionId),s=i(async()=>(await a.getProcess(e,o))?.status==="running","running");if(!await s())return{confirmed:!0};await a.stopProcess(e,o);const c=Date.now()+l;for(;Date.now()<c;){if(!await s())return{confirmed:!0};await new Promise(w=>setTimeout(w,250))}return await a.killProcess(e,o),{confirmed:!await s()}}catch(e){return x(e)?{confirmed:!0}:{confirmed:!1,error:e instanceof Error?e:new Error(String(e))}}},async status(t){try{const n=await d(t);if(n===null)return{state:"gone"};const e=await a.getProcess(n,f(t.executionId));return e===null?{state:"gone"}:e.status==="running"?{state:"running",pid:null}:e.status==="failed"||e.status==="completed"&&e.exitCode!==0?P(e):{state:"gone"}}catch(n){return x(n)?{state:"gone"}:{state:"unknown",error:n instanceof Error?n.message:String(n)}}},async delete(t){for(const n of await(r.sandboxNamesForNode??y)(t))await a.deleteSandbox(n)},async viewerAddress(t){const n=E(t),e=b.get(n);if(e&&e.expiresAt-Date.now()>5*6e4)return _(e.url,e.token);const o=await a.ensurePreview(n,u,m),s=new Date(Date.now()+60*6e4),{token:c}=await a.createPreviewToken(n,u,s);return b.set(n,{url:o,token:c,expiresAt:s.getTime()}),_(o,c)},async sandboxState(t){return(await d(t))?.state??null}}}i(h,"createBlaxelRunner");function _(r,a){return{kind:"wss",url:`${r.replace(/^https:/,"wss:")}/view`,headers:{"x-blaxel-preview-token":a}}}i(_,"viewer");export{m as BROKER_VIEW_PORT,T as BlaxelApiError,S as EXIT_NO_BROKER,N as FAILURE_LINE,C as WAKE_COMMAND,f as brokerProcessName,h as createBlaxelRunner,E as sandboxNameFor};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Runner, RunnerKind } from './types.js';
|
|
2
2
|
/** The Blaxel implementation is installed by the cloud runner module. */
|
|
3
3
|
export declare function registerBlaxelRunner(runner: Runner): void;
|
|
4
|
+
/** A machine environment is this process's own host for a Mac's crtrd (process runner) and another machine for a cloud role (the remote machine runner, design-import I13). */
|
|
4
5
|
export declare function runnerKindForEnvironment(kind: 'machine' | 'blaxel'): RunnerKind;
|
|
5
6
|
export declare function runnerForEnvironment(kind: 'machine' | 'blaxel'): Runner;
|
|
6
7
|
export declare function runnerForEnvironmentId(environmentId: string): Promise<Runner>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var t=Object.defineProperty;var r=(n,e)=>t(n,"name",{value:e,configurable:!0});import{openDb as i}from"../../canvas/db.js";import{isCloudRole as u}from"../../canvas/person-state.js";import{processRunner as l}from"./process.js";import{createMachineRunner as a}from"./machine/runner.js";let o=null;const c=a();function R(n){if(n.kind!=="blaxel")throw new Error("expected a Blaxel runner");o=n}r(R,"registerBlaxelRunner");function f(n){return n==="blaxel"?"blaxel":u()?"machine":"process"}r(f,"runnerKindForEnvironment");function m(n){return p(f(n))}r(m,"runnerForEnvironment");async function h(n){const e=await(await i()).prepare("SELECT kind FROM environments WHERE object = ?").get(n);if(!e)throw new Error(`environment ${n} not found`);return m(e.kind)}r(h,"runnerForEnvironmentId");function p(n){if(n==="process")return l;if(n==="machine")return c;if(o===null)throw new Error("Blaxel runner is not registered");return o}r(p,"runnerForExecution");export{R as registerBlaxelRunner,m as runnerForEnvironment,h as runnerForEnvironmentId,p as runnerForExecution,f as runnerKindForEnvironment};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type MachineOp, type MachineOpTable } from './ops.js';
|
|
2
|
+
/** Seconds a caller waits: `start` 60, every other op 15 (design). */
|
|
3
|
+
export declare const MACHINE_CALL_TIMEOUT_S: Record<MachineOp, number>;
|
|
4
|
+
export interface CallMachineOptions {
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
rereadMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function callMachine<O extends MachineOp>(environmentId: string, op: O, args: MachineOpTable[O]['args'], options?: CallMachineOptions): Promise<MachineOpTable[O]['result']>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var d=Object.defineProperty;var s=(e,n)=>d(e,"name",{value:n,configurable:!0});import{randomUUID as E}from"node:crypto";import{openDb as f,withCanvasWrite as h}from"../../../canvas/db.js";import{MachineCallFailedError as p,MachineLostError as l,MachineOfflineError as o}from"./ops.js";const S={start:60,wake:15,stop:15,status:15,delete:15,viewer:15,"cron.run":15,"cron.cancel":15},m=1e3;async function M(e,n,r,c={}){const i=E(),u=new Date().toISOString();if(!await h(async a=>await a.prepare("SELECT 1 AS live FROM machine_links WHERE environment = ? AND lease_expires_at > ?").get(e,u)===void 0?!1:(await a.prepare("INSERT INTO machine_calls (call_id, environment, op, args_json, created_at) VALUES (?, ?, ?, ?, ?)").run(i,e,n,JSON.stringify(r),u),await a.prepare("SELECT pg_notify(?, ?)").get("crtr_signal",`machine:${e}`),!0)))throw new o(e,"no live link");const w=Date.now()+(c.timeoutMs??S[n]*1e3);for(;;){const a=await(await f()).prepare("SELECT state, result_json, lease_expires_at, claimed_generation FROM machine_calls WHERE call_id = ?").get(i);if(a===void 0)throw new l(e,i);if(a.state==="done")return a.result_json===null?null:JSON.parse(a.result_json);if(a.state==="failed"){const t=a.result_json===null?{}:JSON.parse(a.result_json);throw t.code==="machine_offline"?new o(e,t.message,t.sent===!0):t.code==="machine_lost"?new l(e,i):new p(e,n,t.message??"unknown")}if(a.claimed_generation!==null&&a.lease_expires_at!==null&&a.lease_expires_at<=new Date().toISOString()){if(await _(i,"lease expired")===void 0)continue;throw new l(e,i)}if(Date.now()>=w){const t=await _(i,"timed out");if(t===void 0)continue;throw t===null?new o(e,"no holder claimed the call"):new l(e,i)}await new Promise(t=>setTimeout(t,c.rereadMs??m))}}s(M,"callMachine");async function _(e,n){const r=await(await f()).prepare(`UPDATE machine_calls SET state = 'failed', finished_at = ?,
|
|
2
|
+
result_json = CASE WHEN claimed_generation IS NULL THEN ? ELSE ? END
|
|
3
|
+
WHERE call_id = ? AND state IN ('pending', 'sent') RETURNING claimed_generation`).get(new Date().toISOString(),JSON.stringify({code:"machine_offline",message:n,sent:!1}),JSON.stringify({code:"machine_lost",message:n}),e);return r===void 0?void 0:r.claimed_generation===null?null:Number(r.claimed_generation)}s(_,"failOpenCall");export{S as MACHINE_CALL_TIMEOUT_S,M as callMachine};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function machineEnvironmentOfProfile(profileId: string): Promise<string | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t=Object.defineProperty;var o=(e,n)=>t(e,"name",{value:n,configurable:!0});import{openDb as i}from"../../../canvas/db.js";async function p(e){return(await(await i()).prepare("SELECT e.object AS object FROM profiles p JOIN environments e ON e.object = p.environment_id WHERE p.id = ? AND e.kind = 'machine'").get(e))?.object??null}o(p,"machineEnvironmentOfProfile");export{p as machineEnvironmentOfProfile};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StartBundleDTO } from '../../../../api/index.js';
|
|
2
|
+
import type { MachineOpTable } from './ops.js';
|
|
3
|
+
export interface MachineExecutorDeps {
|
|
4
|
+
/** `CRTR_API_URL` the brokers reach `/v1` at: the control plane. */
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
/** The machine environment's object id, set as `CRTR_ENVIRONMENT_ID`. */
|
|
7
|
+
environmentId: string;
|
|
8
|
+
/** Seconds `stop` waits after SIGTERM before SIGKILL. */
|
|
9
|
+
stopGraceS?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Broker processes: `{pid, execution, node}` for each `broker-cli.js ... --epoch <execution> <node>` command line. */
|
|
12
|
+
export declare function findBrokers(): Array<{
|
|
13
|
+
pid: number;
|
|
14
|
+
execution: string;
|
|
15
|
+
node: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** The env a machine's broker starts with: what the process runner's `buildBrokerEnv` builds for the same node. The environment's secret rows come from the
|
|
18
|
+
* control plane in the start bundle with the profile's metadata (this role has no database and no profiles, so the profile is never looked up here); the operational base, the profile's metadata, the app's pi dir and the launch recipe's env
|
|
19
|
+
* go over them in `buildBrokerEnv`'s order, and the link's own settings are pinned last. */
|
|
20
|
+
export declare function machineBrokerEnv(bundle: StartBundleDTO, deps: Pick<MachineExecutorDeps, 'apiUrl' | 'environmentId'>, executionId: string): NodeJS.ProcessEnv;
|
|
21
|
+
export declare function createMachineExecutor(deps: MachineExecutorDeps): {
|
|
22
|
+
[O in Exclude<keyof MachineOpTable, 'cron.run' | 'cron.cancel'>]: (args: MachineOpTable[O]['args'], signal?: AbortSignal) => Promise<MachineOpTable[O]['result']>;
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var T=Object.defineProperty;var c=(r,n)=>T(r,"name",{value:n,configurable:!0});import{spawn as P}from"node:child_process";import{closeSync as O,existsSync as y,mkdirSync as S,openSync as D,statSync as $}from"node:fs";import{rm as C}from"node:fs/promises";import{dirname as G,join as I}from"node:path";import{fileURLToPath as L}from"node:url";import{jobDir as N,nodeRunDir as v,crtrHome as A,viewSocketPath as U}from"../../../canvas/paths.js";import{captureTeardownSnapshot as B,isAnyPidAlive as F,killProcessTreePids as E,listProcessTable as M}from"../../../canvas/pid.js";import{scopesFilePath as j}from"../../../canvas/paths.js";import{writeFileBeneath as R}from"../../../spaces/open-beneath.js";import{FRONT_DOOR_ENV as K}from"../../front-door-env.js";import{composeAppProcessEnv as V,overlayBrokerEnv as H}from"../../spawn-env.js";const k=c(()=>I(G(L(import.meta.url)),"..","..","broker-cli.js"),"brokerEntry"),b=c(r=>{if(r!==void 0)try{process.kill(-r,"SIGKILL")}catch{}},"killGroup"),J=c(r=>new Promise(n=>setTimeout(n,r)),"sleep");function W(){const r=[];for(const{pid:n,command:i}of M()??[]){const e=/broker-cli\.js .*--epoch (\S+) (\S+)\s*$/.exec(i);e!==null&&r.push({pid:n,execution:e[1],node:e[2]})}return r}c(W,"findBrokers");async function z(r,n,i){const e=await fetch(`${r.replace(/\/$/,"")}/v1/executions/${n}/start`,{headers:{authorization:`Bearer ${i}`},signal:AbortSignal.timeout(3e4)});if(!e.ok)throw new Error(`the control plane answered ${e.status} for the start bundle of ${n}`);return await e.json()}c(z,"fetchBundle");function X(r,n,i){const e=r.launch,o=H({argv:[],env:e.env??{}},V(r.node.cwd,null,r.node.app,r.machine_env??{},{}));return Object.assign(o,{CRTR_API_URL:n.apiUrl,CRTR_EXECUTION_ID:i,CRTR_ENVIRONMENT_ID:n.environmentId,CRTR_VIEW_WSS:"0",[K]:"1"})}c(X,"machineBrokerEnv");function se(r){const n=(r.stopGraceS??10)*1e3,i=c(e=>W().find(o=>o.execution===e),"brokerOf");return{async start(e,o){const t=i(e.executionId);if(t!==void 0)return{pid:t.pid};if(o?.throwIfAborted(),!y(e.cwd)||!$(e.cwd).isDirectory())throw new Error(`the node's cwd ${e.cwd} is not a directory on this machine`);if(!y(k()))throw new Error(`the broker entry ${k()} does not exist`);const u=await z(r.apiUrl,e.executionId,e.nodeToken);o?.throwIfAborted();const a=u.launch,s=v(e.nodeId);S(s,{recursive:!0}),R(s,I(s,"broker-launch.json"),e.launchJson,{atomic:!0}),a.env?.CRTR_SCOPES_FILE!==void 0&&R(s,j(e.nodeId),JSON.stringify(a.scopes??[]),{atomic:!0});const m=N(e.nodeId);S(m,{recursive:!0});const f=D(I(m,"broker.log"),"a"),p=X(u,r,e.executionId);delete p.CRTR_NODE_TOKEN;try{o?.throwIfAborted();const d=P(process.execPath,[k(),"--canvas-home",A(),"--epoch",e.executionId,e.nodeId],{cwd:e.cwd,detached:!0,stdio:["ignore",f,f,"pipe"],env:p}),l=d.stdio[3];if(l==null||!("end"in l))throw b(d.pid),new Error("broker token pipe did not open");const x=await new Promise((_,h)=>{d.once("error",h),d.once("spawn",()=>{d.off("error",h),l.once("error",w=>{b(d.pid),h(w)}),l.end(e.nodeToken,w=>{w?h(w):_(d.pid)})})});return d.unref(),{pid:x}}finally{O(f)}},async wake({execution:e}){const o=i(e.executionId);if(o===void 0)return"no_broker";try{return process.kill(o.pid,"SIGUSR1"),"signalled"}catch(t){if(t.code==="ESRCH")return"no_broker";throw t}},async stop({execution:e,options:o}){const t=i(e.executionId);if(t===void 0)return{confirmed:!0};const{tree:u,identities:a}=B(t.pid,null,o.excludePid),s=c(async(m,f)=>{for(let p=0;F(m);p+=100){if(p>=f)return!1;await J(100)}return!0},"waitUntilDead");try{process.kill(t.pid,"SIGTERM")}catch{}return await s([t.pid],n),E(u,"SIGTERM",a),await s(u,2e3)?{confirmed:!0}:(E(u,"SIGKILL",a),await s(u,5e3)?{confirmed:!0}:{confirmed:!1,error:`broker process tree of ${t.pid} survived SIGKILL`})},async status({execution:e}){const o=i(e.executionId);return o===void 0?{state:"gone"}:{state:"running",pid:o.pid}},async delete({nodeId:e}){return await C(v(e),{recursive:!0,force:!0}),null},async viewer({execution:e}){return{kind:"unix",path:U(e.nodeId)}}}}c(se,"createMachineExecutor");export{se as createMachineExecutor,W as findBrokers,X as machineBrokerEnv};
|