@north-light/cli 0.3.580 → 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/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/node-tokens.d.ts +2 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/directory/person-credential.d.ts +36 -0
- package/dist/core/directory/person-credential.js +1 -0
- 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/reader.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/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/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/daemon/api/bridge.js +3 -3
- 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/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/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- 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/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/runs/observer.js +3 -3
- 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 g=Object.defineProperty;var r=(a,n)=>g(a,"name",{value:n,configurable:!0});const x=r(a=>a.primaryKey.length>0?a.primaryKey:a.columns,"rowKey"),y=r(a=>`"${a.replace(/"/g,'""')}"`,"q");async function O(a,n,p){const i=[...p],d=await a.prepareUncached(`SELECT table_name, column_name, is_identity FROM information_schema.columns
|
|
2
|
+
WHERE table_schema = ? AND table_name = ANY(?::text[]) ORDER BY table_name, ordinal_position`).all(n,`{${i.map(e=>`"${e}"`).join(",")}}`),o=new Map;for(const e of i)o.set(e,{name:e,columns:[],primaryKey:[],identity:[]});for(const e of d){const s=o.get(e.table_name);s.columns.push(e.column_name),e.is_identity==="YES"&&s.identity.push(e.column_name)}const l=await a.prepareUncached(`SELECT c.conrelid::regclass::text AS tbl, c.contype, c.conname,
|
|
3
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord) FROM unnest(c.conkey) WITH ORDINALITY k(attnum, ord) JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum) AS cols,
|
|
4
|
+
c.confrelid::regclass::text AS ptbl,
|
|
5
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord) FROM unnest(c.confkey) WITH ORDINALITY k(attnum, ord) JOIN pg_attribute a ON a.attrelid = c.confrelid AND a.attnum = k.attnum) AS pcols
|
|
6
|
+
FROM pg_constraint c WHERE c.connamespace = ?::regnamespace AND c.contype IN ('p', 'f')`).all(n),c=r(e=>e.replace(/^.*\./,"").replace(/"/g,""),"bare"),t=[];for(const e of l){const s=c(e.tbl);o.has(s)&&(e.contype==="p"?o.get(s).primaryKey=e.cols:o.has(c(e.ptbl))&&t.push({table:s,columns:e.cols,parent:c(e.ptbl),parentColumns:e.pcols}))}const u=(await a.prepareUncached(`SELECT t.relname AS tbl, i.relname AS name, pg_get_expr(x.indpred, x.indrelid) AS predicate, x.indexprs IS NOT NULL AS has_expr,
|
|
7
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord) FROM unnest(x.indkey::int2[]) WITH ORDINALITY k(attnum, ord) JOIN pg_attribute a ON a.attrelid = x.indrelid AND a.attnum = k.attnum) AS cols
|
|
8
|
+
FROM pg_index x JOIN pg_class t ON t.oid = x.indrelid JOIN pg_class i ON i.oid = x.indexrelid
|
|
9
|
+
WHERE t.relnamespace = ?::regnamespace AND x.indisunique AND NOT x.indisprimary`).all(n)).filter(e=>o.has(e.tbl)&&!e.has_expr).map(e=>({table:e.tbl,name:e.name,columns:e.cols,predicate:e.predicate}));return{schema:n,tables:o,foreignKeys:t,uniqueKeys:u}}r(O,"readCatalog");function _(a,n){const p=new Set(n),i=new Map(n.map(t=>[t,new Set]));for(const t of a.foreignKeys)p.has(t.table)&&p.has(t.parent)&&t.table!==t.parent&&i.get(t.table).add(t.parent);const d=[],o=new Set,l=new Set,c=r(t=>{if(!(o.has(t)||l.has(t))){l.add(t);for(const m of[...i.get(t)].sort())c(m);l.delete(t),o.add(t),d.push(t)}},"visit");for(const t of n)c(t);return d}r(_,"topologicalOrder");export{y as q,O as readCatalog,x as rowKey,_ as topologicalOrder};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
import { type PathMap } from '../bundle/layout.js';
|
|
3
|
+
import { type Catalog } from './catalog.js';
|
|
4
|
+
import type { IdMap } from './rewrite.js';
|
|
5
|
+
import type { SourceJson } from '../bundle/layout.js';
|
|
6
|
+
export interface CopyResult {
|
|
7
|
+
inserted: Record<string, number>;
|
|
8
|
+
mapped: Record<string, number>;
|
|
9
|
+
}
|
|
10
|
+
/** `import_manifest.inserted_keys`: a zstd-compressed JSON array of primary-key tuples (each value as text). */
|
|
11
|
+
export declare const encodeKeys: (keys: string[][]) => Buffer;
|
|
12
|
+
export declare const decodeKeys: (data: Buffer) => string[][];
|
|
13
|
+
export interface CopyInput {
|
|
14
|
+
db: CanvasDb;
|
|
15
|
+
runId: string;
|
|
16
|
+
schema: string;
|
|
17
|
+
target: string;
|
|
18
|
+
catalog: Catalog;
|
|
19
|
+
source: SourceJson;
|
|
20
|
+
person: string;
|
|
21
|
+
idMap: IdMap;
|
|
22
|
+
pathMap: PathMap;
|
|
23
|
+
}
|
|
24
|
+
export declare const copyOrder: (catalog: Catalog) => string[];
|
|
25
|
+
/** Must run inside `withCanvasWrite`. */
|
|
26
|
+
export declare function copyRows(input: CopyInput): Promise<CopyResult>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var A=Object.defineProperty;var i=(a,t)=>A(a,"name",{value:t,configurable:!0});import{zstdCompressSync as D,zstdDecompressSync as b}from"node:zlib";import{BODIES_TABLE as U,COPIED_TABLES as k,KEY_MAPPED_TABLES as C}from"../bundle/layout.js";import{q as s,rowKey as M,topologicalOrder as F}from"./catalog.js";import{fillEnvironments as H}from"./prepare.js";const h=i((a,t)=>`${s(a)}.${s(t)}`,"sq"),j=i(a=>D(Buffer.from(JSON.stringify(a))),"encodeKeys"),P=i(a=>JSON.parse(b(a).toString("utf8")),"decodeKeys"),v=i(a=>F(a,k),"copyOrder");async function K(a){const{db:t,runId:O,schema:f,target:I,catalog:T,source:l}=a,c=i(e=>h(f,e),"S"),E=i(e=>h(I,e),"T"),m={inserted:{},mapped:{}},N=i(async(e,n)=>{m.inserted[e]=n.length,await t.prepare("INSERT INTO import_manifest (run_id, table_name, inserted_keys) VALUES (?, ?, ?)").run(O,e,j(n))},"manifest");await H(t,f,I,l,a.person);for(const[e,n]of Object.entries(C)){const o=T.tables.get(e).columns.filter(p=>p!==n).map(s).join(", "),d=[],_=await t.prepareUncached(`SELECT ${s(n)}::text AS key FROM ${c(e)} ORDER BY ${s(n)}::bigint`).all();for(const{key:p}of _){const S=await t.prepareUncached(`INSERT INTO ${E(e)} (${o}) SELECT ${o} FROM ${c(e)} WHERE ${s(n)}::text = ? RETURNING ${s(n)}::text AS key`).get(p);await t.prepare("INSERT INTO import_key_map (source_install_id, table_name, source_key, target_key) VALUES (?, ?, ?, ?)").run(l.installId,e,p,S.key),d.push([S.key])}await N(e,d)}await t.prepareUncached(`UPDATE ${c("review_comments")} c SET created_seq = m.target_key::bigint FROM import_key_map m
|
|
2
|
+
WHERE m.source_install_id = ? AND m.table_name = 'review_comment_events' AND m.source_key = c.created_seq::text`).run(l.installId);for(const e of v(T)){if(e in C)continue;const n=T.tables.get(e),u=Number((await t.prepareUncached(`SELECT count(*) AS n FROM ${c(e)}`).get()).n);if(u===0){m.inserted[e]=0;continue}const o=M(n),d=n.columns.filter(r=>!n.identity.includes(r)),_=n.identity.length>0?n.identity.map(r=>`s.${s(r)}`).join(", "):o.map(r=>`s.${s(r)}`).join(", ");let p=d.map(r=>`s.${s(r)}`),S="";if(e==="messages"){const r=`NOT EXISTS (SELECT 1 FROM ${E("messages")} t WHERE t.message_id = s.message_id)`,g=Number((await t.prepareUncached(`SELECT count(*) AS n FROM ${c("messages")} s WHERE ${r}`).get()).n);if(S=` WHERE ${r}`,g===0){m.inserted[e]=0,await N(e,[]);continue}const w=Number((await t.prepare("UPDATE message_sequence SET seq = seq + ? WHERE id = 1 RETURNING seq").get(g)).seq);p=d.map(y=>y==="seq"?`${w-g} + row_number() OVER (ORDER BY s.seq)`:`s.${s(y)}`)}const L=o.map(r=>`${s(r)}::text`).join(", "),$=n.primaryKey.length===0;$&&(S=` WHERE NOT EXISTS (SELECT 1 FROM ${E(e)} t WHERE ${o.map(r=>`t.${s(r)} IS NOT DISTINCT FROM s.${s(r)}`).join(" AND ")})`);const R=await t.prepareUncached(`INSERT INTO ${E(e)} (${d.map(s).join(", ")}) SELECT ${p.join(", ")} FROM ${c(e)} s${S}
|
|
3
|
+
ORDER BY ${_}${$?"":` ON CONFLICT (${o.map(s).join(", ")}) DO NOTHING`} RETURNING ${L}`).all();e===U?m.inserted[e]=R.length:await N(e,R.map(r=>Object.values(r))),m.mapped[e]=u-R.length}await t.prepareUncached(`DELETE FROM ${E("charge_totals")} t WHERE (t.month, t.payer) IN (SELECT DISTINCT month, payer FROM ${c("charges")})`).run(),await t.prepareUncached(`INSERT INTO ${E("charge_totals")} (month, payer, funding, sub, grantee, provider, usd, billed_usd)
|
|
4
|
+
SELECT month, payer, funding, COALESCE(sub, ''), grantee, COALESCE(provider, ''), COALESCE(SUM(usd), 0), COALESCE(SUM(billed_usd), 0)
|
|
5
|
+
FROM ${E("charges")} WHERE refused IS NULL AND kind <> 'take' AND (month, payer) IN (SELECT DISTINCT month, payer FROM ${c("charges")})
|
|
6
|
+
GROUP BY month, payer, funding, COALESCE(sub, ''), grantee, COALESCE(provider, '')`).run();for(const[e,n]of[["object",a.idMap.object],["grant",a.idMap.grant],["kind",a.idMap.kind]])for(const[u,o]of n)await t.prepare("INSERT INTO import_id_map (run_id, kind, source_value, target_value) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING").run(O,e,u,o);for(const e of a.pathMap)await t.prepare("INSERT INTO import_id_map (run_id, kind, source_value, target_value) VALUES (?, 'path', ?, ?) ON CONFLICT DO NOTHING").run(O,e.from,e.to);return await t.prepare("UPDATE import_runs SET state = 'committed', committed_at = ?, step = 'copy' WHERE run_id = ?").run(new Date().toISOString(),O),m}i(K,"copyRows");export{v as copyOrder,K as copyRows,P as decodeKeys,j as encodeKeys};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
import { type PathMap, type PathPrefix, type SourceJson } from '../bundle/layout.js';
|
|
3
|
+
/** A directory two nodes share (a cwd outside both worktrees) maps once, to the first node's folder: both nodes' rows read the same target and each
|
|
4
|
+
* sandbox unpacks its own archive there. */
|
|
5
|
+
export declare function sandboxPathMap(prefixes: readonly PathPrefix[]): PathMap;
|
|
6
|
+
/** One `import_node_files` row per hosted running node the exporter archived. Runs in the copy transaction, after the nodes are copied. */
|
|
7
|
+
export declare function writeNodeFiles(tx: CanvasDb, schema: string, runId: string, source: SourceJson): Promise<number>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var f=Object.defineProperty;var d=(o,t)=>f(o,"name",{value:t,configurable:!0});import{bundleKeys as l}from"../bundle/layout.js";import{q as c}from"./catalog.js";import{ImportLaneError as s}from"./stage.js";const p="/var/lib/crtr",u="/work/imported";function b(o){const t=o.map(e=>{if(!e.from.startsWith("/")||e.from.split("/").includes(".."))throw new s("stage","bundle_invalid",`path prefix ${e.from} of node ${e.node} is not an absolute path`);const n=e.app.replace(/^app:/,"");if(!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(n)||!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(e.node))throw new s("stage","bundle_invalid",`path prefix names app ${e.app} and node ${e.node}`);const r=`${p}/apps/${n}/nodes/${e.node}`,i=e.role==="context"?`${r}/context`:e.role==="worktree"?`${r}/worktree`:`${u}/${e.node}`;return{from:e.from,to:i}});return t.filter((e,n)=>t.findIndex(r=>r.from===e.from)===n)}d(b,"sandboxPathMap");async function _(o,t,e,n){if(n.kind!=="hosted")return 0;const r=[...new Set((n.pathPrefixes??[]).map(a=>a.node))];let i=0;for(const a of r){if(await o.prepareUncached(`SELECT 1 AS found FROM ${c(t)}.nodes WHERE node_id = ? AND status IN ('active', 'idle')`).get(a)===void 0)throw new s("copy","bundle_invalid",`an archive was uploaded for node ${a}, which is not a running node of the bundle`);i+=Number((await o.prepare("INSERT INTO import_node_files (node, blob_key) VALUES (?, ?) ON CONFLICT DO NOTHING").run(a,l.nodeFiles(e,a))).changes)}return i}d(_,"writeNodeFiles");export{b as sandboxPathMap,_ as writeNodeFiles};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
import { type PathMap, type SourceJson } from '../bundle/layout.js';
|
|
3
|
+
import { type Catalog } from './catalog.js';
|
|
4
|
+
/** A revision of a document the target already holds, to be added through repo sync's own arrival path. */
|
|
5
|
+
export interface ArrivingRevision {
|
|
6
|
+
document: string;
|
|
7
|
+
rev_id: string;
|
|
8
|
+
parents: string[];
|
|
9
|
+
body_hash: string;
|
|
10
|
+
rationale: string | null;
|
|
11
|
+
created_at: string;
|
|
12
|
+
}
|
|
13
|
+
/** Rewrite 4: for rows of running nodes of a hosted source, path columns go through the run's map. Ended nodes' rows stay as historical text. */
|
|
14
|
+
export declare function rewritePaths(db: CanvasDb, schema: string, map: PathMap): Promise<number>;
|
|
15
|
+
/** Rewrite 4b: a human request's files live in the blob store under `requests/<id>/` (the exporter uploaded the request dir there). `request_dir` becomes that
|
|
16
|
+
* prefix; a `file` or `presentation_dir` inside the old dir keeps its relative path, one outside it was uploaded to `source/<basename>`. A path that is not
|
|
17
|
+
* absolute is already a blob path and stays. */
|
|
18
|
+
export declare function rewriteRequestPaths(db: CanvasDb, schema: string): Promise<number>;
|
|
19
|
+
/** A profile whose name the person already uses for another profile is renamed `<name>-<install id>` (staging only; runs before the pre-check). */
|
|
20
|
+
export declare function renameClashingProfiles(db: CanvasDb, schema: string, target: string, installId: string, person: string): Promise<number>;
|
|
21
|
+
/** Fill: a staged profile with no environment gets the source's machine environment (a Mac) or the person's Blaxel environment (hosted, created if
|
|
22
|
+
* absent). Runs in the copy transaction: it writes target objects. */
|
|
23
|
+
export declare function fillEnvironments(tx: CanvasDb, schema: string, target: string, source: SourceJson, person: string): Promise<number>;
|
|
24
|
+
/** Staged edits that need nothing from the target but its key map: limits the directory or an operator wrote stay out, a hosted source's own
|
|
25
|
+
* machine environment is marked for the drop step, claims of the old runtime's lanes are cleared, and rows of the identity-keyed tables already in
|
|
26
|
+
* `import_key_map` are not staged again. Returns the rows removed per table. */
|
|
27
|
+
export declare function pruneStaged(db: CanvasDb, schema: string, catalog: Catalog, source: SourceJson): Promise<Record<string, number>>;
|
|
28
|
+
/** A staged document whose id the target already holds (repo sync keeps the id across runtimes) is not inserted: its revisions arrive through
|
|
29
|
+
* `insertImportedRevisions`. Removes its staged object, document, revision and parent rows and returns the revisions. Runs before the pre-check. */
|
|
30
|
+
export declare function takeRepoSyncedDocuments(db: CanvasDb, schema: string, target: string): Promise<ArrivingRevision[]>;
|
|
31
|
+
export interface Collision {
|
|
32
|
+
table: string;
|
|
33
|
+
key: string;
|
|
34
|
+
values: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Pre-check (I9): every non-primary unique key and every text primary key the target already holds. Throws `unique_conflict` naming the first 10 values. */
|
|
37
|
+
export declare function precheck(db: CanvasDb, schema: string, target: string, catalog: Catalog, tables: readonly string[], skip: ReadonlySet<string>, seqLike: ReadonlyMap<string, string[]>): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var y=Object.defineProperty;var d=(n,o)=>y(n,"name",{value:o,configurable:!0});import{createProfileBlaxelEnvironment as v}from"../../environments.js";import{KEY_MAPPED_TABLES as U,mapPath as S}from"../bundle/layout.js";import{ImportLaneError as O}from"./stage.js";import{q as l}from"./catalog.js";const $=d((n,o)=>`${l(n)}.${l(o)}`,"sq");async function F(n,o,c){if(c.length===0)return 0;const e=d(s=>$(o,s),"S"),t=`(SELECT node_id FROM ${e("nodes")} WHERE status IN ('active', 'idle'))`;let a=0;const E=d(async(s,r,i,u=!1)=>{const _=await n.prepareUncached(`SELECT ${l(r)}::text AS value FROM ${e(s)} WHERE ${i} AND ${l(r)} IS NOT NULL`).all();for(const{value:R}of _){const T=u?H(R,c):S(c,R);T!==R&&(await n.prepareUncached(`UPDATE ${e(s)} SET ${l(r)} = ? WHERE ${l(r)}::text = ? AND ${i}`).run(T,R),a+=1)}},"apply");return await E("nodes","cwd",`node_id IN ${t}`),await E("worktrees","path",`node_id IN ${t}`),await E("worktrees","repo_root",`node_id IN ${t}`),await E("crons","cwd",`anchor_node IN ${t}`),await E("provider_approvals","prepared_files","TRUE",!0),await E("upload_uses","path",`run_id IN ${t}`),a}d(F,"rewritePaths");async function g(n,o){const c=$(o,"human_requests"),e=d(a=>`CASE WHEN ${a} IS NULL OR ${a} NOT LIKE '/%' THEN ${a}
|
|
2
|
+
WHEN rtrim(${a}, '/') = rtrim(request_dir, '/') THEN 'requests/' || request_id
|
|
3
|
+
WHEN ${a} LIKE rtrim(request_dir, '/') || '/%' THEN 'requests/' || request_id || '/' || substr(${a}, length(rtrim(request_dir, '/')) + 2)
|
|
4
|
+
ELSE 'requests/' || request_id || '/source/' || regexp_replace(${a}, '^.*/', '') END`,"moved"),t=await n.prepareUncached(`UPDATE ${c} SET file = ${e("file")}, presentation_dir = ${e("presentation_dir")},
|
|
5
|
+
request_dir = CASE WHEN request_dir LIKE '/%' THEN 'requests/' || request_id ELSE request_dir END`).run();return Number(t.changes)}d(g,"rewriteRequestPaths");function H(n,o){const c=d(e=>typeof e=="string"?S(o,e):Array.isArray(e)?e.map(c):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([t,a])=>[t,c(a)])):e,"walk");try{return JSON.stringify(c(JSON.parse(n)))}catch{return S(o,n)}}d(H,"rewriteJsonPaths");async function j(n,o,c,e,t){const a=d(r=>$(o,r),"S"),E=await n.prepareUncached(`SELECT id, name FROM ${a("profiles")} ORDER BY id`).all();let s=0;for(const r of E)await n.prepareUncached(`SELECT 1 AS found FROM ${$(c,"profiles")} WHERE person = ? AND name = ? AND id <> ?`).get(t,r.name,r.id)!==void 0&&(await n.prepareUncached(`UPDATE ${a("profiles")} SET name = ? WHERE id = ?`).run(`${r.name}-${e}`,r.id),s+=1);return s}d(j,"renameClashingProfiles");async function q(n,o,c,e,t){const a=d(r=>$(o,r),"S");let E=0;const s=await n.prepareUncached(`SELECT id, grantee FROM ${a("profiles")} WHERE environment_id IS NULL ORDER BY id`).all();for(const r of s){let i=e.kind==="machine"?e.environmentObject??null:null;if(e.kind==="hosted"&&(i=(await n.prepareUncached(`SELECT environment_id FROM ${$(c,"profiles")} WHERE id = ?`).get(r.id))?.environment_id??await v(n,{profileId:r.id,grantee:r.grantee??"app:terminal",person:t})),i===null)throw new O("fill","bundle_invalid",`profile ${r.id} has no environment and the source names none`);await n.prepareUncached(`UPDATE ${a("profiles")} SET environment_id = ? WHERE id = ?`).run(i,r.id),E+=1}return E}d(q,"fillEnvironments");async function x(n,o,c,e){const t=d(s=>$(o,s),"S"),a={},E=d(async(s,r,...i)=>{const u=Number((await n.prepareUncached(r).run(...i)).changes);u>0&&(a[s]=(a[s]??0)+u)},"del");await E("limits",`DELETE FROM ${t("limits")} WHERE source <> 'person'`),e.kind==="hosted"&&(await n.prepareUncached(`UPDATE ${t("profiles")} SET environment_id = NULL WHERE environment_id IN (SELECT object FROM ${t("environments")})`).run(),await n.prepareUncached(`UPDATE ${t("objects")} SET home_machine = 'import-hosted-source' WHERE id IN (SELECT object FROM ${t("environments")})`).run());for(const[s,r]of Object.entries(U))await E(s,`DELETE FROM ${t(s)} WHERE ${l(r)}::text IN (SELECT source_key FROM import_key_map WHERE source_install_id = ? AND table_name = ?)`,e.installId,s);for(const s of c.tables.values())s.columns.includes("claimed_by")&&s.columns.includes("lease_expires_at")&&await n.prepareUncached(`UPDATE ${t(s.name)} SET claimed_by = NULL, lease_expires_at = NULL WHERE claimed_by IS NOT NULL OR lease_expires_at IS NOT NULL`).run();return a}d(x,"pruneStaged");async function b(n,o,c){const e=d(E=>$(o,E),"S"),t=`(SELECT d.object FROM ${e("documents")} d WHERE EXISTS (SELECT 1 FROM ${$(c,"documents")} t WHERE t.object = d.object))`;await n.exec(`CREATE TABLE ${e("_arr_revisions")} AS SELECT r.* FROM ${e("revisions")} r WHERE r.document IN ${t};
|
|
6
|
+
CREATE TABLE ${e("_arr_parents")} AS SELECT p.* FROM ${e("revision_parents")} p WHERE p.child IN (SELECT rev_id FROM ${e("revisions")} WHERE document IN ${t})`);const a=await n.prepareUncached(`SELECT r.document, r.rev_id, r.body_hash, r.rationale, r.created_at,
|
|
7
|
+
COALESCE((SELECT array_agg(p.parent) FROM ${e("revision_parents")} p WHERE p.child = r.rev_id), ARRAY[]::text[]) AS parents
|
|
8
|
+
FROM ${e("revisions")} r WHERE r.document IN ${t} ORDER BY r.document, r.number`).all();return await n.prepareUncached(`DELETE FROM ${e("revision_parents")} WHERE child IN (SELECT rev_id FROM ${e("revisions")} WHERE document IN ${t})`).run(),await n.prepareUncached(`DELETE FROM ${e("revisions")} WHERE document IN ${t}`).run(),await n.prepareUncached(`DELETE FROM ${e("objects")} WHERE id IN ${t}`).run(),await n.prepareUncached(`DELETE FROM ${e("documents")} WHERE object IN ${t}`).run(),a.map(E=>({...E}))}d(b,"takeRepoSyncedDocuments");async function k(n,o,c,e,t,a,E){const s=d(i=>[...E.get(i)??[],...i==="profiles"?["environment_id"]:[],"claimed_by","lease_expires_at"],"ignored"),r=[];for(const i of t){const u=e.tables.get(i);if(u===void 0||a.has(i)||u.primaryKey.length===0)continue;const _=u.primaryKey,R=_.some(p=>u.identity.includes(p)),T=_.map(p=>`s.${l(p)} = t.${l(p)}`).join(" AND "),w=R?"TRUE":_.map(p=>`s.${l(p)} IS DISTINCT FROM t.${l(p)}`).join(" OR "),I=new Set([...u.identity,...E.get(i)??[]]);for(const p of e.uniqueKeys.filter(f=>f.table===i&&!f.columns.every(m=>I.has(m)))){const f=p.predicate===null?"":` WHERE ${p.predicate}`,m=p.columns.map(h=>`s.${l(h)} = t.${l(h)}`).join(" AND "),L=await n.prepareUncached(`SELECT ${p.columns.map(h=>`s.${l(h)}::text`).join(" || ',' || ")} AS value
|
|
9
|
+
FROM (SELECT * FROM ${$(o,i)}${f}) s JOIN (SELECT * FROM ${$(c,i)}${f}) t ON ${m} AND (${w}) LIMIT 10`).all();L.length>0&&r.push({table:i,key:p.name,values:L.map(h=>h.value)})}const N=u.columns.filter(p=>!u.identity.includes(p)&&!s(i).includes(p));if(N.length>0&&!R){const p=N.map(m=>`s.${l(m)} IS DISTINCT FROM t.${l(m)}`).join(" OR "),f=await n.prepareUncached(`SELECT ${_.map(m=>`s.${l(m)}::text`).join(" || ',' || ")} AS value
|
|
10
|
+
FROM ${$(o,i)} s JOIN ${$(c,i)} t ON ${T} WHERE ${p} LIMIT 10`).all();f.length>0&&r.push({table:i,key:"primary key payload",values:f.map(m=>m.value)})}}if(r.length>0){const i=r[0];throw new O("pre-check","unique_conflict",`${i.table} ${i.key} collides with the target: ${i.values.join(", ")}`,{collisions:r})}}d(k,"precheck");export{q as fillEnvironments,k as precheck,x as pruneStaged,j as renameClashingProfiles,F as rewritePaths,g as rewriteRequestPaths,b as takeRepoSyncedDocuments};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type CanvasDb } from '../../canvas/db.js';
|
|
2
|
+
import { ImportLaneError } from './stage.js';
|
|
3
|
+
import { type Catalog } from './catalog.js';
|
|
4
|
+
export interface RewriteInput {
|
|
5
|
+
db: CanvasDb;
|
|
6
|
+
/** The staging schema. */
|
|
7
|
+
schema: string;
|
|
8
|
+
/** The crouter schema the rows are copied into. */
|
|
9
|
+
target: string;
|
|
10
|
+
catalog: Catalog;
|
|
11
|
+
sourcePerson: string;
|
|
12
|
+
targetPerson: string;
|
|
13
|
+
/** The control plane's fleet runtime principal (`CRTR_RUNTIME`), the key of the directory's grants. */
|
|
14
|
+
fleetRuntime: string | null;
|
|
15
|
+
/** `source.shippedBodies`: shipped document id → hash of its body, which is a `bodies` row of the bundle (copied with the table). */
|
|
16
|
+
shippedBodies: Readonly<Record<string, string>>;
|
|
17
|
+
}
|
|
18
|
+
/** Source id → target id, per kind. Persisted into `import_id_map` in the copy transaction. */
|
|
19
|
+
export interface IdMap {
|
|
20
|
+
object: Map<string, string>;
|
|
21
|
+
grant: Map<string, string>;
|
|
22
|
+
kind: Map<string, string>;
|
|
23
|
+
}
|
|
24
|
+
/** Object-id columns that carry no foreign key (design-import, "Id columns"). */
|
|
25
|
+
export declare const OBJECT_ID_COLUMNS: ReadonlyArray<[string, string]>;
|
|
26
|
+
/** Every column that holds an object id, per table: the foreign keys onto `objects` in the target's catalog, then the ones without a foreign key. */
|
|
27
|
+
export declare function objectIdColumns(catalog: Catalog): Map<string, Set<string>>;
|
|
28
|
+
/** Rewrite 1: `substitutePerson` against the staging schema (every table it touches is staged, the ones the bundle does not dump empty). */
|
|
29
|
+
export declare function rewritePerson(input: RewriteInput): Promise<void>;
|
|
30
|
+
/** The target's grant for (fleet runtime, sub, grantee), the key the directory writes an importing person's grants under. The lane's wait for those
|
|
31
|
+
* grants (`run.ts`) and rewrite 2 both look a grant up here. A null fleet runtime (`CRTR_RUNTIME` unset) holds none. */
|
|
32
|
+
export declare function findFleetGrant(db: CanvasDb, target: string, fleetRuntime: string | null, sub: string, grantee: string): Promise<string | undefined>;
|
|
33
|
+
/** The `grant_missing` failure, for the grantees the target holds no grant for. */
|
|
34
|
+
export declare function grantMissing(grantees: readonly string[]): ImportLaneError;
|
|
35
|
+
/** Rewrite 2 (id map): build the map, drop the staged rows of mapped objects, rewrite every id column through it. */
|
|
36
|
+
export declare function rewriteIds(input: RewriteInput): Promise<IdMap>;
|
|
37
|
+
/** The drop step: federation stubs' objects and every staged row that points at a dropped row, then the assertion that no staged foreign
|
|
38
|
+
* key points at a row that is neither staged nor in the target. Returns rows dropped per table. */
|
|
39
|
+
export declare function dropStubRows(input: RewriteInput): Promise<Record<string, number>>;
|
|
@@ -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 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 {};
|