@north-light/cli 0.3.550 → 0.3.552
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 +11 -0
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/charges.d.ts +122 -0
- package/dist/api/dto/charges.js +0 -0
- package/dist/api/dto/usage.d.ts +3 -3
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +3 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
- package/dist/clients/attach/viewer.js +50 -50
- package/dist/commands/sys/spend.d.ts +1 -0
- package/dist/commands/sys/spend.js +3 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/canvas/canvas.js +4 -4
- package/dist/core/canvas/export-sqlite.js +2 -2
- package/dist/core/canvas/import-sqlite.js +1 -1
- package/dist/core/canvas/person.js +7 -16
- package/dist/core/canvas/schema-pg.sql +61 -0
- package/dist/core/canvas/types.d.ts +4 -0
- package/dist/core/config.js +1 -1
- package/dist/core/grants/mirror.d.ts +2 -1
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/ledger/backfill.d.ts +12 -0
- package/dist/core/ledger/backfill.js +22 -0
- package/dist/core/ledger/charges.d.ts +18 -0
- package/dist/core/ledger/charges.js +1 -0
- package/dist/core/ledger/check.d.ts +44 -0
- package/dist/core/ledger/check.js +7 -0
- package/dist/core/ledger/index.d.ts +9 -0
- package/dist/core/ledger/index.js +1 -0
- package/dist/core/ledger/limits.d.ts +15 -0
- package/dist/core/ledger/limits.js +3 -0
- package/dist/core/ledger/months.d.ts +6 -0
- package/dist/core/ledger/months.js +1 -0
- package/dist/core/ledger/payer.d.ts +34 -0
- package/dist/core/ledger/payer.js +1 -0
- package/dist/core/ledger/read.d.ts +44 -0
- package/dist/core/ledger/read.js +3 -0
- package/dist/core/ledger/totals.d.ts +19 -0
- package/dist/core/ledger/totals.js +4 -0
- package/dist/core/ledger/types.d.ts +66 -0
- package/dist/core/ledger/types.js +0 -0
- package/dist/core/llm/run.d.ts +17 -5
- package/dist/core/llm/run.js +2 -2
- package/dist/core/providers/call.d.ts +7 -1
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/errors.js +1 -1
- package/dist/core/providers/receipts.d.ts +7 -1
- package/dist/core/providers/receipts.js +1 -3
- package/dist/core/runs/operations.d.ts +1 -0
- package/dist/core/runs/operations.js +7 -7
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/broker/turn-cause.d.ts +7 -0
- package/dist/core/runtime/broker/turn-cause.js +1 -0
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/nodes.d.ts +2 -0
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/spawn.d.ts +2 -0
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/start-check.d.ts +15 -0
- package/dist/core/runtime/start-check.js +1 -0
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/user-settings.d.ts +4 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +13 -13
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/charges.d.ts +3 -0
- package/dist/daemon/api/handlers/charges.js +1 -0
- package/dist/daemon/api/handlers/llm.d.ts +9 -5
- package/dist/daemon/api/handlers/llm.js +3 -3
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/providers.d.ts +2 -0
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/run-routes.js +1 -1
- package/dist/daemon/api/handlers/runs.d.ts +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +8 -0
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/cron/authority.d.ts +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd.js +10 -10
- package/dist/daemon/fleet.js +4 -4
- package/dist/daemon/reconcilers/action-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/doc-editor/editor.css +1 -1
- package/dist/doc-editor/editor.js +16 -16
- package/dist/types.d.ts +4 -0
- package/docs/sdk/release-notes.md +10 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/dist/core/usage/ledger.d.ts +0 -49
- package/dist/core/usage/ledger.js +0 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sysSpendBranch: import("../../core/command.js").BranchDef;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var y=Object.defineProperty;var t=(e,r)=>y(e,"name",{value:r,configurable:!0});import{defineBranch as w,defineLeaf as c}from"../../core/command.js";import{InputError as l}from"../../core/io.js";import{cliClient as m}from"../api-client.js";const d=t(e=>e===null?"unpriced":`$${e.toFixed(e<1?4:2)}`,"usd"),$=t(e=>[e.funding&&`funding ${e.funding}`,e.grantee&&`grantee ${e.grantee}`,e.provider&&`provider ${e.provider}`,e.sub&&`sub ${e.sub}`].filter(Boolean).join(", ")||"everything","filters"),p=t(e=>`- \`${e.id}\` ${e.payer} ${d(e.usd_per_month)}/month on ${$(e)} (${e.source})`,"limitLine"),b=c({name:"show",description:"show a month's spend by payer and funding, with the limits",whenToUse:"checking what a payer has spent this month and which limits apply",help:{name:"sys spend show",summary:"month totals by payer and by payer and funding from the ledger, then every limit row",params:[{kind:"flag",name:"month",type:"string",required:!1,constraint:"UTC month YYYY-MM. Default: the current month."}],output:[{name:"month",type:"string",required:!0,constraint:"The month shown, YYYY-MM."},{name:"totals",type:"ChargeTotalsDTO",required:!0,constraint:"Record: {month, by_payer, by_funding, limits}. Migrated user-paid model history has funding `legacy`."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=await m().listCharges({limit:1,...e.month===void 0?{}:{month:String(e.month)}});if(r.totals===void 0)throw new l({error:"owner_only",message:"month totals and limits are read by the person; this caller sees only its own app's charges",next:"Run `crtr sys spend show` from the person's own shell, not from inside a node."});return{month:r.month,totals:r.totals}},"run"),render:t(e=>{const r=e.totals;return[`Spend for ${r.month}:`,...r.by_payer.length===0?["- nothing charged"]:r.by_payer.map(i=>`- ${i.payer} ${d(i.usd)}${r.by_funding.filter(s=>s.payer===i.payer).map(s=>` ${s.funding} ${d(s.usd)}`).join("")}`),"Limits:",...r.limits.length===0?["- none"]:r.limits.map(p)].join(`
|
|
2
|
+
`)},"render")});function v(e){const r=new Map;for(const n of e)r.set(n.provider??"(none)",(r.get(n.provider??"(none)")??0)+(n.usd??0));const i=new Set(e.map(n=>n.request)),s=t(n=>e.filter(o=>(o.caused_by??null)===n),"children"),a=[],u=new Set,h=t((n,o)=>{if(!u.has(n.id)&&(u.add(n.id),a.push(`${" ".repeat(o)}- ${n.at} ${n.kind} ${n.what} ${d(n.usd)} ${n.payer}/${n.funding}${n.provider?` \u2192 ${n.provider}`:""} vendor_ref ${n.vendor_ref??"none"}${n.refused?` REFUSED by ${n.refused.limit}`:""}`),n.request!==null))for(const g of s(`request:${n.request}`))h(g,o+1)},"print"),f=e.filter(n=>n.caused_by===null||!(n.caused_by.startsWith("request:")&&i.has(n.caused_by.slice(8))));for(const n of f)h(n,0);for(const n of e)h(n,0);return[...a,"Total per provider:",...[...r].map(([n,o])=>`- ${n} ${d(o)}`)].join(`
|
|
3
|
+
`)}t(v,"tree");const q=c({name:"chain",description:"list the charge rows under a run, message, request or charge on this runtime",whenToUse:"finding what one run, message or request cost and matching its vendor_ref to a vendor's usage line",help:{name:"sys spend chain",summary:"the rows under a reference as a tree, with each row's vendor_ref and a total per provider",params:[{kind:"positional",name:"reference",type:"string",required:!0,constraint:"`run:<id>`, `message:<id>`, `request:<id>`, `cron_run:<id>` or a charge id. Reads this runtime only."}],output:[{name:"reference",type:"string",required:!0,constraint:"The reference read."},{name:"charges",type:"ChargeDTO[]",required:!0,constraint:"Rows in time order; empty when this runtime holds none under the reference."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=String(e.reference),i=[];for(let s;;){const a=await m().listCharges({under:r,...s===void 0?{}:{after:s}});if(i.push(...a.charges),a.next===null)break;s=a.next}return{reference:r,charges:i}},"run"),render:t(e=>{const r=e.charges;return r.length===0?`No charges under ${String(e.reference)} on this runtime.`:v(r)},"render")}),_=c({name:"limit",description:"set or clear one of the person's dollar limits",whenToUse:"stopping a payer's spend (0 is an emergency stop) or capping it per month; clearing a limit you set",help:{name:"sys spend limit",summary:"write or remove the limit row `person:<name>`; the check refuses calls billed to the payer once the month reaches it",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"A name for the row; the id is `person:<name>`."},{kind:"flag",name:"payer",type:"string",required:!1,constraint:"`user:<id>` (the person) or `app:<id>`. Required unless --clear."},{kind:"flag",name:"usd",type:"string",required:!1,constraint:"Dollars per month, 0 or more; 0 stops the payer. Required unless --clear."},{kind:"flag",name:"funding",type:"enum",choices:["bill","subscription","key","endpoint","take","legacy"],required:!1,constraint:"Limit only this funding. Default: any."},{kind:"flag",name:"grantee",type:"string",required:!1,constraint:"Limit only charges attributed to this app, such as `app:terminal`. Default: any."},{kind:"flag",name:"provider",type:"string",required:!1,constraint:"Limit only money going to this vendor or provider app, such as `anthropic`. Default: any."},{kind:"flag",name:"clear",type:"bool",required:!1,constraint:"Remove the row instead of writing it."}],output:[{name:"limit",type:"LimitDTO",required:!1,constraint:"The row written; absent with --clear."},{name:"removed",type:"string",required:!1,constraint:"The id removed with --clear."}],outputKind:"object",effects:["Writes or deletes one `limits` row with source `person`. Takes effect on the next call."]},run:t(async e=>{const r=`person:${String(e.name)}`;if(e.clear===!0)return{removed:(await m().removeSpendLimit(r)).id};const i=e.usd===void 0?Number.NaN:Number(e.usd);if(typeof e.payer!="string"||!Number.isFinite(i)||i<0)throw new l({error:"nothing_to_set",message:"a limit needs --payer and --usd (0 or more), or --clear",next:"Pass --payer user:<id> --usd 20, or --clear to remove the row."});return{limit:await m().setSpendLimit(r,{payer:e.payer,usd_per_month:i,...e.funding===void 0?{}:{funding:e.funding},...e.grantee===void 0?{}:{grantee:String(e.grantee)},...e.provider===void 0?{}:{provider:String(e.provider)}})}},"run"),render:t(e=>e.removed!==void 0?`Removed ${String(e.removed)}.`:p(e.limit),"render")}),D=w({name:"spend",description:"the money ledger: spend by payer, the chain under a run, and dollar limits",whenToUse:"reading what was spent and why, or stopping or capping a payer's spend",help:{name:"sys spend",summary:"read this runtime's charges and set the person's dollar limits",model:"Every model call and priced tool call is one charge row naming its payer, funding and cause. A limit row bounds a payer's month; the check refuses calls billed to that payer once it is reached. `sys limits` is the unrelated per-app memory and disk cap."},children:[b,q,_]});export{D as sysSpendBranch};
|
package/dist/commands/sys.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=Object.defineProperty;var r=(o,m)=>s(o,"name",{value:m,configurable:!0});import{defineSysBranch as t}from"./sys/branch.js";import{configBranch as f}from"./sys/config.js";import{sysEnvBranch as e}from"./sys/env.js";import{daemonBranch as i}from"./sys/daemon.js";import{sysDoctorLeaf as a}from"./sys/doctor.js";import{sysFeedbackLeaf as p}from"./sys/feedback.js";import{sysLogsLeaf as n}from"./sys/logs.js";import{sysRetryDeliveryLeaf as y}from"./sys/retry-delivery.js";import{sysWorktreesLeaf as c}from"./sys/worktrees.js";import{sysSpacesLeaf as L}from"./sys/spaces.js";import{sysLimitsBranch as h}from"./sys/limits.js";import{
|
|
1
|
+
var s=Object.defineProperty;var r=(o,m)=>s(o,"name",{value:m,configurable:!0});import{defineSysBranch as t}from"./sys/branch.js";import{configBranch as f}from"./sys/config.js";import{sysEnvBranch as e}from"./sys/env.js";import{daemonBranch as i}from"./sys/daemon.js";import{sysDoctorLeaf as a}from"./sys/doctor.js";import{sysFeedbackLeaf as p}from"./sys/feedback.js";import{sysLogsLeaf as n}from"./sys/logs.js";import{sysRetryDeliveryLeaf as y}from"./sys/retry-delivery.js";import{sysWorktreesLeaf as c}from"./sys/worktrees.js";import{sysSpacesLeaf as L}from"./sys/spaces.js";import{sysLimitsBranch as h}from"./sys/limits.js";import{sysSpendBranch as B}from"./sys/spend.js";import{sysSettingsLeaf as S}from"./sys/settings.js";import{sysConnectLeaf as d}from"./sys/connect.js";import{sysSetupLeaf as g}from"./sys/setup.js";import{tutorialBranch as u}from"./sys/tutorial/branch.js";import{supportBranch as D}from"./sys/support.js";import{contextBranch as b}from"./sys/context.js";import{sysSyncBranch as k}from"./sys/sync.js";import{sysMigrateLeaf as l}from"./sys/migrate.js";import{sysJoinLeaf as v}from"./sys/join.js";import{sysDbBranch as x}from"./sys/db.js";import{sysUpdateLeaf as C,sysVersionLeaf as E}from"./sys/update.js";function _(){return t([S,f,e,d,g,u,a,b,p,n,c,y,L,h,B,D,C,E,l,v,k,x,i])}r(_,"registerSys");export{_ as registerSys};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var i=(e,n)=>ie(e,"name",{value:n,configurable:!0});import{envNodeId as W}from"../../shared/env.js";import{lstatSync as oe,realpathSync as
|
|
1
|
+
var ie=Object.defineProperty;var i=(e,n)=>ie(e,"name",{value:n,configurable:!0});import{envNodeId as W}from"../../shared/env.js";import{lstatSync as oe,realpathSync as b,rmdirSync as re,rmSync as se,statSync as de}from"node:fs";import{basename as ue,dirname as F,isAbsolute as le,join as S,relative as ce,resolve as _e,sep as pe}from"node:path";import{removeTreeBeneath as C}from"../spaces/open-beneath.js";import{emitEvent as fe}from"../events/emit.js";import{withCanvasWrite as p,openDb as s}from"./db.js";import{conversationStore as Ee,ConversationNotFoundError as we}from"../conversation-store/index.js";import{hasUnseenWakeMail as ye,UNSEEN_WAKE_MAIL_SQL as me}from"./deliveries.js";import{isAppRun as H}from"./app-run.js";import{registerOutcomeAction as M}from"./outcome-actions.js";import{publish as Ne}from"../graph/events.js";import{nodeObject as Re}from"../graph/objects.js";import{findNodeBySessionFileSql as Se}from"./sessions.js";import{hydrateFault as he}from"./recovery.js";import{hasUnreconciledWorktree as Oe,openWorktree as Te,readWorktree as Le,worktreeFromRow as De}from"./worktrees.js";import{isPidAlive as ve,isPidPresent as P,recordedPidLiveness as ge}from"./pid.js";import{ensureHome as Ae,jobDir as ke,nodeDir as xe,nodeRunDir as $}from"./paths.js";import{appForNode as Ue,ensureNodeDirs as je,nodeAgentDir as Ie}from"./node-agent-paths.js";import{appSpace as T}from"../layout.js";import{createObject as We,getById as L,ownerForGrantee as be,setObjectKind as Fe,setObjectName as Ce}from"../graph/objects.js";import{profileObject as He}from"../graph/reader.js";import{writeActsFor as q}from"../permissions/facts.js";import{CrtrError as Me}from"../errors.js";import{deleteNodeWithOwned as Pe}from"../graph/deletion.js";import{SUBTREE_ALL_IDS_SQL as $e,SUBTREE_IDS_SQL as qe}from"./tree.js";import{filterAsync as m,mapAsync as D}from"../async-array.js";function E(e,n){if(e==null)return null;const t=JSON.stringify(e);if(t===void 0)throw new TypeError(`${n} must be JSON-serializable`);return t}i(E,"jsonValue");async function vn(e,n){if((await e.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(n))?.deleting_at)throw new Error("run is deleting")}i(vn,"assertRunNotDeleting");async function B(e,n,t){try{return await He(e,n,t)}catch(a){if(a instanceof Me&&a.code==="not_found")return null;throw a}}i(B,"profileObjectFor");async function Be(e,n){const t=await be(n,e.grantee??"app:terminal"),a=e.profile_id?await B(n,e.profile_id,t):null;await We(n,{id:e.node_id,type:"node",kind:e.kind,owner:(a??t).id,privacy:"public",name:e.name,preview:""}),a===null&&e.sub&&await q(n,e.node_id,e.sub),await n.prepare(`INSERT INTO nodes (node_id, description, title, icon, cycles, mode, lifecycle, cwd, host_kind, profile_id, parent, spawned_by, creator, fork_from, fork_source_file, created, passive_default, cycle_pending, model_override, persona_ack_json, review_binding_json, launch_config_json, scopes_json, isolated, status, intent, final_report, finalized_at, deadline_at, "window", tmux_session, pane, sub, grant_id, client_id, metadata_json, run_id, event_cursor, usage_json, deleting_at, caused_by, app) VALUES (${Array(42).fill("?").join(", ")})`).run(e.node_id,e.description??null,e.title??null,e.icon??null,e.cycles??null,e.mode,e.lifecycle,e.cwd,e.host_kind??null,e.profile_id??null,e.parent??null,e.spawned_by??null,e.creator??null,e.fork_from??null,e.fork_source_file??null,e.created,e.passive_default===!0?1:0,e.cycle_pending===!0?1:0,e.model_override??null,E(e.persona_ack,"persona_ack"),E(e.review_binding,"review_binding"),E(e.launch,"launch"),E(e.scopes,"scopes"),e.isolated===!0?1:0,e.status??"active",e.intent??null,e.final_report??null,e.finalized_at??null,e.deadline_at??null,e.window??null,e.tmux_session??null,e.pane??null,e.sub??null,e.grant_id??null,e.client_id??null,e.metadata_json??null,e.run_id??null,e.event_cursor??null,e.usage_json??null,e.deleting_at??null,e.caused_by??null,t.id)}i(Be,"seedRow");function z(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,a])=>[t==="fault_id"?t:t.slice(6),a]);return he(Object.fromEntries(n))}i(z,"faultFrom");function f(e){const n={node_id:e.node_id,name:e.name,description:e.description??void 0,cycles:e.cycles??void 0,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),isolated:e.isolated===1,grantee:e.grantee,sub:e.sub??null,grant_id:e.grant_id??null,client_id:e.client_id??null,metadata_json:e.metadata_json??null,run_id:e.run_id??null,event_cursor:e.event_cursor??null,last_activity_at:e.last_activity_at??null,usage_json:e.usage_json??null,caused_by:e.caused_by??null,last_turn_error_json:e.last_turn_error_json??null,deleting_at:e.deleting_at??null,parent:e.parent??null,created:e.created,intent:e.intent??null,frozen_at:e.frozen_at??null,respawn_failures:e.respawn_failures??0,respawn_not_before:e.respawn_not_before??null,launched_at:e.launched_at??null,last_settled_at:e.last_settled_at??null,terminal_reason:e.terminal_reason??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,outcome_kind:e.outcome_kind??null,outcome_reason:e.outcome_reason??null,outcome_at:e.outcome_at??null,outcome_revision:e.outcome_revision??0,outcome_detail_json:e.outcome_detail_json??null,deadline_at:e.deadline_at??null,telemetry_tokens_in:e.telemetry_tokens_in??null,telemetry_context_tokens:e.telemetry_context_tokens??null,telemetry_last_activity:e.telemetry_last_activity??null,telemetry_updated_at:e.telemetry_updated_at??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,fault:null,streaming:!1},t=P(n.pi_pid),a=z(e);return n.fault=a?.link==="pi\u2192provider"&&a.retry.by==="daemon"&&a.retry.disposition==="auto"&&!t?null:a,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}i(f,"rowFrom");async function J(e,n){return n??=await Le(e.node_id),{...f(e),title:e.title??void 0,icon:e.icon??void 0,spawned_by:e.spawned_by??null,creator:e.creator??null,fork_from:e.fork_from??null,fork_source_file:e.fork_source_file??null,passive_default:e.passive_default===1,cycle_pending:e.cycle_pending===1,model_override:e.model_override??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),persona_ack:e.persona_ack_json==null?void 0:JSON.parse(e.persona_ack_json),review_binding:e.review_binding_json==null?void 0:JSON.parse(e.review_binding_json),launch:e.launch_config_json==null?void 0:JSON.parse(e.launch_config_json),pi_session_id:e.pi_session_id??null,pi_session_file:e.pi_session_file??null,...n===null?{}:{managed_worktree:n}}}i(J,"metaFrom");async function gn(e,n={}){return Ae(),await p(async t=>{await Be(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&await Te(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&await M(t,e.node_id,n.outcomeDelivery),await n.withinCreate?.(t,e)}),await je(e.node_id),await h(e.node_id)}i(gn,"createNode");async function h(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:await J(n)}i(h,"getNode");const ze=1440*60*1e3;function Y(e){return{requestKey:e.request_key,nodeId:e.node_id,state:e.state}}i(Y,"createRequestRecord");async function An(e){const n=await(await s()).prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return n===void 0?null:Y(n)}i(An,"findCreateRequest");async function kn(e){return await p(async n=>{const t=Date.now();await n.prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(t);const a=await n.prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return a!==void 0?Y(a):(await n.prepareUncached("INSERT INTO create_requests (request_key, node_id, expires_at, state) VALUES (?, NULL, ?, 'reserved')").run(e,t+ze),{requestKey:e,nodeId:null,state:"reserved"})})}i(kn,"reserveCreateRequest");async function xn(e=Date.now()){return Number((await(await s()).prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(e)).changes)}i(xn,"pruneExpiredCreateRequests");async function Un(e,n){await(await s()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'complete' WHERE request_key = ?").run(n,e)}i(Un,"recordCreateRequestNode");async function jn(e,n){await(await s()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'reserved' WHERE request_key = ?").run(n,e)}i(jn,"reserveCreateRequestNode");async function In(e,n){await(await s()).prepareUncached("UPDATE create_requests SET state = 'complete' WHERE request_key = ? AND node_id = ?").run(e,n)}i(In,"completeCreateRequest");async function Wn(e,n){await p(async t=>{if(n===null){await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id IS NULL").run(e);return}await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id = ?").run(e,n)})}i(Wn,"abandonCreateRequest");function bn(e){return _e(e)}i(bn,"canonicalSessionFile");async function Fn(e){const n=await Se(e);return n===null?null:await h(n)}i(Fn,"findNodeBySessionFile");async function Cn(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?f(n):null}i(Cn,"getRow");async function Hn(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE pane = ?").get(e);return n?f(n):null}i(Hn,"getRowByPane");async function Mn(e){return(await(await s()).prepare(`SELECT * FROM node_rows
|
|
2
2
|
WHERE deadline_at IS NOT NULL AND outcome_at IS NULL
|
|
3
3
|
AND deadline_at <= ? AND status IN ('active','idle') AND kind != 'human'
|
|
4
4
|
ORDER BY deadline_at, created, node_id`).all(e)).map(f)}i(Mn,"dueNodeDeadlines");async function Pn(e,n){return Number((await(await s()).prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e)).changes)===1}i(Pn,"setNodeDeadline");async function $n(e,n){return!Number.isFinite(n)||n<=0?0:await p(async t=>{const a=await t.prepare(`SELECT node_id, deadline_at FROM nodes
|
|
5
|
-
WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),o=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let r=0;for(const d of a){const l=Date.parse(d.deadline_at);Number.isNaN(l)||(r+=Number((await o.run(new Date(l+n).toISOString(),d.node_id,d.deadline_at)).changes))}return r})}i($n,"shiftProfileNodeDeadlines");function v(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}i(v,"sqlInput");async function qn(e,n){const t=[],a=i((r,d=r)=>{Object.prototype.hasOwnProperty.call(n,r)&&t.push([d,v(n[r],r)])},"add");if(a("description"),a("title"),a("icon"),a("cycles"),a("mode"),a("lifecycle"),a("cwd"),a("host_kind"),a("profile_id"),a("parent"),a("spawned_by"),a("creator"),a("fork_from"),a("fork_source_file"),a("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",E(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",E(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"isolated"))throw new TypeError("isolated cannot change after node creation");Object.prototype.hasOwnProperty.call(n,"scopes")&&t.push(["scopes_json",E(n.scopes,"scopes")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",E(n.launch,"launch")]);const o=i(r=>Object.prototype.hasOwnProperty.call(n,r),"has");return await p(async r=>{const d=await L(r,e);if(d===null||d.type!=="node")throw new Error(`unknown node: ${e}`);if(o("name")&&await Ce(r,d,v(n.name,"name")),o("kind")&&await
|
|
5
|
+
WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),o=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let r=0;for(const d of a){const l=Date.parse(d.deadline_at);Number.isNaN(l)||(r+=Number((await o.run(new Date(l+n).toISOString(),d.node_id,d.deadline_at)).changes))}return r})}i($n,"shiftProfileNodeDeadlines");function v(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}i(v,"sqlInput");async function qn(e,n){const t=[],a=i((r,d=r)=>{Object.prototype.hasOwnProperty.call(n,r)&&t.push([d,v(n[r],r)])},"add");if(a("description"),a("title"),a("icon"),a("cycles"),a("mode"),a("lifecycle"),a("cwd"),a("host_kind"),a("profile_id"),a("parent"),a("spawned_by"),a("creator"),a("fork_from"),a("fork_source_file"),a("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",E(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",E(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"isolated"))throw new TypeError("isolated cannot change after node creation");Object.prototype.hasOwnProperty.call(n,"scopes")&&t.push(["scopes_json",E(n.scopes,"scopes")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",E(n.launch,"launch")]);const o=i(r=>Object.prototype.hasOwnProperty.call(n,r),"has");return await p(async r=>{const d=await L(r,e);if(d===null||d.type!=="node")throw new Error(`unknown node: ${e}`);if(o("name")&&await Ce(r,d,v(n.name,"name")),o("kind")&&await Fe(r,d,v(n.kind,"kind")),t.length===0)return;if(o("profile_id")){const u=await r.prepare("SELECT app FROM nodes WHERE node_id = ?").get(e),_=u?.app?await L(r,u.app):null;if(_){const w=n.profile_id?await B(r,n.profile_id,_):null;await r.prepare("UPDATE objects SET owner = ? WHERE id = ?").run((w??_).id,e);const R=(await r.prepare("SELECT sub FROM nodes WHERE node_id = ?").get(e)).sub;w===null&&R&&await q(r,e,R)}}if((await r.prepareUncached(`UPDATE nodes SET ${t.map(([u])=>`${u} = ?`).join(", ")} WHERE node_id = ?`).run(...t.map(([,u])=>u),e)).changes!==1)throw new Error(`unknown node: ${e}`)}),await h(e)}i(qn,"updateNode");async function Bn(e,n){await(await s()).prepare("UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}i(Bn,"setStatus");async function zn(e,n){await(await s()).prepare("UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}i(zn,"setIntent");async function Jn(e,n,t={}){if(t.outcome===void 0){const o=[],r=[];Object.prototype.hasOwnProperty.call(n,"status")&&(o.push("status = ?"),r.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(o.push("intent = ?"),r.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(o.push("terminal_reason = ?"),r.push(n.terminal_reason??null));const d=["node_id = ?"];r.push(e),t.fromStatuses!==void 0&&(d.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),r.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&d.push("final_report IS NULL");const l=await(await s()).prepareUncached(`UPDATE nodes SET ${o.join(", ")} WHERE ${d.join(" AND ")}`).run(...r);return Number(l.changes)}const a=t.outcome;return await p(async o=>{const r=[],d=[];Object.prototype.hasOwnProperty.call(n,"status")&&(r.push("status = ?"),d.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(r.push("intent = ?"),d.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(r.push("terminal_reason = ?"),d.push(n.terminal_reason??null));const l=i((R,y)=>a.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${y} END`,"outcomeValue");r.push(`outcome_kind = ${l(a.kind,"outcome_kind")}`,`outcome_reason = ${l(a.reason,"outcome_reason")}`,`outcome_detail_json = ${l(a.detailJson,"outcome_detail_json")}`,`outcome_revision = ${a.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${l(a.at,"outcome_at")}`),d.push(a.kind,a.reason,a.detailJson,a.at);const u=["node_id = ?"];d.push(e),t.fromStatuses!==void 0&&(u.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),d.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&u.push("final_report IS NULL");const _=await o.prepareUncached(`UPDATE nodes SET ${r.join(", ")} WHERE ${u.join(" AND ")}`).run(...d);if(Number(_.changes)===0)return 0;const w=await o.prepare("SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(a.supersede===!0||w.outcome_at===a.at)&&a.documentJson!==null&&a.documentJson!==void 0&&await Ne(o,{event:"outcome",object:await Re(o,e),actor:null,attrs:{revision:Number((await o.prepare("SELECT outcome_revision FROM nodes WHERE node_id = ?").get(e)).outcome_revision)},messageBody:JSON.parse(a.documentJson)}),Number(_.changes)})}i(Jn,"transitionStatusIntent");async function Yn(e){return(await(await s()).prepare("SELECT final_report FROM nodes WHERE node_id = ?").get(e))?.final_report??null}i(Yn,"getFinalReport");async function Qn(e,n){return(await(await s()).prepare("UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n)).changes>0}i(Qn,"clearFinalReportIfMatches");async function Vn(e,n){await(await s()).prepare('UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}i(Vn,"setPresence");async function Kn(e,n){await(await s()).prepare("UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}i(Kn,"recordLaunch");async function Gn(e,n){await(await s()).prepare("UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}i(Gn,"recordSettledTurn");async function Xn(e,n){await(await s()).prepare("UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}i(Xn,"setFrozen");async function Zn(e){await(await s()).prepare("UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}i(Zn,"clearFrozen");async function et(e,n){await(await s()).prepare("UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}i(et,"recordRespawnAttempt");const N="node_id NOT IN (SELECT node_id FROM warm_pool)",Q=["state","cleanup_state","path","branch","repo_root","base_ref","base_sha","created_at","closed_at","next_attempt_at","attempts","quarantined","sweep_reason","sweep_detail","sweep_last_at","sweep_observed_json","abandoned_json","land_intent_json","disposal_json"];function Je(e){return e.worktree_state===null?null:De(Object.fromEntries(Q.map(n=>[n,e[`worktree_${n}`]])))}i(Je,"worktreeFromProjection");async function nt(e){const n=Q.map(a=>`w.${a} AS worktree_${a}`).join(", "),t=await(await s()).prepareUncached(`SELECT n.*, ${n} FROM node_rows n LEFT JOIN worktrees w ON w.node_id = n.node_id WHERE n.profile_id = ? ORDER BY n.created`).all(e);return await D(t,async a=>await J(a,Je(a)))}i(nt,"listNodesByProfile");async function tt(){return(await(await s()).prepare(`SELECT
|
|
6
6
|
node_id, name, description, kind, mode, lifecycle, status, cwd, profile_id,
|
|
7
7
|
grantee, parent, created, frozen_at, terminal_reason, final_report,
|
|
8
8
|
telemetry_tokens_in, telemetry_updated_at, pi_pid, turn_open_at, turn_closed_at,
|
|
@@ -56,7 +56,7 @@ var ie=Object.defineProperty;var i=(e,n)=>ie(e,"name",{value:n,configurable:!0})
|
|
|
56
56
|
AND status IN ('active','idle') AND cwd = ?
|
|
57
57
|
AND ${N}
|
|
58
58
|
ORDER BY created DESC`).all(e)).map(f)}i(yt,"listResumableRoots");export*from"./tree.js";async function mt(e,n,t){return await p(async a=>{const o=await a.prepare("SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return o===void 0?{kind:"missing"}:n(o)?{kind:"terminal",status:o.status,final_report:o.final_report}:{kind:"ran",result:await t()}})}i(mt,"withFreshTerminalGuard");async function O(e){return await Oe(e)}i(O,"hasUnreconciledManagedWorktree");async function G(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||await O(e.node_id)||e.node_id===W()||H(e)?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}i(G,"isCollectible");async function A(e){if(e.length===0)return[];const n=e.map(()=>"?").join(","),t=await(await s()).prepareUncached(`SELECT s.session_id, s.transcript_path, s.node_id, n.grantee FROM sessions s JOIN node_rows n ON n.node_id = s.node_id WHERE s.node_id IN (${n}) AND s.session_id IS NOT NULL AND s.transcript_path IS NOT NULL ORDER BY s.created_at, s.seq`).all(...e);return[...new Map(t.map(a=>[a.session_id,{id:a.session_id,path:a.transcript_path,dir:S(T(a.grantee).conversations,a.node_id)}])).values()]}i(A,"nodeConversationIds");async function k(e){const n=await s(),t=n.prepare("SELECT 1 FROM sessions WHERE session_id = ? LIMIT 1"),a=n.prepare(`SELECT 1 FROM nodes n WHERE n.fork_source_file LIKE '%\\_' || ? || '.jsonl' ESCAPE '\\'
|
|
59
|
-
AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const{id:o,path:r,dir:d}of e)if(!(await t.get(o)!==void 0||await a.get(o)!==void 0)&&oe(r,{throwIfNoEntry:!1})!==void 0){if(!Ge(d,r)){console.error(`[canvas] not deleting transcript outside its node's conversations directory: ${r}`);continue}try{await Ee().delete(o,r)}catch(l){if(!(l instanceof we))throw l}}}i(k,"deleteNodeConversations");function Ge(e,n){try{const t=ce(
|
|
59
|
+
AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const{id:o,path:r,dir:d}of e)if(!(await t.get(o)!==void 0||await a.get(o)!==void 0)&&oe(r,{throwIfNoEntry:!1})!==void 0){if(!Ge(d,r)){console.error(`[canvas] not deleting transcript outside its node's conversations directory: ${r}`);continue}try{await Ee().delete(o,r)}catch(l){if(!(l instanceof we))throw l}}}i(k,"deleteNodeConversations");function Ge(e,n){try{const t=ce(b(e),S(b(F(n)),ue(n)));return t!==""&&t!==".."&&!t.startsWith(`..${pe}`)&&!le(t)}catch(t){if(t.code==="ENOENT")return!1;throw t}}i(Ge,"isBeneath");async function x(e,n){const t=await L(e,n);return t===null||t.deleted_at!==null?!1:(await Pe(e,t),!0)}i(x,"deleteNodeObject");async function U(e){return{nodeId:e,app:await h(e)===null?null:await Ue(e)}}i(U,"nodeFiles");async function X({nodeId:e,app:n}){n!==null&&C(T(n).nodes,await Ie(e,n)),C(F($(e)),$(e))}i(X,"removeNodeAppTrees");function Z({nodeId:e}){return[xe(e)]}i(Z,"nodeOwnedDirs");function ee({nodeId:e,app:n}){if(n!==null)try{re(S(T(n).conversations,e))}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}i(ee,"removeNodeConversationDir");async function j(e){await X(e);for(const n of Z(e))se(n,{recursive:!0,force:!0});ee(e)}i(j,"removeNodeFiles");async function Nt(e){if(await O(e))return{deleted:!1};const n=await U(e),t=await A([e]),a=await p(async o=>(await x(o,e),{deleted:!0}));return await k(t),await j(n),a}i(Nt,"deleteNode");async function Rt(e){const n=[...new Set(e)];if(n.length===0)return[];const t=await m(n,O);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const a=await D(n,U),o=await A(n),r=n.map(()=>"?").join(","),d=(await(await s()).prepareUncached(`SELECT node_id FROM nodes WHERE node_id IN (${r}) ORDER BY created`).all(...n)).map(({node_id:u})=>u),l=await m(d,async u=>await p(async _=>await x(_,u)));await k(o);for(const u of l){const _=a[n.indexOf(u)];await I(_,async()=>await j(_))}return l}i(Rt,"deleteNodes");async function St(e){const n=e.dryRun??!1,t=e.includeStale??!1,a=Date.now()-e.ttlDays*864e5,o=new Date(a).toISOString(),r=W()??"",d=await s(),l=i(c=>ae(c)<a,"quiet"),u=i(c=>({node_id:c.node_id,status:c.status,created:c.created}),"toPruned"),_=await Xe(),w=(await m((await d.prepare(`SELECT * FROM node_rows
|
|
60
60
|
WHERE status IN ('dead', 'done', 'canceled') AND created < ?
|
|
61
61
|
ORDER BY created`).all(o)).map(f),async c=>await G(c,{pastTtl:!0})&&l(c)&&!_.has(c.node_id)&&!await e.held(c.node_id))).map(u),R=t?(await m((await d.prepare(`SELECT * FROM node_rows
|
|
62
62
|
WHERE status IN ('active', 'idle') AND created < ?
|
|
@@ -64,4 +64,4 @@ var ie=Object.defineProperty;var i=(e,n)=>ie(e,"name",{value:n,configurable:!0})
|
|
|
64
64
|
JOIN objects d ON d.id = w.object AND d.type = 'document' AND d.deleted_at IS NULL
|
|
65
65
|
JOIN objects o ON o.id = w.watcher AND o.deleted_at IS NULL
|
|
66
66
|
LEFT JOIN nodes n ON n.node_id = w.watcher
|
|
67
|
-
WHERE w.watcher != d.owner AND d.owner IS NOT NULL AND (n.node_id IS NULL OR n.status IN ('active', 'idle'))`).all();return new Set(e.map(n=>n.owner))}i(Xe,"ownersOfWatchedDocuments");async function ne(e){const t=(await s()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ?"),a=new Set(e.map(o=>o.node_id));return await m(e,async o=>(await t.all(o.node_id,o.node_id)).every(r=>a.has(r.node_id)))}i(ne,"retainRunRootsWithMembers");async function te(e,n){if(e.length===0)return;const t=await D(e,async o=>await U(o.node_id)),a=await A(e.map(o=>o.node_id));for(const o of e)await p(async r=>await x(r,o.node_id));if(await k(a),n!==void 0){for(const o of t)await I(o,async()=>{await X(o),ee(o)});n(t.flatMap(Z));return}for(const o of t)await I(o,async()=>await j(o))}i(te,"deletePrunedNodes");async function I(e,n){try{n()}catch(t){fe({level:"error",event:"canvas.node_files.remove_failed",error:t,fields:{node_id:e.nodeId}})}}i(I,"eachNodeBestEffort");function ae(e){let n=0;for(const t of[e.created,e.launched_at,e.last_settled_at,e.finalized_at,e.outcome_at,e.last_activity_at]){if(t==null)continue;const a=Date.parse(t);Number.isFinite(a)&&a>n&&(n=a)}try{const t=de(S(ke(e.node_id),"telemetry.json"),{throwIfNoEntry:!1});t!==void 0&&t.mtimeMs>n&&(n=t.mtimeMs)}catch{}return n}i(ae,"lastActivityMs");async function ht(e){const n=e.dryRun??!1,t=await Ye(),a=await m(t,async u=>await G(u)&&!await e.held(u.node_id)),o=t.length-a.length,r=Math.max(0,e.maxNodes-o),d=a.map(u=>({row:u,recency:ae(u)})).sort((u,_)=>_.recency-u.recency).slice(r).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created})),l=await ne(d);return n||l.length===0?{pruned:l,dryRun:n}:(await te(l),{pruned:l,dryRun:n})}i(ht,"pruneToLimit");export{V as PARKED_RESIDENT_SQL,Ke as RESUMABLE_NODE_SQL,Wn as abandonCreateRequest,vn as assertRunNotDeleting,tt as browseNodes,
|
|
67
|
+
WHERE w.watcher != d.owner AND d.owner IS NOT NULL AND (n.node_id IS NULL OR n.status IN ('active', 'idle'))`).all();return new Set(e.map(n=>n.owner))}i(Xe,"ownersOfWatchedDocuments");async function ne(e){const t=(await s()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ?"),a=new Set(e.map(o=>o.node_id));return await m(e,async o=>(await t.all(o.node_id,o.node_id)).every(r=>a.has(r.node_id)))}i(ne,"retainRunRootsWithMembers");async function te(e,n){if(e.length===0)return;const t=await D(e,async o=>await U(o.node_id)),a=await A(e.map(o=>o.node_id));for(const o of e)await p(async r=>await x(r,o.node_id));if(await k(a),n!==void 0){for(const o of t)await I(o,async()=>{await X(o),ee(o)});n(t.flatMap(Z));return}for(const o of t)await I(o,async()=>await j(o))}i(te,"deletePrunedNodes");async function I(e,n){try{n()}catch(t){fe({level:"error",event:"canvas.node_files.remove_failed",error:t,fields:{node_id:e.nodeId}})}}i(I,"eachNodeBestEffort");function ae(e){let n=0;for(const t of[e.created,e.launched_at,e.last_settled_at,e.finalized_at,e.outcome_at,e.last_activity_at]){if(t==null)continue;const a=Date.parse(t);Number.isFinite(a)&&a>n&&(n=a)}try{const t=de(S(ke(e.node_id),"telemetry.json"),{throwIfNoEntry:!1});t!==void 0&&t.mtimeMs>n&&(n=t.mtimeMs)}catch{}return n}i(ae,"lastActivityMs");async function ht(e){const n=e.dryRun??!1,t=await Ye(),a=await m(t,async u=>await G(u)&&!await e.held(u.node_id)),o=t.length-a.length,r=Math.max(0,e.maxNodes-o),d=a.map(u=>({row:u,recency:ae(u)})).sort((u,_)=>_.recency-u.recency).slice(r).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created})),l=await ne(d);return n||l.length===0?{pruned:l,dryRun:n}:(await te(l),{pruned:l,dryRun:n})}i(ht,"pruneToLimit");export{V as PARKED_RESIDENT_SQL,Ke as RESUMABLE_NODE_SQL,Wn as abandonCreateRequest,vn as assertRunNotDeleting,tt as browseNodes,bn as canonicalSessionFile,Et as childrenOf,pt as claimWarmSpare,Qn as clearFinalReportIfMatches,Zn as clearFrozen,In as completeCreateRequest,gn as createNode,Nt as deleteNode,Rt as deleteNodes,Mn as dueNodeDeadlines,An as findCreateRequest,Fn as findNodeBySessionFile,Yn as getFinalReport,h as getNode,Cn as getRow,Hn as getRowByPane,it as graphNodes,G as isCollectible,_t as isWarmSpare,ae as lastActivityMs,Ye as listNodes,nt as listNodesByProfile,rt as listNodesForSupervision,dt as listParkedResidentsWithWakeMail,yt as listResumableRoots,ot as listTerminalPlacementResidue,ct as listWarmSpares,U as nodeFiles,Ve as nodesForSupervisionSql,xn as pruneExpiredCreateRequests,St as pruneNodes,ht as pruneToLimit,Un as recordCreateRequestNode,Kn as recordLaunch,et as recordRespawnAttempt,Gn as recordSettledTurn,ut as registerWarmSpare,j as removeNodeFiles,kn as reserveCreateRequest,jn as reserveCreateRequestNode,st as resumableNodeCwds,wt as rosterNodes,Xn as setFrozen,zn as setIntent,Pn as setNodeDeadline,Vn as setPresence,Bn as setStatus,$n as shiftProfileNodeDeadlines,Qe as terminalPlacementResidueSql,Jn as transitionStatusIntent,lt as unregisterWarmSpare,qn as updateNode,at as updateNodeTelemetry,ft as warmSpareCount,mt as withFreshTerminalGuard};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var V=Object.defineProperty;var
|
|
1
|
+
var V=Object.defineProperty;var l=(i,a)=>V(i,"name",{value:a,configurable:!0});import{DatabaseSync as W}from"node:sqlite";import{existsSync as Y,mkdirSync as k,mkdtempSync as J,renameSync as X,rmSync as P}from"node:fs";import{tmpdir as Q}from"node:os";import{join as A}from"node:path";import j from"pg";import{migrate as z,MIGRATIONS as I}from"./migrations.js";import{canvasDbPath as Z}from"./paths.js";import{EXPORT_MARK_KEY as F,IMPORT_MARK_KEY as ee,OBJECT_COLUMNS as te,pgColumns as ne,quote as c,TABLE_ORDER as C}from"./import-sqlite.js";const re=5e3,se=new Set(["environments","relations","schemas","charges","charge_totals","limits"]),oe={exposures:"node, object, channel",rules:"object, position",edges:"type, src, dst",unresolved_links:"src, name",revision_parents:"child, parent",canvas_meta:"key",runtime_state:"key",message_causes:"message_id",peer_ingested:"key",peer_ingested_destinations:"key",message_sequence:"id",messages:"seq",review_comment_events:"seq",audit_rows:"id",peer_outbox:"id",app_users:"uid"},ae={objects:"id",revisions:"rev_id",watches:"watch_id"},H=new Set(["daemon_owner","schema_version","ledger_migrated",ee,F]);function ie(i){const a=J(A(Q(),"crtr-export-")),r=process.env.CRTR_HOME;process.env.CRTR_HOME=a,k(A(a,"runtime","nodes"),{recursive:!0});try{const s=new W(i);return s.exec("PRAGMA journal_mode = DELETE;"),s.exec("PRAGMA foreign_keys = ON;"),z(s),s.exec("DELETE FROM canvas_meta; DELETE FROM message_sequence;"),s}finally{r===void 0?delete process.env.CRTR_HOME:process.env.CRTR_HOME=r,P(a,{recursive:!0,force:!0})}}l(ie,"createEmptyDatabase");async function _e(i,a=()=>{}){const r=Z();if(Y(r))throw new Error(`${r} already exists; refusing to overwrite it`);k(A(r,".."),{recursive:!0,mode:448});const s=`${r}.exporting-${process.pid}`,m=Date.now(),t=new j.Client({connectionString:i,application_name:`crtr-export-${process.pid}`,types:{getTypeParser:l(((f,o)=>f===20?d=>Number(d):j.types.getTypeParser(f,o)),"getTypeParser")}});await t.connect();let u;try{if((await t.query("SELECT value FROM canvas_meta WHERE key = 'schema_version'").catch(()=>({rows:[]}))).rows.length===0)throw new Error("the Postgres database has no canvas schema; nothing to export");u=ie(s);const o=u;o.exec("PRAGMA foreign_keys = OFF;");const d=await ne(t),L=[...d.keys()].filter(e=>!se.has(e)&&!C.includes(e));if(L.length>0)throw new Error(`export: Postgres tables with no export rule: ${L.join(", ")}`);await t.query("BEGIN READ ONLY ISOLATION LEVEL REPEATABLE READ");const h={};for(const[e,O]of Object.entries(ae)){const _=new Map;for(const E of(await t.query(`SELECT ${O} AS id, seq FROM ${e}`)).rows)_.set(E.id,Number(E.seq));h[e]=_}const B=h.objects;let M=0;o.exec("BEGIN");for(const e of C){const O=Date.now(),_=new Set(o.prepare(`PRAGMA table_info(${c(e)})`).all().map(n=>n.name)),E=d.get(e);if(E===void 0)throw new Error(`export: Postgres has no table ${e}`);const G=E.some(n=>n.name==="seq"),$=E.filter(n=>_.has(n.name)),K=new Set(te[e]??[]),R=e==="objects"||e==="revisions"||e==="watches"||e==="watch_subscriptions",v=$.map(n=>n.type==="jsonb"?`${c(n.name)}::text AS ${c(n.name)}`:c(n.name));e==="watches"&&v.push("watch_id AS _watch_id"),R&&v.push("seq AS _seq");const g=$.map(n=>c(n.name)),U=o.prepare(`INSERT INTO ${c(e)} (${R?["rowid",...g]:g}) VALUES (${(R?["?",...g]:g).map(()=>"?").join(", ")})`),q=G?"seq":oe[e],T=`export_${e}`;await t.query(`DECLARE ${T} NO SCROLL CURSOR FOR SELECT ${v.join(", ")} FROM ${c(e)}${e==="canvas_meta"?` WHERE key NOT IN (${[...H].map(n=>`'${n}'`).join(", ")})`:""}${q===void 0?"":` ORDER BY ${q}`}`);let b=0;for(;;){const n=await t.query(`FETCH ${re} FROM ${T}`);if(n.rows.length===0)break;for(const N of n.rows){const D=R?[Number(N._seq)]:[];for(const p of $){let w=N[p.name];e==="revision_parents"&&(p.name==="child"||p.name==="parent")?w=x(h.revisions,"revision",e,p.name,w):e==="watch_subscriptions"&&p.name==="watch"?w=x(h.watches,"watch",e,p.name,w):K.has(p.name)&&(w=x(B,"object",e,p.name,w)),D.push(w??null)}U.run(...D)}b+=n.rows.length}await t.query(`CLOSE ${T}`),M+=b,a(`export ${e}: ${b} rows in ${Date.now()-O} ms`)}o.exec("COMMIT"),await t.query("COMMIT");const y=o.prepare("PRAGMA foreign_key_check").all();if(y.length>0)throw new Error(`export: ${y.length} foreign key violation(s) in the exported canvas.db, first: ${JSON.stringify(y[0])}`);await ce(t,o);const S=o.prepare("PRAGMA user_version").get().user_version;if(S!==I.length)throw new Error(`export: exported canvas.db is at user_version ${S}, expected ${I.length}`);return o.close(),u=void 0,await t.query("INSERT INTO canvas_meta (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value",[F,JSON.stringify({at:new Date().toISOString(),path:r})]),X(s,r),{path:r,rows:M,ms:Date.now()-m,userVersion:S}}catch(f){await t.query("ROLLBACK").catch(()=>{});try{u?.close()}catch{}for(const o of["","-wal","-shm","-journal"])P(`${s}${o}`,{force:!0});throw f}finally{await t.end().catch(()=>{})}}l(_e,"exportPostgresToSqlite");function x(i,a,r,s,m){if(m==null)return null;const t=i.get(m);if(t===void 0)throw new Error(`export: ${r}.${s} references ${a} ${String(m)}, which was not exported (`);return t}l(x,"mapId");async function ce(i,a){const r=[];for(const s of C){const m=Number((await i.query(`SELECT count(*) AS n FROM ${c(s)}`)).rows[0].n);let t=Number(a.prepare(`SELECT count(*) AS n FROM ${c(s)}`).get().n),u=m;s==="canvas_meta"&&(u=Number((await i.query("SELECT count(*) AS n FROM canvas_meta WHERE key <> ALL($1)",[[...H]])).rows[0].n),t=Number(a.prepare("SELECT count(*) AS n FROM canvas_meta").get().n)),u!==t&&r.push(`${s}: Postgres ${u} rows, SQLite ${t}`)}if(r.length>0)throw new Error(`Postgres \u2192 SQLite export verification failed:
|
|
2
2
|
${r.join(`
|
|
3
|
-
`)}`)}
|
|
3
|
+
`)}`)}l(ce,"verify");export{_e as exportPostgresToSqlite};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var Q=Object.defineProperty;var m=(t,o)=>Q(t,"name",{value:o,configurable:!0});import{DatabaseSync as X}from"node:sqlite";import{createHash as z,randomBytes as Z}from"node:crypto";import{existsSync as O,mkdirSync as ee,renameSync as F}from"node:fs";import{dirname as te}from"node:path";import oe from"pg";import{withExclusiveDirectoryLockAsync as se}from"../exclusive-lock.js";import{DAEMON_STARTUP_WINDOW_MS as re}from"../../daemon/startup-policy.js";import{migrate as ne}from"./migrations.js";import{readLegacyPrivacy as ae}from"../graph/types.js";import{canvasDbPath as B,onDiskMigrationLockPath as ie}from"./paths.js";const q="imported_from_sqlite",U="exported_to_sqlite",M=1e4,L=["objects","documents","revisions","revision_parents","jobs","identities","custom_objects","context_sessions","peer_stubs","object_kinds","watches","watch_subscriptions","exposures","rules","edges","unresolved_links","nodes","focuses","canvas_meta","runtime_state","warm_pool","sessions","executions","worktrees","node_faults","node_tokens","node_outcome_deliveries","deleted_isolated_nodes","create_requests","waits","messages","message_sequence","message_causes","deliveries","structured_requests","daemon_actions","human_requests","human_action_deliveries","review_comments","review_comment_events","run_events","idempotency_keys","grants","memory_reads","app_users","uploads","upload_uses","shares","audit_rows","grantee_usage","provider_receipts","provider_approvals","usage","crons","cron_runs","peer_outbox","peer_locations","peer_ingested","peer_ingested_destinations"],ce=new Set(["sqlite_sequence","sqlite_stat1","sqlite_stat4","reviews"]),ue={objects:["owner"],documents:["object"],revisions:["document","author"],jobs:["object"],identities:["object"],custom_objects:["object"],context_sessions:["node"],peer_stubs:["object"],object_kinds:["owner"],watches:["watcher","object","link_app"],exposures:["node","object"],rules:["object","owner"],edges:["src","dst"],unresolved_links:["src"]},pe={objects:["schema_type"],nodes:["app"],revisions:["acting_app","acting_for"]},W=new Set(["daemon_owner","schema_version"]),de={canvas_meta:"key",message_sequence:"id"};function H(){return Z(16).toString("hex")}m(H,"newId");function f(t){return`"${t.replace(/"/g,'""')}"`}m(f,"quote");function me(t){switch(t){case"bigint":return"bigint[]";case"double precision":return"float8[]";case"bytea":return"bytea[]";case"text":case"jsonb":return"text[]";default:throw new Error(`import: no array type for Postgres column type ${t}`)}}m(me,"arrayType");async function fe(t){const o=await t.query(`SELECT c.relname AS tbl, a.attname AS col, format_type(a.atttypid, a.atttypmod) AS type, a.attidentity <> '' AS identity
|
|
1
|
+
var Q=Object.defineProperty;var m=(t,o)=>Q(t,"name",{value:o,configurable:!0});import{DatabaseSync as X}from"node:sqlite";import{createHash as z,randomBytes as Z}from"node:crypto";import{existsSync as O,mkdirSync as ee,renameSync as F}from"node:fs";import{dirname as te}from"node:path";import oe from"pg";import{withExclusiveDirectoryLockAsync as se}from"../exclusive-lock.js";import{DAEMON_STARTUP_WINDOW_MS as re}from"../../daemon/startup-policy.js";import{migrate as ne}from"./migrations.js";import{readLegacyPrivacy as ae}from"../graph/types.js";import{canvasDbPath as B,onDiskMigrationLockPath as ie}from"./paths.js";const q="imported_from_sqlite",U="exported_to_sqlite",M=1e4,L=["objects","documents","revisions","revision_parents","jobs","identities","custom_objects","context_sessions","peer_stubs","object_kinds","watches","watch_subscriptions","exposures","rules","edges","unresolved_links","nodes","focuses","canvas_meta","runtime_state","warm_pool","sessions","executions","worktrees","node_faults","node_tokens","node_outcome_deliveries","deleted_isolated_nodes","create_requests","waits","messages","message_sequence","message_causes","deliveries","structured_requests","daemon_actions","human_requests","human_action_deliveries","review_comments","review_comment_events","run_events","idempotency_keys","grants","memory_reads","app_users","uploads","upload_uses","shares","audit_rows","grantee_usage","provider_receipts","provider_approvals","usage","crons","cron_runs","peer_outbox","peer_locations","peer_ingested","peer_ingested_destinations"],ce=new Set(["sqlite_sequence","sqlite_stat1","sqlite_stat4","reviews"]),ue={objects:["owner"],documents:["object"],revisions:["document","author"],jobs:["object"],identities:["object"],custom_objects:["object"],context_sessions:["node"],peer_stubs:["object"],object_kinds:["owner"],watches:["watcher","object","link_app"],exposures:["node","object"],rules:["object","owner"],edges:["src","dst"],unresolved_links:["src"]},pe={objects:["schema_type"],nodes:["app","caused_by"],revisions:["acting_app","acting_for"]},W=new Set(["daemon_owner","schema_version","ledger_migrated"]),de={canvas_meta:"key",message_sequence:"id"};function H(){return Z(16).toString("hex")}m(H,"newId");function f(t){return`"${t.replace(/"/g,'""')}"`}m(f,"quote");function me(t){switch(t){case"bigint":return"bigint[]";case"double precision":return"float8[]";case"bytea":return"bytea[]";case"text":case"jsonb":return"text[]";default:throw new Error(`import: no array type for Postgres column type ${t}`)}}m(me,"arrayType");async function fe(t){const o=await t.query(`SELECT c.relname AS tbl, a.attname AS col, format_type(a.atttypid, a.atttypmod) AS type, a.attidentity <> '' AS identity
|
|
2
2
|
FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid
|
|
3
3
|
WHERE c.relnamespace = current_schema()::regnamespace AND c.relkind = 'r' AND a.attnum > 0 AND NOT a.attisdropped
|
|
4
4
|
ORDER BY c.relname, a.attnum`),e=new Map;for(const a of o.rows){const r=e.get(a.tbl)??[];r.push({name:a.col,type:a.type,identity:a.identity}),e.set(a.tbl,r)}return e}m(fe,"pgColumns");const we="\uFFFD";function Ee(t){if(!t.includes("\\u0000"))return{text:t,replaced:0};let o;try{o=JSON.parse(t)}catch{return{text:t,replaced:0}}let e=0;const a=m(i=>{const u=i.split("\0");return e+=u.length-1,u.join(we)},"clean"),r=m(i=>typeof i=="string"?a(i):Array.isArray(i)?i.map(r):i!==null&&typeof i=="object"?Object.fromEntries(Object.entries(i).map(([u,l])=>[a(u),r(l)])):i,"walk"),E=r(o);return e===0?{text:t,replaced:e}:{text:JSON.stringify(E),replaced:e}}m(Ee,"scrubNul");async function le(t,o,e,a,r,E,i){for(let u=0;u<a.length;u++)for(const l of e){const n=r[E.indexOf(l)][u];if(n!=null){await t.query("SAVEPOINT import_probe");try{await t.query("SELECT $1::jsonb",[n]),await t.query("RELEASE SAVEPOINT import_probe")}catch(c){return await t.query("ROLLBACK TO SAVEPOINT import_probe"),new Error(`import: ${o}.${l.name} at ${i(a[u])} is not a value jsonb accepts: ${c.message}`,{cause:c})}}}}m(le,"describeJsonbFailure");function j(t,o,e,a,r){if(r==null)return null;const E=t.get(Number(r));if(E===void 0)throw new Error(`import: ${e}.${a} references ${o} rowid ${String(r)}, which does not exist`);return E}m(j,"lookup");async function ye(t,o,e,a,r,E){const i=a.filter(s=>!(pe[e]??[]).includes(s.name)),u=t.prepare(`PRAGMA table_info(${f(e)})`).all(),l=new Set(u.map(s=>s.name)),c=!t.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?").get(e).sql.toUpperCase().includes("WITHOUT ROWID"),_=new Set(ue[e]??[]),h=[];for(const s of i)if(s.name==="seq"&&!l.has("seq")){if(!c)throw new Error(`import: ${e} needs seq from rowid but has none`);h.push("rowid AS seq")}else if(s.name==="watch_id"||s.name==="subscription_id")h.push("NULL AS "+f(s.name));else if(l.has(s.name))h.push(f(s.name));else throw new Error(`import: SQLite table ${e} has no column ${s.name}`);c&&h.push("rowid AS _rowid");const S=e==="canvas_meta"?` WHERE key NOT IN (${[...W].map(s=>`'${s}'`).join(",")})`:"",y=t.prepare(`SELECT ${h.join(", ")} FROM ${f(e)}${S}${c?" ORDER BY rowid":""}`),$=i.map(s=>f(s.name)),g=i.map((s,p)=>`$${p+1}::${me(s.type)}`),T=i.map((s,p)=>`c${p}`),A=i.map((s,p)=>s.type==="jsonb"?`c${p}::jsonb`:`c${p}`);let v=`INSERT INTO ${f(e)} (${$.join(", ")}) SELECT ${A.join(", ")} FROM unnest(${g.join(", ")}) AS u(${T.join(", ")})`;const N=de[e];if(N!==void 0){const s=i.filter(p=>p.name!==N).map(p=>`${f(p.name)} = EXCLUDED.${f(p.name)}`);v+=` ON CONFLICT (${f(N)}) DO UPDATE SET ${s.join(", ")}`}const I=e==="objects",D=i.filter(s=>s.type==="jsonb"),k=c?"_rowid":i[0].name,V=m(s=>`${c?"rowid":k} ${String(s[k])}`,"key");let x=0,b=[];const P=m(async()=>{if(b.length===0)return;const s=i.map(()=>new Array(b.length));if(b.forEach((p,R)=>{i.forEach((d,J)=>{let w=p[d.name];if(e==="objects"&&d.name==="privacy"?w=ae(w):d.name==="watch_id"||d.name==="subscription_id"?w=H():e==="revision_parents"&&(d.name==="child"||d.name==="parent")?w=j(r.revisions,"revision",e,d.name,w):e==="watch_subscriptions"&&d.name==="watch"?w=j(r.watches,"watch",e,d.name,w):_.has(d.name)&&(w=I?null:j(r.objects,"object",e,d.name,w)),d.type==="bytea"&&w instanceof Uint8Array&&!Buffer.isBuffer(w)&&(w=Buffer.from(w.buffer,w.byteOffset,w.byteLength)),d.type==="jsonb"&&typeof w=="string"){const C=Ee(w);C.replaced>0&&(w=C.text,E.set(`${e}.${d.name}`,(E.get(`${e}.${d.name}`)??0)+C.replaced))}s[J][R]=w??null}),e==="watches"&&r.watches.set(Number(p._rowid),s[i.findIndex(d=>d.name==="watch_id")][R])}),D.length===0)await o.query(v,s);else{await o.query("SAVEPOINT import_batch");try{await o.query(v,s)}catch(p){throw await o.query("ROLLBACK TO SAVEPOINT import_batch"),await le(o,e,D,b,s,i,V)??p}await o.query("RELEASE SAVEPOINT import_batch")}x+=b.length,b=[]},"flush");for(const s of y.iterate())e==="objects"&&r.objects.set(Number(s._rowid),s.id),e==="revisions"&&r.revisions.set(Number(s._rowid),s.rev_id),b.push(s),b.length>=M&&await P();if(await P(),I){const s=t.prepare("SELECT id, owner FROM objects WHERE owner IS NOT NULL").all();for(let p=0;p<s.length;p+=M){const R=s.slice(p,p+M);await o.query("UPDATE objects o SET owner = v.owner FROM unnest($1::text[], $2::text[]) AS v(id, owner) WHERE o.id = v.id",[R.map(d=>d.id),R.map(d=>j(r.objects,"object","objects","owner",d.owner))])}}return x}m(ye,"copyTable");async function _e(t,o){for(const[e,a]of o)for(const r of a)r.identity&&await t.query(`SELECT setval(pg_get_serial_sequence($1, $2), COALESCE((SELECT max(${f(r.name)}) FROM ${f(e)}), 1), (SELECT max(${f(r.name)}) IS NOT NULL FROM ${f(e)}))`,[f(e),r.name])}m(_e,"advanceIdentities");function G(t,o,e=""){return Number(t.prepare(`SELECT count(*) AS n FROM ${f(o)}${e}`).get().n)}m(G,"sqliteCount");async function he(t,o,e){const a=[];for(const n of L){if(n==="canvas_meta")continue;const c=G(t,n),_=Number((await o.query(`SELECT count(*) AS n FROM ${f(n)}`)).rows[0].n);c!==_&&a.push(`${n}: SQLite ${c} rows, Postgres ${_}`)}for(const n of t.prepare(`SELECT key, value FROM canvas_meta WHERE key NOT IN (${[...W].map(c=>`'${c}'`).join(",")})`).all())(await o.query("SELECT value FROM canvas_meta WHERE key = $1",[n.key])).rows[0]?.value!==n.value&&a.push(`canvas_meta ${n.key}: value differs`);const r=m(n=>{const c=z("sha256");for(const _ of n)c.update(_).update(`
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
var
|
|
1
|
+
var U=Object.defineProperty;var i=(e,n)=>U(e,"name",{value:n,configurable:!0});import{randomBytes as L}from"node:crypto";import{CrtrError as T}from"../errors.js";import{readConfig as j}from"../config.js";import{joinedOwner as D}from"../directory/join.js";import{installLocalTerminalGrant as b}from"../grants/local.js";import{dropLocalGrantMirror as v}from"../grants/mirror.js";import{ownerForGrantee as H,ensureOwner as W}from"../graph/objects.js";import{canvasDatabaseUrl as $,CanvasConstraintError as k,withCanvasWrite as R}from"./db.js";import{LEGACY_LOCAL_PERSON as u,LEGACY_LOCAL_TERMINAL_GRANT as C}from"./legacy-person.js";import{rebuildTotalsFor as x}from"../ledger/totals.js";const E="person_id",h="local_person_retired",M=/^user:[A-Za-z0-9._-]+$/,I="abcdefghijklmnopqrstuvwxyz0123456789";class f extends Error{static{i(this,"PersonUnresolvedError")}code="person_unresolved";constructor(){super("the install's person is not resolved yet"),this.name="PersonUnresolvedError"}}let l;const S=new Map;function F(e){l=e}i(F,"setPersonId");function ie(){if(l===void 0)throw new f;return l}i(ie,"personId");async function ce(){if(l!==void 0)return l;const e=await $(),n=S.get(e);if(n!==void 0)return n;const r=await Y();if(r===null)throw new f;return S.set(e,r),r}i(ce,"personIdAsync");function G(){const e=L(12);let n="user:";for(let r=0;r<12;r++)n+=I[e[r]%I.length];return n}i(G,"mintPersonId");async function N(e,n){return(await e.prepare("SELECT value FROM canvas_meta WHERE key = ?").get(n))?.value??null}i(N,"readMeta");async function d(e,n,r){await e.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(n,r)}i(d,"writeMeta");async function J(){return await R(async e=>{const n=await N(e,E);if(n!==null)return{id:n,source:"stored"};const r=D();if(r!==null)return await d(e,E,r),{id:r,source:"joined"};if(j("user").runtime?.issuer){const a=await e.prepare("SELECT DISTINCT sub FROM grants").all();return a.length!==1?null:(await d(e,E,a[0].sub),{id:a[0].sub,source:"grants"})}const t=G();return await d(e,E,t),{id:t,source:"minted"}})}i(J,"resolvePerson");async function Y(){return(await J())?.id??null}i(Y,"resolvePersonId");const s=i(e=>Number(e.changes),"changes"),z=[["nodes","sub"],["node_tokens","sub"],["grants","sub"],["crons","sub"],["audit_rows","sub"],["provider_approvals","sub"],["audit_rows","grantee"],["run_events","grantee"],["node_tokens","grantee"],["uploads","grantee"],["provider_approvals","grantee"]],B=[["charges","sub"],["charges","payer"],["charges","grantee"],["limits","payer"],["limits","sub"],["limits","grantee"]];function O(e,n){if(!M.test(n))throw new T("invalid_person",`${e} must be a user:<id> principal, got ${JSON.stringify(n)}`)}i(O,"assertPerson");async function P(e,n,r){if(O("from",n),O("to",r),n===r)throw new T("invalid_person","cannot substitute a person with itself");const t={};try{t.identities=s(await e.prepare("UPDATE identities SET scheme = 'user', external_id = ? WHERE scheme IN ('local-user', 'user') AND external_id = ?").run(r,n))}catch(o){throw o instanceof k?new T("person_conflict",`another person object already holds ${r}; merging two person objects is not supported (${o.message})`,void 0,{from:n,to:r}):o}t["daemon_actions.principal_sub"]=s(await e.prepare(`UPDATE daemon_actions SET adapter_json = jsonb_set(adapter_json::jsonb, '{principal,sub}', to_jsonb(?::text))::text
|
|
2
2
|
WHERE state IN ('pending', 'handed_off') AND adapter_json::jsonb ->> 'adapter' = 'cron_spawn'
|
|
3
|
-
AND adapter_json::jsonb #>> '{principal,sub}' = ?`).run(
|
|
3
|
+
AND adapter_json::jsonb #>> '{principal,sub}' = ?`).run(r,n));for(const[o,c]of z)t[`${o}.${c}`]=s(await e.prepareUncached(`UPDATE ${o} SET ${c} = ? WHERE ${c} = ?`).run(r,n));t["idempotency_keys.grantee"]=s(await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key IN (SELECT key FROM idempotency_keys WHERE grantee = ?)").run(n,r))+s(await e.prepare("UPDATE idempotency_keys SET grantee = ? WHERE grantee = ?").run(r,n));const a=n.replace(/^user:/,""),p=r.replace(/^user:/,"");t["relations.subject_id"]=s(await e.prepare(`DELETE FROM relations r WHERE r.subject_type = 'user' AND r.subject_id = ?
|
|
4
4
|
AND EXISTS (SELECT 1 FROM relations n WHERE n.subject_type = 'user' AND n.subject_id = ? AND n.resource_type = r.resource_type
|
|
5
|
-
AND n.resource_id = r.resource_id AND n.relation = r.relation AND n.subject_relation = r.subject_relation)`).run(a,
|
|
6
|
-
|
|
7
|
-
ON CONFLICT(grantee, month) DO UPDATE SET usd_equivalent = grantee_usage.usd_equivalent + excluded.usd_equivalent`).run(t,n),r["grantee_usage.grantee"]=s(await e.prepare("DELETE FROM grantee_usage WHERE grantee = ?").run(n)),await e.prepare(`INSERT INTO usage (grantee, month, payer, source, served_model, input_tokens, output_tokens, cached_tokens, usd_equivalent)
|
|
8
|
-
SELECT ?::text, month, payer, source, served_model, input_tokens, output_tokens, cached_tokens, usd_equivalent FROM usage WHERE grantee = ?
|
|
9
|
-
ON CONFLICT(grantee, month, payer, source, served_model) DO UPDATE SET
|
|
10
|
-
input_tokens = usage.input_tokens + excluded.input_tokens,
|
|
11
|
-
output_tokens = usage.output_tokens + excluded.output_tokens,
|
|
12
|
-
cached_tokens = usage.cached_tokens + excluded.cached_tokens,
|
|
13
|
-
usd_equivalent = CASE WHEN usage.usd_equivalent IS NULL AND excluded.usd_equivalent IS NULL THEN NULL
|
|
14
|
-
ELSE COALESCE(usage.usd_equivalent, 0) + COALESCE(excluded.usd_equivalent, 0) END`).run(t,n),r["usage.grantee"]=s(await e.prepare("DELETE FROM usage WHERE grantee = ?").run(n)),r}o(L,"substitutePerson");async function Y(e){const n=`SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner JOIN nodes n ON n.node_id = o.id
|
|
15
|
-
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = '${p}'`;return(await e.prepareUncached(`${n} LIMIT 1`).get()!==void 0?s(await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${n})`).run((await H(e,"app:terminal")).id)):0)+s(await e.prepare("UPDATE node_tokens SET grantee = 'app:terminal' WHERE grantee = ?").run(p))+s(await e.prepare("UPDATE run_events SET grantee = 'app:terminal' WHERE grantee = ?").run(p))+s(await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key IN (SELECT key FROM idempotency_keys WHERE grantee = 'app:terminal')").run(p))+s(await e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = ?").run(p))}o(Y,"rewriteLegacyGrantees");async function z(e,n,t){const r=[b,`terminal:${n}`].filter(c=>c!==t),a=r.map(()=>"?").join(", "),u={};u["nodes.grant_id"]=s(await e.prepareUncached(`UPDATE nodes SET grant_id = ? WHERE grant_id IN (${a})`).run(t,...r)),u["node_tokens.grant"]=s(await e.prepareUncached(`UPDATE node_tokens SET "grant" = ? WHERE "grant" IN (${a})`).run(t,...r)),u["crons.grant_id"]=s(await e.prepareUncached(`UPDATE crons SET grant_id = ? WHERE grant_id IN (${a})`).run(t,...r));const i=t===null?"'null'::jsonb":"to_jsonb(?::text)";return u["daemon_actions.principal_grant_id"]=s(await e.prepareUncached(`UPDATE daemon_actions SET adapter_json = jsonb_set(adapter_json::jsonb, '{principal,grant_id}', ${i})::text
|
|
5
|
+
AND n.resource_id = r.resource_id AND n.relation = r.relation AND n.subject_relation = r.subject_relation)`).run(a,p))+s(await e.prepare("UPDATE relations SET subject_id = ? WHERE subject_type = 'user' AND subject_id = ?").run(p,a)),t["relations.written_by"]=s(await e.prepare("UPDATE relations SET written_by = ? WHERE written_by = ?").run(r,n)),t["revisions.acting_for"]=s(await e.prepare("UPDATE revisions SET acting_for = ? WHERE acting_for = ?").run(r,n));for(const[o,c]of B)t[`${o}.${c}`]=s(await e.prepareUncached(`UPDATE ${o} SET ${c} = ? WHERE ${c} = ?`).run(r,n));return Object.entries(t).some(([o,c])=>o.startsWith("charges.")&&c!==0)&&(await x(e,n,r),t["charge_totals.rebuilt"]=1),t}i(P,"substitutePerson");async function K(e){const n=`SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner JOIN nodes n ON n.node_id = o.id
|
|
6
|
+
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = '${u}'`;return(await e.prepareUncached(`${n} LIMIT 1`).get()!==void 0?s(await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${n})`).run((await H(e,"app:terminal")).id)):0)+s(await e.prepare("UPDATE node_tokens SET grantee = 'app:terminal' WHERE grantee = ?").run(u))+s(await e.prepare("UPDATE run_events SET grantee = 'app:terminal' WHERE grantee = ?").run(u))+s(await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key IN (SELECT key FROM idempotency_keys WHERE grantee = 'app:terminal')").run(u))+s(await e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = ?").run(u))}i(K,"rewriteLegacyGrantees");async function q(e,n,r){const t=[C,`terminal:${n}`].filter(c=>c!==r),a=t.map(()=>"?").join(", "),p={};p["nodes.grant_id"]=s(await e.prepareUncached(`UPDATE nodes SET grant_id = ? WHERE grant_id IN (${a})`).run(r,...t)),p["node_tokens.grant"]=s(await e.prepareUncached(`UPDATE node_tokens SET "grant" = ? WHERE "grant" IN (${a})`).run(r,...t)),p["crons.grant_id"]=s(await e.prepareUncached(`UPDATE crons SET grant_id = ? WHERE grant_id IN (${a})`).run(r,...t));const o=r===null?"'null'::jsonb":"to_jsonb(?::text)";return p["daemon_actions.principal_grant_id"]=s(await e.prepareUncached(`UPDATE daemon_actions SET adapter_json = jsonb_set(adapter_json::jsonb, '{principal,grant_id}', ${o})::text
|
|
16
7
|
WHERE state IN ('pending', 'handed_off') AND adapter_json::jsonb ->> 'adapter' = 'cron_spawn'
|
|
17
|
-
AND adapter_json::jsonb #>> '{principal,grant_id}' IN (${a})`).run(...
|
|
18
|
-
WHERE o.type = 'node' AND o.reception = 2 AND s.envelope_json ->> 'app' IS NULL AND i.scheme = 'app' AND i.external_id = 'app:terminal'`;if(await n.prepareUncached(`${w} LIMIT 1`).get()!==void 0){const
|
|
8
|
+
AND adapter_json::jsonb #>> '{principal,grant_id}' IN (${a})`).run(...r===null?[]:[r],...t)),p}i(q,"repointGrantReferences");async function pe(){const e=await R(async n=>{const r={},t=i((w,m="")=>{for(const[y,A]of Object.entries(w))A!==0&&(r[m+y]=(r[m+y]??0)+A)},"add");let a=await N(n,E);if(a===null)throw new f;let p=null;const o=D();o!==null&&o!==a&&(t(await P(n,a,o),"join."),await d(n,E,o),p=a,a=o);const c=j("user").runtime?.issuer,_=await N(n,"install_id");if(_===null)throw new Error("retireLocalPerson: the install id is not stored");const g=await N(n,h)!==a;if(g){t({legacy_grantees:await K(n)}),t(await P(n,u,a));const w=`SELECT o.id FROM objects o JOIN peer_stubs s ON s.object = o.id JOIN identities i ON i.object = o.owner
|
|
9
|
+
WHERE o.type = 'node' AND o.reception = 2 AND s.envelope_json ->> 'app' IS NULL AND i.scheme = 'app' AND i.external_id = 'app:terminal'`;if(await n.prepareUncached(`${w} LIMIT 1`).get()!==void 0){const m=await W(n,"person","user",a,"user");t({repaired_stubs:s(await n.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${w})`).run(m.id))})}t({"nodes.sub_null_terminal":s(await n.prepare(`UPDATE nodes SET sub = ? WHERE sub IS NULL AND node_id IN (
|
|
19
10
|
SELECT n.node_id FROM nodes n JOIN identities i ON i.object = n.app
|
|
20
|
-
WHERE i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(a))}),
|
|
11
|
+
WHERE i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(a))}),t(await q(n,_,c?null:`terminal:${_}`)),c&&t({local_grant_mirror:await v(n)}),await d(n,h,a)}return c||await b(_,a),{person:a,joinedFrom:p,retired:g,columns:r}});return F(e.person),e}i(pe,"retireLocalPerson");export{u as LEGACY_LOCAL_PERSON,f as PersonUnresolvedError,ie as personId,ce as personIdAsync,J as resolvePerson,Y as resolvePersonId,pe as retireLocalPerson,F as setPersonId,P as substitutePerson};
|
|
@@ -939,6 +939,67 @@ CREATE TABLE peer_ingested_destinations (
|
|
|
939
939
|
ingested_at bigint NOT NULL
|
|
940
940
|
);
|
|
941
941
|
|
|
942
|
+
-- ---------------------------------------------------------------- money ledger (cycle 4)
|
|
943
|
+
|
|
944
|
+
-- One `charges` row per charge, each naming its cause (`caused_by`); one `charge_totals` rollup upserted in the same
|
|
945
|
+
-- transaction as each charge; one `limits` row shape. Added after schema version 1 shipped: `ensureSchema` runs this block
|
|
946
|
+
-- alone against an older database (idempotent, additive; the version stays 1). It sits BEFORE the permissions block on
|
|
947
|
+
-- purpose: that block drops and recreates `node_rows` (`SELECT n.*`), which only carries `nodes.caused_by` when the column
|
|
948
|
+
-- exists first. The whole block is one multi-statement query, so it applies entirely or not at all.
|
|
949
|
+
-- ledger:begin
|
|
950
|
+
CREATE TABLE IF NOT EXISTS charges (
|
|
951
|
+
id text PRIMARY KEY,
|
|
952
|
+
request text,
|
|
953
|
+
at text NOT NULL,
|
|
954
|
+
month text NOT NULL,
|
|
955
|
+
kind text NOT NULL CHECK (kind IN ('model','tool','sandbox','job','storage','take')),
|
|
956
|
+
what text NOT NULL,
|
|
957
|
+
units jsonb,
|
|
958
|
+
usd numeric(14,6),
|
|
959
|
+
payer text NOT NULL,
|
|
960
|
+
funding text NOT NULL CHECK (funding IN ('bill','subscription','key','endpoint','take','legacy')),
|
|
961
|
+
sub text,
|
|
962
|
+
grantee text NOT NULL,
|
|
963
|
+
node text,
|
|
964
|
+
run text,
|
|
965
|
+
provider text,
|
|
966
|
+
caused_by text,
|
|
967
|
+
vendor_ref text,
|
|
968
|
+
refused jsonb
|
|
969
|
+
);
|
|
970
|
+
CREATE INDEX IF NOT EXISTS charges_month_payer ON charges(month, payer);
|
|
971
|
+
CREATE INDEX IF NOT EXISTS charges_request ON charges(request) WHERE request IS NOT NULL;
|
|
972
|
+
CREATE INDEX IF NOT EXISTS charges_caused_by ON charges(caused_by) WHERE caused_by IS NOT NULL;
|
|
973
|
+
CREATE INDEX IF NOT EXISTS charges_run ON charges(run) WHERE run IS NOT NULL;
|
|
974
|
+
CREATE INDEX IF NOT EXISTS charges_grantee_month ON charges(grantee, month);
|
|
975
|
+
|
|
976
|
+
CREATE TABLE IF NOT EXISTS charge_totals (
|
|
977
|
+
month text NOT NULL,
|
|
978
|
+
payer text NOT NULL,
|
|
979
|
+
funding text NOT NULL,
|
|
980
|
+
sub text NOT NULL DEFAULT '',
|
|
981
|
+
grantee text NOT NULL,
|
|
982
|
+
provider text NOT NULL DEFAULT '',
|
|
983
|
+
usd numeric(16,6) NOT NULL DEFAULT 0,
|
|
984
|
+
PRIMARY KEY (month, payer, funding, sub, grantee, provider)
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
CREATE TABLE IF NOT EXISTS limits (
|
|
988
|
+
id text PRIMARY KEY,
|
|
989
|
+
payer text NOT NULL,
|
|
990
|
+
funding text,
|
|
991
|
+
grantee text,
|
|
992
|
+
provider text,
|
|
993
|
+
sub text,
|
|
994
|
+
usd_per_month numeric(14,6) NOT NULL CHECK (usd_per_month >= 0),
|
|
995
|
+
source text NOT NULL CHECK (source IN ('grant_sync','person','operator')),
|
|
996
|
+
updated_at text NOT NULL
|
|
997
|
+
);
|
|
998
|
+
CREATE INDEX IF NOT EXISTS limits_payer ON limits(payer);
|
|
999
|
+
|
|
1000
|
+
ALTER TABLE nodes ADD COLUMN IF NOT EXISTS caused_by text;
|
|
1001
|
+
-- ledger:end
|
|
1002
|
+
|
|
942
1003
|
-- ---------------------------------------------------------------- permissions (cycle 3)
|
|
943
1004
|
|
|
944
1005
|
-- One permission model: relation facts, app schemas, the columns the evaluator and owner tree need, the narrowed privacy
|
|
@@ -264,6 +264,8 @@ export interface NodeIdentity {
|
|
|
264
264
|
event_cursor?: number | null;
|
|
265
265
|
last_activity_at?: string | null;
|
|
266
266
|
usage_json?: string | null;
|
|
267
|
+
/** The reference that caused this run (`message:<id>`, `request:<id>`, `cron_run:<id>`), set on a run's root from `run.start`; null for a root. */
|
|
268
|
+
caused_by?: string | null;
|
|
267
269
|
/** A run root's latest turn error (`run.get` `last_turn_error`), JSON; null once a turn completes without one. */
|
|
268
270
|
last_turn_error_json?: string | null;
|
|
269
271
|
deleting_at?: string | null;
|
|
@@ -384,6 +386,8 @@ export interface NodeRow {
|
|
|
384
386
|
event_cursor?: number | null;
|
|
385
387
|
last_activity_at?: string | null;
|
|
386
388
|
usage_json?: string | null;
|
|
389
|
+
/** The reference that caused this run (`message:<id>`, `request:<id>`, `cron_run:<id>`), set on a run's root from `run.start`; null for a root. */
|
|
390
|
+
caused_by?: string | null;
|
|
387
391
|
/** A run root's latest turn error (`run.get` `last_turn_error`), JSON; null once a turn completes without one. */
|
|
388
392
|
last_turn_error_json?: string | null;
|
|
389
393
|
deleting_at?: string | null;
|
package/dist/core/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Ke=Object.defineProperty;var s=(e,n)=>Ke(e,"name",{value:n,configurable:!0});import{envProfileId as qe}from"../shared/env.js";import{basename as X,join as Q}from"node:path";import{existsSync as Ge,mkdirSync as Be,statSync as We}from"node:fs";import{isDeepStrictEqual as He}from"node:util";import{CONFIG_FILE as Je,STATE_FILE as Ze,CONDENSED_HISTORY_MODES as Ye,MOUSE_MODE_DEFAULTS as Ve,WHIP_MESSAGE_MODES as Xe,DEFAULT_WHIP_MESSAGES as ee,defaultScopeConfig as k,defaultScopeState as ne,defaultModelLaddersConfig as Qe,defaultKindsConfig as en,defaultRemoteCanvasConfig as nn}from"../types.js";import{BINDING_CATALOG as on,BINDING_IDS as tn,isAttachPaneBinding as rn}from"./keybindings/catalog.js";import{notFound as sn}from"./errors.js";import{emitEvent as cn}from"./events/emit.js";import{atomicWriteJson as oe,readJsonIfExists as K,ensureDir as un}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as w,findProjectScopeRoots as dn,userScopeRoot as E}from"./scope.js";import{listInstalledPluginsInRoot as te}from"./installed-plugins.js";import{profileDir as q,listProfiles as re}from"./profiles/manifest.js";import{canonicalRoot as A,projectStore as fn,userStore as ie}from"./scoped-state/paths.js";import{convertLegacyScopedStore as ln,initializeFreshScopedStore as an}from"./scoped-state/migrate.js";import{mutateRawSettings as mn,readBookkeeping as pn,readRawSettings as gn,readRawSettingsWithRevision as yn,replaceRawSettings as hn,writeBookkeeping as bn,writeRawSettings as _n}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as vn}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as kn}from"./user-settings.js";import{normalizeWorkingGerunds as wn}from"../shared/working-activity.js";import{mergePageComponentLayers as An,normalizePageComponents as se}from"./human/page-catalog.js";function b(e){return Q(e,Je)}s(b,"configPathFor");function ce(e,n){return vn(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ce,"withConfigPathLock");function Sn(e){return Q(e,Ze)}s(Sn,"statePathFor");function vo(e){const n=y(e);return n?b(n):null}s(vo,"configPath");function ko(e){const n=y(e);return n?Sn(n):null}s(ko,"statePath");function g(e){const n=A(e),o=A(E());if(n===o)return{store:ie(o),key:"user",kind:"user",root:o};if(X(n)===".crouter")return ln({kind:"project",root:n}),{store:fn(n),key:"project",kind:"project",root:n};for(const t of re()){const r=A(q(t.profileId));if(n===r)return{store:ie(o),key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function I(e){if(X(e)===".crouter"){let n;try{n=A(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==A(E()))return K(b(e))}return gn(g(e))}s(I,"readRawAtRoot");function G(e,n){const o=g(e);if(o.kind==="project"){ce(b(o.root),t=>oe(t,n,{createParent:!1}));return}_n(o,n)}s(G,"writeRawAtRoot");function S(e,n){const o=g(e);return o.kind==="project"?ce(b(o.root),t=>{const r=n(K(t)??{});return oe(t,r.next,{createParent:!1}),r.value}):mn(o,t=>n(t))}s(S,"mutateRawAtRoot");const P=globalThis,T=Symbol.for("crtr.broker.config-snapshot");function wo(e){P[T]=e}s(wo,"installBrokerConfigSnapshot");function Ao(){return P[T]}s(Ao,"brokerConfigSnapshot");function jn(e){const n=P[T];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=y(e);return o?Rn(o):k()}s(jn,"readConfig");function Rn(e){const n=I(e);return n?z(n):k()}s(Rn,"readConfigAtRoot");function xn(e){const n=y(e);if(!n)return ne();try{return pn(g(n))}catch(o){if(e==="project"&&!Ge(n))return ne();throw o}}s(xn,"readState");class On extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function ue(e){if(e.scope==="user")return g(E());if(!re().some(n=>n.profileId===e.profileId))throw sn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(q(e.profileId))}s(ue,"rawSettingsOwnerForTarget");function So(e){return yn(ue(e))}s(So,"readRawSettingsForTarget");function jo(e,n,o){return hn(ue(e),n,o,t=>{try{z(t)}catch(r){throw new On(r)}})}s(jo,"replaceRawSettingsForTarget");function Ro(e,n){const o=w(e);return S(o,t=>{const r=n(t);return{value:r,next:r}})}s(Ro,"updateRawConfigAtomically");function xo(e,n){G(w(e),n)}s(xo,"writeConfig");function Oo(e,n){G(w(e),n)}s(Oo,"writeRawConfig");function En(e,n){const o=w(e);bn(g(o),n)}s(En,"writeState");function Eo(e,n){if(e==="project")try{Be(n)}catch(t){if(t.code!=="EEXIST"||!We(n).isDirectory())throw t}else un(n);const o=g(e==="user"?E():n);an({kind:o.kind==="user"?"user":"project",root:o.store.root}),o.kind==="project"&&K(b(o.root))===null&&G(o.root,{schema_version:k().schema_version})}s(Eo,"ensureScopeInitialized");function In(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(In,"normalizeKeybindings");const Pn=new Set(on.filter(rn).map(e=>e.id));function Tn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&tn.has(n)&&Pn.has(n)))]:[]}s(Tn,"normalizeTmuxPassthrough");function C(e,n=Qe()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s(C,"mergeModelLadders");function de(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(de,"validStrength");const B=["ultra","strong","medium","light"];function W(){return Object.create(null)}s(W,"routeRecord");function j(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(j,"setRouteRecord");function fe(e){const n=W();for(const[o,t]of Object.entries(e??{}))j(n,o,t);return n}s(fe,"copyRouteRecord");function R(e,n){cn({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(R,"routeInvalid");function $(e,n={}){const o=fe(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){R(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){R(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const l of["family","credentialSource","providerId"]){const f=i[l];if(f!==void 0){if(typeof f!="string"||f.trim()===""){d=`${l} must be a non-empty string`;break}u[l]=f}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const l={...c?.models};for(const[f,a]of Object.entries(i.models)){if(!de(f)){d=`models.${f} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){d=`models.${f} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){d=`models.${f} must be provider/id`;break}l[f]=a}u.models=l}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[l,f]of Object.entries(u.models))if(f.slice(0,f.indexOf("/"))!==u.providerId){d=`models.${l} provider prefix must equal providerId`;break}}if(d!==void 0){R(t,d);continue}j(o,t,u)}return o}s($,"mergeModelRoutePatches");function le(e){const n=W(),o=W();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){R(t,"route must include family, credentialSource, providerId, and models");continue}const i=B.filter(c=>r.models[c]===void 0);if(i.length>0){R(t,`incomplete route; missing strengths: ${i.join(", ")}`),j(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}j(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(le,"resolveModelRoutes");function Cn(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=B.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of B){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s(Cn,"assertCompleteModelRoute");function M(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>de(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(M,"mergeModelRouting");function $n(e){return e!==""&&e.replace(/\*/g,"")===""}s($n,"isInheritAllGlob");function N(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if($n(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(N,"mergeSpawnEnv");function L(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(L,"mergeProviderOptions");const ae=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Mn=new Set(["crtr","crtrd"]);function F(e,n){if(n==="bin"&&Mn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!ae.test(e))return`${n}.${e} is not a safe bare command name (expected ${ae.source})`}s(F,"bareCommandNameIssue");function Nn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=F(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Nn,"binDeclarationIssues");function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))F(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Ln,"normalizeBin");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(me.test(o)||r.push(`action name must match ${me.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(Fn,"humanActionDeclarationIssues");function zn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(Fn(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(zn,"normalizeHumanActions");function Io(e){return Nn(e).map(n=>n.message)}s(Io,"invalidPluginBinReasons");function Po(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))F(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(Po,"normalizeRequires");function To(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=F(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(To,"invalidPluginRequiresReasons");function pe(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(pe,"normalizeKindFields");function x(e,n=en()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=pe(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(x,"mergeKinds");function ge(e,n,o){if(n===null)return o;const t=te(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=x(i.manifest.kinds,r);return r}s(ge,"layerPluginKinds");function Co(){const e=[{origin:"config.json",components:jn("user").page_components}],n=y("user");if(n!==null){const o=te("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:se(t.manifest.page_components,r)})}}return An(e)}s(Co,"resolvePageComponents");const H=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function $o(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))H.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...H].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);pe(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...H].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s($o,"invalidPluginKindsReasons");function Dn(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(Dn,"normalizeRemoteCanvasTarget");function Un(e,n=nn()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=Dn(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Un,"mergeRemoteCanvas");function ye(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(ye,"normalizeMode");function O(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(O,"normalizePositiveInteger");function Kn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=O(o.warning,n.warning),r=O(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(Kn,"mergeBrokerThresholds");function qn(e,n){return{unattendedParkMs:O((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(qn,"mergeLifecycle");function Gn(e){if(!Array.isArray(e))return[...ee];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...ee]}s(Gn,"normalizeWhipMessages");function Bn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Bn,"mergeApi");function z(e){const n=k(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:ye(i?.crtr,n.auto_update.crtr),content:ye(i?.content,n.auto_update.content),interval_hours:u},l=e.max_panes_per_window,f=O(l,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=Kn(e.brokerThresholds,n.brokerThresholds),h=qn(e.lifecycle,n.lifecycle),D=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,p=e.working_gerunds===void 0?[...n.working_gerunds]:wn(e.working_gerunds),be=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,_e=se(e.page_components),ve=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,ke=Gn(e.whip_messages),we=Xe.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Ae=Ve.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,Se=O(e.live_cycles,n.live_cycles),je=Ye.includes(e.condensed_history)?e.condensed_history:n.condensed_history,Re=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,xe=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Oe=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ee=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Ie=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Pe=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Te=In(e.keybindings),Ce=Tn(e.tmux_passthrough),$e=C(e.modelLadders),Me=L(e.providerOptions,n.providerOptions),U=le($(e.modelRoutes)),J=U.complete,Z=M(e.modelRouting,void 0),Ne=x(e.kinds),Le=Un(e.remoteCanvas),Fe=Bn(e.api,n.api),_=e.paths;if(_?.user_files!==void 0&&(typeof _.user_files!="string"||!_.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const Y=e.store,v=e.runtime;if(v?.person_uids!==void 0&&(!Array.isArray(v.person_uids)||!v.person_uids.every(V=>Number.isSafeInteger(V)&&V>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const ze=N(e.spawnEnv,n.spawnEnv?.allow),De=Ln(e.bin),Ue=zn(e.humanActions);return{bin:De,humanActions:Ue,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:f,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:h,completion_bell:D,working_gerunds:p,whip_mode:be,page_components:_e,page_surface:ve,whip_messages:ke,whip_message_mode:we,mouse_mode_default:Ae,live_cycles:Se,condensed_history:je,bash_tool_purpose:Re,fold_finished_tools:xe,summarize_tool_calls:Oe,detailed_tool_recaps:Ee,document_port:Ie,consolidate_replies:Pe,keybindings:Te,tmux_passthrough:Ce,modelLadders:$e,providerOptions:Me,...Object.keys(J).length>0?{modelRoutes:J}:{},...Object.keys(U.legacy).length>0?{legacyModelRoutes:U.legacy}:{},...Z!==void 0?{modelRouting:Z}:{},kinds:Ne,remoteCanvas:Le,api:Fe,..._?{paths:_}:{},...Y?{store:Y}:{},...v?{runtime:v}:{},spawnEnv:ze}}s(z,"mergeConfig");function Wn(e){return I(e)}s(Wn,"readRawConfigAtRoot");function Hn(e){const n=y(e);return n?Wn(n):null}s(Hn,"readRawScopeConfig");function Jn(e){if(e===null||e==="")return null;try{return I(q(e))}catch{return null}}s(Jn,"readRawProfileConfig");function Zn(e,n){return[...dn(e,n)].reverse().map(r=>({root:r,raw:I(r)}))}s(Zn,"readRawProjectScopeConfigs");function he(e=process.cwd(),n=qe()||null){const o=P[T];if(o)return o.launch;const t=k(),r=Hn("user"),i=Jn(n),c=Zn(e,n);let u=x(r?.kinds,ge("user",y("user"),t.kinds)),d=C(r?.modelLadders,t.modelLadders),l=L(r?.providerOptions,t.providerOptions),f=$(r?.modelRoutes),a=M(r?.modelRouting,void 0),m=N(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=x(i.kinds,u),d=C(i.modelLadders,d),l=L(i.providerOptions,l),f=$(i.modelRoutes,f),a=M(i.modelRouting,a),m=N(i.spawnEnv,m.allow));for(const{root:D,raw:p}of c)u=x(p?.kinds,ge("project",D,u)),p!==null&&(d=C(p.modelLadders,d),l=L(p.providerOptions,l),f=$(p.modelRoutes,f),a=M(p.modelRouting,a),m=N(p.spawnEnv,m.allow));const h=le(f);return{kinds:u,modelLadders:d,providerOptions:l,...Object.keys(h.complete).length>0?{modelRoutes:h.complete}:{},...Object.keys(h.legacy).length>0?{legacyModelRoutes:h.legacy}:{},...a!==void 0?{modelRouting:a}:{},spawnEnv:m}}s(he,"readMergedLaunchConfig");function Mo(e){return he().kinds[e]}s(Mo,"resolveKindConfig");function No(e){const n=he().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s(No,"subKindsAvailableTo");function Yn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Yn,"sparseModelLaddersToPersist");function Vn(e,n){return S(e,o=>{const t=z(o),r=z(o);n(r);const i={...o};for(const u of kn)u!=="modelLadders"&&!He(r[u],t[u])&&(i[u]=r[u]);const c=Yn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Vn,"mutateConfigAtRoot");function Lo(e,n){S(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Lo,"persistModelLadders");function Fo(e,n,o){if(o!==void 0)Cn(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");S(e,t=>{const r=fe(t.modelRoutes??{});o===void 0?delete r[n]:j(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(Fo,"persistModelRoute");function Xn(e,n){return Vn(e,n)}s(Xn,"updateConfigAtRoot");function zo(e,n){return Xn(w(e),n)}s(zo,"updateConfig");function Do(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return S(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:b(e.root),field:n}}s(Do,"persistDefaultKindModel");function Uo(e,n){const o=xn(e);return n(o),En(e,o),o}s(Uo,"updateState");export{On as InvalidRawSettingsError,Nn as binDeclarationIssues,Ao as brokerConfigSnapshot,vo as configPath,Eo as ensureScopeInitialized,Fn as humanActionDeclarationIssues,wo as installBrokerConfigSnapshot,Io as invalidPluginBinReasons,$o as invalidPluginKindsReasons,To as invalidPluginRequiresReasons,Ln as normalizeBin,zn as normalizeHumanActions,Po as normalizeRequires,Tn as normalizeTmuxPassthrough,Do as persistDefaultKindModel,Lo as persistModelLadders,Fo as persistModelRoute,jn as readConfig,Rn as readConfigAtRoot,he as readMergedLaunchConfig,Wn as readRawConfigAtRoot,Hn as readRawScopeConfig,So as readRawSettingsForTarget,xn as readState,jo as replaceRawSettingsForTarget,Mo as resolveKindConfig,Co as resolvePageComponents,ko as statePath,No as subKindsAvailableTo,zo as updateConfig,Xn as updateConfigAtRoot,Ro as updateRawConfigAtomically,Uo as updateState,xo as writeConfig,Oo as writeRawConfig,En as writeState};
|
|
1
|
+
var qe=Object.defineProperty;var s=(e,n)=>qe(e,"name",{value:n,configurable:!0});import{envProfileId as Ge}from"../shared/env.js";import{basename as Q,join as ee}from"node:path";import{existsSync as Be,mkdirSync as We,statSync as He}from"node:fs";import{isDeepStrictEqual as Je}from"node:util";import{CONFIG_FILE as Ze,STATE_FILE as Ye,CONDENSED_HISTORY_MODES as Ve,MOUSE_MODE_DEFAULTS as Xe,WHIP_MESSAGE_MODES as Qe,DEFAULT_WHIP_MESSAGES as ne,defaultScopeConfig as w,defaultScopeState as oe,defaultModelLaddersConfig as en,defaultKindsConfig as nn,defaultRemoteCanvasConfig as on}from"../types.js";import{BINDING_CATALOG as tn,BINDING_IDS as rn,isAttachPaneBinding as sn}from"./keybindings/catalog.js";import{notFound as cn}from"./errors.js";import{emitEvent as un}from"./events/emit.js";import{atomicWriteJson as te,readJsonIfExists as q,ensureDir as dn}from"./fs-utils.js";import{scopeRoot as h,requireScopeRoot as A,findProjectScopeRoots as fn,userScopeRoot as I}from"./scope.js";import{listInstalledPluginsInRoot as re}from"./installed-plugins.js";import{profileDir as G,listProfiles as ie}from"./profiles/manifest.js";import{canonicalRoot as S,projectStore as ln,userStore as se}from"./scoped-state/paths.js";import{convertLegacyScopedStore as an,initializeFreshScopedStore as mn}from"./scoped-state/migrate.js";import{mutateRawSettings as pn,readBookkeeping as gn,readRawSettings as yn,readRawSettingsWithRevision as hn,replaceRawSettings as bn,writeBookkeeping as _n,writeRawSettings as vn}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as kn}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as wn}from"./user-settings.js";import{normalizeWorkingGerunds as An}from"../shared/working-activity.js";import{mergePageComponentLayers as Sn,normalizePageComponents as ce}from"./human/page-catalog.js";function _(e){return ee(e,Ze)}s(_,"configPathFor");function ue(e,n){return kn(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ue,"withConfigPathLock");function jn(e){return ee(e,Ye)}s(jn,"statePathFor");function ko(e){const n=h(e);return n?_(n):null}s(ko,"configPath");function wo(e){const n=h(e);return n?jn(n):null}s(wo,"statePath");function g(e){const n=S(e),o=S(I());if(n===o)return{store:se(o),key:"user",kind:"user",root:o};if(Q(n)===".crouter")return an({kind:"project",root:n}),{store:ln(n),key:"project",kind:"project",root:n};for(const t of ie()){const r=S(G(t.profileId));if(n===r)return{store:se(o),key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function P(e){if(Q(e)===".crouter"){let n;try{n=S(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==S(I()))return q(_(e))}return yn(g(e))}s(P,"readRawAtRoot");function B(e,n){const o=g(e);if(o.kind==="project"){ue(_(o.root),t=>te(t,n,{createParent:!1}));return}vn(o,n)}s(B,"writeRawAtRoot");function j(e,n){const o=g(e);return o.kind==="project"?ue(_(o.root),t=>{const r=n(q(t)??{});return te(t,r.next,{createParent:!1}),r.value}):pn(o,t=>n(t))}s(j,"mutateRawAtRoot");const T=globalThis,C=Symbol.for("crtr.broker.config-snapshot");function Ao(e){T[C]=e}s(Ao,"installBrokerConfigSnapshot");function So(){return T[C]}s(So,"brokerConfigSnapshot");function Rn(e){const n=T[C];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=h(e);return o?xn(o):w()}s(Rn,"readConfig");function xn(e){const n=P(e);return n?D(n):w()}s(xn,"readConfigAtRoot");function On(e){const n=h(e);if(!n)return oe();try{return gn(g(n))}catch(o){if(e==="project"&&!Be(n))return oe();throw o}}s(On,"readState");class En extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function de(e){if(e.scope==="user")return g(I());if(!ie().some(n=>n.profileId===e.profileId))throw cn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(G(e.profileId))}s(de,"rawSettingsOwnerForTarget");function jo(e){return hn(de(e))}s(jo,"readRawSettingsForTarget");function Ro(e,n,o){return bn(de(e),n,o,t=>{try{D(t)}catch(r){throw new En(r)}})}s(Ro,"replaceRawSettingsForTarget");function xo(e,n){const o=A(e);return j(o,t=>{const r=n(t);return{value:r,next:r}})}s(xo,"updateRawConfigAtomically");function Oo(e,n){B(A(e),n)}s(Oo,"writeConfig");function Eo(e,n){B(A(e),n)}s(Eo,"writeRawConfig");function In(e,n){const o=A(e);_n(g(o),n)}s(In,"writeState");function Io(e,n){if(e==="project")try{We(n)}catch(t){if(t.code!=="EEXIST"||!He(n).isDirectory())throw t}else dn(n);const o=g(e==="user"?I():n);mn({kind:o.kind==="user"?"user":"project",root:o.store.root}),o.kind==="project"&&q(_(o.root))===null&&B(o.root,{schema_version:w().schema_version})}s(Io,"ensureScopeInitialized");function Pn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(Pn,"normalizeKeybindings");const Tn=new Set(tn.filter(sn).map(e=>e.id));function Cn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&rn.has(n)&&Tn.has(n)))]:[]}s(Cn,"normalizeTmuxPassthrough");function $(e,n=en()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s($,"mergeModelLadders");function fe(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(fe,"validStrength");const W=["ultra","strong","medium","light"];function H(){return Object.create(null)}s(H,"routeRecord");function R(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(R,"setRouteRecord");function le(e){const n=H();for(const[o,t]of Object.entries(e??{}))R(n,o,t);return n}s(le,"copyRouteRecord");function x(e,n){un({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(x,"routeInvalid");function M(e,n={}){const o=le(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){x(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){x(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const l of["family","credentialSource","providerId"]){const f=i[l];if(f!==void 0){if(typeof f!="string"||f.trim()===""){d=`${l} must be a non-empty string`;break}u[l]=f}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const l={...c?.models};for(const[f,a]of Object.entries(i.models)){if(!fe(f)){d=`models.${f} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){d=`models.${f} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){d=`models.${f} must be provider/id`;break}l[f]=a}u.models=l}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[l,f]of Object.entries(u.models))if(f.slice(0,f.indexOf("/"))!==u.providerId){d=`models.${l} provider prefix must equal providerId`;break}}if(d!==void 0){x(t,d);continue}R(o,t,u)}return o}s(M,"mergeModelRoutePatches");function ae(e){const n=H(),o=H();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){x(t,"route must include family, credentialSource, providerId, and models");continue}const i=W.filter(c=>r.models[c]===void 0);if(i.length>0){x(t,`incomplete route; missing strengths: ${i.join(", ")}`),R(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}R(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(ae,"resolveModelRoutes");function $n(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=W.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of W){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s($n,"assertCompleteModelRoute");function N(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>fe(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(N,"mergeModelRouting");function Mn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Mn,"isInheritAllGlob");function L(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if(Mn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(L,"mergeSpawnEnv");function F(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(F,"mergeProviderOptions");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Nn=new Set(["crtr","crtrd"]);function z(e,n){if(n==="bin"&&Nn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!me.test(e))return`${n}.${e} is not a safe bare command name (expected ${me.source})`}s(z,"bareCommandNameIssue");function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Ln,"binDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Fn,"normalizeBin");const pe=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function zn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(pe.test(o)||r.push(`action name must match ${pe.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(zn,"humanActionDeclarationIssues");function Dn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(zn(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(Dn,"normalizeHumanActions");function Po(e){return Ln(e).map(n=>n.message)}s(Po,"invalidPluginBinReasons");function To(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(To,"normalizeRequires");function Co(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(Co,"invalidPluginRequiresReasons");function ge(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(ge,"normalizeKindFields");function O(e,n=nn()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=ge(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(O,"mergeKinds");function ye(e,n,o){if(n===null)return o;const t=re(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=O(i.manifest.kinds,r);return r}s(ye,"layerPluginKinds");function $o(){const e=[{origin:"config.json",components:Rn("user").page_components}],n=h("user");if(n!==null){const o=re("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:ce(t.manifest.page_components,r)})}}return Sn(e)}s($o,"resolvePageComponents");const J=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Mo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))J.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...J].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);ge(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...J].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Mo,"invalidPluginKindsReasons");function Un(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(Un,"normalizeRemoteCanvasTarget");function Kn(e,n=on()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=Un(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Kn,"mergeRemoteCanvas");function he(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(he,"normalizeMode");function E(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(E,"normalizePositiveInteger");function qn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=E(o.warning,n.warning),r=E(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(qn,"mergeBrokerThresholds");function Gn(e,n){return{unattendedParkMs:E((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Gn,"mergeLifecycle");function Bn(e){if(!Array.isArray(e))return[...ne];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...ne]}s(Bn,"normalizeWhipMessages");function Wn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Wn,"mergeApi");function D(e){const n=w(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:he(i?.crtr,n.auto_update.crtr),content:he(i?.content,n.auto_update.content),interval_hours:u},l=e.max_panes_per_window,f=E(l,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=qn(e.brokerThresholds,n.brokerThresholds),b=Gn(e.lifecycle,n.lifecycle),U=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,p=e.working_gerunds===void 0?[...n.working_gerunds]:An(e.working_gerunds),_e=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,ve=ce(e.page_components),ke=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,we=Bn(e.whip_messages),Ae=Qe.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Se=Xe.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,je=E(e.live_cycles,n.live_cycles),Re=Ve.includes(e.condensed_history)?e.condensed_history:n.condensed_history,xe=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,Oe=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Ee=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ie=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Pe=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Te=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Ce=Pn(e.keybindings),$e=Cn(e.tmux_passthrough),Me=$(e.modelLadders),Ne=F(e.providerOptions,n.providerOptions),K=ae(M(e.modelRoutes)),Z=K.complete,Y=N(e.modelRouting,void 0),Le=O(e.kinds),Fe=Kn(e.remoteCanvas),ze=Wn(e.api,n.api),v=e.paths;if(v?.user_files!==void 0&&(typeof v.user_files!="string"||!v.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const y=e.ledger;if(y?.take_pct!==void 0&&(typeof y.take_pct!="number"||!Number.isFinite(y.take_pct)||y.take_pct<0||y.take_pct>100))throw new Error("ledger.take_pct must be a number from 0 to 100");const V=e.store,k=e.runtime;if(k?.person_uids!==void 0&&(!Array.isArray(k.person_uids)||!k.person_uids.every(X=>Number.isSafeInteger(X)&&X>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const De=L(e.spawnEnv,n.spawnEnv?.allow),Ue=Fn(e.bin),Ke=Dn(e.humanActions);return{bin:Ue,humanActions:Ke,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:f,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:b,completion_bell:U,working_gerunds:p,whip_mode:_e,page_components:ve,page_surface:ke,whip_messages:we,whip_message_mode:Ae,mouse_mode_default:Se,live_cycles:je,condensed_history:Re,bash_tool_purpose:xe,fold_finished_tools:Oe,summarize_tool_calls:Ee,detailed_tool_recaps:Ie,document_port:Pe,consolidate_replies:Te,keybindings:Ce,tmux_passthrough:$e,modelLadders:Me,providerOptions:Ne,...Object.keys(Z).length>0?{modelRoutes:Z}:{},...Object.keys(K.legacy).length>0?{legacyModelRoutes:K.legacy}:{},...Y!==void 0?{modelRouting:Y}:{},kinds:Le,remoteCanvas:Fe,api:ze,...v?{paths:v}:{},...y?{ledger:y}:{},...V?{store:V}:{},...k?{runtime:k}:{},spawnEnv:De}}s(D,"mergeConfig");function Hn(e){return P(e)}s(Hn,"readRawConfigAtRoot");function Jn(e){const n=h(e);return n?Hn(n):null}s(Jn,"readRawScopeConfig");function Zn(e){if(e===null||e==="")return null;try{return P(G(e))}catch{return null}}s(Zn,"readRawProfileConfig");function Yn(e,n){return[...fn(e,n)].reverse().map(r=>({root:r,raw:P(r)}))}s(Yn,"readRawProjectScopeConfigs");function be(e=process.cwd(),n=Ge()||null){const o=T[C];if(o)return o.launch;const t=w(),r=Jn("user"),i=Zn(n),c=Yn(e,n);let u=O(r?.kinds,ye("user",h("user"),t.kinds)),d=$(r?.modelLadders,t.modelLadders),l=F(r?.providerOptions,t.providerOptions),f=M(r?.modelRoutes),a=N(r?.modelRouting,void 0),m=L(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=O(i.kinds,u),d=$(i.modelLadders,d),l=F(i.providerOptions,l),f=M(i.modelRoutes,f),a=N(i.modelRouting,a),m=L(i.spawnEnv,m.allow));for(const{root:U,raw:p}of c)u=O(p?.kinds,ye("project",U,u)),p!==null&&(d=$(p.modelLadders,d),l=F(p.providerOptions,l),f=M(p.modelRoutes,f),a=N(p.modelRouting,a),m=L(p.spawnEnv,m.allow));const b=ae(f);return{kinds:u,modelLadders:d,providerOptions:l,...Object.keys(b.complete).length>0?{modelRoutes:b.complete}:{},...Object.keys(b.legacy).length>0?{legacyModelRoutes:b.legacy}:{},...a!==void 0?{modelRouting:a}:{},spawnEnv:m}}s(be,"readMergedLaunchConfig");function No(e){return be().kinds[e]}s(No,"resolveKindConfig");function Lo(e){const n=be().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s(Lo,"subKindsAvailableTo");function Vn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Vn,"sparseModelLaddersToPersist");function Xn(e,n){return j(e,o=>{const t=D(o),r=D(o);n(r);const i={...o};for(const u of wn)u!=="modelLadders"&&!Je(r[u],t[u])&&(i[u]=r[u]);const c=Vn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Xn,"mutateConfigAtRoot");function Fo(e,n){j(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Fo,"persistModelLadders");function zo(e,n,o){if(o!==void 0)$n(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");j(e,t=>{const r=le(t.modelRoutes??{});o===void 0?delete r[n]:R(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(zo,"persistModelRoute");function Qn(e,n){return Xn(e,n)}s(Qn,"updateConfigAtRoot");function Do(e,n){return Qn(A(e),n)}s(Do,"updateConfig");function Uo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return j(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:_(e.root),field:n}}s(Uo,"persistDefaultKindModel");function Ko(e,n){const o=On(e);return n(o),In(e,o),o}s(Ko,"updateState");export{En as InvalidRawSettingsError,Ln as binDeclarationIssues,So as brokerConfigSnapshot,ko as configPath,Io as ensureScopeInitialized,zn as humanActionDeclarationIssues,Ao as installBrokerConfigSnapshot,Po as invalidPluginBinReasons,Mo as invalidPluginKindsReasons,Co as invalidPluginRequiresReasons,Fn as normalizeBin,Dn as normalizeHumanActions,To as normalizeRequires,Cn as normalizeTmuxPassthrough,Uo as persistDefaultKindModel,Fo as persistModelLadders,zo as persistModelRoute,Rn as readConfig,xn as readConfigAtRoot,be as readMergedLaunchConfig,Hn as readRawConfigAtRoot,Jn as readRawScopeConfig,jo as readRawSettingsForTarget,On as readState,Ro as replaceRawSettingsForTarget,No as resolveKindConfig,$o as resolvePageComponents,wo as statePath,Lo as subKindsAvailableTo,Do as updateConfig,Qn as updateConfigAtRoot,xo as updateRawConfigAtomically,Ko as updateState,Oo as writeConfig,Eo as writeRawConfig,In as writeState};
|
|
@@ -108,7 +108,8 @@ export interface TeamRecord {
|
|
|
108
108
|
}
|
|
109
109
|
/** The `teams` a grant sync answer carried; absent (an unjoined install, an older directory) reads as none. */
|
|
110
110
|
export declare function teamsOf(value: unknown): TeamRecord[];
|
|
111
|
-
/** Replace the mirror with `grants` and the `written_by = 'directory'` team
|
|
111
|
+
/** Replace the mirror with `grants`, the ledger's `grant:<id>` limit rows from their caps, and the `written_by = 'directory'` team
|
|
112
|
+
* `member` facts with `teams`, in one transaction. */
|
|
112
113
|
export declare function replaceGrants(grants: readonly GrantRecord[], syncedAt: string, source: string, teams?: readonly TeamRecord[]): Promise<void>;
|
|
113
114
|
/** Bumped by every `replaceGrants`. A launch compiled against one generation
|
|
114
115
|
* and started under another may hold mounts the new mirror no longer grants. */
|