@north-light/cli 0.3.589 → 0.3.590
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 +4 -1
- package/dist/api/client.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/docs.d.ts +5 -0
- package/dist/api/dto/settings.d.ts +21 -0
- package/dist/build-root.d.ts +2 -0
- package/dist/build-root.js +1 -1
- package/dist/cli.js +8 -8
- package/dist/clients/attach/viewer.js +468 -468
- package/dist/commands/pkg/app-installs.d.ts +53 -0
- package/dist/commands/pkg/app-installs.js +2 -0
- package/dist/commands/pkg/market-inspect.js +1 -1
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-inspect.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +13 -13
- package/dist/core/canvas/schema-pg/011-package-revision.sql +12 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +1 -1
- package/dist/core/graph/names.js +8 -8
- package/dist/core/graph/package-docs.d.ts +6 -15
- package/dist/core/graph/package-docs.js +8 -6
- package/dist/core/graph/package-publish.d.ts +35 -5
- package/dist/core/graph/package-publish.js +3 -3
- package/dist/core/graph/package-reconcile.d.ts +20 -1
- package/dist/core/graph/package-reconcile.js +3 -1
- package/dist/core/import/export/dump.js +4 -3
- package/dist/core/import/load/stores.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/packages/directory-sync.d.ts +41 -0
- package/dist/core/packages/directory-sync.js +6 -0
- package/dist/core/packages/eligibility.d.ts +16 -0
- package/dist/core/packages/eligibility.js +4 -0
- package/dist/core/packages/launch-kinds.d.ts +6 -0
- package/dist/core/packages/launch-kinds.js +2 -0
- package/dist/core/packages/source-url.d.ts +3 -0
- package/dist/core/packages/source-url.js +1 -0
- package/dist/core/permissions/ceiling.d.ts +9 -2
- package/dist/core/permissions/ceiling.js +11 -12
- package/dist/core/permissions/evaluator.js +2 -2
- package/dist/core/runtime/launch-config-worker.js +1 -1
- package/dist/core/runtime/launch-target.d.ts +6 -2
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/launch.d.ts +8 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scoped-state/legacy-profiles.js +1 -1
- package/dist/core/scoped-state/migrate-app-installs.d.ts +13 -0
- package/dist/core/scoped-state/migrate-app-installs.js +1 -0
- package/dist/core/scoped-state/person-rows.js +4 -6
- package/dist/core/scoped-state/person-store.d.ts +23 -0
- package/dist/core/scoped-state/person-store.js +1 -1
- package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
- package/dist/daemon/api/handlers/execution-start.js +2 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/package-docs.d.ts +1 -1
- package/dist/daemon/api/handlers/package-docs.js +1 -1
- package/dist/daemon/api/handlers/settings.d.ts +4 -1
- package/dist/daemon/api/handlers/settings.js +1 -1
- package/dist/daemon/crtrd.js +19 -19
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/dist/core/graph/package-kinds.d.ts +0 -22
- package/dist/core/graph/package-kinds.js +0 -1
- package/dist/core/scoped-state/materialized-plugins.d.ts +0 -20
- package/dist/core/scoped-state/materialized-plugins.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
var N=Object.defineProperty;var n=(e,r)=>N(e,"name",{value:r,configurable:!0});import{createHash as R,randomUUID as L}from"node:crypto";import{openDb as b}from"../canvas/db.js";import{claimReconcilerLease as C,releaseReconcilerLease as E,renewReconcilerLease as W}from"../canvas/reconciler-leases.js";import{claimWarmSpare as M,deleteNode as u,getNode as
|
|
1
|
+
var N=Object.defineProperty;var n=(e,r)=>N(e,"name",{value:r,configurable:!0});import{createHash as R,randomUUID as L}from"node:crypto";import{openDb as b}from"../canvas/db.js";import{claimReconcilerLease as C,releaseReconcilerLease as E,renewReconcilerLease as W}from"../canvas/reconciler-leases.js";import{claimWarmSpare as M,deleteNode as u,getNode as p,listNodes as P,listWarmSpares as y,registerWarmSpare as I,unregisterWarmSpare as h,updateNode as A,warmSpareCount as g}from"../canvas/index.js";import{recordedPidLiveness as D}from"../canvas/pid.js";import{nowIso as _}from"../fs-utils.js";import{admitNodeCreate as O}from"../command-hooks/lifecycle-create.js";import{isDrained as T}from"../../daemon/drain.js";import{spawnChildPrepared as H}from"./spawn.js";import{blaxelEnvironmentOf as F}from"./blaxel-environment.js";import{newNodeId as K}from"./nodes.js";import{checkStart as U}from"./start-check.js";import{buildLaunchSpecAsync as j}from"./launch.js";import{setModelLive as B}from"./model-swap.js";import{setSituationalContextLive as G}from"./situational-live.js";import{deliverBearingsLive as J}from"./deliver-live.js";import{closeNode as f}from"./close.js";function v(){return process.env.CRTR_WARM_POOL!=="0"}n(v,"warmPoolEnabled");function z(e,r,a){const t=Object.entries(a.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,a.tools??[],a.extensions??[],a.systemPrompt??null,t]);return R("sha256").update(o).digest("hex").slice(0,32)}n(z,"warmRecipeKey");async function d(e){const{launch:r}=await j(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId,app:"app:terminal"});return{key:z(e.cwd,e.profileId,r),launch:r,request:e}}n(d,"resolveRecipe");async function S(e){const r=e.creator===null?null:await p(e.creator);await U({grantee:r?.grantee??"app:terminal",sub:r?.sub,grant_id:r?.grant_id})}n(S,"checkClaimantStart");async function ye(e,r={},a){await S(e);const t=await d(e);if(await g(t.key)===0)return null;const o=_(),s=await O({kind:e.kind,mode:e.mode,cwd:e.cwd,profile:e.profileId,root:!0,parentId:null,requestingNodeId:e.creator,lifecycle:"resident",replaces:null},e.creator===null?"app:terminal":await(async()=>{const c=await p(e.creator);if(!c?.grantee)throw new Error("warm node creator has no app");return c.grantee})());let i;try{i=await M(t.key,o,r)}finally{s()}return i===null?null:k(i,t,o,a)}n(ye,"claimWarmNode");async function he(e,r,a){return await S(e),k(r,await d(e),_(),a)}n(he,"resumeWarmClaim");async function k(e,r,a,t){const{request:o}=r,i=(await p(e))?.launch?.model;await A(e,{created:a,kind:o.kind,mode:o.mode,name:o.name??o.kind,creator:o.creator,launch:r.launch,persona_ack:{kind:o.kind,mode:o.mode,lifecycle:"resident"},...o.model!==null?{model_override:o.model}:{}});try{t?.(e)}catch(l){return await m(e,"birth preparation",l)}try{await J(e)}catch(l){return await m(e,"bearings delivery",l)}const c=r.launch.model;if(c!==void 0&&c!==i)try{await B(e,c,r.launch.modelIntent)}catch(l){return await m(e,"model swap",l)}if(o.situationalContext!==null)try{await G(e,o.situationalContext)}catch(l){return await m(e,"situational-context delivery",l)}return e}n(k,"completeWarmClaim");async function m(e,r,a){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${a.message}`);try{await f(e)}catch{}return null}n(m,"abandonSpare");const Q=3600*1e3;async function ge(){const e=[];let r;try{r=await y()}catch(t){return console.error(`[warm-pool] spare scan failed: ${t.message}`),e}const a=Date.now()-Q;for(const t of r){if(await V(t.node_id))continue;const o=Date.parse(t.created),s=Number.isNaN(o)||o<a,i=D(t.pi_pid,t.pi_pid_identity),c=(t.status==="active"||t.status==="idle")&&i==="alive";if(!(c&&!s)&&!(i==="indeterminate"&&!s))try{if(!await h(t.node_id))continue;if(c)try{await f(t.node_id)}catch{}await u(t.node_id),e.push(t.node_id)}catch(l){console.error(`[warm-pool] reap failed for ${t.node_id}: ${l.message}`)}}return e}n(ge,"reapStaleSpares");async function _e(){for(const e of await y())if(await h(e.node_id)){try{await f(e.node_id)}catch(r){console.error(`[warm-pool] close failed for ${e.node_id}: ${r.message}`)}await u(e.node_id)}}n(_e,"emptyWarmPool");const w=6e4;async function x(e,r){const a=L();if(await C(e,r,a,w)===void 0)return;const t=setInterval(()=>{W(e,r,a,w).catch(()=>{})},w/3);return t.unref(),async()=>{clearInterval(t),await E(e,r,a)}}n(x,"holdMintLease");async function V(e){return await(await b()).prepare("SELECT 1 FROM reconciler_leases WHERE lane = ? AND key = ? AND expires_at > ?").get("warm-pool-mint",e,new Date().toISOString())!==void 0}n(V,"mintLeaseHeld");function ve(e){if(v())try{d({...e,model:null,situationalContext:null}).then($).catch(r=>console.error(`[warm-pool] recipe resolution failed: ${r.message}`))}catch(r){console.error(`[warm-pool] recipe resolution failed: ${r.message}`)}}n(ve,"refillWarmPool");async function $(e){if(await T())return;const{key:r}=e;if(await F(e.request.profileId)!==null)return;const a=await x("warm-pool",r);if(a!==void 0){if(await g(r)>0){await a();return}X(e,await K()).finally(()=>a().catch(()=>{}))}}n($,"mint");async function X({key:e,request:r},a){const t=await x("warm-pool-mint",a);if(t===void 0){console.error(`[warm-pool] mint refused for ${r.kind}: the mint lease of ${a} is held elsewhere`);return}try{await H({nodeId:a,kind:r.kind,mode:r.mode,cwd:r.cwd,prompt:"",root:!0,readiness:"await",profile:r.profileId},async o=>{await I(o,e)})}catch(o){console.error(`[warm-pool] mint failed for ${r.kind}: ${o.message}`)}finally{await t().catch(()=>{})}}n(X,"birthSpare");const Y=2;async function Se(){if(!v())return;let e;try{const r=new Set;e=[];for(const a of(await P({status:["active","idle"]})).reverse()){if(a.parent!==null||a.kind==="human")continue;const t=a.profile_id??null;if(!r.has(t??"")&&(r.add(t??""),e.push({cwd:a.cwd,profileId:t}),e.length>=Y))break}}catch(r){console.error(`[warm-pool] prewarm scan failed: ${r.message}`);return}for(const r of e)try{d({kind:"general",mode:"base",cwd:r.cwd,profileId:r.profileId,model:null,situationalContext:null,name:null,creator:null}).then($).catch(a=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`))}catch(a){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`)}}n(Se,"prewarmRecentRecipes");export{X as birthSpare,ye as claimWarmNode,_e as emptyWarmPool,x as holdMintLease,Se as prewarmRecentRecipes,ge as reapStaleSpares,ve as refillWarmPool,he as resumeWarmClaim,v as warmPoolEnabled};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var y=Object.defineProperty;var r=(s,a)=>y(s,"name",{value:a,configurable:!0});import{prepared as o}from"../sqlite-statements.js";import{userStore as c}from"./paths.js";import{openScopedStore as u,scopedStoreExists as i,withScopedWrite as g}from"./db.js";function S(s){const a=c(s);if(!i(a))return null;const t=u(a),m=o(t,"SELECT profile_id, path FROM profile_projects ORDER BY profile_id, position").all(),E=o(t,"SELECT id, name, created_at, last_used_at, paused_at, default_kind, grantee, metadata_json, delivery_limits_json, environment_id FROM profiles ORDER BY rowid").all().map(e=>{const n=JSON.parse(e.metadata_json),f=JSON.parse(e.delivery_limits_json);return{profileId:e.id,manifest:{schema_version:1,name:e.name,projects:m.filter(_=>_.profile_id===e.id).map(_=>({path:_.path})),paused_at:e.paused_at,...e.default_kind===null?{}:{default_kind:e.default_kind},...e.grantee===null?{}:{grantee:e.grantee},...e.environment_id===null?{}:{environment_id:e.environment_id},...Object.keys(f).length===0?{}:{delivery_limits:f},...Object.keys(n).length===0?{}:{metadata:n},created_at:e.created_at,last_used_at:e.last_used_at}}}),k=Object.fromEntries(o(t,"SELECT directory, profile_id FROM profile_defaults").all().map(e=>[e.directory,e.profile_id])),p={};for(const e of o(t,"SELECT owner_key, raw_json FROM scope_settings WHERE owner_key != 'project'").all())p[e.owner_key]=JSON.parse(e.raw_json);const d={},l=r(e=>d[e]??={marketplaces:{},plugins:{},activeCanvas:null},"stateOf");for(const e of o(t,"SELECT owner_key, last_self_check, active_canvas FROM scope_bookkeeping WHERE owner_key != 'project'").all()){const n=l(e.owner_key);e.last_self_check!==null&&(n.last_self_check=e.last_self_check),n.activeCanvas=e.active_canvas}for(const e of o(t,"SELECT owner_key, name, last_updated FROM scope_marketplaces WHERE owner_key != 'project'").all())l(e.owner_key).marketplaces[e.name]=e.last_updated===null?{}:{last_updated:e.last_updated};for(const e of o(t,"SELECT owner_key, name, last_updated, etag, checked_at FROM scope_plugins WHERE owner_key != 'project'").all())l(e.owner_key).plugins[e.name]={...e.last_updated===null?{}:{last_updated:e.last_updated},...e.etag===null?{}:{etag:e.etag},...e.checked_at===null?{}:{checked_at:e.checked_at}};return{profiles:E,defaults:k,settings:p,state:d}}r(S,"readLegacyUserSnapshot");function v(s){const a=c(s);return i(a)?o(u(a),"SELECT profile_id, path, memory FROM legacy_project_caps ORDER BY profile_id, path").all().map(t=>({profileId:t.profile_id,path:t.path,memory:t.memory})):[]}r(v,"listLegacyProjectCaps");function w(s){const a=c(s);i(a)&&g(a,t=>{o(t,"DELETE FROM legacy_project_caps").run()})}r(w,"deleteLegacyProjectCaps");export{w as deleteLegacyProjectCaps,v as listLegacyProjectCaps,S as readLegacyUserSnapshot};
|
|
1
|
+
var y=Object.defineProperty;var r=(s,a)=>y(s,"name",{value:a,configurable:!0});import{prepared as o}from"../sqlite-statements.js";import{userStore as c}from"./paths.js";import{openScopedStore as u,scopedStoreExists as i,withScopedWrite as g}from"./db.js";function S(s){const a=c(s);if(!i(a))return null;const t=u(a),m=o(t,"SELECT profile_id, path FROM profile_projects ORDER BY profile_id, position").all(),E=o(t,"SELECT id, name, created_at, last_used_at, paused_at, default_kind, grantee, metadata_json, delivery_limits_json, environment_id FROM profiles ORDER BY rowid").all().map(e=>{const n=JSON.parse(e.metadata_json),f=JSON.parse(e.delivery_limits_json);return{profileId:e.id,manifest:{schema_version:1,name:e.name,projects:m.filter(_=>_.profile_id===e.id).map(_=>({path:_.path})),paused_at:e.paused_at,...e.default_kind===null?{}:{default_kind:e.default_kind},...e.grantee===null?{}:{grantee:e.grantee},...e.environment_id===null?{}:{environment_id:e.environment_id},...Object.keys(f).length===0?{}:{delivery_limits:f},...Object.keys(n).length===0?{}:{metadata:n},created_at:e.created_at,last_used_at:e.last_used_at}}}),k=Object.fromEntries(o(t,"SELECT directory, profile_id FROM profile_defaults").all().map(e=>[e.directory,e.profile_id])),p={};for(const e of o(t,"SELECT owner_key, raw_json FROM scope_settings WHERE owner_key != 'project'").all())p[e.owner_key]=JSON.parse(e.raw_json);const d={},l=r(e=>d[e]??={marketplaces:{},plugins:{},activeCanvas:null},"stateOf");for(const e of o(t,"SELECT owner_key, last_self_check, active_canvas FROM scope_bookkeeping WHERE owner_key != 'project'").all()){const n=l(e.owner_key);e.last_self_check!==null&&(n.last_self_check=e.last_self_check),n.activeCanvas=e.active_canvas}for(const e of o(t,"SELECT owner_key, name, last_updated FROM scope_marketplaces WHERE owner_key != 'project'").all())l(e.owner_key).marketplaces[e.name]=e.last_updated===null?{}:{last_updated:e.last_updated};for(const e of o(t,"SELECT owner_key, name, last_updated, etag, checked_at FROM scope_plugins WHERE owner_key != 'project'").all())l(e.owner_key).plugins[e.name]={...e.last_updated===null?{}:{last_updated:e.last_updated},...e.etag===null?{}:{etag:e.etag},...e.checked_at===null?{}:{checked_at:e.checked_at}};return{profiles:E,defaults:k,settings:p,state:d,apps:{}}}r(S,"readLegacyUserSnapshot");function v(s){const a=c(s);return i(a)?o(u(a),"SELECT profile_id, path, memory FROM legacy_project_caps ORDER BY profile_id, path").all().map(t=>({profileId:t.profile_id,path:t.path,memory:t.memory})):[]}r(v,"listLegacyProjectCaps");function w(s){const a=c(s);i(a)&&g(a,t=>{o(t,"DELETE FROM legacy_project_caps").run()})}r(w,"deleteLegacyProjectCaps");export{w as deleteLegacyProjectCaps,v as listLegacyProjectCaps,S as readLegacyUserSnapshot};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CanvasDb } from '../canvas/db.js';
|
|
2
|
+
export declare const APP_INSTALLS_MIGRATED_KEY = "app_installs_migrated";
|
|
3
|
+
export interface AppInstallMigrationReport {
|
|
4
|
+
moved: number;
|
|
5
|
+
discarded: number;
|
|
6
|
+
people: number;
|
|
7
|
+
alreadyDone: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Which of two owners' installs wins a name within one app: a profile over the user row; among profiles the most recently used, then the owner key.
|
|
10
|
+
* Negative when `a` wins. The startup migration and the import share it. */
|
|
11
|
+
export declare function compareInstallOwners(a: string, lastUsedA: string, b: string, lastUsedB: string): number;
|
|
12
|
+
/** Move every person's `user` and `profile:<id>` plugin and marketplace rows to `app:*` owner keys. Runs inside the caller's write transaction. */
|
|
13
|
+
export declare function migrateAppInstalls(db: CanvasDb): Promise<AppInstallMigrationReport>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var $=Object.defineProperty;var l=(n,p)=>$(n,"name",{value:p,configurable:!0});import{emitEvent as v}from"../events/emit.js";const N="app_installs_migrated";function M(n,p,_,c){return n==="user"!=(_==="user")?n==="user"?1:-1:p!==c?p<c?1:-1:n<_?-1:n>_?1:0}l(M,"compareInstallOwners");async function F(n){if(await n.prepare("SELECT pg_advisory_xact_lock(hashtext('app_installs_migrated'))").get(),await n.prepare("SELECT value FROM canvas_meta WHERE key = ?").get(N)!==void 0)return{moved:0,discarded:0,people:0,alreadyDone:!0};const p="(owner_key = 'user' OR owner_key LIKE 'profile:%')",_=await n.prepare(`SELECT person, owner_key, name, source_marketplace FROM scope_plugins WHERE ${p}`).all(),c=await n.prepare(`SELECT person, owner_key, name, url FROM scope_marketplaces WHERE ${p}`).all(),A=await n.prepare("SELECT person, id, grantee, last_used_at FROM profiles").all(),k=new Map(A.map(r=>[`${r.person}\0profile:${r.id}`,r])),w=l((r,a)=>a==="user"?"app:terminal":k.get(`${r}\0${a}`)?.grantee??"app:terminal","appOf"),y=l((r,a)=>k.get(`${r}\0${a}`)?.last_used_at??"","lastUsed"),f=l((r,a)=>M(r.owner_key,y(r.person,r.owner_key),a.owner_key,y(a.person,a.owner_key)),"order"),m=new Set;let g=0,T=0;const u=new Map;for(const r of _){const a=`${r.person}\0${w(r.person,r.owner_key)}`;u.set(a,[...u.get(a)??[],r])}for(const r of c){const a=`${r.person}\0${w(r.person,r.owner_key)}`;u.has(a)||u.set(a,[])}const O=l((r,a,o)=>c.find(s=>s.person===r&&s.owner_key===a&&s.name===o)?.url??null,"marketUrl");for(const[r,a]of[...u].sort(([o],[s])=>o<s?-1:1)){const[o,s]=r.split("\0"),R=new Set((await n.prepare("SELECT name FROM scope_plugins WHERE person = ? AND owner_key = ?").all(o,s)).map(e=>e.name)),E=new Map((await n.prepare("SELECT name, url FROM scope_marketplaces WHERE person = ? AND owner_key = ?").all(o,s)).map(e=>[e.name,e.url])),S=l(async(e,t)=>{const d=O(o,e,t);let i=t;for(let D=2;E.has(i)&&E.get(i)!==d;D+=1)i=`${t}-${D}`;return E.has(i)||(await n.prepare("UPDATE scope_marketplaces SET owner_key = ?, name = ? WHERE person = ? AND owner_key = ? AND name = ?").run(s,i,o,e,t),E.set(i,d)),i},"moveMarket");for(const e of[...a].sort(f)){if(R.has(e.name)){T+=1,v({level:"warn",event:"daemon.packages.install_migration",fields:{person:o,app:s,owner:e.owner_key,name:e.name,source:e.source_marketplace===null?null:O(o,e.owner_key,e.source_marketplace)}});continue}R.add(e.name);const t=e.source_marketplace===null?null:await S(e.owner_key,e.source_marketplace);await n.prepare("UPDATE scope_plugins SET owner_key = ?, source_marketplace = ? WHERE person = ? AND owner_key = ? AND name = ?").run(s,t,o,e.owner_key,e.name),g+=1,m.add(o)}const L=c.filter(e=>e.person===o&&w(o,e.owner_key)===s).sort((e,t)=>f({...e,source_marketplace:null},{...t,source_marketplace:null})||(e.name<t.name?-1:e.name>t.name?1:0));for(const e of L)await n.prepare("SELECT 1 AS one FROM scope_marketplaces WHERE person = ? AND owner_key = ? AND name = ?").get(o,e.owner_key,e.name)!==void 0&&(await S(e.owner_key,e.name),m.add(o))}await n.prepare(`DELETE FROM scope_plugins WHERE ${p}`).run(),await n.prepare(`DELETE FROM scope_marketplaces WHERE ${p}`).run();for(const r of m)await n.prepare("INSERT INTO person_settings (person, plugins_revision) VALUES (?, 1) ON CONFLICT (person) DO UPDATE SET plugins_revision = person_settings.plugins_revision + 1").run(r);return await n.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT (key) DO NOTHING").run(N,new Date().toISOString()),{moved:g,discarded:T,people:m.size,alreadyDone:!1}}l(F,"migrateAppInstalls");export{N as APP_INSTALLS_MIGRATED_KEY,M as compareInstallOwners,F as migrateAppInstalls};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ON CONFLICT (person, owner_key, name) DO UPDATE SET url = EXCLUDED.url, ref = EXCLUDED.ref, installed_at = EXCLUDED.installed_at`).run(t,n.owner,d,c.url??null,c.ref??null,c.installed_at??null)}else if(n.op==="state.write"){await a.prepare(`INSERT INTO scope_bookkeeping (person, owner_key, last_self_check, active_canvas) VALUES (?, ?, ?, ?)
|
|
6
|
-
ON CONFLICT (person, owner_key) DO UPDATE SET last_self_check = EXCLUDED.last_self_check, active_canvas = EXCLUDED.active_canvas`).run(t,n.owner,n.state.last_self_check??null,n.state.activeCanvas??null);for(const[r,i]of Object.entries(n.state.marketplaces))await a.prepare("UPDATE scope_marketplaces SET last_updated = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,t,n.owner,r);for(const[r,i]of Object.entries(n.state.plugins))await a.prepare("UPDATE scope_plugins SET last_updated = ?, etag = ?, checked_at = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,i.etag??null,i.checked_at??null,t,n.owner,r)}else if(n.op==="profile.insert"){const r=n.profile.manifest;await a.prepare("INSERT INTO profiles (id, person, name, created_at, last_used_at, paused_at, default_kind, grantee, metadata_json, delivery_limits_json, environment_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(n.profile.profileId,t,r.name,r.created_at,r.last_used_at,r.paused_at,r.default_kind??null,r.grantee??null,JSON.stringify(r.metadata??{}),JSON.stringify(r.delivery_limits??{}),r.environment_id??null),await k(a,n.profile)}else if(n.op==="profile.update"){const r=n.profile.manifest;if((await a.prepare("UPDATE profiles SET name = ?, last_used_at = ?, paused_at = ?, default_kind = ?, grantee = ?, metadata_json = ?, delivery_limits_json = ?, environment_id = ? WHERE id = ? AND person = ?").run(r.name,r.last_used_at,r.paused_at,r.default_kind??null,r.grantee??null,JSON.stringify(r.metadata??{}),JSON.stringify(r.delivery_limits??{}),r.environment_id??null,n.profile.profileId,t)).changes!==1)throw new Error(`no stored profile ${n.profile.profileId}`);await k(a,n.profile)}else if(n.op==="profile.delete"){const r=`profile:${n.profileId}`;for(const i of["scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins"])await a.prepare(`DELETE FROM ${i} WHERE person = ? AND owner_key = ?`).run(t,r);await a.prepare("DELETE FROM profiles WHERE id = ? AND person = ?").run(n.profileId,t)}else{await a.prepare("DELETE FROM profile_defaults WHERE person = ?").run(t);for(const[r,i]of Object.entries(n.defaults))await a.prepare("INSERT INTO profile_defaults (person, directory, profile_id) VALUES (?, ?, ?)").run(t,r,i)}u&&await a.prepare("INSERT INTO person_settings (person, plugins_revision) VALUES (?, 1) ON CONFLICT (person) DO UPDATE SET plugins_revision = person_settings.plugins_revision + 1").run(t),await a.prepare("SELECT pg_notify('crtr_signal', ?)").get(`settings:${t}`)}_(U,"applyOpsToRows");async function k(a,t){await a.prepare("DELETE FROM profile_projects WHERE profile_id = ?").run(t.profileId);let o=0;for(const u of t.manifest.projects)await a.prepare("INSERT INTO profile_projects (profile_id, path, position) VALUES (?, ?, ?)").run(t.profileId,u.path,o++)}_(k,"replaceProjects");const F=_(async(a,t)=>(await N(o=>U(o,a,t)),await g(a)),"rowsTransport");h(F),C(g);export{U as applyOpsToRows,g as loadPersonSettings,w as readSnapshotFromRows,F as rowsTransport};
|
|
1
|
+
var R=Object.defineProperty;var p=(t,a)=>R(t,"name",{value:a,configurable:!0});import{openDb as v,withCanvasWrite as D}from"../canvas/db.js";import{appRevisionOf as w,revisionOf as L,setPersonSnapshot as h,setSettingsReloader as C,setSettingsTransport as j,SettingsRevisionConflictError as S}from"./person-store.js";const s=p(t=>typeof t=="string"?t:void 0,"s");async function O(t,a){const o=await t.prepare("SELECT * FROM profiles WHERE person = ? AND deleting_since IS NULL ORDER BY created_at, id").all(a),c=await t.prepare("SELECT p.profile_id, p.path FROM profile_projects p JOIN profiles f ON f.id = p.profile_id WHERE f.person = ? ORDER BY p.profile_id, p.position").all(a),n=new Map;for(const e of c)(n.get(e.profile_id)??n.set(e.profile_id,[]).get(e.profile_id)).push({path:e.path});const r=o.map(e=>{const l=JSON.parse(String(e.metadata_json)),_=JSON.parse(String(e.delivery_limits_json));return{profileId:String(e.id),manifest:{schema_version:1,name:String(e.name),projects:n.get(String(e.id))??[],paused_at:s(e.paused_at)??null,...s(e.default_kind)===void 0?{}:{default_kind:s(e.default_kind)},...s(e.grantee)===void 0?{}:{grantee:s(e.grantee)},...s(e.environment_id)===void 0?{}:{environment_id:s(e.environment_id)},...Object.keys(_).length===0?{}:{delivery_limits:_},...Object.keys(l).length===0?{}:{metadata:l},created_at:String(e.created_at),last_used_at:s(e.last_used_at)??null}}}),i=Object.fromEntries((await t.prepare("SELECT directory, profile_id FROM profile_defaults WHERE person = ?").all(a)).map(e=>[e.directory,e.profile_id])),f={};for(const e of await t.prepare("SELECT owner_key, raw_json FROM scope_settings WHERE person = ?").all(a))f[e.owner_key]=JSON.parse(e.raw_json);const E={},u={},d=p(e=>u[e]??={plugins:{},marketplaces:{},revision:""},"appOf"),m=p(e=>E[e]??={marketplaces:{},plugins:{},activeCanvas:null},"stateOf");for(const e of await t.prepare("SELECT owner_key, last_self_check, active_canvas FROM scope_bookkeeping WHERE person = ?").all(a)){const l=m(e.owner_key);e.last_self_check!==null&&(l.last_self_check=e.last_self_check),l.activeCanvas=e.active_canvas}for(const e of await t.prepare("SELECT * FROM scope_marketplaces WHERE person = ? ORDER BY owner_key, name").all(a)){const l=String(e.owner_key),_=String(e.name);if(l.startsWith("app:")){d(l).marketplaces[_]={url:s(e.url),ref:s(e.ref)??"",installed_at:s(e.installed_at)??""};continue}if(m(l).marketplaces[_]=s(e.last_updated)===void 0?{}:{last_updated:s(e.last_updated)},s(e.url)!==void 0){const g=f[l]??={},k=g.marketplaces??={};k[_]={url:s(e.url),ref:s(e.ref)??"",installed_at:s(e.installed_at)??""}}}for(const e of await t.prepare("SELECT * FROM scope_plugins WHERE person = ? ORDER BY owner_key, name").all(a)){const l=String(e.owner_key),_=String(e.name);if(l.startsWith("app:")){d(l).plugins[_]={enabled:Number(e.enabled)===1,...s(e.source_marketplace)===void 0?{}:{source_marketplace:s(e.source_marketplace)},...s(e.version)===void 0?{}:{version:s(e.version)}};continue}m(l).plugins[_]={...s(e.last_updated)===void 0?{}:{last_updated:s(e.last_updated)},...s(e.etag)===void 0?{}:{etag:s(e.etag)},...s(e.checked_at)===void 0?{}:{checked_at:s(e.checked_at)}};const g=f[l]??={},k=g.plugins??={};k[_]={enabled:Number(e.enabled)===1,...s(e.source_marketplace)===void 0?{}:{source_marketplace:s(e.source_marketplace)},...s(e.version)===void 0?{}:{version:s(e.version)}}}for(const e of Object.values(u))e.revision=w(e);return{profiles:r,defaults:i,settings:f,state:E,apps:u}}p(O,"readSnapshotFromRows");async function N(t){const a=await v(),o=await O(a,t);return h(t,o),o}p(N,"loadPersonSettings");async function I(t,a,o){return(await O(t,a)).settings[o]}p(I,"currentRaw");async function A(t,a,o){let c=!1;for(const n of o)if(n.op==="settings.replace"){const r=await I(t,a,n.owner);if(n.ifRevision!==L(r))throw new S;const{plugins:i,marketplaces:f,...E}=n.raw,u=JSON.stringify(E);await t.prepare("INSERT INTO scope_settings (person, owner_key, raw_json) VALUES (?, ?, ?) ON CONFLICT (person, owner_key) DO UPDATE SET raw_json = EXCLUDED.raw_json").run(a,n.owner,u);const d=JSON.stringify([r?.plugins,r?.marketplaces]);d!==JSON.stringify([i,f])&&!(d==="[null,null]"&&i===void 0&&f===void 0)&&(c=!0),await T(t,a,n.owner,i??{},f??{})}else if(n.op==="app-plugins.replace"){await t.prepare("SELECT pg_advisory_xact_lock(hashtext(?))").get(`app-plugins|${a}|${n.app}`);const r=(await O(t,a)).apps[n.app];if(n.ifRevision!==w(r))throw new S;w(n)!==w(r)&&(c=!0),await T(t,a,n.app,n.plugins,n.marketplaces)}else if(n.op==="state.write"){await t.prepare(`INSERT INTO scope_bookkeeping (person, owner_key, last_self_check, active_canvas) VALUES (?, ?, ?, ?)
|
|
2
|
+
ON CONFLICT (person, owner_key) DO UPDATE SET last_self_check = EXCLUDED.last_self_check, active_canvas = EXCLUDED.active_canvas`).run(a,n.owner,n.state.last_self_check??null,n.state.activeCanvas??null);for(const[r,i]of Object.entries(n.state.marketplaces))await t.prepare("UPDATE scope_marketplaces SET last_updated = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,a,n.owner,r);for(const[r,i]of Object.entries(n.state.plugins))await t.prepare("UPDATE scope_plugins SET last_updated = ?, etag = ?, checked_at = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,i.etag??null,i.checked_at??null,a,n.owner,r)}else if(n.op==="profile.insert"){const r=n.profile.manifest;await t.prepare("INSERT INTO profiles (id, person, name, created_at, last_used_at, paused_at, default_kind, grantee, metadata_json, delivery_limits_json, environment_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(n.profile.profileId,a,r.name,r.created_at,r.last_used_at,r.paused_at,r.default_kind??null,r.grantee??null,JSON.stringify(r.metadata??{}),JSON.stringify(r.delivery_limits??{}),r.environment_id??null),await y(t,n.profile)}else if(n.op==="profile.update"){const r=n.profile.manifest;if((await t.prepare("UPDATE profiles SET name = ?, last_used_at = ?, paused_at = ?, default_kind = ?, grantee = ?, metadata_json = ?, delivery_limits_json = ?, environment_id = ? WHERE id = ? AND person = ?").run(r.name,r.last_used_at,r.paused_at,r.default_kind??null,r.grantee??null,JSON.stringify(r.metadata??{}),JSON.stringify(r.delivery_limits??{}),r.environment_id??null,n.profile.profileId,a)).changes!==1)throw new Error(`no stored profile ${n.profile.profileId}`);await y(t,n.profile)}else if(n.op==="profile.delete"){const r=`profile:${n.profileId}`;for(const i of["scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins"])await t.prepare(`DELETE FROM ${i} WHERE person = ? AND owner_key = ?`).run(a,r);await t.prepare("DELETE FROM profiles WHERE id = ? AND person = ?").run(n.profileId,a)}else{await t.prepare("DELETE FROM profile_defaults WHERE person = ?").run(a);for(const[r,i]of Object.entries(n.defaults))await t.prepare("INSERT INTO profile_defaults (person, directory, profile_id) VALUES (?, ?, ?)").run(a,r,i)}c&&await t.prepare("INSERT INTO person_settings (person, plugins_revision) VALUES (?, 1) ON CONFLICT (person) DO UPDATE SET plugins_revision = person_settings.plugins_revision + 1").run(a),await t.prepare("SELECT pg_notify('crtr_signal', ?)").get(`settings:${a}`)}p(A,"applyOpsToRows");async function T(t,a,o,c,n){await t.prepare("DELETE FROM scope_plugins WHERE person = ? AND owner_key = ? AND NOT (name IN (SELECT jsonb_array_elements_text(?::jsonb)))").run(a,o,JSON.stringify(Object.keys(c)));for(const[r,i]of Object.entries(c))await t.prepare(`INSERT INTO scope_plugins (person, owner_key, name, enabled, source_marketplace, version) VALUES (?, ?, ?, ?, ?, ?)
|
|
3
|
+
ON CONFLICT (person, owner_key, name) DO UPDATE SET enabled = EXCLUDED.enabled, source_marketplace = EXCLUDED.source_marketplace, version = EXCLUDED.version`).run(a,o,r,i.enabled===!1?0:1,i.source_marketplace??null,i.version??null);await t.prepare("DELETE FROM scope_marketplaces WHERE person = ? AND owner_key = ? AND NOT (name IN (SELECT jsonb_array_elements_text(?::jsonb)))").run(a,o,JSON.stringify(Object.keys(n)));for(const[r,i]of Object.entries(n))await t.prepare(`INSERT INTO scope_marketplaces (person, owner_key, name, url, ref, installed_at) VALUES (?, ?, ?, ?, ?, ?)
|
|
4
|
+
ON CONFLICT (person, owner_key, name) DO UPDATE SET url = EXCLUDED.url, ref = EXCLUDED.ref, installed_at = EXCLUDED.installed_at`).run(a,o,r,i.url??null,i.ref??null,i.installed_at??null)}p(T,"writeInstallRows");async function y(t,a){await t.prepare("DELETE FROM profile_projects WHERE profile_id = ?").run(a.profileId);let o=0;for(const c of a.manifest.projects)await t.prepare("INSERT INTO profile_projects (profile_id, path, position) VALUES (?, ?, ?)").run(a.profileId,c.path,o++)}p(y,"replaceProjects");const U=p(async(t,a)=>(await D(o=>A(o,t,a)),await N(t)),"rowsTransport");j(U),C(N);export{A as applyOpsToRows,N as loadPersonSettings,O as readSnapshotFromRows,U as rowsTransport};
|
|
@@ -10,12 +10,33 @@ export interface PersonSnapshot {
|
|
|
10
10
|
defaults: Record<string, string>;
|
|
11
11
|
settings: Record<string, Record<string, unknown>>;
|
|
12
12
|
state: Record<string, ScopeState>;
|
|
13
|
+
/** App installs (`app:<id>` → plugins, marketplaces) with a revision covering only that app's block. Cloud roles write plugins here, never to `settings`. */
|
|
14
|
+
apps: Record<string, AppInstallBlock>;
|
|
15
|
+
}
|
|
16
|
+
export interface AppInstallBlock {
|
|
17
|
+
plugins: Record<string, {
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
source_marketplace?: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
}>;
|
|
22
|
+
marketplaces: Record<string, {
|
|
23
|
+
url?: string;
|
|
24
|
+
ref?: string;
|
|
25
|
+
installed_at?: string;
|
|
26
|
+
}>;
|
|
27
|
+
revision: string;
|
|
13
28
|
}
|
|
14
29
|
export type SettingsOp = {
|
|
15
30
|
op: 'settings.replace';
|
|
16
31
|
owner: string;
|
|
17
32
|
raw: Record<string, unknown>;
|
|
18
33
|
ifRevision: string;
|
|
34
|
+
} | {
|
|
35
|
+
op: 'app-plugins.replace';
|
|
36
|
+
app: string;
|
|
37
|
+
plugins: AppInstallBlock['plugins'];
|
|
38
|
+
marketplaces: AppInstallBlock['marketplaces'];
|
|
39
|
+
ifRevision: string;
|
|
19
40
|
} | {
|
|
20
41
|
op: 'state.write';
|
|
21
42
|
owner: string;
|
|
@@ -40,6 +61,8 @@ export declare class PersonSettingsNotLoadedError extends Error {
|
|
|
40
61
|
constructor(person: string);
|
|
41
62
|
}
|
|
42
63
|
declare const BLOCKS: readonly ["plugins", "marketplaces"];
|
|
64
|
+
/** The revision of an app's install block; `absent` for an app with no rows. */
|
|
65
|
+
export declare function appRevisionOf(block: Pick<AppInstallBlock, 'plugins' | 'marketplaces'> | undefined): string;
|
|
43
66
|
export declare function revisionOf(raw: Record<string, unknown> | undefined): string;
|
|
44
67
|
export declare function installPersonSnapshot(person: string, snapshot: PersonSnapshot): void;
|
|
45
68
|
export declare function heldPersons(): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var h=Object.defineProperty;var n=(e,t)=>h(e,"name",{value:t,configurable:!0});import{createHash as x}from"node:crypto";import{PersonOutsideRequestError as g,PersonUnresolvedError as S,personId as u}from"../canvas/person-state.js";class m extends Error{static{n(this,"SettingsRevisionConflictError")}constructor(){super("settings changed since the supplied revision"),this.name="SettingsRevisionConflictError"}}class w extends Error{static{n(this,"PersonSettingsNotLoadedError")}constructor(t){super(`settings for ${t} are not loaded in this process`),this.name="PersonSettingsNotLoadedError"}}const P=["plugins","marketplaces"],o=new Map;function O(e){return e===void 0?"absent":p({plugins:e.plugins,marketplaces:e.marketplaces})}n(O,"appRevisionOf");function p(e){return e===void 0?"absent":x("sha256").update(JSON.stringify(e)).digest("hex")}n(p,"revisionOf");function R(e,t){o.set(e,t)}n(R,"installPersonSnapshot");function I(){return[...o.keys()]}n(I,"heldPersons");function L(){o.clear()}n(L,"dropPersonSnapshots");const f=n(()=>({profiles:[],defaults:{},settings:{},state:{},apps:{}}),"emptySnapshot");let a;function N(e){a=e}n(N,"installPreludeSnapshot");function r(){let e;try{e=u()}catch(s){if(s instanceof g)return f();if(s instanceof S)return a??f();throw s}const t=o.get(e);if(t!==void 0)return t;if(a!==void 0)return a;throw new w(e)}n(r,"currentSnapshot");function T(){try{return o.has(u())}catch{return!1}}n(T,"personHasSnapshot");let d=n(async()=>{throw new Error("no settings transport installed in this process")},"transport");function _(e){d=e}n(_,"setSettingsTransport");async function k(e){const t=u();for(let s=0;;s++){const c=e(r());if(c.length===0)return r();try{const i=await d(t,c);return o.set(t,i),i}catch(i){if(!(i instanceof m)||s>=2)throw i;await C(t)}}}n(k,"writeSettings");function K(e,t){o.set(e,t),a=void 0}n(K,"setPersonSnapshot");let l;function B(e){l=e}n(B,"setSettingsReloader");async function C(e){o.set(e,await(l??(async()=>{throw new Error("no settings reloader installed in this process")}))(e))}n(C,"reloadViaTransport");function H(e){return e===void 0?"user":`profile:${e}`}n(H,"ownerKeyOf");function $(e){const t=r().settings[e];return{settings:t===void 0?null:structuredClone(t),revision:p(t)}}n($,"readCachedSettings");function q(e){const t=r().state[e];return t===void 0?{marketplaces:{},plugins:{},activeCanvas:null}:structuredClone(t)}n(q,"readCachedState");function D(){return structuredClone(r().profiles)}n(D,"listCachedProfiles");function G(e){const t=r().profiles.find(s=>s.profileId===e);return t===void 0?null:structuredClone(t)}n(G,"getCachedProfile");function J(e){return r().profiles.find(t=>t.profileId===e)?.manifest.paused_at!=null}n(J,"cachedProfilePaused");function M(){return new Set(r().profiles.filter(e=>e.manifest.paused_at!==null).map(e=>e.profileId))}n(M,"cachedPausedProfileIds");function U(){return{...r().defaults}}n(U,"cachedDefaults");export{w as PersonSettingsNotLoadedError,P as SETTINGS_ROW_BLOCKS,m as SettingsRevisionConflictError,O as appRevisionOf,U as cachedDefaults,M as cachedPausedProfileIds,J as cachedProfilePaused,r as currentSnapshot,L as dropPersonSnapshots,G as getCachedProfile,I as heldPersons,R as installPersonSnapshot,N as installPreludeSnapshot,D as listCachedProfiles,H as ownerKeyOf,T as personHasSnapshot,$ as readCachedSettings,q as readCachedState,p as revisionOf,K as setPersonSnapshot,B as setSettingsReloader,_ as setSettingsTransport,k as writeSettings};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var f=Object.defineProperty;var
|
|
2
|
-
WHERE person = ? AND enabled = 1 AND owner_key
|
|
1
|
+
var f=Object.defineProperty;var u=(o,e)=>f(o,"name",{value:e,configurable:!0});import{ApiError as a}from"../../../api/errors.js";import{getNode as w}from"../../../core/canvas/canvas.js";import{openDb as l}from"../../../core/canvas/db.js";import{blobStore as h}from"../../../core/blobs/index.js";import{presignGet as E,releaseSignerFromEnv as b}from"../../../core/secrets/blaxel-launch.js";import{grantedProviderIds as g,isProviderBundleRow as k}from"../../../core/grants/mirror.js";import{profileMetadataEnv as x}from"../../../core/runtime/spawn-env.js";import{localEnvironmentSecrets as v}from"../../../core/secrets/environment-owner.js";import{environmentOfNode as y,recipeOf as R}from"../environment-of.js";import{mintInstallationToken as S}from"./git-credential.js";async function O(o,e){const n=await l(),s=new Map((await n.prepare(`SELECT owner_key, name, version, source_marketplace, source_path FROM scope_plugins
|
|
2
|
+
WHERE person = ? AND enabled = 1 AND owner_key = ? ORDER BY name`).all(o,e)).map(i=>[i.name,i])),t=[],r=await g(o);for(const i of s.values()){if(k(i,r))continue;if(i.source_path!==null){t.push({name:i.name,source:{path:i.source_path},version:i.version});continue}if(i.source_marketplace===null)throw new a(500,"plugin_source_missing",`plugin ${i.name} names neither a marketplace nor a path`);const c=await n.prepare("SELECT url, ref FROM scope_marketplaces WHERE person = ? AND owner_key = ? AND name = ?").get(o,i.owner_key,i.source_marketplace);t.push({name:i.name,source:{marketplace:{url:c?.url??null,ref:c?.ref??null}},version:i.version})}return t}u(O,"plugins");const T=900;async function $(o){const e=await l(),n=await e.prepare("SELECT blob_key, unpacked_at FROM import_node_files WHERE node = ?").get(o);if(n===void 0)return null;if(!(await(await h()).list(n.blob_key)).includes(n.blob_key)){if(n.unpacked_at!==null)return null;throw new a(500,"import_files_missing",`the imported archive ${n.blob_key} of ${o} is gone and no sandbox unpacked it`)}const s=/^imports\/([^/]+)\/node-files\//.exec(n.blob_key)?.[1];if(s===void 0)throw new a(500,"import_files_invalid",`import_node_files names ${n.blob_key} for ${o}, which is no imports/<run>/node-files key`);const t=await e.prepare("SELECT source_value, target_value FROM import_id_map WHERE run_id = ? AND kind = 'path' ORDER BY source_value").all(s);return{url:E(b(),n.blob_key,T),path_map:t.map(r=>({from:r.source_value,to:r.target_value}))}}u($,"importFiles");async function N(o){const{principal:e}=o;if(e.class!=="broker")throw new a(403,"broker_only","this route is called with a node token");const n=o.params.execution_id??"",t=await(await l()).prepare("SELECT node_id, state FROM executions WHERE execution_id = ?").get(n);if(t===void 0||t.node_id!==e.node)throw new a(403,"not_your_execution",`execution ${n} is not an execution of this node`);if(t.state!=="launching"&&t.state!=="running")throw new a(403,"execution_ended",`execution ${n} is ${t.state}`);return e.node}u(N,"ownedExecution");async function D(o){const e=await N(o);return await(await l()).prepare("UPDATE import_node_files SET unpacked_at = ? WHERE node = ? AND unpacked_at IS NULL").run(new Date().toISOString(),e),{status:200,body:{}}}u(D,"handleImportUnpacked");async function L(o){const{principal:e}=o;if(e.class!=="broker")throw new a(403,"broker_only","the start bundle is read with a node token");const n=o.params.execution_id??"",s=await l(),t=await s.prepare("SELECT node_id, state, launch_json, runner FROM executions WHERE execution_id = ?").get(n);if(t===void 0||t.node_id!==e.node)throw new a(403,"not_your_execution",`execution ${n} is not an execution of this node`);if(t.state!=="launching"&&t.state!=="running")throw new a(403,"execution_ended",`execution ${n} is ${t.state}`);if(t.launch_json===null)throw new a(409,"launch_missing",`execution ${n} carries no launch recipe`);const r=await w(e.node);if(r===null)throw new a(404,"node_not_found",`no node ${e.node}`);const i=await s.prepare("SELECT plugins_revision FROM person_settings WHERE person = ?").get(e.sub),c=await y(r.profile_id??null),p=await R(c),d=p?.repositories.map(m=>m.github_full_name)??[],_=d.length===0?null:(await S(e.sub,d)).author;return{status:200,body:{launch:JSON.parse(t.launch_json),node:{id:r.node_id,app:e.app,cwd:r.cwd,profile:r.profile_id??null,isolated:r.isolated===!0,environment_id:c},recipe:p,git_identity:_,plugins_revision:i===void 0?0:Number(i.plugins_revision),plugins:await O(e.sub,e.app),import_node_files:await $(r.node_id),...t.runner==="machine"?{machine_env:{...x(r.profile_id??null),...await v(r.profile_id??null,e.app)}}:{}}}}u(L,"handleStart");const Y=[{method:"GET",pattern:"/v1/executions/:execution_id/start",handler:L},{method:"POST",pattern:"/v1/executions/:execution_id/import-unpacked",handler:D}];export{Y as executionStartRoutes,O as plugins};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var $e=Object.defineProperty;var s=(e,n)=>$e(e,"name",{value:n,configurable:!0});import{envProfileId as Ne}from"../../../shared/env.js";import{pausedCanvasProfiles as Ce}from"../../../core/profiles/manifest.js";import{existsSync as C,realpathSync as ee,statSync as ne}from"node:fs";import{isAbsolute as x,resolve as D}from"node:path";import{appendSituationalContext as Ee,formatSituationalProse as Te}from"../../../core/runtime/situational-context.js";import{closeNode as Pe}from"../../../core/runtime/close.js";import{reviveNode as De}from"../../../core/runtime/revive.js";import{nowIso as K}from"../../../core/fs-utils.js";import{appPaidLaunch as Le,assertLaunchModelRegistered as V,forkNode as je,resolveForkSource as te,spawnChildPrepared as Me}from"../../../core/runtime/spawn.js";import{forkSourceNode as ie,newNodeId as re}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as oe,childrenOf as Ge,completeCreateRequest as ae,findCreateRequest as de,getNode as R,recordCreateRequestNode as Fe,reserveCreateRequest as se,reserveCreateRequestNode as Be,listNodes as xe,recordRespawnAttempt as Ke,subscribersOf as Ve,subscriptionsOf as le,updateNode as E}from"../../../core/canvas/canvas.js";import{armControllerWait as We}from"../../../core/canvas/waits.js";import{withCanvasWrite as W}from"../../../core/canvas/db.js";import{markNodeRead as ze}from"../../../core/canvas/recovery.js";import{nodeObject as Je}from"../../../core/graph/objects.js";import{recordActedOn as Ue}from"../../../core/graph/edges.js";import{publish as Ye}from"../../../core/graph/events.js";import{readerFor as He}from"../reader.js";import{relocateSessionCwd as Qe,unbindSession as Xe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Ze}from"../../../core/canvas/attention.js";import{isSafeNodeId as qe}from"../../../core/canvas/paths.js";import{contextDir as ce,nodeAgentDir as z}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as en,cronRefusalError as nn}from"../../cron/authority.js";import{cronBirthPlacement as tn}from"../../cron/armed-context.js";import{existsBeneath as rn,isAbsentOrRefused as on,isBeneathRefusal as an,readdirBeneath as dn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as sn,readNodeSession as ln,readNodeSnapshot as cn,transcriptMarkdown as un}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as fn}from"../../../core/substrate/subject.js";import{reviveAll as pn}from"../../../core/runtime/revive-all.js";import{promoteAsync as mn,requestYieldAsync as wn,reshapeNodeAsync as J}from"../../../core/runtime/promote.js";import{recycleNode as hn}from"../../../core/runtime/recycle.js";import{relaunchRoot as yn}from"../../../core/runtime/reset.js";import{assertReopenGate as _n}from"../../../core/runtime/reopen.js";import{requireCurrentExecution as gn}from"./broker-recovery.js";import{readOutputRequest as bn}from"../../../core/runtime/output-result.js";import{writeYieldMessage as vn,readGoal as kn,captureGoalIfAbsent as Sn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as Rn,hasRoadmap as In}from"../../../core/runtime/roadmap.js";import{renameWindow as On}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as An,explicitModelIntent as $n,normalizeModel as Nn,readMergedLaunchConfigAsync as ue}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Cn}from"../../../core/model-routes.js";import{persistDormantModel as En,setModelLive as Tn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as fe}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as Pn}from"../../../core/runtime/broker-request.js";import{boundFleet as L}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as Dn}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Ln}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as pe}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as jn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Mn}from"../../../core/human-actions.js";import{parseDurationMs as Gn}from"../../../core/wake.js";import{claimWarmNode as Fn,refillWarmPool as me,resumeWarmClaim as Bn,warmPoolEnabled as xn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as U,isLaunchKind as Kn,resolveLaunchTarget as Vn}from"../../../core/runtime/launch-target.js";import{fullName as Wn}from"../../../core/canvas/labels.js";import{reportsForNode as we}from"./reports.js";import{requireUsableProfile as zn}from"./profiles.js";import{assertProfileActive as Jn,loadExactProfileManifest as Un}from"../../../core/profiles/manifest.js";import{getCron as he}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Yn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Hn}from"../../control.js";import{notFound as T,usage as w}from"../../../core/errors.js";import{assertScope as Qn,validateScopes as ye}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Xn,toNodeDetailDTO as Y,toNodeSummaryDTO as Zn,toReviveResultDTO as qn}from"../map.js";import{ApiError as p}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{runsOnBlaxel as et}from"../environment-of.js";import{actsAsPerson as j,canReadNode as $,mayOnNode as nt,readableNodeIds as tt,resolvedScopes as it}from"../router.js";import{forwardVerb as rt,queryWithoutMachine as ot,relayError as at,unknownError as dt,withMachine as st}from"../../peer/forward.js";import{fileRoot as lt}from"../../../core/spaces/file-root.js";import{activeGrant as ct,payerOfGrant as ut}from"../../../core/grants/mirror.js";import{nodeTerminalGrant as ft}from"../../../core/grants/terminal.js";import{appRungForGrant as pt}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as mt}from"../../../core/model-routes.js";import{listProfileEnvNames as wt}from"../../../core/profiles/env-store.js";import{hasConfiguredProviderCredential as ht,NO_PROVIDER_CREDENTIAL_MESSAGE as _e}from"../../../core/runtime/provider-credential-gate.js";import{filterAsync as yt,mapAsync as ge}from"../../../core/async-array.js";async function m(e){const n=await R(e);if(n===null)throw T(`unknown node: ${e}`,{received:e});return n}s(m,"requireMeta");async function H(e){return{subscribesTo:await le(e),subscribers:await Ve(e),children:await Ge(e)}}s(H,"edgesFor");async function b(e){const n=await m(e);return await Y(n,await H(e))}s(b,"detailOf");async function _t(e){let n=(await we(e)).length;try{n+=dn(await z(e),await ce(e)).length}catch(t){if(!on(t))throw t}return n}s(_t,"countFiles");function gt(e){if(typeof e!="object"||e===null)throw w("a node create requires a JSON body");const n=e;if(n.kind!==void 0&&(typeof n.kind!="string"||n.kind.trim()===""))throw w("kind must be a non-empty string when provided");if(n.description!==void 0&&(typeof n.description!="string"||n.description.trim()===""))throw w("description must be a non-empty string when provided");if(n.creator!==void 0&&(typeof n.creator!="string"||n.creator.trim()===""))throw w("creator must be a non-empty node id when provided");if(n.scopes!==void 0&&ye(n.scopes),n.isolated!==void 0&&typeof n.isolated!="boolean")throw new p(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const t=n.root_lifecycle;if(t!==void 0&&t!=="resident"&&t!=="terminal")throw w("root_lifecycle must be 'resident' or 'terminal'");if(n.request_key!==void 0&&(typeof n.request_key!="string"||n.request_key.trim()===""||n.request_key.length>128))throw w("request_key must be a non-empty string of at most 128 characters when provided");return n}s(gt,"parseCreateBody");function bt(e){if(e===void 0)return;const n=Gn(e),t=n===null?null:new Date(Date.now()+n);if(n===null||!Number.isFinite(n)||n<=0||t===null||!Number.isFinite(t.getTime()))throw new p(422,"invalid_deadline","`deadline` must be a positive representable duration");return t.toISOString()}s(bt,"parseDeadline");function vt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new p(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!jn.test(e.action))throw new p(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let n;try{n=JSON.stringify(e.payload)}catch{throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(n===void 0)throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(n,"utf8")>pe)throw new p(413,"payload_too_large",`serialized payload exceeds ${pe} bytes`)}return e}}s(vt,"parseOutcomeDelivery");function kt(e,n){const t=Mn(e.action,n);if(!("kind"in t))return{actionName:e.action,argv:t.argv,cwd:t.cwd,configOrigin:t.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw t.kind==="unknown_action"?new p(422,"unknown_action",`no action named ${e.action} is declared from ${n}`):new p(422,"invalid_action",`${e.action} is declared in ${t.configOrigin} but unusable: ${t.reason}`,{reason:t.reason,configOrigin:t.configOrigin})}s(kt,"resolveOutcomeDelivery");function St(e,n,t){const r={kind:e.kind,cwd:t,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),n!==void 0&&(r.parent=n),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=D(e.pin_cwd??e.cwd??t)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}s(St,"buildRecipe");function Rt(e,n,t){return!xn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:n,profileId:t,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}s(Rt,"warmRequestFor");import{resolveCreateKind as Nr}from"../../../core/runtime/launch-target.js";function be(e){const n=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Cn(e.model,n,e.modelExact===!0)}s(be,"requestFromLaunch");function It(e,n){if(n===null)return e;if(e.scopes===void 0)return{...e,scopes:[...n]};const t=e.scopes.filter(r=>!O(n,r));if(t.length===0)return e;throw new p(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${t.join(", ")}`,{scopes:t,ceiling:n})}s(It,"withinCeiling");async function ve(e,n,t){const r=(await An(n.kind,n.mode,{lifecycle:n.lifecycle,hasManager:e.parent!==null,model:n.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await V(be(r),{cwd:e.cwd,profileId:e.profile_id??null},t)}s(ve,"assertNodeModelChangeRegistered");async function ke(e,n){const t=e.principal;if(t.class!=="broker"&&t.class!=="cron")return;const r=lt({app:t.app,resolved:await it(t),launched:t.scopes},n,"read");if("root"in r)return;const i="missing"in r?r.missing:null;throw new p(403,"scope_missing",i?`the child's directory ${n} needs missing scope ${i}`:`no permission of this run names the child's directory ${n}`,void 0,void 0,i?{scope:i}:void 0)}s(ke,"assertCallerReaches");const Q=new Map;async function Ot(e,n={},t={}){const r=It(gt(e.body),e.ceiling);if(e.principal.class==="broker"){const d=e.principal;if(r.prefer_warm===!0&&d.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const o=await m(r.parent);if(o.grantee!==d.app)throw new p(403,"other_app_run","cannot create a child under another app's node");if(!await $(d,o.grantee??"app:terminal",r.parent))throw T(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==d.node)throw new p(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let o=null;try{o=await ie(await te(r.fork_from))}catch{}if(o?.grantee!==d.app||!await $(d,o.grantee,o.node_id))throw new p(403,"other_app_run","cannot fork another app's conversation")}r.creator=d.node}if(e.principal.class==="person"&&e.principal.sub!==void 0){const d=r.fork_from===void 0?null:await ie(await te(r.fork_from)).catch(()=>null);for(const o of[r.parent,r.creator,d?.node_id])if(o!=null&&await R(o)!==null&&!await nt(e.principal,"edit",o))throw T(`unknown node: ${o}`,{received:o})}if(e.principal.class==="cron"){const d=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new p(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1,r.node_id=await re(),d.isolated&&(r.isolated=!0,r.cwd=await z(r.node_id,d.app));const o=await en({grantee:d.app,sub:d.sub,grant_id:d.grant,scopes:d.scopes,from_exec:d.from_exec},{profile:r.profile,cwd:r.cwd,pin_cwd:r.pin_cwd,kind:r.kind,model:r.model,mode:r.mode});if(!o.allowed)throw nn(o);if(r.scopes!==void 0){const l=r.scopes.find(f=>!O(o.effectiveScopes,f)||!O(d.scopes,f));if(l!==void 0)throw new p(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else d.scopes!==null&&(r.scopes=[...d.scopes])}r.creator!==void 0&&Qn(await m(r.creator),"crtr:act");const i=r.request_key?.trim();if(i===void 0||r.node_id!==void 0&&qe(r.node_id)&&await R(r.node_id)!==null&&(await de(i))?.nodeId!==r.node_id)return M(e,r,n,t);const a=Q.get(i);if(a!==void 0)return a;const u=$t(e,r,i,n,t);Q.set(i,u);try{return await u}finally{Q.delete(i)}}s(Ot,"handleCreate");const Se="create_request_in_progress";async function At(e,n,t){const r=Date.now()+1e4;for(;t!==null;){const i=await R(t);if(i!==null){if(!j(e.principal)&&!await $(e.principal,i.grantee??"app:terminal",t))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(t)}}if(Date.now()>=r||(await de(n))?.nodeId!==t)break;await new Promise(a=>setTimeout(a,100))}throw new p(409,Se,"another create with this request_key is in progress; retry it")}s(At,"awaitForeignCreate");async function $t(e,n,t,r,i){const a=await se(t);if(a.nodeId!==null&&await R(a.nodeId)!==null){if(a.state!=="warm_claimed"){const u=await R(a.nodeId);if(!j(e.principal)&&!await $(e.principal,u.grantee??"app:terminal",a.nodeId))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(a.nodeId)}}return M(e,n,r,i,a)}try{return await M(e,n,r,i,a)}catch(u){if(u instanceof p&&u.code===Se)throw u;const d=await se(t);throw(d.nodeId===null||await R(d.nodeId)===null)&&await oe(t,d.nodeId),u}}s($t,"handleKeyedCreateRequest");async function M(e,n,t,r,i=void 0){const a=r.deadlineAt??bt(n.deadline),u=vt(n.outcome_delivery),d=e.principal.class==="cron"?await tn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:e.principal.kind==="exec"?null:(await he(e.principal.cron))?.created_by??null},n.node_id):null;d!==null&&(n.root=d.root===!0);const o=d?.parent??n.parent??void 0;if(o==null&&n.root!==!0)throw w("a node create requires a parent (or root: true for an independent root)");let l=null;if(n.output_schema!==void 0){try{l=JSON.parse(n.output_schema)}catch{throw w("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw w("output_schema must be a JSON schema object");await Ln(l)}const{profileId:f,kind:h,cwd:c,launch:S}=await Vn(n,{validateKind:Ae});if(n.pin_cwd!==void 0&&n.pin_cwd!==""&&n.worktree===void 0&&n.isolated!==!0&&!C(c)&&!await et(f))throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${c}`,received:c,field:"cwd",next:"Pass an existing directory with --cwd."});await ke(e,c),n.worktree!==void 0&&await ke(e,D(n.pin_cwd??n.cwd??c));const _={...n,kind:h},v=u===void 0?void 0:kt(u,c),Z=("grant"in e.principal?e.principal.grant:null)??(o==null?null:(await R(o))?.grant_id??null);if(await V(be(await Le(S,Z,n.model)),{cwd:c,profileId:f},t.modelRegistry),await ut(Z)!=="app"&&!await ht(f===null?[]:await wt(f)))throw new p(412,"no_provider_credential",_e,{error:"no_provider_credential",message:_e,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let F=null;{const A=i===void 0||i.nodeId===null||i.state==="warm_claimed"?Rt(_,c,f):null,B=l===null&&r.beforeBrokerLaunch===void 0?void 0:async g=>{l!==null&&await Dn(g,"terminal",l),r.beforeBrokerLaunch?.(g)};if(i?.state==="warm_claimed"&&i.nodeId!==null){const g=A===null?null:await Bn(A,i.nodeId,B);if(g===null)throw await oe(i.requestKey,i.nodeId),new p(503,"create_resume_failed",`could not resume warm claim ${i.nodeId}; retry the create`);return await ae(i.requestKey,g),{status:201,body:await b(g)}}if(A!==null){const g=await Fn(A,{...a===void 0?{}:{deadlineAt:a},...v===void 0?{}:{outcomeDelivery:v},...i===void 0?{}:{requestKey:i.requestKey}},B);if(g!==null)return i!==void 0&&await ae(i.requestKey,g),me(A),{status:201,body:await b(g)};F=A}const P=i?.nodeId??n.node_id??(i===void 0?void 0:await re());if(i!==void 0&&i.nodeId===null){const g=await Be(i.requestKey,P);if(g!==P)return await At(e,i.requestKey,g)}const I=St(P===void 0?_:{..._,node_id:P},o,c);d!==null&&(d.rootLifecycle!==void 0&&(I.rootLifecycle=d.rootLifecycle),d.scopes!==void 0&&_.scopes===void 0&&(I.scopes=d.scopes),d.run!==void 0&&(I.run=d.run),d.withinCreate!==void 0&&(I.withinCreate=d.withinCreate)),a!==void 0&&(I.deadlineAt=a),v!==void 0&&(I.outcomeDelivery=v),I.readiness=n.root===!0?"await":"launch";const q=await Me(I,B,()=>{F!==null&&me(F)});return i!==void 0&&await Fe(i.requestKey,q.node.node_id),{status:201,body:await b(q.node.node_id)}}}s(M,"handleCreateRequest");function k(e,n){const t=e.query.getAll(n);if(t.length>1)throw w(`${n} must appear at most once`);return t[0]}s(k,"singleQueryValue");function X(e,n){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw w(`${n} must be true or false`)}}s(X,"optionalBoolean");function G(e,n,t){if(e!==void 0){if(t.includes(e))return e;throw w(`${n} must be one of: ${t.join(", ")}`)}}s(G,"oneOf");function Nt(e){const n=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","under_inclusive","hanging","include"]);for(const[_]of e.query)if(!n.has(_))throw w(`unknown nodes query parameter: ${_}`);const t=G(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=G(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),i=k(e,"kind"),a=G(k(e,"mode"),"mode",["base","orchestrator"]),u=k(e,"profile_id"),d=k(e,"profile_prefix"),o=k(e,"parent"),l=X(k(e,"top_level"),"top_level"),f=k(e,"under"),h=X(k(e,"under_inclusive"),"under_inclusive"),c=X(k(e,"hanging"),"hanging"),S=G(k(e,"include"),"include",["activity"]);if(o!==void 0&&l===!0)throw w("parent and top_level=true cannot be combined");return{...t!==void 0?{status:t}:{},...r!==void 0?{lifecycle:r}:{},...i!==void 0?{kind:i}:{},...a!==void 0?{mode:a}:{},...u!==void 0?{profile_id:u}:{},...d!==void 0?{profile_prefix:d}:{},...o!==void 0?{parent:o}:{},...l!==void 0?{top_level:l}:{},...f!==void 0?{under:f}:{},...h!==void 0?{under_inclusive:h}:{},...c!==void 0?{hanging:c}:{},...S!==void 0?{include:S}:{}}}s(Nt,"parseListQuery");async function Ct(e){const n=Nt(e);let t=await xe({...n.status!==void 0?{status:n.status}:{},...n.lifecycle!==void 0?{lifecycle:n.lifecycle}:{},...n.kind!==void 0?{kind:n.kind}:{},...n.mode!==void 0?{mode:n.mode}:{},...n.profile_id!==void 0?{profileId:n.profile_id}:{},...n.profile_prefix!==void 0?{profilePrefix:n.profile_prefix}:{},...n.parent!==void 0?{parent:n.parent}:{},...n.top_level===!0?{topLevel:!0}:{},...n.under!==void 0?{under:n.under}:{},...n.under_inclusive===!0?{underInclusive:!0}:{},...n.hanging===!0?{hanging:!0}:{}});const r=await tt(e.principal);r!==null&&(t=t.filter(d=>r.has(d.node_id)));const i=n.include==="activity"?await Ze(t.map(d=>d.node_id)):null,a=t.length>0?Ce():new Set;return{status:200,body:await ge(t,async d=>{const o=await Zn(d,d.profile_id!==null&&a.has(d.profile_id));if(i!==null){const l=await we(d.node_id);o.activity={latest_report:l[0]??null,final_report:d.final_report===null?null:l.find(f=>f.name===d.final_report)??null,pending_human_count:i[d.node_id]??0}}return o})}}s(Ct,"handleList");async function Et(e){const n=e.params.id,t=await rt(e,n,{method:"GET",path:`/v1/nodes/${encodeURIComponent(n)}`,query:ot(e)});if(t.kind==="unknown")throw dt(n,t.unreachable);if(t.kind==="remote"){if(t.status>=400)throw at(t.status,t.body);return{status:t.status,body:st(t.body,t.machine)}}return await m(n),{status:200,body:await b(n)}}s(Et,"handleDetail");async function Tt(e){const n=e.params.id;await m(n);const t=await cn(n);return{status:200,body:{node_id:n,snapshot:{messages:t.snapshot.messages,...t.snapshot.messageIds===void 0?{}:{messageIds:t.snapshot.messageIds},messageVisibility:t.snapshot.messageVisibility,turnVisibility:t.snapshot.turnVisibility,stats:t.snapshot.stats,state:t.snapshot.state,display:t.snapshot.display,...t.snapshot.queued===void 0?{}:{queued:t.snapshot.queued},...t.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:t.snapshot.toolGroupSummaries},...t.snapshot.turnReplies===void 0?{}:{turnReplies:t.snapshot.turnReplies},...t.snapshot.workingActivity===void 0?{}:{workingActivity:t.snapshot.workingActivity}},commands:t.commands.map(i=>({name:i.name,description:i.description,source:i.source})),captured_at:K()}}}s(Tt,"handleSnapshot");async function Pt(e){const n=e.params.id,t=await fn(n);if(t===null)throw T(`unknown node: ${n}`,{received:n});return{status:200,body:t}}s(Pt,"handleSubject");function Dt(e){for(const[a]of e.query)if(a!=="cursor"&&a!=="limit")throw w(`unknown messages query parameter: ${a}`);const n=e.query.getAll("cursor"),t=e.query.getAll("limit");if(n.length>1)throw w("cursor must appear at most once");if(t.length>1)throw w("limit must appear at most once");if(t.length===0)return n.length===0?{}:{cursor:n[0]};const r=t[0],i=Number(r);if(!Number.isSafeInteger(i)||r==="")throw w("limit must be an integer from 1 through 500");return n.length===0?{limit:i}:{cursor:n[0],limit:i}}s(Dt,"parseMessagesQuery");async function Lt(e){const n=e.params.id,t=await sn(n,Dt(e));return{status:200,body:{node_id:n,messages:t.messages,...t.messageIds===void 0?{}:{message_ids:t.messageIds},message_visibility:t.messageVisibility,next_cursor:t.nextCursor,captured_at:K()}}}s(Lt,"handleMessages");async function jt(e){const n=e.params.id;await m(n);const t=await ln(n);return{status:200,body:{node_id:n,session_file:t.sessionFile,session_jsonl:t.sessionJsonl,system_prompt:t.systemPrompt,captured_at:K()}}}s(jt,"handleSession");async function Mt(e){const n=e.params.id;return await m(n),{status:200,body:{node_id:n,markdown:await un(n)}}}s(Mt,"handleTranscript");async function Gt(e){const n=e.params.id;await m(n);const t=s(async(i,a)=>({node_id:i,label:(await R(i))?.name??i,dir:await ce(i),self:a,files:await _t(i)}),"root"),r=await yt([await t(n,!0),...await ge(await le(n),async i=>await t(i.node_id,!1))],async i=>await Ft(i.node_id,i.dir)||i.files>0);return{status:200,body:{node_id:n,roots:r}}}s(Gt,"handleContext");async function Ft(e,n){try{return rn(await z(e),n)}catch(t){if(an(t))return!1;throw t}}s(Ft,"hasDir");async function Bt(e){const n=await m(e.params.id),t=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=t===null?void 0:n.scopes==null?[...t]:[...new Set([...n.scopes.filter(a=>O(t,a)),...t.filter(a=>O(n.scopes,a))])],i=await je(n.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:await b(i.node.node_id)}}s(Bt,"handleFork");const xt=1e4;async function Kt(e){const n=e.params.id;await m(n);const t=e.body,r=t?.resume??!0,i=t?.reopen??!1;await _n(n,i,e.principal.class==="broker"?e.principal.node:null);const a=!r&&t?.cron_id!==void 0?await he(t.cron_id):null,u=await De(n,{resume:r,capacity:"refuse",...a!==null?{wakeReason:await Yn(a,"schedule_revive")}:{}});u.outcome!=="already-live"&&await Ke(n,{failures:0,notBefore:null});const d=(await R(n))?.status??"active",o=(u.launch??L().get(n)?.handle)?.exited,l=u.outcome!=="frozen"&&await fe(n,o,xt);return{status:200,body:qn(n,u,d,l)}}s(Kt,"handleRevive");async function Vt(e){const n=e.params.id;return{status:200,body:{newNodeId:(await yn(n))?.newNodeId??null}}}s(Vt,"handleRelaunchRoot");async function Wt(e){const n=e.params.id;await m(n);const t=e.body;if(t?.caller_pid!==void 0&&(!Number.isInteger(t.caller_pid)||t.caller_pid<=0))throw w("caller_pid must be a positive integer when provided");const r=Hn(),i=new Promise(u=>{e.res.once("close",()=>u())}),a=await Pe(n,{teardownAfter:i,rootEvent:t?.finish===!0?"finish":"cancel",callerPid:t?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Xn(a)}}s(Wt,"handleClose");async function zt(e){if(!j(e.principal))throw new p(403,"permission_error","only the person marks a conversation read");const n=e.params.id;return await m(n),await ze(n),{status:204}}s(zt,"handleMarkRead");async function Jt(e){const n=e.params.id;await m(n);const t=await hn(n);return{status:200,body:{recycled:t.recycled,finalized:t.finalized,new_root:t.newRoot,delivered:t.delivered}}}s(Jt,"handleRecycle");async function Ut(e){const n=e.params.id;return await m(n),await J(n,{lifecycle:"terminal"}),await N(e,n,["lifecycle"]),{status:200,body:await b(n)}}s(Ut,"handleDemote");async function Yt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:"orchestrator",lifecycle:i.resident===!0?"resident":r.lifecycle,model:i.model},n.modelRegistry);const a=await mn(t,{...i.kind!==void 0?{kind:i.kind}:{},...i.resident===!0?{resident:!0}:{},...i.model!==void 0?{model:i.model}:{}});await N(e,t,["mode",...i.kind!==void 0?["kind"]:[],...i.resident===!0?["lifecycle"]:[],...i.model!==void 0?["model"]:[]]);const u=await Y(a.meta,await H(t));return u.roadmap_written=a.roadmapWritten,u.roadmap_ref=a.roadmapRef,u.goal_path=a.goalPath,{status:200,body:u}}s(Yt,"handlePromote");async function Ht(e){const n=e.params.id;return await m(n),{status:200,body:{request:await bn(n)}}}s(Ht,"handleBrokerStructuredRequest");async function Qt(e){const n=e.params.id,t=e.body??{};if(await gn(n,t.expected_execution_id),typeof t.text!="string")throw new p(400,"invalid_request","text must be a string");return await m(n),{status:200,body:{captured:await Sn(n,t.text)}}}s(Qt,"handleBrokerGoal");async function Xt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:i.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:i.model},n.modelRegistry);const a=i.note??"Refresh: continue against your roadmap or goal.";await vn(t,a);const u=await wn(t,{...i.promote===!0?{promote:!0}:{},...i.kind!==void 0?{kind:i.kind}:{},...i.model!==void 0?{model:i.model}:{}});return{status:200,body:await Y(u.meta,await H(t))}}s(Xt,"handleYield");async function Zt(e){const n=e.params.id;await m(n);const t=e.body;if(t===void 0||typeof t.controller!="string"||t.controller.trim()==="")throw w("a wait requires a controller node id");const r=await R(t.controller);if(r===null)throw T(`unknown controller: ${t.controller}`,{received:t.controller});if(r.status!=="active"&&r.status!=="idle")throw new p(422,"unprocessable",`controller ${t.controller} is ${r.status}`);return await We(n,t.controller),{status:200,body:await b(n)}}s(Zt,"handleWait");async function qt(e){const n=e.principal,t=await pn(n.class==="broker"?async i=>i.grantee===n.app&&await $(n,i.grantee,i.node_id):n.class==="person"&&!j(n)?async i=>await $(n,i.grantee??"app:terminal",i.node_id):void 0);return{status:200,body:{revived:[...t.revived],failed:[...t.failed],frozen:[...t.frozen]}}}s(qt,"handleReviveAll");const ei=new Set(["interrupt","steer","after-turn","next-turn"]);function ni(e){if(e===null)return null;const n=s(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return n("listen must be an object or null");const t=Object.entries(e);if(t.length===0)return n("listen must name at least one level");for(const[r,i]of t)/^(?:[1-9]|10)$/.test(r)||n(`listen level must be 1..10: ${r}`),(typeof i!="string"||!ei.has(i))&&n(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(i)}`);return JSON.stringify(Object.fromEntries(t))}s(ni,"listenJson");async function N(e,n,t,r){t.length===0&&r===void 0||await W(async i=>{if(r?.(i),t.length===0)return;const a=await Je(i,n),u=await He(i,e),d=u.class==="person"?u.person:u.class==="app"?u.app:u.node;await Ue(i,d,a),await Ye(i,{event:"configured",object:a,actor:d,attrs:{changed:t.join(",")}})})}s(N,"recordConfigured");function Re(e){const n=L().get(e);if(n===void 0)return!1;try{return process.kill(n.pid,"SIGTERM"),!0}catch{return!1}}s(Re,"restartLiveBroker");function Ie(e,n){try{return ee(e)===ee(n)}catch{return!1}}s(Ie,"sameDirectory");async function ti(e,n={}){const t=e.params.id,r=e.body;let i;if(r===void 0)i={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))i=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(i.profile!==void 0){if(typeof i.profile!="string"||i.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:i.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(i).some(h=>h!=="profile"&&h!=="restart"&&i[h]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const o=await m(t),l=await zn(e,i.profile);Jn(l.profileId);const f=Un(l.profileId).manifest.grantee??"app:terminal";if(f!==(o.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${f}, node ${t} to ${o.grantee}`,received:i.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(o.profile_id??null)!==l.profileId&&(Kn(o.kind)?(await U(o.kind,o.cwd,l.profileId),await J(t,{profileId:l.profileId})):await E(t,{profile_id:l.profileId}),await N(e,t,["profile"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(Object.prototype.hasOwnProperty.call(i,"cwd")){const o=i.cwd;if(typeof o!="string"||o==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:o,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(i).some(c=>c!=="cwd"&&c!=="keep_session"&&c!=="restart"&&i[c]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:i,field:"cwd",next:"Send cwd as the only config field."});const l=await m(t),f=C(l.cwd);if(i.keep_session===!0||f&&x(o)&&C(o)&&Ie(l.cwd,o)){if(!x(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const c=D(o);let S=!1;try{S=ne(c).isDirectory()}catch{}if(!S)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${c}`,received:o,field:"cwd",next:"Send an existing absolute directory."});if(f&&!Ie(l.cwd,c))throw new y({error:"cwd_not_same_directory",message:`${c} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:o,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot relocate its cwd`,received:o,field:"cwd",next:"Reconcile the managed worktree first."});const _=l.cwd;return _!==c&&(await W(async v=>{await E(t,{cwd:c}),await v.prepare("UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(c,t,_),await Qe(t,_,c)}),await N(e,t,["cwd"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(await L().has(t)){const c=`${t} cannot repair its cwd while its broker is live`;throw new p(409,"cwd_node_live",c,{error:"cwd_node_live",message:c,received:o,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${t} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:o,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot repair its cwd`,received:o,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(C(l.cwd))throw new y({error:"cwd_still_present",message:`${t} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:o,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!x(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const h=D(o);if(!C(h))throw new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ne(h).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${h}`,received:o,field:"cwd",next:"Send an existing absolute directory."})}catch(c){throw c instanceof y?c:new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return await W(async()=>{await E(t,{cwd:h}),await Xe(t)}),await N(e,t,["cwd"]),{status:200,body:await b(t)}}let a=await m(t);const u=i.listen===void 0?void 0:ni(i.listen);if(i.scopes!==void 0){const o=ye(i.scopes),l=a.grantee==="app:terminal"?await ft(a):a.grant_id?await ct(a.grant_id):null;if(!o.every(f=>O(a.scopes,f)&&l!==null&&O(l.resolved,f)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:o,field:"scopes",next:"Send only scopes the node currently holds."});if(o.includes("crtr:act")&&!O(o,"crtr:llm"))throw new p(400,"invalid_scope","crtr:act requires crtr:llm");a=await E(t,{scopes:o})}if(i.situational_context!==void 0&&await Ee(t,Te(i.situational_context)),i.model!==void 0){const o=(await ue(a.cwd,a.profile_id??null)).modelLadders,l=$n(i.model,o),f=await pt(a.grant_id,i.model,l===void 0),h=f?{family:mt,strength:f.strength}:l,c=f?f.model:Nn(i.model,o);await V({kind:"concrete",spec:c},{cwd:a.cwd,profileId:a.profile_id??null},n.modelRegistry);const S=L();let _=!1;if(await S.isClaimed(t)&&await fe(t,S.get(t)?.handle.exited)&&(_=await Tn(t,c,h).then(()=>!0,v=>{if(v instanceof Pn)return!1;throw v})),!_){if(await S.isClaimed(t)){const v=`${t}'s broker did not accept the model switch; the model was not changed`;throw new p(409,"broker_not_ready",v,{error:"broker_not_ready",message:v,received:i.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!c.includes("/"))throw w(`model must resolve to a provider/id spec: ${i.model}`);await En(t,c,h)}a=await m(t)}if(i.kind!==void 0||i.mode!==void 0||i.lifecycle!==void 0){i.kind!==void 0&&await Ae(i.kind);const o=i.kind??a.kind,l=i.mode??a.mode,f=i.lifecycle??a.lifecycle;let h;l==="orchestrator"&&!await In(t)&&(h=s(async()=>{const c=await kn(t);await Rn(t,c!==null&&c.trim()!==""?{goal:c.trim()}:{})},"beforePersist")),a=await J(t,{...i.kind!==void 0?{kind:o}:{},...i.mode!==void 0?{mode:l}:{},...i.lifecycle!==void 0?{lifecycle:f}:{}},h)}i.name!==void 0&&(a=await E(t,{name:i.name}),a.window&&On(a.window,Wn(a)));const d=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(o=>i[o]!==void 0);return await N(e,t,d,u===void 0?void 0:async o=>{await o.prepare("UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(u,t)}),{status:200,body:await b(t)}}s(ti,"handleConfig");async function Oe(){return(await ue(process.cwd(),Ne()||null)).kinds}s(Oe,"daemonKinds");async function Ae(e){const n=Object.keys(await Oe());if(!n.includes(e))throw w(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${n.sort().join(", ")}.`})}s(Ae,"assertKindServer");async function ii(){const e=await Oe();return{status:200,body:{kinds:Object.keys(e).sort().map(t=>({kind:t,when_to_use:e[t]?.whenToUse??null,available_to:e[t]?.availableTo??null}))}}}s(ii,"handleListKinds");const Or=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:Ot},{method:"GET",pattern:"/v1/nodes",handler:Ct},{method:"GET",pattern:"/v1/kinds",handler:s(()=>ii(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:qt},{method:"GET",pattern:"/v1/nodes/:id",handler:Et},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:Tt},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:Pt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:Lt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:jt},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:Mt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:Gt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Bt},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Kt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:Vt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Wt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:zt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Jt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Ut},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Yt},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Xt},{method:"GET",pattern:"/v1/nodes/:id/broker/structured-request",handler:Ht},{method:"POST",pattern:"/v1/nodes/:id/broker/goal",handler:Qt},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Zt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:ti}];export{ti as handleConfig,Ot as handleCreate,Bt as handleFork,Ct as handleList,Yt as handlePromote,Xt as handleYield,Or as nodeRoutes,Nr as resolveCreateKind};
|
|
1
|
+
var $e=Object.defineProperty;var s=(e,n)=>$e(e,"name",{value:n,configurable:!0});import{envProfileId as Ne}from"../../../shared/env.js";import{pausedCanvasProfiles as Ce}from"../../../core/profiles/manifest.js";import{existsSync as C,realpathSync as ee,statSync as ne}from"node:fs";import{isAbsolute as K,resolve as D}from"node:path";import{appendSituationalContext as Ee,formatSituationalProse as Te}from"../../../core/runtime/situational-context.js";import{closeNode as Pe}from"../../../core/runtime/close.js";import{reviveNode as De}from"../../../core/runtime/revive.js";import{nowIso as x}from"../../../core/fs-utils.js";import{appPaidLaunch as Le,assertLaunchModelRegistered as V,forkNode as je,resolveForkSource as te,spawnChildPrepared as Me}from"../../../core/runtime/spawn.js";import{forkSourceNode as ie,newNodeId as re}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as oe,childrenOf as Ge,completeCreateRequest as ae,findCreateRequest as de,getNode as R,recordCreateRequestNode as Fe,reserveCreateRequest as se,reserveCreateRequestNode as Be,listNodes as Ke,recordRespawnAttempt as xe,subscribersOf as Ve,subscriptionsOf as le,updateNode as E}from"../../../core/canvas/canvas.js";import{armControllerWait as We}from"../../../core/canvas/waits.js";import{withCanvasWrite as W}from"../../../core/canvas/db.js";import{markNodeRead as ze}from"../../../core/canvas/recovery.js";import{nodeObject as Je}from"../../../core/graph/objects.js";import{recordActedOn as Ue}from"../../../core/graph/edges.js";import{publish as Ye}from"../../../core/graph/events.js";import{readerFor as He}from"../reader.js";import{relocateSessionCwd as Qe,unbindSession as Xe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Ze}from"../../../core/canvas/attention.js";import{isSafeNodeId as qe}from"../../../core/canvas/paths.js";import{contextDir as ce,nodeAgentDir as z}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as en,cronRefusalError as nn}from"../../cron/authority.js";import{cronBirthPlacement as tn}from"../../cron/armed-context.js";import{existsBeneath as rn,isAbsentOrRefused as on,isBeneathRefusal as an,readdirBeneath as dn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as sn,readNodeSession as ln,readNodeSnapshot as cn,transcriptMarkdown as un}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as fn}from"../../../core/substrate/subject.js";import{reviveAll as pn}from"../../../core/runtime/revive-all.js";import{promoteAsync as mn,requestYieldAsync as wn,reshapeNodeAsync as J}from"../../../core/runtime/promote.js";import{recycleNode as hn}from"../../../core/runtime/recycle.js";import{relaunchRoot as yn}from"../../../core/runtime/reset.js";import{assertReopenGate as _n}from"../../../core/runtime/reopen.js";import{requireCurrentExecution as gn}from"./broker-recovery.js";import{readOutputRequest as bn}from"../../../core/runtime/output-result.js";import{writeYieldMessage as vn,readGoal as kn,captureGoalIfAbsent as Sn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as Rn,hasRoadmap as In}from"../../../core/runtime/roadmap.js";import{renameWindow as On}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as An,explicitModelIntent as $n,normalizeModel as Nn,readMergedLaunchConfigAsync as ue}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Cn}from"../../../core/model-routes.js";import{persistDormantModel as En,setModelLive as Tn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as fe}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as Pn}from"../../../core/runtime/broker-request.js";import{boundFleet as L}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as Dn}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Ln}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as pe}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as jn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Mn}from"../../../core/human-actions.js";import{parseDurationMs as Gn}from"../../../core/wake.js";import{claimWarmNode as Fn,refillWarmPool as me,resumeWarmClaim as Bn,warmPoolEnabled as Kn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as U,isLaunchKind as xn,resolveLaunchTarget as Vn}from"../../../core/runtime/launch-target.js";import{fullName as Wn}from"../../../core/canvas/labels.js";import{reportsForNode as we}from"./reports.js";import{requireUsableProfile as zn}from"./profiles.js";import{assertProfileActive as Jn,loadExactProfileManifest as Un}from"../../../core/profiles/manifest.js";import{getCron as he}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Yn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Hn}from"../../control.js";import{notFound as T,usage as w}from"../../../core/errors.js";import{assertScope as Qn,validateScopes as ye}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Xn,toNodeDetailDTO as Y,toNodeSummaryDTO as Zn,toReviveResultDTO as qn}from"../map.js";import{ApiError as p}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{runsOnBlaxel as et}from"../environment-of.js";import{actsAsPerson as j,canReadNode as $,mayOnNode as nt,readableNodeIds as tt,resolvedScopes as it}from"../router.js";import{forwardVerb as rt,queryWithoutMachine as ot,relayError as at,unknownError as dt,withMachine as st}from"../../peer/forward.js";import{fileRoot as lt}from"../../../core/spaces/file-root.js";import{activeGrant as ct,payerOfGrant as ut}from"../../../core/grants/mirror.js";import{nodeTerminalGrant as ft}from"../../../core/grants/terminal.js";import{appRungForGrant as pt}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as mt}from"../../../core/model-routes.js";import{listProfileEnvNames as wt}from"../../../core/profiles/env-store.js";import{hasConfiguredProviderCredential as ht,NO_PROVIDER_CREDENTIAL_MESSAGE as _e}from"../../../core/runtime/provider-credential-gate.js";import{filterAsync as yt,mapAsync as ge}from"../../../core/async-array.js";async function m(e){const n=await R(e);if(n===null)throw T(`unknown node: ${e}`,{received:e});return n}s(m,"requireMeta");async function H(e){return{subscribesTo:await le(e),subscribers:await Ve(e),children:await Ge(e)}}s(H,"edgesFor");async function b(e){const n=await m(e);return await Y(n,await H(e))}s(b,"detailOf");async function _t(e){let n=(await we(e)).length;try{n+=dn(await z(e),await ce(e)).length}catch(t){if(!on(t))throw t}return n}s(_t,"countFiles");function gt(e){if(typeof e!="object"||e===null)throw w("a node create requires a JSON body");const n=e;if(n.kind!==void 0&&(typeof n.kind!="string"||n.kind.trim()===""))throw w("kind must be a non-empty string when provided");if(n.description!==void 0&&(typeof n.description!="string"||n.description.trim()===""))throw w("description must be a non-empty string when provided");if(n.creator!==void 0&&(typeof n.creator!="string"||n.creator.trim()===""))throw w("creator must be a non-empty node id when provided");if(n.scopes!==void 0&&ye(n.scopes),n.isolated!==void 0&&typeof n.isolated!="boolean")throw new p(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const t=n.root_lifecycle;if(t!==void 0&&t!=="resident"&&t!=="terminal")throw w("root_lifecycle must be 'resident' or 'terminal'");if(n.request_key!==void 0&&(typeof n.request_key!="string"||n.request_key.trim()===""||n.request_key.length>128))throw w("request_key must be a non-empty string of at most 128 characters when provided");return n}s(gt,"parseCreateBody");function bt(e){if(e===void 0)return;const n=Gn(e),t=n===null?null:new Date(Date.now()+n);if(n===null||!Number.isFinite(n)||n<=0||t===null||!Number.isFinite(t.getTime()))throw new p(422,"invalid_deadline","`deadline` must be a positive representable duration");return t.toISOString()}s(bt,"parseDeadline");function vt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new p(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!jn.test(e.action))throw new p(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let n;try{n=JSON.stringify(e.payload)}catch{throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(n===void 0)throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(n,"utf8")>pe)throw new p(413,"payload_too_large",`serialized payload exceeds ${pe} bytes`)}return e}}s(vt,"parseOutcomeDelivery");function kt(e,n){const t=Mn(e.action,n);if(!("kind"in t))return{actionName:e.action,argv:t.argv,cwd:t.cwd,configOrigin:t.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw t.kind==="unknown_action"?new p(422,"unknown_action",`no action named ${e.action} is declared from ${n}`):new p(422,"invalid_action",`${e.action} is declared in ${t.configOrigin} but unusable: ${t.reason}`,{reason:t.reason,configOrigin:t.configOrigin})}s(kt,"resolveOutcomeDelivery");function St(e,n,t){const r={kind:e.kind,cwd:t,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),n!==void 0&&(r.parent=n),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=D(e.pin_cwd??e.cwd??t)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}s(St,"buildRecipe");function Rt(e,n,t){return!Kn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:n,profileId:t,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}s(Rt,"warmRequestFor");import{resolveCreateKind as Nr}from"../../../core/runtime/launch-target.js";function be(e){const n=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Cn(e.model,n,e.modelExact===!0)}s(be,"requestFromLaunch");function It(e,n){if(n===null)return e;if(e.scopes===void 0)return{...e,scopes:[...n]};const t=e.scopes.filter(r=>!O(n,r));if(t.length===0)return e;throw new p(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${t.join(", ")}`,{scopes:t,ceiling:n})}s(It,"withinCeiling");async function ve(e,n,t){const r=(await An(n.kind,n.mode,{lifecycle:n.lifecycle,hasManager:e.parent!==null,model:n.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null,app:e.grantee??"app:terminal"})).launch;await V(be(r),{cwd:e.cwd,profileId:e.profile_id??null},t)}s(ve,"assertNodeModelChangeRegistered");async function ke(e,n){const t=e.principal;if(t.class!=="broker"&&t.class!=="cron")return;const r=lt({app:t.app,resolved:await it(t),launched:t.scopes},n,"read");if("root"in r)return;const i="missing"in r?r.missing:null;throw new p(403,"scope_missing",i?`the child's directory ${n} needs missing scope ${i}`:`no permission of this run names the child's directory ${n}`,void 0,void 0,i?{scope:i}:void 0)}s(ke,"assertCallerReaches");const Q=new Map;async function Ot(e,n={},t={}){const r=It(gt(e.body),e.ceiling);if(e.principal.class==="broker"){const d=e.principal;if(r.prefer_warm===!0&&d.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const o=await m(r.parent);if(o.grantee!==d.app)throw new p(403,"other_app_run","cannot create a child under another app's node");if(!await $(d,o.grantee??"app:terminal",r.parent))throw T(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==d.node)throw new p(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let o=null;try{o=await ie(await te(r.fork_from))}catch{}if(o?.grantee!==d.app||!await $(d,o.grantee,o.node_id))throw new p(403,"other_app_run","cannot fork another app's conversation")}r.creator=d.node}if(e.principal.class==="person"&&e.principal.sub!==void 0){const d=r.fork_from===void 0?null:await ie(await te(r.fork_from)).catch(()=>null);for(const o of[r.parent,r.creator,d?.node_id])if(o!=null&&await R(o)!==null&&!await nt(e.principal,"edit",o))throw T(`unknown node: ${o}`,{received:o})}if(e.principal.class==="cron"){const d=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new p(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1,r.node_id=await re(),d.isolated&&(r.isolated=!0,r.cwd=await z(r.node_id,d.app));const o=await en({grantee:d.app,sub:d.sub,grant_id:d.grant,scopes:d.scopes,from_exec:d.from_exec},{profile:r.profile,cwd:r.cwd,pin_cwd:r.pin_cwd,kind:r.kind,model:r.model,mode:r.mode});if(!o.allowed)throw nn(o);if(r.scopes!==void 0){const l=r.scopes.find(f=>!O(o.effectiveScopes,f)||!O(d.scopes,f));if(l!==void 0)throw new p(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else d.scopes!==null&&(r.scopes=[...d.scopes])}r.creator!==void 0&&Qn(await m(r.creator),"crtr:act");const i=r.request_key?.trim();if(i===void 0||r.node_id!==void 0&&qe(r.node_id)&&await R(r.node_id)!==null&&(await de(i))?.nodeId!==r.node_id)return M(e,r,n,t);const a=Q.get(i);if(a!==void 0)return a;const u=$t(e,r,i,n,t);Q.set(i,u);try{return await u}finally{Q.delete(i)}}s(Ot,"handleCreate");const Se="create_request_in_progress";async function At(e,n,t){const r=Date.now()+1e4;for(;t!==null;){const i=await R(t);if(i!==null){if(!j(e.principal)&&!await $(e.principal,i.grantee??"app:terminal",t))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(t)}}if(Date.now()>=r||(await de(n))?.nodeId!==t)break;await new Promise(a=>setTimeout(a,100))}throw new p(409,Se,"another create with this request_key is in progress; retry it")}s(At,"awaitForeignCreate");async function $t(e,n,t,r,i){const a=await se(t);if(a.nodeId!==null&&await R(a.nodeId)!==null){if(a.state!=="warm_claimed"){const u=await R(a.nodeId);if(!j(e.principal)&&!await $(e.principal,u.grantee??"app:terminal",a.nodeId))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(a.nodeId)}}return M(e,n,r,i,a)}try{return await M(e,n,r,i,a)}catch(u){if(u instanceof p&&u.code===Se)throw u;const d=await se(t);throw(d.nodeId===null||await R(d.nodeId)===null)&&await oe(t,d.nodeId),u}}s($t,"handleKeyedCreateRequest");async function M(e,n,t,r,i=void 0){const a=r.deadlineAt??bt(n.deadline),u=vt(n.outcome_delivery),d=e.principal.class==="cron"?await tn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:e.principal.kind==="exec"?null:(await he(e.principal.cron))?.created_by??null},n.node_id):null;d!==null&&(n.root=d.root===!0);const o=d?.parent??n.parent??void 0;if(o==null&&n.root!==!0)throw w("a node create requires a parent (or root: true for an independent root)");let l=null;if(n.output_schema!==void 0){try{l=JSON.parse(n.output_schema)}catch{throw w("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw w("output_schema must be a JSON schema object");await Ln(l)}const{profileId:f,kind:h,cwd:c,launch:S}=await Vn(n,{validateKind:Ae,...e.principal.class==="broker"||e.principal.class==="cron"?{app:e.principal.app}:{}});if(n.pin_cwd!==void 0&&n.pin_cwd!==""&&n.worktree===void 0&&n.isolated!==!0&&!C(c)&&!await et(f))throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${c}`,received:c,field:"cwd",next:"Pass an existing directory with --cwd."});await ke(e,c),n.worktree!==void 0&&await ke(e,D(n.pin_cwd??n.cwd??c));const _={...n,kind:h},v=u===void 0?void 0:kt(u,c),Z=("grant"in e.principal?e.principal.grant:null)??(o==null?null:(await R(o))?.grant_id??null);if(await V(be(await Le(S,Z,n.model)),{cwd:c,profileId:f},t.modelRegistry),await ut(Z)!=="app"&&!await ht(f===null?[]:await wt(f)))throw new p(412,"no_provider_credential",_e,{error:"no_provider_credential",message:_e,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let F=null;{const A=i===void 0||i.nodeId===null||i.state==="warm_claimed"?Rt(_,c,f):null,B=l===null&&r.beforeBrokerLaunch===void 0?void 0:async g=>{l!==null&&await Dn(g,"terminal",l),r.beforeBrokerLaunch?.(g)};if(i?.state==="warm_claimed"&&i.nodeId!==null){const g=A===null?null:await Bn(A,i.nodeId,B);if(g===null)throw await oe(i.requestKey,i.nodeId),new p(503,"create_resume_failed",`could not resume warm claim ${i.nodeId}; retry the create`);return await ae(i.requestKey,g),{status:201,body:await b(g)}}if(A!==null){const g=await Fn(A,{...a===void 0?{}:{deadlineAt:a},...v===void 0?{}:{outcomeDelivery:v},...i===void 0?{}:{requestKey:i.requestKey}},B);if(g!==null)return i!==void 0&&await ae(i.requestKey,g),me(A),{status:201,body:await b(g)};F=A}const P=i?.nodeId??n.node_id??(i===void 0?void 0:await re());if(i!==void 0&&i.nodeId===null){const g=await Be(i.requestKey,P);if(g!==P)return await At(e,i.requestKey,g)}const I=St(P===void 0?_:{..._,node_id:P},o,c);d!==null&&(d.rootLifecycle!==void 0&&(I.rootLifecycle=d.rootLifecycle),d.scopes!==void 0&&_.scopes===void 0&&(I.scopes=d.scopes),d.run!==void 0&&(I.run=d.run),d.withinCreate!==void 0&&(I.withinCreate=d.withinCreate)),a!==void 0&&(I.deadlineAt=a),v!==void 0&&(I.outcomeDelivery=v),I.readiness=n.root===!0?"await":"launch";const q=await Me(I,B,()=>{F!==null&&me(F)});return i!==void 0&&await Fe(i.requestKey,q.node.node_id),{status:201,body:await b(q.node.node_id)}}}s(M,"handleCreateRequest");function k(e,n){const t=e.query.getAll(n);if(t.length>1)throw w(`${n} must appear at most once`);return t[0]}s(k,"singleQueryValue");function X(e,n){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw w(`${n} must be true or false`)}}s(X,"optionalBoolean");function G(e,n,t){if(e!==void 0){if(t.includes(e))return e;throw w(`${n} must be one of: ${t.join(", ")}`)}}s(G,"oneOf");function Nt(e){const n=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","under_inclusive","hanging","include"]);for(const[_]of e.query)if(!n.has(_))throw w(`unknown nodes query parameter: ${_}`);const t=G(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=G(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),i=k(e,"kind"),a=G(k(e,"mode"),"mode",["base","orchestrator"]),u=k(e,"profile_id"),d=k(e,"profile_prefix"),o=k(e,"parent"),l=X(k(e,"top_level"),"top_level"),f=k(e,"under"),h=X(k(e,"under_inclusive"),"under_inclusive"),c=X(k(e,"hanging"),"hanging"),S=G(k(e,"include"),"include",["activity"]);if(o!==void 0&&l===!0)throw w("parent and top_level=true cannot be combined");return{...t!==void 0?{status:t}:{},...r!==void 0?{lifecycle:r}:{},...i!==void 0?{kind:i}:{},...a!==void 0?{mode:a}:{},...u!==void 0?{profile_id:u}:{},...d!==void 0?{profile_prefix:d}:{},...o!==void 0?{parent:o}:{},...l!==void 0?{top_level:l}:{},...f!==void 0?{under:f}:{},...h!==void 0?{under_inclusive:h}:{},...c!==void 0?{hanging:c}:{},...S!==void 0?{include:S}:{}}}s(Nt,"parseListQuery");async function Ct(e){const n=Nt(e);let t=await Ke({...n.status!==void 0?{status:n.status}:{},...n.lifecycle!==void 0?{lifecycle:n.lifecycle}:{},...n.kind!==void 0?{kind:n.kind}:{},...n.mode!==void 0?{mode:n.mode}:{},...n.profile_id!==void 0?{profileId:n.profile_id}:{},...n.profile_prefix!==void 0?{profilePrefix:n.profile_prefix}:{},...n.parent!==void 0?{parent:n.parent}:{},...n.top_level===!0?{topLevel:!0}:{},...n.under!==void 0?{under:n.under}:{},...n.under_inclusive===!0?{underInclusive:!0}:{},...n.hanging===!0?{hanging:!0}:{}});const r=await tt(e.principal);r!==null&&(t=t.filter(d=>r.has(d.node_id)));const i=n.include==="activity"?await Ze(t.map(d=>d.node_id)):null,a=t.length>0?Ce():new Set;return{status:200,body:await ge(t,async d=>{const o=await Zn(d,d.profile_id!==null&&a.has(d.profile_id));if(i!==null){const l=await we(d.node_id);o.activity={latest_report:l[0]??null,final_report:d.final_report===null?null:l.find(f=>f.name===d.final_report)??null,pending_human_count:i[d.node_id]??0}}return o})}}s(Ct,"handleList");async function Et(e){const n=e.params.id,t=await rt(e,n,{method:"GET",path:`/v1/nodes/${encodeURIComponent(n)}`,query:ot(e)});if(t.kind==="unknown")throw dt(n,t.unreachable);if(t.kind==="remote"){if(t.status>=400)throw at(t.status,t.body);return{status:t.status,body:st(t.body,t.machine)}}return await m(n),{status:200,body:await b(n)}}s(Et,"handleDetail");async function Tt(e){const n=e.params.id;await m(n);const t=await cn(n);return{status:200,body:{node_id:n,snapshot:{messages:t.snapshot.messages,...t.snapshot.messageIds===void 0?{}:{messageIds:t.snapshot.messageIds},messageVisibility:t.snapshot.messageVisibility,turnVisibility:t.snapshot.turnVisibility,stats:t.snapshot.stats,state:t.snapshot.state,display:t.snapshot.display,...t.snapshot.queued===void 0?{}:{queued:t.snapshot.queued},...t.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:t.snapshot.toolGroupSummaries},...t.snapshot.turnReplies===void 0?{}:{turnReplies:t.snapshot.turnReplies},...t.snapshot.workingActivity===void 0?{}:{workingActivity:t.snapshot.workingActivity}},commands:t.commands.map(i=>({name:i.name,description:i.description,source:i.source})),captured_at:x()}}}s(Tt,"handleSnapshot");async function Pt(e){const n=e.params.id,t=await fn(n);if(t===null)throw T(`unknown node: ${n}`,{received:n});return{status:200,body:t}}s(Pt,"handleSubject");function Dt(e){for(const[a]of e.query)if(a!=="cursor"&&a!=="limit")throw w(`unknown messages query parameter: ${a}`);const n=e.query.getAll("cursor"),t=e.query.getAll("limit");if(n.length>1)throw w("cursor must appear at most once");if(t.length>1)throw w("limit must appear at most once");if(t.length===0)return n.length===0?{}:{cursor:n[0]};const r=t[0],i=Number(r);if(!Number.isSafeInteger(i)||r==="")throw w("limit must be an integer from 1 through 500");return n.length===0?{limit:i}:{cursor:n[0],limit:i}}s(Dt,"parseMessagesQuery");async function Lt(e){const n=e.params.id,t=await sn(n,Dt(e));return{status:200,body:{node_id:n,messages:t.messages,...t.messageIds===void 0?{}:{message_ids:t.messageIds},message_visibility:t.messageVisibility,next_cursor:t.nextCursor,captured_at:x()}}}s(Lt,"handleMessages");async function jt(e){const n=e.params.id;await m(n);const t=await ln(n);return{status:200,body:{node_id:n,session_file:t.sessionFile,session_jsonl:t.sessionJsonl,system_prompt:t.systemPrompt,captured_at:x()}}}s(jt,"handleSession");async function Mt(e){const n=e.params.id;return await m(n),{status:200,body:{node_id:n,markdown:await un(n)}}}s(Mt,"handleTranscript");async function Gt(e){const n=e.params.id;await m(n);const t=s(async(i,a)=>({node_id:i,label:(await R(i))?.name??i,dir:await ce(i),self:a,files:await _t(i)}),"root"),r=await yt([await t(n,!0),...await ge(await le(n),async i=>await t(i.node_id,!1))],async i=>await Ft(i.node_id,i.dir)||i.files>0);return{status:200,body:{node_id:n,roots:r}}}s(Gt,"handleContext");async function Ft(e,n){try{return rn(await z(e),n)}catch(t){if(an(t))return!1;throw t}}s(Ft,"hasDir");async function Bt(e){const n=await m(e.params.id),t=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=t===null?void 0:n.scopes==null?[...t]:[...new Set([...n.scopes.filter(a=>O(t,a)),...t.filter(a=>O(n.scopes,a))])],i=await je(n.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:await b(i.node.node_id)}}s(Bt,"handleFork");const Kt=1e4;async function xt(e){const n=e.params.id;await m(n);const t=e.body,r=t?.resume??!0,i=t?.reopen??!1;await _n(n,i,e.principal.class==="broker"?e.principal.node:null);const a=!r&&t?.cron_id!==void 0?await he(t.cron_id):null,u=await De(n,{resume:r,capacity:"refuse",...a!==null?{wakeReason:await Yn(a,"schedule_revive")}:{}});u.outcome!=="already-live"&&await xe(n,{failures:0,notBefore:null});const d=(await R(n))?.status??"active",o=(u.launch??L().get(n)?.handle)?.exited,l=u.outcome!=="frozen"&&await fe(n,o,Kt);return{status:200,body:qn(n,u,d,l)}}s(xt,"handleRevive");async function Vt(e){const n=e.params.id;return{status:200,body:{newNodeId:(await yn(n))?.newNodeId??null}}}s(Vt,"handleRelaunchRoot");async function Wt(e){const n=e.params.id;await m(n);const t=e.body;if(t?.caller_pid!==void 0&&(!Number.isInteger(t.caller_pid)||t.caller_pid<=0))throw w("caller_pid must be a positive integer when provided");const r=Hn(),i=new Promise(u=>{e.res.once("close",()=>u())}),a=await Pe(n,{teardownAfter:i,rootEvent:t?.finish===!0?"finish":"cancel",callerPid:t?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Xn(a)}}s(Wt,"handleClose");async function zt(e){if(!j(e.principal))throw new p(403,"permission_error","only the person marks a conversation read");const n=e.params.id;return await m(n),await ze(n),{status:204}}s(zt,"handleMarkRead");async function Jt(e){const n=e.params.id;await m(n);const t=await hn(n);return{status:200,body:{recycled:t.recycled,finalized:t.finalized,new_root:t.newRoot,delivered:t.delivered}}}s(Jt,"handleRecycle");async function Ut(e){const n=e.params.id;return await m(n),await J(n,{lifecycle:"terminal"}),await N(e,n,["lifecycle"]),{status:200,body:await b(n)}}s(Ut,"handleDemote");async function Yt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:"orchestrator",lifecycle:i.resident===!0?"resident":r.lifecycle,model:i.model},n.modelRegistry);const a=await mn(t,{...i.kind!==void 0?{kind:i.kind}:{},...i.resident===!0?{resident:!0}:{},...i.model!==void 0?{model:i.model}:{}});await N(e,t,["mode",...i.kind!==void 0?["kind"]:[],...i.resident===!0?["lifecycle"]:[],...i.model!==void 0?["model"]:[]]);const u=await Y(a.meta,await H(t));return u.roadmap_written=a.roadmapWritten,u.roadmap_ref=a.roadmapRef,u.goal_path=a.goalPath,{status:200,body:u}}s(Yt,"handlePromote");async function Ht(e){const n=e.params.id;return await m(n),{status:200,body:{request:await bn(n)}}}s(Ht,"handleBrokerStructuredRequest");async function Qt(e){const n=e.params.id,t=e.body??{};if(await gn(n,t.expected_execution_id),typeof t.text!="string")throw new p(400,"invalid_request","text must be a string");return await m(n),{status:200,body:{captured:await Sn(n,t.text)}}}s(Qt,"handleBrokerGoal");async function Xt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:i.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:i.model},n.modelRegistry);const a=i.note??"Refresh: continue against your roadmap or goal.";await vn(t,a);const u=await wn(t,{...i.promote===!0?{promote:!0}:{},...i.kind!==void 0?{kind:i.kind}:{},...i.model!==void 0?{model:i.model}:{}});return{status:200,body:await Y(u.meta,await H(t))}}s(Xt,"handleYield");async function Zt(e){const n=e.params.id;await m(n);const t=e.body;if(t===void 0||typeof t.controller!="string"||t.controller.trim()==="")throw w("a wait requires a controller node id");const r=await R(t.controller);if(r===null)throw T(`unknown controller: ${t.controller}`,{received:t.controller});if(r.status!=="active"&&r.status!=="idle")throw new p(422,"unprocessable",`controller ${t.controller} is ${r.status}`);return await We(n,t.controller),{status:200,body:await b(n)}}s(Zt,"handleWait");async function qt(e){const n=e.principal,t=await pn(n.class==="broker"?async i=>i.grantee===n.app&&await $(n,i.grantee,i.node_id):n.class==="person"&&!j(n)?async i=>await $(n,i.grantee??"app:terminal",i.node_id):void 0);return{status:200,body:{revived:[...t.revived],failed:[...t.failed],frozen:[...t.frozen]}}}s(qt,"handleReviveAll");const ei=new Set(["interrupt","steer","after-turn","next-turn"]);function ni(e){if(e===null)return null;const n=s(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return n("listen must be an object or null");const t=Object.entries(e);if(t.length===0)return n("listen must name at least one level");for(const[r,i]of t)/^(?:[1-9]|10)$/.test(r)||n(`listen level must be 1..10: ${r}`),(typeof i!="string"||!ei.has(i))&&n(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(i)}`);return JSON.stringify(Object.fromEntries(t))}s(ni,"listenJson");async function N(e,n,t,r){t.length===0&&r===void 0||await W(async i=>{if(r?.(i),t.length===0)return;const a=await Je(i,n),u=await He(i,e),d=u.class==="person"?u.person:u.class==="app"?u.app:u.node;await Ue(i,d,a),await Ye(i,{event:"configured",object:a,actor:d,attrs:{changed:t.join(",")}})})}s(N,"recordConfigured");function Re(e){const n=L().get(e);if(n===void 0)return!1;try{return process.kill(n.pid,"SIGTERM"),!0}catch{return!1}}s(Re,"restartLiveBroker");function Ie(e,n){try{return ee(e)===ee(n)}catch{return!1}}s(Ie,"sameDirectory");async function ti(e,n={}){const t=e.params.id,r=e.body;let i;if(r===void 0)i={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))i=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(i.profile!==void 0){if(typeof i.profile!="string"||i.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:i.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(i).some(h=>h!=="profile"&&h!=="restart"&&i[h]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const o=await m(t),l=await zn(e,i.profile);Jn(l.profileId);const f=Un(l.profileId).manifest.grantee??"app:terminal";if(f!==(o.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${f}, node ${t} to ${o.grantee}`,received:i.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(o.profile_id??null)!==l.profileId&&(xn(o.kind)?(await U(o.kind,o.cwd,l.profileId),await J(t,{profileId:l.profileId})):await E(t,{profile_id:l.profileId}),await N(e,t,["profile"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(Object.prototype.hasOwnProperty.call(i,"cwd")){const o=i.cwd;if(typeof o!="string"||o==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:o,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(i).some(c=>c!=="cwd"&&c!=="keep_session"&&c!=="restart"&&i[c]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:i,field:"cwd",next:"Send cwd as the only config field."});const l=await m(t),f=C(l.cwd);if(i.keep_session===!0||f&&K(o)&&C(o)&&Ie(l.cwd,o)){if(!K(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const c=D(o);let S=!1;try{S=ne(c).isDirectory()}catch{}if(!S)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${c}`,received:o,field:"cwd",next:"Send an existing absolute directory."});if(f&&!Ie(l.cwd,c))throw new y({error:"cwd_not_same_directory",message:`${c} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:o,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot relocate its cwd`,received:o,field:"cwd",next:"Reconcile the managed worktree first."});const _=l.cwd;return _!==c&&(await W(async v=>{await E(t,{cwd:c}),await v.prepare("UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(c,t,_),await Qe(t,_,c)}),await N(e,t,["cwd"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(await L().has(t)){const c=`${t} cannot repair its cwd while its broker is live`;throw new p(409,"cwd_node_live",c,{error:"cwd_node_live",message:c,received:o,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${t} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:o,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot repair its cwd`,received:o,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(C(l.cwd))throw new y({error:"cwd_still_present",message:`${t} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:o,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!K(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const h=D(o);if(!C(h))throw new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ne(h).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${h}`,received:o,field:"cwd",next:"Send an existing absolute directory."})}catch(c){throw c instanceof y?c:new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return await W(async()=>{await E(t,{cwd:h}),await Xe(t)}),await N(e,t,["cwd"]),{status:200,body:await b(t)}}let a=await m(t);const u=i.listen===void 0?void 0:ni(i.listen);if(i.scopes!==void 0){const o=ye(i.scopes),l=a.grantee==="app:terminal"?await ft(a):a.grant_id?await ct(a.grant_id):null;if(!o.every(f=>O(a.scopes,f)&&l!==null&&O(l.resolved,f)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:o,field:"scopes",next:"Send only scopes the node currently holds."});if(o.includes("crtr:act")&&!O(o,"crtr:llm"))throw new p(400,"invalid_scope","crtr:act requires crtr:llm");a=await E(t,{scopes:o})}if(i.situational_context!==void 0&&await Ee(t,Te(i.situational_context)),i.model!==void 0){const o=(await ue(a.cwd,a.profile_id??null,a.grantee??"app:terminal")).modelLadders,l=$n(i.model,o),f=await pt(a.grant_id,i.model,l===void 0),h=f?{family:mt,strength:f.strength}:l,c=f?f.model:Nn(i.model,o);await V({kind:"concrete",spec:c},{cwd:a.cwd,profileId:a.profile_id??null},n.modelRegistry);const S=L();let _=!1;if(await S.isClaimed(t)&&await fe(t,S.get(t)?.handle.exited)&&(_=await Tn(t,c,h).then(()=>!0,v=>{if(v instanceof Pn)return!1;throw v})),!_){if(await S.isClaimed(t)){const v=`${t}'s broker did not accept the model switch; the model was not changed`;throw new p(409,"broker_not_ready",v,{error:"broker_not_ready",message:v,received:i.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!c.includes("/"))throw w(`model must resolve to a provider/id spec: ${i.model}`);await En(t,c,h)}a=await m(t)}if(i.kind!==void 0||i.mode!==void 0||i.lifecycle!==void 0){i.kind!==void 0&&await Ae(i.kind,a.grantee??"app:terminal");const o=i.kind??a.kind,l=i.mode??a.mode,f=i.lifecycle??a.lifecycle;let h;l==="orchestrator"&&!await In(t)&&(h=s(async()=>{const c=await kn(t);await Rn(t,c!==null&&c.trim()!==""?{goal:c.trim()}:{})},"beforePersist")),a=await J(t,{...i.kind!==void 0?{kind:o}:{},...i.mode!==void 0?{mode:l}:{},...i.lifecycle!==void 0?{lifecycle:f}:{}},h)}i.name!==void 0&&(a=await E(t,{name:i.name}),a.window&&On(a.window,Wn(a)));const d=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(o=>i[o]!==void 0);return await N(e,t,d,u===void 0?void 0:async o=>{await o.prepare("UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(u,t)}),{status:200,body:await b(t)}}s(ti,"handleConfig");async function Oe(e="app:terminal"){return(await ue(process.cwd(),Ne()||null,e)).kinds}s(Oe,"daemonKinds");async function Ae(e,n="app:terminal"){const t=Object.keys(await Oe(n));if(!t.includes(e))throw w(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}s(Ae,"assertKindServer");async function ii(){const e=await Oe();return{status:200,body:{kinds:Object.keys(e).sort().map(t=>({kind:t,when_to_use:e[t]?.whenToUse??null,available_to:e[t]?.availableTo??null}))}}}s(ii,"handleListKinds");const Or=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:Ot},{method:"GET",pattern:"/v1/nodes",handler:Ct},{method:"GET",pattern:"/v1/kinds",handler:s(()=>ii(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:qt},{method:"GET",pattern:"/v1/nodes/:id",handler:Et},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:Tt},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:Pt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:Lt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:jt},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:Mt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:Gt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Bt},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:xt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:Vt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Wt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:zt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Jt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Ut},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Yt},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Xt},{method:"GET",pattern:"/v1/nodes/:id/broker/structured-request",handler:Ht},{method:"POST",pattern:"/v1/nodes/:id/broker/goal",handler:Qt},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Zt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:ti}];export{ti as handleConfig,Ot as handleCreate,Bt as handleFork,Ct as handleList,Yt as handlePromote,Xt as handleYield,Or as nodeRoutes,Nr as resolveCreateKind};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RouteTable } from '../router.js';
|
|
2
2
|
export declare const packageDocRoutes: RouteTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var c=Object.defineProperty;var d=(i,e)=>c(i,"name",{value:e,configurable:!0});import{withCanvasWrite as f}from"../../../core/canvas/db.js";import{isCloudRole as m}from"../../../core/canvas/person-state.js";import{personIdAsync as k}from"../../../core/canvas/person.js";import{reconcilePackages as g}from"../../../core/graph/package-reconcile.js";import{syncInstall as h}from"../../../core/packages/directory-sync.js";import{normalizeSourceUrl as b}from"../../../core/packages/source-url.js";import{loadPersonSettings as v}from"../../../core/scoped-state/person-rows.js";import{ApiError as p}from"../../../api/errors.js";import{appOf as w}from"../router.js";const y=d(()=>({created:0,updated:0,deleted:0,conflicts:[],invalid:[],quarantined:[],kinds:{applied:[],refused:[],invalid:[]},tokens:{granted:[],revoked:[]}}),"EMPTY_REPORT");async function _(i){const e=y(),t=i.body?.plugins,l=(await v(await k())).apps[w(i.principal)??"app:terminal"];if(l===void 0)return e;for(const[n,s]of Object.entries(l.plugins)){if(s.enabled===!1||s.source_marketplace===void 0||t!==void 0&&!t.includes(n))continue;const u=l.marketplaces[s.source_marketplace]?.url;if(u===void 0)continue;const{out:o,published:r}=await h(n,b(u));if(r!==void 0){e.created+=r.created,e.deleted+=r.deleted,e.invalid.push(...r.invalid);for(const a of r.kinds.refused)e.kinds.refused.push({plugin:n,kind:a.kind,code:"kind_owned",message:a.message})}if(o.ok){e.updated+="pkg"in o?1:0;continue}if(o.reason==="name_taken"){const a=`plugin ${n} is already provided by ${o.holder??"another marketplace"}`;if(t!==void 0)throw new p(409,"name_taken",a,{plugin:n,holder:o.holder??null});e.conflicts.push({plugin:n,message:a})}else if(o.reason==="not_found"){const a=`the directory does not list plugin ${n} in marketplace ${s.source_marketplace}`;if(t!==void 0)throw new p(404,"not_found",a,{plugin:n});(e.unavailable??=[]).push({plugin:n,reason:"not_found"})}else(e.unavailable??=[]).push({plugin:n,reason:o.reason==="unavailable"?"directory_unreachable":"not_public"})}return e}d(_,"resolveApp");const j=[{method:"POST",pattern:"/v1/documents/reconcile-packages",handler:d(async i=>({status:200,body:m()?await _(i):await f(async e=>await g(e))}),"handler")}];export{j as packageDocRoutes};
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SettingsOp } from '../../../core/scoped-state/person-store.js';
|
|
2
|
+
import { type RequestContext, type RouteTable } from '../router.js';
|
|
3
|
+
/** On an unsandboxed host every node's CLI loads the person's settings through its relay at startup, as the person's terminal does, so any node reads them. Only the terminal app's node writes them, and a node of any app (the terminal's included) writes only its own app's plugin installs. */
|
|
4
|
+
export declare function requireWriter(ctx: RequestContext, ops: readonly SettingsOp[]): void;
|
|
2
5
|
export declare const settingsRoutes: RouteTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.defineProperty;var s=(r,e)=>i(r,"name",{value:e,configurable:!0});import{ApiError as o}from"../../../api/errors.js";import{personIdAsync as p}from"../../../core/canvas/person.js";import{isCloudRole as a}from"../../../core/canvas/person-state.js";import{SettingsRevisionConflictError as l,currentSnapshot as c,personHasSnapshot as f}from"../../../core/scoped-state/person-store.js";import{loadPersonSettings as w,rowsTransport as u}from"../../../core/scoped-state/person-rows.js";import{ownerOnly as h}from"../router.js";const g=new Set(["settings.replace","app-plugins.replace","state.write","profile.insert","profile.update","profile.delete","defaults.replace"]);function m(r){const e=r?.ops;if(!Array.isArray(e)||e.length===0)throw new o(400,"invalid_request","ops must be a non-empty array");for(const n of e)if(n===null||typeof n!="object"||!g.has(n.op))throw new o(400,"invalid_request",`unknown settings op: ${String(n?.op)}`);return e}s(m,"parseOps");function d(r,e){if(a()){for(const t of e)if(t.op==="settings.replace"&&("plugins"in t.raw||"marketplaces"in t.raw))throw new o(400,"invalid_request","plugin and marketplace installs are written with app-plugins.replace, not settings.replace")}const{principal:n}=r;if(n.class==="broker")for(const t of e){if(t.op==="settings.replace"&&t.owner.startsWith("app:"))throw new o(403,"permission_error","an app's plugin installs are written with app-plugins.replace, not settings.replace");if(t.op==="app-plugins.replace"){if(t.app!==n.app)throw new o(403,"permission_error",`a node of ${n.app} changes only its own app's plugin installs, not ${t.app}'s`)}else if(n.app!=="app:terminal")throw new o(403,"permission_error","only the person's terminal nodes change the person's settings")}}s(d,"requireWriter");async function y(){const r=await p();return{status:200,body:{person:r,snapshot:f()?c():await w(r)}}}s(y,"handleGet");async function S(r){const e=m(r.body);d(r,e);const n=await p();try{return{status:200,body:{person:n,snapshot:await u(n,e)}}}catch(t){throw t instanceof l?new o(409,"conflict",t.message):t}}s(S,"handlePut");const E=h([{method:"GET",pattern:"/v1/settings",handler:y},{method:"PUT",pattern:"/v1/settings",handler:S}]);export{d as requireWriter,E as settingsRoutes};
|