@north-light/cli 0.3.457 → 0.3.459
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/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/profiles.d.ts +3 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +6 -0
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/viewer.js +3 -3
- package/dist/commands/profile/new.js +1 -1
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/core/command-plugins/compose.js +1 -1
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/grants/on-sync.js +1 -1
- package/dist/core/layout-migrate/stored-paths.js +3 -3
- package/dist/core/layout-migrate/stores.js +1 -1
- package/dist/core/layout.d.ts +2 -2
- package/dist/core/layout.js +2 -2
- package/dist/core/profiles/manifest.d.ts +1 -1
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/relocate.d.ts +8 -0
- package/dist/core/profiles/relocate.js +1 -0
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/providers/call.d.ts +2 -2
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/roots.d.ts +19 -0
- package/dist/core/providers/roots.js +1 -0
- package/dist/core/providers/token-cache.d.ts +10 -2
- package/dist/core/providers/token-cache.js +1 -1
- package/dist/core/scoped-state/migrate.js +1 -1
- package/dist/core/scoped-state/profiles.js +1 -1
- package/dist/core/scoped-state/settings.js +1 -1
- package/dist/core/spaces/space.js +2 -2
- package/dist/core/storage/download.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/crtrd.js +8 -7
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/migrations/004-canvas-documents/legacy/types.d.ts +1 -1
- package/docs/sdk/release-notes.md +6 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
var l=Object.defineProperty;var
|
|
1
|
+
var l=Object.defineProperty;var i=(e,t)=>l(e,"name",{value:t,configurable:!0});import{defineLeaf as p}from"../../core/command.js";import{usage as n}from"../../core/errors.js";import{resolve as f}from"node:path";import{cliClient as s}from"../api-client.js";import{resolveMetaPairs as c}from"./meta.js";const k=p({name:"new",description:"create a new profile",whenToUse:"you are establishing a new agent identity \u2014 a stable id, a display name, and its own documents (a profile owns documents like any other owner). Pass at most one initial project directory here (the parser has no repeatable-flag support); use `profile project add` afterward for every additional one. Use `--root` (no name) to provision the canonical stable root profile \u2014 the default identity a home falls back to \u2014 idempotently, without spawning a node.",help:{name:"profile new",summary:"create a profile of the caller's app in the scoped store, with its own app directory",params:[{kind:"flag",name:"name",type:"string",required:!1,constraint:"Display name for the profile. Also slugified into the stable profile id \u2014 the id never changes on later rename. Required unless `--root` is given; mutually exclusive with `--root`."},{kind:"flag",name:"root",type:"bool",required:!1,constraint:"Provision the canonical stable root profile (fixed id `root-00000000`, name `root`) \u2014 the fallback default identity for a home \u2014 instead of a fresh named one. Idempotent: re-running returns the existing root. Node-free (no `node new --root` needed). Mutually exclusive with `--name`/`--project`/`--default-kind`/`--meta`."},{kind:"flag",name:"project",type:"path",required:!1,constraint:"One initial project directory. Must already exist and be a directory; resolved to its absolute real path before storing. Creates a purview relationship. Singular \u2014 add more with `crtr profile project add` after creation."},{kind:"flag",name:"default-kind",type:"string",required:!1,constraint:"Installed persona kind for node creates under this profile that omit --kind. Defaults to general when omitted; the daemon validates it against its installed kind registry."},{kind:"flag",name:"meta",type:"string",required:!1,repeatable:!0,constraint:"KEY=VALUE metadata entry (repeat per entry). KEY starts with a letter or digit, followed by letters, digits, `_`, or `-`. Each entry reaches every broker launched under the profile as `CRTR_PROFILE_META_<KEY>` env; readable back via `profile show` \u2014 not for secrets (those go to `profile env`)."}],output:[{name:"profile_id",type:"string",required:!0,constraint:"Stable directory id (`<slug>-<shortid>`). Pass this, or the name, to every other `profile` verb and to `--profile` elsewhere."},{name:"profile_path",type:"string",required:!0,constraint:"Absolute path to the profile directory, `<app space>/profiles/<id>`: its settings root. Documents the profile owns are canvas documents, read with `crtr canvas read`, not files here."},{name:"projects",type:"ProfileProject[]",required:!0,constraint:"Explicit `{path}` project relationships in manifest order. `path` defines purview. Empty when --project was omitted."},{name:"app",type:"string",required:!0,constraint:"The app that owns this profile."},{name:"default_kind",type:"string",required:!0,constraint:"Default persona kind for node creates that omit --kind; `general` when none is stored."},{name:"metadata",type:"object",required:!0,constraint:"Stored metadata map; empty when --meta was omitted."},{name:"created_at",type:"string",required:!0,constraint:"ISO 8601 creation timestamp."}],outputKind:"object",effects:["Creates a profile row owned by the caller's app (the terminal app for a person) and its directory under that app's space. A name the caller's app already holds is refused."]},run:i(async e=>{const t=e.name,r=e.project,a=e.defaultKind,o=c(e.meta,"meta");if(e.root===!0){if(t!==void 0||r!==void 0||a!==void 0||Object.keys(o).length>0)throw n("`--root` provisions the canonical stable root profile and takes no `--name`/`--project`/`--default-kind`/`--meta`.");return d(await s().ensureProfile("root"))}if(t===void 0)throw n("provide `--name <name>` to create a profile, or `--root` to provision the stable root profile.");return d(await s().createProfile({name:t,...r!==void 0?{projects:[{path:f(r)}]}:{},...a!==void 0?{default_kind:a}:{},...Object.keys(o).length>0?{metadata:o}:{}}))},"run")});function d(e){return{profile_id:e.id,profile_path:e.profile_path??e.memory_path,projects:e.projects,app:e.app,default_kind:e.default_kind,metadata:e.metadata,created_at:e.created_at}}i(d,"newProfileOutput");export{k as newLeaf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a=Object.defineProperty;var i=(r,e)=>a(r,"name",{value:e,configurable:!0});import{defineLeaf as n}from"../../core/command.js";import{resolveProfileViaDaemon as o}from"./daemon-profiles.js";const l=n({name:"show",description:"one profile's manifest in full",whenToUse:"you need a profile's full project list, owning app, id, and timestamps \u2014 after `profile list` narrows to a name, to find where its nodes will run, or to inspect what a node's bearings named as its profile.",help:{name:"profile show",summary:"print one profile's settings and directory path",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr. A name shared by several profiles fails listing every matching id."}],output:[{name:"profile_id",type:"string",required:!0,constraint:"Stable directory id."},{name:"name",type:"string",required:!0,constraint:"Manifest name."},{name:"projects",type:"ProfileProject[]",required:!0,constraint:"Explicit `{path}` relationships in manifest order. `path` defines profile purview."},{name:"app",type:"string",required:!0,constraint:"The app that owns this profile."},{name:"paused_at",type:"string | null",required:!0,constraint:"ISO 8601 pause timestamp, or null when the profile is active."},{name:"default_kind",type:"string",required:!0,constraint:"Default node kind for creates that omit --kind; `general` when none is stored."},{name:"metadata",type:"object",required:!0,constraint:"Stored metadata map \u2014 each entry reaches brokers launched under the profile as `CRTR_PROFILE_META_<KEY>` env. Empty when none."},{name:"created_at",type:"string",required:!0,constraint:"ISO 8601 creation timestamp."},{name:"last_used_at",type:"string | null",required:!0,constraint:"ISO 8601 timestamp of the most recent selection, or null if never selected."},{name:"profile_path",type:"string",required:!0,constraint:"Absolute path to the profile directory, `<app space>/profiles/<id>`: its settings root. Documents the profile owns are canvas documents, read with `crtr canvas read`, not files here."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands, including the SQL-backed raw settings surface."}],outputKind:"object",effects:["None. Read-only."]},run:i(async r=>{const e=await o(r.profile),t=e.id;return{profile_id:t,name:e.name,projects:e.projects,app:e.app,paused_at:e.paused_at,default_kind:e.default_kind,metadata:e.metadata,created_at:e.created_at,last_used_at:e.last_used_at,profile_path:e.profile_path??e.memory_path,follow_up:e.paused_at===null?`Inspect its SQL-backed settings with \`crtr sys config get-raw --scope profile --profile ${t}\`; manage its purview with \`crtr profile project add ${t} --dir <path>\`, pause it with \`crtr profile pause ${t}\`, or set its default kind with \`crtr profile kind ${t} <kind>\`.`:`Inspect its SQL-backed settings with \`crtr sys config get-raw --scope profile --profile ${t}\`; manage its purview with \`crtr profile project add ${t} --dir <path>\`, or resume it with \`crtr profile resume ${t}\`.`}},"run")});export{l as showLeaf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var ge=Object.defineProperty;var v=(p,e)=>ge(p,"name",{value:e,configurable:!0});import{envProfileId as pe}from"../../../shared/env.js";import{ModelSelectorComponent as $e,ThinkingSelectorComponent as ee}from"@earendil-works/pi-coding-agent";import{Input as ye,truncateToWidth as V}from"@earendil-works/pi-tui";import{basename as ve,dirname as ke,join as S}from"node:path";import{ANTHROPIC_PROVIDER_ID as be,OPENAI_CODEX_PROVIDER_ID as Re,isManagedProvider as we,readSubscriptionPool as xe}from"../../../core/subscription-state.js";import{readRawConfigAtRoot as P,persistDefaultKindModel as Me,persistModelLadders as te,persistModelRoute as ie,readMergedLaunchConfig as re}from"../../../core/config.js";import{findProjectScopeRoots as Ie,userScopeRoot as Se}from"../../../core/scope.js";import{loadProfileManifest as Pe,profileMemoryDir as Ce}from"../../../core/profiles/manifest.js";import{configuredLadderProviders as Te,inferPortableModelSelection as q,MODEL_PROVIDER_KEYS as oe,MODEL_STRENGTHS as k,THINKING_SUFFIXES as se}from"../../../core/runtime/model-selection.js";import{fitTail as U,padAnsi as f,renderRows as Fe,theme as o,wrapText as Oe}from"../../../core/tui/panel.js";const ne=3,Le={anthropic:be,openai:Re},ce={anthropic:"Anthropic",openai:"OpenAI"},de=[{mode:"base",dimension:"family"},{mode:"base",dimension:"strength"},{mode:"orchestrator",dimension:"family"},{mode:"orchestrator",dimension:"strength"}];function Ee(){const p=Se(),e=pe()||null;let t;if(e!==null)try{const s=Pe(e);t={label:`Profile: ${s.manifest.name}`,root:Ce(s.profileId)}}catch{}const i=Ie(process.cwd(),e),r=i.map(s=>({label:`Project: ${ve(ke(s))}`,root:s}));return{targets:[{label:"User",root:p},...t?[t]:[],...r],precedenceRoots:[...i,...t?[t.root]:[],p]}}v(Ee,"modelConfigTargets");function j(p){if(!p)return{};const e=p.trim(),t=e.indexOf("/"),i=t===-1?void 0:e.slice(0,t),r=t===-1?e:e.slice(t+1),s=r.match(/^(.*?):(off|minimal|low|medium|high|xhigh|max)$/i);return{provider:i,id:s?s[1]:r,level:s?s[2].toLowerCase():void 0}}v(j,"parseModelRef");function G(p){if(!p)return"\u2014";const e=p.indexOf("/");return e===-1?p:p.slice(e+1)}v(G,"shortRef");class Xe{static{v(this,"ModelsPanel")}tui;runtime;registry;matches;label;mode="list";ladders;modelRoutes;legacyModelRoutes;kinds;providerKeys=oe;targets;precedenceRoots;targetIndex=0;rawTarget;rows=[];selected=0;column=0;notice="";modelSelector;thinkingSelector;pending;choice;choiceIndex=0;routeForm;routeInput=new ye;pendingRouteCell;onChange;constructor(e,t,i,r,s){this.tui=e,this.runtime=t,this.registry=i,this.matches=r,this.label=s;const n=Ee();this.targets=n.targets,this.precedenceRoots=n.precedenceRoots,this.rawTarget=P(this.currentTarget().root);const c=re();this.ladders=c.modelLadders,this.modelRoutes=c.modelRoutes??{},this.legacyModelRoutes=c.legacyModelRoutes??{},this.kinds=c.kinds,this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.routeInput.onSubmit=l=>{const u=this.routeForm;!u||u.editing===null||(u.text[u.editing]=l.trim(),u.editing=null,this.routeInput.focused=!1,this.notify())},this.routeInput.onEscape=()=>{this.routeForm&&(this.routeForm.editing=null,this.routeInput.focused=!1,this.notify())}}offeredProviders(){try{return Te(e=>we(e)&&xe(e).length>0||this.registry.getProviderAuthStatus(e).configured,this.ladders)}catch{return oe}}currentTarget(){return this.targets[this.targetIndex]}cycleTarget(){this.targetIndex=(this.targetIndex+1)%this.targets.length,this.rawTarget=P(this.currentTarget().root),this.notice="",this.notify()}shadowingPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)break;const i=P(t);if(i&&e(i))return S(t,"config.json")}}savedButShadowed(e){return`Saved to ${this.currentTarget().label}; overridden by ${e??"a more specific config"}`}routeIds(){return[...new Set([...Object.keys(this.modelRoutes),...Object.keys(this.legacyModelRoutes)])]}routeFamilies(){return[...new Set(this.routeIds().map(e=>(this.modelRoutes[e]??this.legacyModelRoutes[e]).family))]}buildRows(){const e=[{section:"ladder",kind:"defaultProvider"}];for(const t of k)e.push({section:"ladder",kind:"strength",strength:t});for(const t of this.routeIds())e.push({section:"route",routeId:t});e.push({section:"route",routeId:null});for(const t of Object.keys(this.kinds))t.includes("/")||e.push({section:"kind",name:t});return e}reload(){const e=re();this.ladders=e.modelLadders,this.modelRoutes=e.modelRoutes??{},this.legacyModelRoutes=e.legacyModelRoutes??{},this.kinds=e.kinds,this.rawTarget=P(this.currentTarget().root),this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.selected=Math.min(this.selected,this.rows.length-1),this.clampColumn()}refresh(){this.reload(),this.notify()}notify(){this.onChange?.(),this.tui.requestRender()}isPickerOpen(){return this.mode!=="list"}currentRow(){return this.rows[Math.min(this.selected,this.rows.length-1)]}columnsFor(e){return e.section==="ladder"?e.kind==="strength"?this.providerKeys.length:1:e.section==="route"?1:de.length}clampColumn(){this.column=Math.min(this.column,this.columnsFor(this.currentRow())-1)}handleInput(e){if(this.mode==="route-form"){const t=this.routeForm;return t?t.editing!==null?(this.routeInput.handleInput(e),!0):this.matches("crtr.setup.models.cancel",e)?(this.closeRouteForm(),!0):this.matches("crtr.setup.list-down",e)?(t.index=Math.min(t.fields.length-1,t.index+1),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(t.index=Math.max(0,t.index-1),this.notice="",!0):((this.matches("crtr.setup.models.open",e)||this.matches("crtr.setup.models.commit",e))&&this.activateRouteField(),!0):(this.mode="list",!0)}if(this.mode==="route-delete")return this.matches("crtr.setup.confirm.accept",e)?(this.deleteRoute(),!0):(this.matches("crtr.setup.confirm.back",e)&&(this.mode="route-form",this.notify()),!0);if(this.mode==="dimension-picker")return this.matches("crtr.setup.models.commit",e)?(this.commitChoice(),!0):this.matches("crtr.setup.models.cancel",e)?(this.closePicker(),!0):this.matches("crtr.setup.list-down",e)?(this.choiceIndex=Math.min((this.choice?.options.length??1)-1,this.choiceIndex+1),!0):(this.matches("crtr.setup.list-up",e)&&(this.choiceIndex=Math.max(0,this.choiceIndex-1)),!0);if(this.mode==="model-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.modelSelector?.handleInput(t),!0}if(this.mode==="thinking-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.thinkingSelector?.getSelectList().handleInput(t),!0}return this.matches("crtr.setup.list-down",e)?(this.selected=Math.min(this.rows.length-1,this.selected+1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(this.selected=Math.max(0,this.selected-1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.cell-previous",e)?(this.column=Math.max(0,this.column-1),!0):this.matches("crtr.setup.cell-next",e)?(this.column=Math.min(this.columnsFor(this.currentRow())-1,this.column+1),!0):this.matches("crtr.setup.models.scope-next",e)?(this.cycleTarget(),!0):this.matches("crtr.setup.models.open",e)?(this.activateCell(),!0):!1}activateCell(){const e=this.currentRow();if(this.notice="",e.section==="ladder"&&e.kind==="defaultProvider"){const t=q(void 0,this.ladders).provider,i=this.providerKeys,r=i[(Math.max(0,i.indexOf(t))+1)%i.length];if(r===t)return;try{te(this.currentTarget().root,{defaultProvider:r})}catch(s){this.notice=`Could not save: ${s instanceof Error?s.message:String(s)}`,this.notify();return}if(this.reload(),(this.ladders.defaultProvider??"anthropic")!==r){const s=this.shadowingPath(n=>n.modelLadders?.defaultProvider!==void 0);this.notice=this.savedButShadowed(s)}this.notify();return}if(e.section==="ladder"&&e.kind==="strength"){this.openModelPicker(this.providerKeys[this.column],e.strength);return}if(e.section==="route"){this.openRouteForm(e.routeId);return}if(e.section==="kind"){const t=de[this.column];if(!t)return;this.openDimensionPicker(e.name,t.mode,t.dimension)}}portableSelection(e){if(e!==void 0){const i=e.lastIndexOf("/"),r=i===-1?"":e.slice(0,i),s=i===-1?"":e.slice(i+1);if(this.routeFamilies().includes(r)&&k.includes(s))return{family:r,strength:s}}const t=q(e,this.ladders);return{family:t.provider,strength:t.strength}}familyLabel(e){return e==="anthropic"||e==="openai"?ce[e]:e}familyOptions(){return[...new Set([...this.providerKeys,...this.routeFamilies()])]}kindSelection(e,t){const i=this.kinds[e],r=t==="orchestrator"?i?.orchestratorModel??i?.model:i?.model;return this.portableSelection(r)}openDimensionPicker(e,t,i){const r=this.kindSelection(e,t),s=i==="family"?this.familyOptions():k,n=i==="family"?r.family:r.strength,c=t==="orchestrator"?"orchestrator":"base",l=i==="family"?`strength ${r.strength}`:`family ${this.familyLabel(r.family)}`;this.choice={title:`Choose ${c} ${i}`,subtitle:`${e} \xB7 keeps ${c} ${l}`,options:s,label:v(u=>i==="family"?this.familyLabel(u):u,"label"),commit:v(u=>{const m=i==="family"?u:r.family,a=i==="strength"?u:r.strength;this.writeKindSelection(e,t,m,a)},"commit")},this.choiceIndex=Math.max(0,s.indexOf(n)),this.mode="dimension-picker",this.notify()}writeKindSelection(e,t,i,r){const s=`${i}/${r}`;try{Me({root:this.currentTarget().root,kind:e,model:s,orchestrator:t==="orchestrator"})}catch(l){this.notice=`Could not save: ${l instanceof Error?l.message:String(l)}`;return}this.reload();const n=this.kinds[e];if((t==="orchestrator"?n?.orchestratorModel:n?.model)!==s){const l=t==="orchestrator"?"orchestratorModel":"model",u=this.shadowingPath(m=>m.kinds?.[e]?.[l]!==void 0);this.notice=this.savedButShadowed(u)}}commitChoice(){const e=this.choice,t=e?.options[this.choiceIndex];e&&t!==void 0&&e.commit(t),this.closePicker()}openRouteForm(e){const t=e===null?void 0:this.modelRoutes[e]??this.legacyModelRoutes[e],i=[...e===null?[{kind:"text",key:"routeId",label:"Route id"}]:[],{kind:"text",key:"family",label:"Family"},{kind:"text",key:"credentialSource",label:"Credential source"},{kind:"provider",label:"Provider id"},...k.map(r=>({kind:"cell",strength:r})),{kind:"save"},...e===null?[]:[{kind:"delete"}]];this.routeForm={existing:e,text:{routeId:e??"",family:t?.family??"",credentialSource:t?.credentialSource??""},providerId:t?.providerId??"",models:{...t?.models},fields:i,index:0,editing:null},this.mode="route-form",this.notice="",this.notify()}closeRouteForm(){this.routeInput.focused=!1,this.routeForm=void 0,this.mode="list",this.notice="",this.notify()}activateRouteField(){const e=this.routeForm,t=e?.fields[e.index];if(!(!e||!t)){if(t.kind==="text"){e.editing=t.key,this.routeInput.setValue(e.text[t.key]),this.routeInput.handleInput(""),this.routeInput.focused=!0,this.notify();return}if(t.kind==="provider"){const i=[...new Set([...this.registry.getAll().map(r=>r.provider),...e.providerId?[e.providerId]:[]])].sort();this.choice={title:"Choose provider id",subtitle:"Route cells must all belong to this registry provider",options:i,label:v(r=>r,"label"),commit:v(r=>this.setRouteProvider(r),"commit")},this.choiceIndex=Math.max(0,i.indexOf(e.providerId)),this.mode="dimension-picker",this.notify();return}if(t.kind==="cell"){this.openRouteCell(t.strength);return}if(t.kind==="save"){this.saveRoute();return}this.mode="route-delete",this.notify()}}setRouteProvider(e){const t=this.routeForm;if(!t)return;t.providerId=e;const i=[];for(const r of k){const s=t.models[r];s!==void 0&&!s.startsWith(`${e}/`)&&(delete t.models[r],i.push(r))}this.notice=i.length===0?"":`Cleared ${i.join(", ")} because those models belong to another provider.`}openRouteCell(e){const t=this.routeForm;if(!t)return;if(!t.providerId){this.notice="Choose the provider id first",this.notify();return}const i=this.registry.getAll().filter(n=>n.provider===t.providerId);if(i.length===0){this.notice=`No models registered for provider "${t.providerId}" \u2014 this route cannot be edited here.`,this.notify();return}const r=j(t.models[e]),s=r.provider&&r.id?this.registry.find(r.provider,r.id):void 0;this.pendingRouteCell={strength:e},this.showModelSelector(i,s,n=>this.onRouteModelPicked(n))}onRouteModelPicked(e){const t=this.pendingRouteCell,i=this.routeForm;if(!t||!i){this.closePicker();return}if(e.provider!==i.providerId){this.notice=`That is a ${e.provider} model \u2014 pick a ${i.providerId} model for this route.`,this.closePicker();return}if(t.model=e,e.reasoning){const r=j(i.models[t.strength]).level??"medium";this.thinkingSelector=new ee(r,[...se],s=>this.onThinkingPicked(s),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}i.models[t.strength]=`${e.provider}/${e.id}`,this.closePicker()}saveRoute(){const e=this.routeForm;if(!e)return;const t=e.text.routeId.trim();if(!t){this.notice="Route id is required.",this.notify();return}if(!e.text.family.trim()){this.notice="Family is required.",this.notify();return}if(!e.text.credentialSource.trim()){this.notice="Credential source is required.",this.notify();return}if(!e.providerId.trim()){this.notice="Provider id is required.",this.notify();return}const i=k.filter(n=>e.models[n]===void 0);if(i.length>0){this.notice=`Choose models for ${i.join(", ")} before saving.`,this.notify();return}const r={family:e.text.family.trim(),credentialSource:e.text.credentialSource.trim(),providerId:e.providerId.trim(),models:{ultra:e.models.ultra,strong:e.models.strong,medium:e.models.medium,light:e.models.light}};try{ie(this.currentTarget().root,t,r)}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`,this.notify();return}this.routeForm=void 0,this.mode="list",this.reload();const s=this.rows.findIndex(n=>n.section==="route"&&n.routeId===t);if(s>=0&&(this.selected=s),JSON.stringify(this.modelRoutes[t])!==JSON.stringify(r)){const n=this.shadowingPath(c=>c.modelRoutes?.[t]!==void 0);this.notice=this.savedButShadowed(n)}else this.notice=`Saved route "${t}" to ${this.currentTarget().label}.`;this.notify()}declaringPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)continue;if(P(t)?.modelRoutes?.[e]!==void 0)return S(t,"config.json")}}deleteRoute(){const e=this.routeForm?.existing;if(!e){this.mode="route-form",this.notify();return}try{ie(this.currentTarget().root,e,void 0)}catch(i){this.mode="route-form",this.notice=`Could not delete: ${i instanceof Error?i.message:String(i)}`,this.notify();return}const t=this.declaringPath(e);this.routeForm=void 0,this.mode="list",this.reload(),this.notice=t?`Removed route "${e}" from ${this.currentTarget().label}; it is still declared by ${t}.`:`Removed route "${e}" from ${this.currentTarget().label}.`,this.notify()}showModelSelector(e,t,i){this.modelSelector=new $e(this.tui,t,this.runtime,e.map(r=>({model:r})),i,()=>this.closePicker()),this.modelSelector.focused=!0,this.mode="model-picker",this.notify()}openModelPicker(e,t){const i=Le[e],r=this.registry,s=j(this.ladders[e][t]),n=s.provider&&s.id?r.find(s.provider,s.id):void 0,c=r.getAvailable().filter(l=>l.provider===i);if(c.length===0){this.notice=`No ${e} models available \u2014 sign in first.`,this.notify();return}this.pending={providerKey:e,strength:t,expectedRuntime:i},this.showModelSelector(c,n,l=>this.onModelPicked(l))}onModelPicked(e){if(!this.pending){this.closePicker();return}if(e.provider!==this.pending.expectedRuntime){this.notice=`That is a ${e.provider} model \u2014 pick an ${this.pending.providerKey} model for this column.`,this.closePicker();return}if(this.pending.model=e,e.reasoning){const t=j(this.ladders[this.pending.providerKey][this.pending.strength]).level??"medium";this.thinkingSelector=new ee(t,[...se],i=>this.onThinkingPicked(i),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}this.writeLadder(e,void 0),this.closePicker()}onThinkingPicked(e){if(this.pendingRouteCell?.model&&this.routeForm){const{model:t,strength:i}=this.pendingRouteCell;this.routeForm.models[i]=`${t.provider}/${t.id}${e!=="off"?`:${e}`:""}`}else this.pending?.model&&this.writeLadder(this.pending.model,e);this.closePicker()}writeLadder(e,t){if(!this.pending)return;const i=`${e.provider}/${e.id}${t&&t!=="off"?`:${t}`:""}`,{providerKey:r,strength:s}=this.pending;try{te(this.currentTarget().root,{[r]:{[s]:i}})}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`;return}if(this.reload(),this.ladders[r][s]!==i){const n=this.shadowingPath(c=>c.modelLadders?.[r]?.[s]!==void 0);this.notice=this.savedButShadowed(n)}}closePicker(){this.mode=this.routeForm!==void 0?"route-form":"list",this.modelSelector=void 0,this.thinkingSelector=void 0,this.pending=void 0,this.pendingRouteCell=void 0,this.choice=void 0,this.notify()}dispose(){this.routeForm=void 0,this.closePicker()}targetLadderOverride(e,t){return this.rawTarget?.modelLadders?.[e]?.[t]!==void 0}targetKindOverride(e,t){const i=this.rawTarget?.kinds,r=t?"orchestratorModel":"model";return i?.[e]?.[r]!==void 0}footerHint(){return this.mode==="dimension-picker"?`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} choice \xB7 ${this.label("crtr.setup.models.commit")} save \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="model-picker"?`type to search \xB7 ${this.label("crtr.setup.models.commit")} select \xB7 tab all/scoped \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="thinking-picker"?`\u2191/\u2193 level \xB7 ${this.label("crtr.setup.models.commit")} set \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="route-delete"?`${this.label("crtr.setup.confirm.accept")} delete \xB7 ${this.label("crtr.setup.confirm.back")} cancel`:this.mode==="route-form"?typeof this.routeForm?.editing=="string"?"type a value \xB7 enter save \xB7 esc cancel":`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} field \xB7 ${this.label("crtr.setup.models.open")} edit \xB7 ${this.label("crtr.setup.models.cancel")} back`:""}renderChoicePicker(){const e=this.choice;if(!e)return[o.fg("warning","No setting selected.")];const t=[o.fg("accent",o.bold(e.title)),o.fg("dim",e.subtitle),""];for(const[i,r]of e.options.entries()){const s=i===this.choiceIndex,n=s?o.fg("accent","\u25B6"):" ",c=e.label(r);t.push(`${n} ${s?o.fg("accent",`[${c}]`):o.fg("dim",` ${c} `)}`)}return t}renderRouteForm(e){const t=this.routeForm;if(!t)return[o.fg("warning","No route selected.")];const i=this.currentTarget(),r=[o.fg("accent",o.bold(t.existing===null?"New provider route":`Provider route: ${t.existing}`)),o.fg("dim",`${i.label} \xB7 ${S(i.root,"config.json")}`),""],s=20;for(const[n,c]of t.fields.entries()){const l=n===t.index,u=l?o.fg("accent","\u25B6"):" ";let m,a;if(c.kind==="text"){if(m=c.label,a=t.text[c.key]||"\u2014",l&&t.editing===c.key){const K=Math.max(8,e-s-4);a=this.routeInput.render(K)[0]??""}}else c.kind==="provider"?(m=c.label,a=t.providerId||"\u2014"):c.kind==="cell"?(m=c.strength,a=G(t.models[c.strength])):c.kind==="save"?(m="",a="Save route"):(m="",a="Delete route");const C=a==="\u2014",T=l?o.fg("accent",`[${a}]`):o.fg(C?"warning":"dim",` ${a} `);r.push(`${u} ${f(m,s)}${T}`)}return this.notice&&r.push("",o.fg("warning",this.notice)),r}renderRouteDelete(e){const t=this.routeForm?.existing??"this route",i=this.currentTarget(),r=Oe(`This removes the entry from ${i.label}. Any "${t}" declared by a lower-precedence config becomes effective again; this does not guarantee the route is gone.`,e).map(s=>o.fg("warning",s));return[o.fg("accent",o.bold(`Delete provider route: ${t}`)),o.fg("dim",S(i.root,"config.json")),"",...r,"",o.fg("dim",`${this.label("crtr.setup.confirm.accept")} delete ${this.label("crtr.setup.confirm.back")} cancel`)]}fitBody(e,t,i){if(e.length<=i)return e;const r=Math.min(ne,e.length-i),s=e.slice(r);if(s.length<=i)return s;const n=Math.max(0,t-r),c=Math.max(0,Math.min(n-i+2,s.length-i));return s.slice(c,c+i)}render(e,t){const i=Math.max(1,t),r=v(d=>Fe(d,e),"frame");if(this.mode==="dimension-picker")return r(this.fitBody(this.renderChoicePicker(),ne+this.choiceIndex,i));if(this.mode==="model-picker")return r(U(this.modelSelector?.render(e)??[],i));if(this.mode==="thinking-picker")return r(U(this.thinkingSelector?.render(e)??[],i));if(this.mode==="route-form"){const d=3+(this.routeForm?.index??0);return r(this.fitBody(this.renderRouteForm(e),d,i))}if(this.mode==="route-delete")return r(U(this.renderRouteDelete(e),i));let s=0;const n=[o.fg("accent",o.bold("Models")),o.fg("dim","global user defaults \xB7 project/profile scopes can shadow these"),""],c=this.currentRow(),l=c.section==="ladder"&&c.kind==="strength",u=Math.max(1,e),m=Math.max(12,Math.min(20,Math.floor(u*.24))),a=this.providerKeys.length,C=Math.max(1,u-2-m),T=12,K=Math.max(1,Math.floor((C+1)/(T+1))),b=Math.min(a,K),N=Math.max(T,Math.floor((C-(b-1))/b)),J=l?Math.min(this.column,a-1):0,F=Math.max(0,Math.min(J>=b?J-b+1:0,a-b)),_=F+b,X=this.providerKeys.map((d,h)=>({provider:d,column:h})).slice(F,_),Y=F>0,z=_<a,he=Y||z?` ${o.fg("dim",`${Y?"\u2039 ":""}${F+1}\u2013${_} of ${a}${z?" \u203A":""}`)}`:"",O=this.currentTarget();n.push(`${o.fg("accent","Editing config")} ${o.fg("accent",`[${O.label}]`)}${o.fg("dim",` ${this.targetIndex+1}/${this.targets.length}`)}`),n.push(o.fg("muted",S(O.root,"config.json")),""),n.push(o.fg("accent","Strength ladders")+he);const le=q(void 0,this.ladders).provider,W=this.rows.find(d=>d.section==="ladder"&&d.kind==="defaultProvider")===c;W&&(s=n.length),n.push(`${W?o.fg("accent","\u25B6"):" "} ${f(W?o.fg("accent","Default provider"):"Default provider",20)} ${o.fg("success",le)}`);const ue=v((d,h)=>{const g=f(o.bold(ce[d]),N);return l&&this.column===h?o.fg("accent",g):o.fg("dim",g)},"providerHeading"),ae=v((d,h)=>{const g=f(V(d,Math.max(1,N-2)),Math.max(1,N-2));return h?o.fg("accent",`[${g}]`):o.fg("dim",` ${g} `)},"ladderCell");n.push(`${" ".repeat(2)}${f(o.fg("dim","Strength"),m)}${X.map(({provider:d,column:h})=>ue(d,h)).join(" ")}`);for(const d of this.rows){if(d.section!=="ladder"||d.kind!=="strength")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=X.map(({provider:y,column:R})=>{const w=this.targetLadderOverride(y,d.strength)?o.fg("warning","\u2022"):" ";return ae(`${w}${G(this.ladders[y][d.strength])}`,h&&R===this.column)});n.push(`${g} ${f(d.strength,m)}${$.join(" ")}`)}n.push("",o.fg("accent","Provider routes")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 a declared route replaces the ladders above at launch \xB7 id, then family \xB7 source \xB7 provider`));const A=Math.max(10,Math.floor((u-8)/4));n.push(`${" ".repeat(4)}${k.map(d=>f(o.fg("dim",d),A)).join(" ")}`),this.routeIds().length===0&&n.push(o.fg("dim"," No routes declared \u2014 the ladders above are used."));for(const d of this.rows){if(d.section!=="route"||d.routeId===null)continue;const h=d.routeId,g=this.modelRoutes[h],$=g??this.legacyModelRoutes[h],y=d===c;y&&(s=n.length);const R=y?o.fg("accent","\u25B6"):" ",w=this.rawTarget?.modelRoutes?.[h]!==void 0?o.fg("warning","\u2022"):" ",E=g?"":o.fg("warning"," \xB7 incomplete"),D=o.fg("dim",`${$.family} \xB7 ${$.credentialSource} \xB7 ${$.providerId}`);n.push(`${R} ${w}${o.fg(y?"accent":"dim",h)} ${D}${E}`);const x=k.map(fe=>{const Z=$.models[fe],me=f(V(G(Z),A),A);return o.fg(Z===void 0?"warning":"dim",me)});n.push(`${" ".repeat(4)}${x.join(" ")}`)}const B=this.rows.find(d=>d.section==="route"&&d.routeId===null)===c;B&&(s=n.length),n.push(`${B?o.fg("accent","\u25B6"):" "} ${o.fg(B?"accent":"dim","+ New route")}`),n.push("",o.fg("accent","Kind defaults")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 orchestrator inherits base until you set it`));const H=16,M=12,I=9,Q=M+1+I,L=v((d,h,g,$)=>{const y=f(V(d,Math.max(1,h-2)),Math.max(1,h-2));return g?o.fg("accent",`[${y}]`):$?o.fg("muted",` ${y} `):o.fg("dim",` ${y} `)},"cell");n.push(`${" ".repeat(2+H)}${f(o.bold(o.fg("dim","Base")),Q)} ${f(o.bold(o.fg("dim","Orchestrator")),Q)}`),n.push(`${" ".repeat(2)}${f(o.fg("dim","Kind"),H)}${f(o.fg("dim","Family"),M)} ${f(o.fg("dim","Strength"),I)} ${f(o.fg("dim","Family"),M)} ${f(o.fg("dim","Strength"),I)}`);for(const d of this.rows){if(d.section!=="kind")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=this.kinds[d.name],y=this.portableSelection($?.model),R=$?.orchestratorModel===void 0,w=this.portableSelection($?.orchestratorModel??$?.model),E=this.targetKindOverride(d.name,!1)?o.fg("warning","\u2022"):" ",D=this.targetKindOverride(d.name,!0)?o.fg("warning","\u2022"):" ",x=[L(`${E}${this.familyLabel(y.family)}`,M,h&&this.column===0,!1),L(`${E}${y.strength}`,I,h&&this.column===1,!1),L(`${D}${this.familyLabel(w.family)}`,M,h&&this.column===2,R),L(`${D}${w.strength}`,I,h&&this.column===3,R)];n.push(`${g} ${f(d.name,H)}${x[0]} ${x[1]} ${x[2]} ${x[3]}`)}return this.notice&&n.push("",o.fg("warning",this.notice)),r(this.fitBody(n,s,i))}}export{Xe as ModelsPanel};
|
|
1
|
+
var ge=Object.defineProperty;var y=(p,e)=>ge(p,"name",{value:e,configurable:!0});import{envProfileId as pe}from"../../../shared/env.js";import{ModelSelectorComponent as $e,ThinkingSelectorComponent as ee}from"@earendil-works/pi-coding-agent";import{Input as ve,truncateToWidth as V}from"@earendil-works/pi-tui";import{basename as ye,dirname as ke,join as S}from"node:path";import{ANTHROPIC_PROVIDER_ID as be,OPENAI_CODEX_PROVIDER_ID as Re,isManagedProvider as we,readSubscriptionPool as xe}from"../../../core/subscription-state.js";import{readRawConfigAtRoot as P,persistDefaultKindModel as Ie,persistModelLadders as te,persistModelRoute as ie,readMergedLaunchConfig as re}from"../../../core/config.js";import{findProjectScopeRoots as Me,userScopeRoot as Se}from"../../../core/scope.js";import{loadProfileManifest as Pe,profileDir as Ce}from"../../../core/profiles/manifest.js";import{configuredLadderProviders as Te,inferPortableModelSelection as q,MODEL_PROVIDER_KEYS as oe,MODEL_STRENGTHS as k,THINKING_SUFFIXES as se}from"../../../core/runtime/model-selection.js";import{fitTail as U,padAnsi as f,renderRows as Fe,theme as o,wrapText as Oe}from"../../../core/tui/panel.js";const ne=3,Le={anthropic:be,openai:Re},ce={anthropic:"Anthropic",openai:"OpenAI"},de=[{mode:"base",dimension:"family"},{mode:"base",dimension:"strength"},{mode:"orchestrator",dimension:"family"},{mode:"orchestrator",dimension:"strength"}];function Ee(){const p=Se(),e=pe()||null;let t;if(e!==null)try{const s=Pe(e);t={label:`Profile: ${s.manifest.name}`,root:Ce(s.profileId)}}catch{}const i=Me(process.cwd(),e),r=i.map(s=>({label:`Project: ${ye(ke(s))}`,root:s}));return{targets:[{label:"User",root:p},...t?[t]:[],...r],precedenceRoots:[...i,...t?[t.root]:[],p]}}y(Ee,"modelConfigTargets");function j(p){if(!p)return{};const e=p.trim(),t=e.indexOf("/"),i=t===-1?void 0:e.slice(0,t),r=t===-1?e:e.slice(t+1),s=r.match(/^(.*?):(off|minimal|low|medium|high|xhigh|max)$/i);return{provider:i,id:s?s[1]:r,level:s?s[2].toLowerCase():void 0}}y(j,"parseModelRef");function G(p){if(!p)return"\u2014";const e=p.indexOf("/");return e===-1?p:p.slice(e+1)}y(G,"shortRef");class Xe{static{y(this,"ModelsPanel")}tui;runtime;registry;matches;label;mode="list";ladders;modelRoutes;legacyModelRoutes;kinds;providerKeys=oe;targets;precedenceRoots;targetIndex=0;rawTarget;rows=[];selected=0;column=0;notice="";modelSelector;thinkingSelector;pending;choice;choiceIndex=0;routeForm;routeInput=new ve;pendingRouteCell;onChange;constructor(e,t,i,r,s){this.tui=e,this.runtime=t,this.registry=i,this.matches=r,this.label=s;const n=Ee();this.targets=n.targets,this.precedenceRoots=n.precedenceRoots,this.rawTarget=P(this.currentTarget().root);const c=re();this.ladders=c.modelLadders,this.modelRoutes=c.modelRoutes??{},this.legacyModelRoutes=c.legacyModelRoutes??{},this.kinds=c.kinds,this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.routeInput.onSubmit=l=>{const u=this.routeForm;!u||u.editing===null||(u.text[u.editing]=l.trim(),u.editing=null,this.routeInput.focused=!1,this.notify())},this.routeInput.onEscape=()=>{this.routeForm&&(this.routeForm.editing=null,this.routeInput.focused=!1,this.notify())}}offeredProviders(){try{return Te(e=>we(e)&&xe(e).length>0||this.registry.getProviderAuthStatus(e).configured,this.ladders)}catch{return oe}}currentTarget(){return this.targets[this.targetIndex]}cycleTarget(){this.targetIndex=(this.targetIndex+1)%this.targets.length,this.rawTarget=P(this.currentTarget().root),this.notice="",this.notify()}shadowingPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)break;const i=P(t);if(i&&e(i))return S(t,"config.json")}}savedButShadowed(e){return`Saved to ${this.currentTarget().label}; overridden by ${e??"a more specific config"}`}routeIds(){return[...new Set([...Object.keys(this.modelRoutes),...Object.keys(this.legacyModelRoutes)])]}routeFamilies(){return[...new Set(this.routeIds().map(e=>(this.modelRoutes[e]??this.legacyModelRoutes[e]).family))]}buildRows(){const e=[{section:"ladder",kind:"defaultProvider"}];for(const t of k)e.push({section:"ladder",kind:"strength",strength:t});for(const t of this.routeIds())e.push({section:"route",routeId:t});e.push({section:"route",routeId:null});for(const t of Object.keys(this.kinds))t.includes("/")||e.push({section:"kind",name:t});return e}reload(){const e=re();this.ladders=e.modelLadders,this.modelRoutes=e.modelRoutes??{},this.legacyModelRoutes=e.legacyModelRoutes??{},this.kinds=e.kinds,this.rawTarget=P(this.currentTarget().root),this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.selected=Math.min(this.selected,this.rows.length-1),this.clampColumn()}refresh(){this.reload(),this.notify()}notify(){this.onChange?.(),this.tui.requestRender()}isPickerOpen(){return this.mode!=="list"}currentRow(){return this.rows[Math.min(this.selected,this.rows.length-1)]}columnsFor(e){return e.section==="ladder"?e.kind==="strength"?this.providerKeys.length:1:e.section==="route"?1:de.length}clampColumn(){this.column=Math.min(this.column,this.columnsFor(this.currentRow())-1)}handleInput(e){if(this.mode==="route-form"){const t=this.routeForm;return t?t.editing!==null?(this.routeInput.handleInput(e),!0):this.matches("crtr.setup.models.cancel",e)?(this.closeRouteForm(),!0):this.matches("crtr.setup.list-down",e)?(t.index=Math.min(t.fields.length-1,t.index+1),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(t.index=Math.max(0,t.index-1),this.notice="",!0):((this.matches("crtr.setup.models.open",e)||this.matches("crtr.setup.models.commit",e))&&this.activateRouteField(),!0):(this.mode="list",!0)}if(this.mode==="route-delete")return this.matches("crtr.setup.confirm.accept",e)?(this.deleteRoute(),!0):(this.matches("crtr.setup.confirm.back",e)&&(this.mode="route-form",this.notify()),!0);if(this.mode==="dimension-picker")return this.matches("crtr.setup.models.commit",e)?(this.commitChoice(),!0):this.matches("crtr.setup.models.cancel",e)?(this.closePicker(),!0):this.matches("crtr.setup.list-down",e)?(this.choiceIndex=Math.min((this.choice?.options.length??1)-1,this.choiceIndex+1),!0):(this.matches("crtr.setup.list-up",e)&&(this.choiceIndex=Math.max(0,this.choiceIndex-1)),!0);if(this.mode==="model-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.modelSelector?.handleInput(t),!0}if(this.mode==="thinking-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.thinkingSelector?.getSelectList().handleInput(t),!0}return this.matches("crtr.setup.list-down",e)?(this.selected=Math.min(this.rows.length-1,this.selected+1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(this.selected=Math.max(0,this.selected-1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.cell-previous",e)?(this.column=Math.max(0,this.column-1),!0):this.matches("crtr.setup.cell-next",e)?(this.column=Math.min(this.columnsFor(this.currentRow())-1,this.column+1),!0):this.matches("crtr.setup.models.scope-next",e)?(this.cycleTarget(),!0):this.matches("crtr.setup.models.open",e)?(this.activateCell(),!0):!1}activateCell(){const e=this.currentRow();if(this.notice="",e.section==="ladder"&&e.kind==="defaultProvider"){const t=q(void 0,this.ladders).provider,i=this.providerKeys,r=i[(Math.max(0,i.indexOf(t))+1)%i.length];if(r===t)return;try{te(this.currentTarget().root,{defaultProvider:r})}catch(s){this.notice=`Could not save: ${s instanceof Error?s.message:String(s)}`,this.notify();return}if(this.reload(),(this.ladders.defaultProvider??"anthropic")!==r){const s=this.shadowingPath(n=>n.modelLadders?.defaultProvider!==void 0);this.notice=this.savedButShadowed(s)}this.notify();return}if(e.section==="ladder"&&e.kind==="strength"){this.openModelPicker(this.providerKeys[this.column],e.strength);return}if(e.section==="route"){this.openRouteForm(e.routeId);return}if(e.section==="kind"){const t=de[this.column];if(!t)return;this.openDimensionPicker(e.name,t.mode,t.dimension)}}portableSelection(e){if(e!==void 0){const i=e.lastIndexOf("/"),r=i===-1?"":e.slice(0,i),s=i===-1?"":e.slice(i+1);if(this.routeFamilies().includes(r)&&k.includes(s))return{family:r,strength:s}}const t=q(e,this.ladders);return{family:t.provider,strength:t.strength}}familyLabel(e){return e==="anthropic"||e==="openai"?ce[e]:e}familyOptions(){return[...new Set([...this.providerKeys,...this.routeFamilies()])]}kindSelection(e,t){const i=this.kinds[e],r=t==="orchestrator"?i?.orchestratorModel??i?.model:i?.model;return this.portableSelection(r)}openDimensionPicker(e,t,i){const r=this.kindSelection(e,t),s=i==="family"?this.familyOptions():k,n=i==="family"?r.family:r.strength,c=t==="orchestrator"?"orchestrator":"base",l=i==="family"?`strength ${r.strength}`:`family ${this.familyLabel(r.family)}`;this.choice={title:`Choose ${c} ${i}`,subtitle:`${e} \xB7 keeps ${c} ${l}`,options:s,label:y(u=>i==="family"?this.familyLabel(u):u,"label"),commit:y(u=>{const m=i==="family"?u:r.family,a=i==="strength"?u:r.strength;this.writeKindSelection(e,t,m,a)},"commit")},this.choiceIndex=Math.max(0,s.indexOf(n)),this.mode="dimension-picker",this.notify()}writeKindSelection(e,t,i,r){const s=`${i}/${r}`;try{Ie({root:this.currentTarget().root,kind:e,model:s,orchestrator:t==="orchestrator"})}catch(l){this.notice=`Could not save: ${l instanceof Error?l.message:String(l)}`;return}this.reload();const n=this.kinds[e];if((t==="orchestrator"?n?.orchestratorModel:n?.model)!==s){const l=t==="orchestrator"?"orchestratorModel":"model",u=this.shadowingPath(m=>m.kinds?.[e]?.[l]!==void 0);this.notice=this.savedButShadowed(u)}}commitChoice(){const e=this.choice,t=e?.options[this.choiceIndex];e&&t!==void 0&&e.commit(t),this.closePicker()}openRouteForm(e){const t=e===null?void 0:this.modelRoutes[e]??this.legacyModelRoutes[e],i=[...e===null?[{kind:"text",key:"routeId",label:"Route id"}]:[],{kind:"text",key:"family",label:"Family"},{kind:"text",key:"credentialSource",label:"Credential source"},{kind:"provider",label:"Provider id"},...k.map(r=>({kind:"cell",strength:r})),{kind:"save"},...e===null?[]:[{kind:"delete"}]];this.routeForm={existing:e,text:{routeId:e??"",family:t?.family??"",credentialSource:t?.credentialSource??""},providerId:t?.providerId??"",models:{...t?.models},fields:i,index:0,editing:null},this.mode="route-form",this.notice="",this.notify()}closeRouteForm(){this.routeInput.focused=!1,this.routeForm=void 0,this.mode="list",this.notice="",this.notify()}activateRouteField(){const e=this.routeForm,t=e?.fields[e.index];if(!(!e||!t)){if(t.kind==="text"){e.editing=t.key,this.routeInput.setValue(e.text[t.key]),this.routeInput.handleInput(""),this.routeInput.focused=!0,this.notify();return}if(t.kind==="provider"){const i=[...new Set([...this.registry.getAll().map(r=>r.provider),...e.providerId?[e.providerId]:[]])].sort();this.choice={title:"Choose provider id",subtitle:"Route cells must all belong to this registry provider",options:i,label:y(r=>r,"label"),commit:y(r=>this.setRouteProvider(r),"commit")},this.choiceIndex=Math.max(0,i.indexOf(e.providerId)),this.mode="dimension-picker",this.notify();return}if(t.kind==="cell"){this.openRouteCell(t.strength);return}if(t.kind==="save"){this.saveRoute();return}this.mode="route-delete",this.notify()}}setRouteProvider(e){const t=this.routeForm;if(!t)return;t.providerId=e;const i=[];for(const r of k){const s=t.models[r];s!==void 0&&!s.startsWith(`${e}/`)&&(delete t.models[r],i.push(r))}this.notice=i.length===0?"":`Cleared ${i.join(", ")} because those models belong to another provider.`}openRouteCell(e){const t=this.routeForm;if(!t)return;if(!t.providerId){this.notice="Choose the provider id first",this.notify();return}const i=this.registry.getAll().filter(n=>n.provider===t.providerId);if(i.length===0){this.notice=`No models registered for provider "${t.providerId}" \u2014 this route cannot be edited here.`,this.notify();return}const r=j(t.models[e]),s=r.provider&&r.id?this.registry.find(r.provider,r.id):void 0;this.pendingRouteCell={strength:e},this.showModelSelector(i,s,n=>this.onRouteModelPicked(n))}onRouteModelPicked(e){const t=this.pendingRouteCell,i=this.routeForm;if(!t||!i){this.closePicker();return}if(e.provider!==i.providerId){this.notice=`That is a ${e.provider} model \u2014 pick a ${i.providerId} model for this route.`,this.closePicker();return}if(t.model=e,e.reasoning){const r=j(i.models[t.strength]).level??"medium";this.thinkingSelector=new ee(r,[...se],s=>this.onThinkingPicked(s),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}i.models[t.strength]=`${e.provider}/${e.id}`,this.closePicker()}saveRoute(){const e=this.routeForm;if(!e)return;const t=e.text.routeId.trim();if(!t){this.notice="Route id is required.",this.notify();return}if(!e.text.family.trim()){this.notice="Family is required.",this.notify();return}if(!e.text.credentialSource.trim()){this.notice="Credential source is required.",this.notify();return}if(!e.providerId.trim()){this.notice="Provider id is required.",this.notify();return}const i=k.filter(n=>e.models[n]===void 0);if(i.length>0){this.notice=`Choose models for ${i.join(", ")} before saving.`,this.notify();return}const r={family:e.text.family.trim(),credentialSource:e.text.credentialSource.trim(),providerId:e.providerId.trim(),models:{ultra:e.models.ultra,strong:e.models.strong,medium:e.models.medium,light:e.models.light}};try{ie(this.currentTarget().root,t,r)}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`,this.notify();return}this.routeForm=void 0,this.mode="list",this.reload();const s=this.rows.findIndex(n=>n.section==="route"&&n.routeId===t);if(s>=0&&(this.selected=s),JSON.stringify(this.modelRoutes[t])!==JSON.stringify(r)){const n=this.shadowingPath(c=>c.modelRoutes?.[t]!==void 0);this.notice=this.savedButShadowed(n)}else this.notice=`Saved route "${t}" to ${this.currentTarget().label}.`;this.notify()}declaringPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)continue;if(P(t)?.modelRoutes?.[e]!==void 0)return S(t,"config.json")}}deleteRoute(){const e=this.routeForm?.existing;if(!e){this.mode="route-form",this.notify();return}try{ie(this.currentTarget().root,e,void 0)}catch(i){this.mode="route-form",this.notice=`Could not delete: ${i instanceof Error?i.message:String(i)}`,this.notify();return}const t=this.declaringPath(e);this.routeForm=void 0,this.mode="list",this.reload(),this.notice=t?`Removed route "${e}" from ${this.currentTarget().label}; it is still declared by ${t}.`:`Removed route "${e}" from ${this.currentTarget().label}.`,this.notify()}showModelSelector(e,t,i){this.modelSelector=new $e(this.tui,t,this.runtime,e.map(r=>({model:r})),i,()=>this.closePicker()),this.modelSelector.focused=!0,this.mode="model-picker",this.notify()}openModelPicker(e,t){const i=Le[e],r=this.registry,s=j(this.ladders[e][t]),n=s.provider&&s.id?r.find(s.provider,s.id):void 0,c=r.getAvailable().filter(l=>l.provider===i);if(c.length===0){this.notice=`No ${e} models available \u2014 sign in first.`,this.notify();return}this.pending={providerKey:e,strength:t,expectedRuntime:i},this.showModelSelector(c,n,l=>this.onModelPicked(l))}onModelPicked(e){if(!this.pending){this.closePicker();return}if(e.provider!==this.pending.expectedRuntime){this.notice=`That is a ${e.provider} model \u2014 pick an ${this.pending.providerKey} model for this column.`,this.closePicker();return}if(this.pending.model=e,e.reasoning){const t=j(this.ladders[this.pending.providerKey][this.pending.strength]).level??"medium";this.thinkingSelector=new ee(t,[...se],i=>this.onThinkingPicked(i),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}this.writeLadder(e,void 0),this.closePicker()}onThinkingPicked(e){if(this.pendingRouteCell?.model&&this.routeForm){const{model:t,strength:i}=this.pendingRouteCell;this.routeForm.models[i]=`${t.provider}/${t.id}${e!=="off"?`:${e}`:""}`}else this.pending?.model&&this.writeLadder(this.pending.model,e);this.closePicker()}writeLadder(e,t){if(!this.pending)return;const i=`${e.provider}/${e.id}${t&&t!=="off"?`:${t}`:""}`,{providerKey:r,strength:s}=this.pending;try{te(this.currentTarget().root,{[r]:{[s]:i}})}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`;return}if(this.reload(),this.ladders[r][s]!==i){const n=this.shadowingPath(c=>c.modelLadders?.[r]?.[s]!==void 0);this.notice=this.savedButShadowed(n)}}closePicker(){this.mode=this.routeForm!==void 0?"route-form":"list",this.modelSelector=void 0,this.thinkingSelector=void 0,this.pending=void 0,this.pendingRouteCell=void 0,this.choice=void 0,this.notify()}dispose(){this.routeForm=void 0,this.closePicker()}targetLadderOverride(e,t){return this.rawTarget?.modelLadders?.[e]?.[t]!==void 0}targetKindOverride(e,t){const i=this.rawTarget?.kinds,r=t?"orchestratorModel":"model";return i?.[e]?.[r]!==void 0}footerHint(){return this.mode==="dimension-picker"?`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} choice \xB7 ${this.label("crtr.setup.models.commit")} save \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="model-picker"?`type to search \xB7 ${this.label("crtr.setup.models.commit")} select \xB7 tab all/scoped \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="thinking-picker"?`\u2191/\u2193 level \xB7 ${this.label("crtr.setup.models.commit")} set \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="route-delete"?`${this.label("crtr.setup.confirm.accept")} delete \xB7 ${this.label("crtr.setup.confirm.back")} cancel`:this.mode==="route-form"?typeof this.routeForm?.editing=="string"?"type a value \xB7 enter save \xB7 esc cancel":`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} field \xB7 ${this.label("crtr.setup.models.open")} edit \xB7 ${this.label("crtr.setup.models.cancel")} back`:""}renderChoicePicker(){const e=this.choice;if(!e)return[o.fg("warning","No setting selected.")];const t=[o.fg("accent",o.bold(e.title)),o.fg("dim",e.subtitle),""];for(const[i,r]of e.options.entries()){const s=i===this.choiceIndex,n=s?o.fg("accent","\u25B6"):" ",c=e.label(r);t.push(`${n} ${s?o.fg("accent",`[${c}]`):o.fg("dim",` ${c} `)}`)}return t}renderRouteForm(e){const t=this.routeForm;if(!t)return[o.fg("warning","No route selected.")];const i=this.currentTarget(),r=[o.fg("accent",o.bold(t.existing===null?"New provider route":`Provider route: ${t.existing}`)),o.fg("dim",`${i.label} \xB7 ${S(i.root,"config.json")}`),""],s=20;for(const[n,c]of t.fields.entries()){const l=n===t.index,u=l?o.fg("accent","\u25B6"):" ";let m,a;if(c.kind==="text"){if(m=c.label,a=t.text[c.key]||"\u2014",l&&t.editing===c.key){const K=Math.max(8,e-s-4);a=this.routeInput.render(K)[0]??""}}else c.kind==="provider"?(m=c.label,a=t.providerId||"\u2014"):c.kind==="cell"?(m=c.strength,a=G(t.models[c.strength])):c.kind==="save"?(m="",a="Save route"):(m="",a="Delete route");const C=a==="\u2014",T=l?o.fg("accent",`[${a}]`):o.fg(C?"warning":"dim",` ${a} `);r.push(`${u} ${f(m,s)}${T}`)}return this.notice&&r.push("",o.fg("warning",this.notice)),r}renderRouteDelete(e){const t=this.routeForm?.existing??"this route",i=this.currentTarget(),r=Oe(`This removes the entry from ${i.label}. Any "${t}" declared by a lower-precedence config becomes effective again; this does not guarantee the route is gone.`,e).map(s=>o.fg("warning",s));return[o.fg("accent",o.bold(`Delete provider route: ${t}`)),o.fg("dim",S(i.root,"config.json")),"",...r,"",o.fg("dim",`${this.label("crtr.setup.confirm.accept")} delete ${this.label("crtr.setup.confirm.back")} cancel`)]}fitBody(e,t,i){if(e.length<=i)return e;const r=Math.min(ne,e.length-i),s=e.slice(r);if(s.length<=i)return s;const n=Math.max(0,t-r),c=Math.max(0,Math.min(n-i+2,s.length-i));return s.slice(c,c+i)}render(e,t){const i=Math.max(1,t),r=y(d=>Fe(d,e),"frame");if(this.mode==="dimension-picker")return r(this.fitBody(this.renderChoicePicker(),ne+this.choiceIndex,i));if(this.mode==="model-picker")return r(U(this.modelSelector?.render(e)??[],i));if(this.mode==="thinking-picker")return r(U(this.thinkingSelector?.render(e)??[],i));if(this.mode==="route-form"){const d=3+(this.routeForm?.index??0);return r(this.fitBody(this.renderRouteForm(e),d,i))}if(this.mode==="route-delete")return r(U(this.renderRouteDelete(e),i));let s=0;const n=[o.fg("accent",o.bold("Models")),o.fg("dim","global user defaults \xB7 project/profile scopes can shadow these"),""],c=this.currentRow(),l=c.section==="ladder"&&c.kind==="strength",u=Math.max(1,e),m=Math.max(12,Math.min(20,Math.floor(u*.24))),a=this.providerKeys.length,C=Math.max(1,u-2-m),T=12,K=Math.max(1,Math.floor((C+1)/(T+1))),b=Math.min(a,K),N=Math.max(T,Math.floor((C-(b-1))/b)),J=l?Math.min(this.column,a-1):0,F=Math.max(0,Math.min(J>=b?J-b+1:0,a-b)),_=F+b,X=this.providerKeys.map((d,h)=>({provider:d,column:h})).slice(F,_),Y=F>0,z=_<a,he=Y||z?` ${o.fg("dim",`${Y?"\u2039 ":""}${F+1}\u2013${_} of ${a}${z?" \u203A":""}`)}`:"",O=this.currentTarget();n.push(`${o.fg("accent","Editing config")} ${o.fg("accent",`[${O.label}]`)}${o.fg("dim",` ${this.targetIndex+1}/${this.targets.length}`)}`),n.push(o.fg("muted",S(O.root,"config.json")),""),n.push(o.fg("accent","Strength ladders")+he);const le=q(void 0,this.ladders).provider,W=this.rows.find(d=>d.section==="ladder"&&d.kind==="defaultProvider")===c;W&&(s=n.length),n.push(`${W?o.fg("accent","\u25B6"):" "} ${f(W?o.fg("accent","Default provider"):"Default provider",20)} ${o.fg("success",le)}`);const ue=y((d,h)=>{const g=f(o.bold(ce[d]),N);return l&&this.column===h?o.fg("accent",g):o.fg("dim",g)},"providerHeading"),ae=y((d,h)=>{const g=f(V(d,Math.max(1,N-2)),Math.max(1,N-2));return h?o.fg("accent",`[${g}]`):o.fg("dim",` ${g} `)},"ladderCell");n.push(`${" ".repeat(2)}${f(o.fg("dim","Strength"),m)}${X.map(({provider:d,column:h})=>ue(d,h)).join(" ")}`);for(const d of this.rows){if(d.section!=="ladder"||d.kind!=="strength")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=X.map(({provider:v,column:R})=>{const w=this.targetLadderOverride(v,d.strength)?o.fg("warning","\u2022"):" ";return ae(`${w}${G(this.ladders[v][d.strength])}`,h&&R===this.column)});n.push(`${g} ${f(d.strength,m)}${$.join(" ")}`)}n.push("",o.fg("accent","Provider routes")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 a declared route replaces the ladders above at launch \xB7 id, then family \xB7 source \xB7 provider`));const A=Math.max(10,Math.floor((u-8)/4));n.push(`${" ".repeat(4)}${k.map(d=>f(o.fg("dim",d),A)).join(" ")}`),this.routeIds().length===0&&n.push(o.fg("dim"," No routes declared \u2014 the ladders above are used."));for(const d of this.rows){if(d.section!=="route"||d.routeId===null)continue;const h=d.routeId,g=this.modelRoutes[h],$=g??this.legacyModelRoutes[h],v=d===c;v&&(s=n.length);const R=v?o.fg("accent","\u25B6"):" ",w=this.rawTarget?.modelRoutes?.[h]!==void 0?o.fg("warning","\u2022"):" ",E=g?"":o.fg("warning"," \xB7 incomplete"),D=o.fg("dim",`${$.family} \xB7 ${$.credentialSource} \xB7 ${$.providerId}`);n.push(`${R} ${w}${o.fg(v?"accent":"dim",h)} ${D}${E}`);const x=k.map(fe=>{const Z=$.models[fe],me=f(V(G(Z),A),A);return o.fg(Z===void 0?"warning":"dim",me)});n.push(`${" ".repeat(4)}${x.join(" ")}`)}const B=this.rows.find(d=>d.section==="route"&&d.routeId===null)===c;B&&(s=n.length),n.push(`${B?o.fg("accent","\u25B6"):" "} ${o.fg(B?"accent":"dim","+ New route")}`),n.push("",o.fg("accent","Kind defaults")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 orchestrator inherits base until you set it`));const H=16,I=12,M=9,Q=I+1+M,L=y((d,h,g,$)=>{const v=f(V(d,Math.max(1,h-2)),Math.max(1,h-2));return g?o.fg("accent",`[${v}]`):$?o.fg("muted",` ${v} `):o.fg("dim",` ${v} `)},"cell");n.push(`${" ".repeat(2+H)}${f(o.bold(o.fg("dim","Base")),Q)} ${f(o.bold(o.fg("dim","Orchestrator")),Q)}`),n.push(`${" ".repeat(2)}${f(o.fg("dim","Kind"),H)}${f(o.fg("dim","Family"),I)} ${f(o.fg("dim","Strength"),M)} ${f(o.fg("dim","Family"),I)} ${f(o.fg("dim","Strength"),M)}`);for(const d of this.rows){if(d.section!=="kind")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=this.kinds[d.name],v=this.portableSelection($?.model),R=$?.orchestratorModel===void 0,w=this.portableSelection($?.orchestratorModel??$?.model),E=this.targetKindOverride(d.name,!1)?o.fg("warning","\u2022"):" ",D=this.targetKindOverride(d.name,!0)?o.fg("warning","\u2022"):" ",x=[L(`${E}${this.familyLabel(v.family)}`,I,h&&this.column===0,!1),L(`${E}${v.strength}`,M,h&&this.column===1,!1),L(`${D}${this.familyLabel(w.family)}`,I,h&&this.column===2,R),L(`${D}${w.strength}`,M,h&&this.column===3,R)];n.push(`${g} ${f(d.name,H)}${x[0]} ${x[1]} ${x[2]} ${x[3]}`)}return this.notice&&n.push("",o.fg("warning",this.notice)),r(this.fitBody(n,s,i))}}export{Xe as ModelsPanel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var w=Object.defineProperty;var u=(n,e)=>w(n,"name",{value:e,configurable:!0});import{resolve as x}from"node:path";import{envNodeId as C}from"../../shared/env.js";import{cliClient as f}from"../../commands/api-client.js";import{defineBranch as h,defineLeaf as j}from"../command.js";import{resolveCommandRegistry as L}from"../command-manifests/registry.js";import{executeExternalLeaf as U}from"./transport/exec-invoke.js";import{invokeHttpLeaf as M}from"./transport/http-invoke.js";async function T(n){const e=await f().request("GET",`/v1/providers/${encodeURIComponent(n)}/tools`);return new Set(e.groups.flatMap(r=>r.leaves.map(a=>a.tool)))}u(T,"allowedProviderTools");function m(n,e,r){return n.children.some(a=>a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))}u(m,"hasAllowedLeaf");function S(n,e,r){return n.children.filter(a=>a.tier!=="hidden"&&(a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))).length}u(S,"visibleChildCount");function A(n,e,r){return async()=>{if(!C())return n.help;const a=await T(e.id);return{...n.help,listing:n.help.listing?.flatMap(t=>{const i=n.children.find(s=>s.name===t.name);if(i?.kind==="leaf")return a.has([...r,i.name].join(" "))?[t]:[];if(i?.kind!=="branch")return[];const o=[...r,i.name];if(!m(i,o,a))return[];const p=S(i,o,a);return[{...t,...t.subCount!==void 0?{subCount:p}:{}}]})}}}u(A,"providerHelp");const N="Runs on one of your devices. Add `--machine <machine_id>` to pick which; without it the call goes to your only device, and with several the answer is `machine_required` listing each one's machine_id. The `runtime:` prefix on the id is optional.";function g(n,e,r,a=!1){return{outputKind:"object",...a?{machineSelector:!0}:{},run:u(async(t,i)=>{const o={...t};for(const p of r.params){if(!("type"in p)||p.type!=="file")continue;const s=p.name.replace(/-([a-z])/g,(c,k)=>k.toUpperCase()),d=o[s];typeof d=="string"&&(o[s]=x(d))}return f({timeoutMs:0}).request("POST","/v1/provider/call",{provider:n,tool:e,arguments:o,...i?.machine===void 0?{}:{machine:i.machine}},{timeout:0})},"run")}}u(g,"providerLeafAdapter");function v(n,e){return/^[A-Za-z0-9_-]{1,64}$/.test(n)&&n!=="crtr"&&!e.has(n)}u(v,"validRootName");function B(n,e){const r=[],a=[];for(const t of n){const{provider:i,commands:o}=t;if(!Array.isArray(o)||t.status!=="available"&&!v(i,e))continue;if(t.status!=="available"){const s=t.error??"bundle installation pending",d=`Unavailable (${t.status}): ${s}`,c=h({name:i,rootEntry:{concept:t.display_name,desc:d,useWhen:d},help:{name:i,summary:d},children:[]});c.unavailable=d,a.push(c);continue}const p=u(s=>s.kind==="branch"?{...s,children:s.children.map(p)}:{...s,rest:{method:"GET",path:"/",params:{}}},"helpNode");for(const s of o)s.kind!=="branch"||!Array.isArray(s.children)||!v(s.name,e)||r.push({contributor:{name:i,scope:"user"},manifestName:s.name,node:p(s),adaptLeaf:u((d,c)=>g(i,c.slice(1).join(" "),d,t.transport==="machine"),"adaptLeaf")})}return[..._(L(r,e)),...a]}u(B,"composeSandboxProviderSubtrees");function y(n,e){return(r,a)=>{const t=n.transport,i=e(a);if(n.provider!==void 0)return g(n.provider.id,i.slice(1).join(" "),r,t.kind==="machine");if(t.kind==="exec"){const p=t.executable;if(p===void 0)throw new Error(`exec plugin "${n.plugin.name}" has an executable leaf without transport.executable`);return{outputKind:"object",run:u(async s=>U({plugin:n.plugin,executable:p,commandPath:i,output:r.output},s),"run")}}if(t.kind==="machine")throw new Error(`machine plugin "${n.plugin.name}" is not a capability provider`);const o=r;return{outputKind:o.rest.streaming===!0?"jsonl":"object",run:u((p,s)=>M({registration:{name:n.plugin.name,endpoint:t.endpoint,...t.authEnv!==void 0?{authEnv:t.authEnv}:{}},...n.manifest?.baseUrl!==void 0?{baseUrl:n.manifest.baseUrl}:{},...n.manifest?.timeouts!==void 0?{timeouts:n.manifest.timeouts}:{},params:o.params,rest:o.rest,output:o.output,commandPath:i},p,s),"run")}}}u(y,"adaptLeaf");function G(n){return{contributions:n.map(e=>({contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,manifestName:e.manifestName,adaptLeaf:y(e,r=>[e.manifestName,...r.slice(1)]),...e.provider!==void 0?{provider:e.provider}:{}})),coreMounts:[],issues:[]}}u(G,"adaptPluginContributions");function z(n){return n.map(e=>({parent:e.parent,plugin:e.plugin.name,contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,...e.provider!==void 0?{provider:e.provider}:{},adaptLeaf:y({...e,manifestName:e.node.name},r=>e.provider===void 0?[...r]:[e.provider.id,...r.slice(e.parent.length)])}))}u(z,"adaptPluginCoreMounts");function _(n){return n.contributions.map(e=>l(e,e.node,[e.node.name]))}u(_,"composeExternalSubtrees");function D(n,e){return n.filter(r=>r.parent.join("\0")===e.join("\0")).map(r=>r.node.kind==="branch"?l(r,r.node,[...e,r.node.name],r.provider===void 0?1:e.length):E(r,r.node,[...e,r.node.name]))}u(D,"composeCoreBranchMounts");function l(n,e,r,a=1){const t=e.rootEntry===void 0?void 0:{concept:e.rootEntry.concept,desc:e.rootEntry.description,useWhen:e.rootEntry.whenToUse},i=h({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...t!==void 0?{rootEntry:t}:{},help:{name:r.join(" "),summary:e.summary,...e.model!==void 0?{model:e.model}:{},...r.length===1&&n.extensionIssue!==void 0?{extensionIssue:n.extensionIssue}:{}},...e.passthrough!==void 0?{passthrough:e.passthrough}:{},children:e.children.map(o=>o.kind==="branch"?l(n,o,[...r,o.name],a):E(n,o,[...r,o.name]))});return n.provider!==void 0&&(i.effectiveHelp=A(i,n.provider,r.slice(a))),i}u(l,"buildBranch");function E(n,e,r){const a=n.adaptLeaf(e,r);return j({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...a.machineSelector===!0?{machineSelector:!0}:{},help:{name:r.join(" "),summary:e.summary,...a.machineSelector===!0?{guide:N}:{},params:e.params,output:e.output,outputKind:a.outputKind,effects:[...e.effects]},run:a.run})}u(E,"buildLeaf");export{G as adaptPluginContributions,z as adaptPluginCoreMounts,D as composeCoreBranchMounts,_ as composeExternalSubtrees,B as composeSandboxProviderSubtrees};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var C=Object.defineProperty;var u=(e,t)=>C(e,"name",{value:t,configurable:!0});import{realpathSync as j,readFileSync as N,statSync as g}from"node:fs";import{isSandboxedNode as F}from"../../shared/env.js";import{isAbsolute as O,resolve as k,sep as q}from"node:path";import{listInstalledPlugins as A,listInstalledPluginsInRoot as E}from"../resolver.js";import{projectScopeRoots as R}from"../scope.js";import{validateCommandManifest as I}from"../../api/command-manifest/manifest.js";import{qualifiedTopLevelCommandName as J,resolveCommandRegistry as $}from"../command-manifests/registry.js";import{adaptPluginContributions as T,adaptPluginCoreMounts as B}from"./compose.js";import{validateHttpPluginTransport as H}from"./endpoint.js";import{applyCommandExtensions as L}from"./extensions.js";function _(e=process.cwd(),t){const i=new Set,a=[],s=u(n=>{i.has(n.name)||(i.add(n.name),a.push(n))},"consider");for(const n of R(e,t))for(const r of E("project",n))s(r);if(!F())for(const n of A("user"))s(n);return a.filter(n=>n.enabled&&(n.manifest.commands!==void 0||n.manifest.transport!==void 0))}u(_,"effectiveCommandPlugins");function W(e,t){return i=>t.push({...i,plugin:e.name})}u(W,"issueFor");function v(e,t){if(typeof t!="string"||t.length===0)return null;try{const i=j(e),a=j(k(e,t));return(a===i||a.startsWith(i+q))&&g(a).isFile()?a:null}catch{return null}}u(v,"safePath");function X(e,t){const i=e.manifest.transport;if(i===void 0){t.push({code:"command_manifest_invalid",plugin:e.name,message:"commands requires transport in plugin.json",received:"(missing)",expected:"a transport object",next:"Add plugin.json.transport.",path:"transport"});return}if(typeof i!="object"||i===null||Array.isArray(i)){t.push({code:"command_manifest_invalid",plugin:e.name,message:"transport must be an object",received:Array.isArray(i)?"array":typeof i,expected:"an exec or http transport object",next:"Fix plugin.json.transport.",path:"transport"});return}const a=i;if(a.kind==="http"){const n=H(a);if(n.transport!==void 0)return n.transport;t.push({code:"command_manifest_invalid",plugin:e.name,message:n.errors.join("; "),received:JSON.stringify(i),expected:"a valid HTTP transport",next:"Fix plugin.json.transport.",path:"transport"});return}if(a.kind==="machine"){if(e.manifest.provider===void 0||Object.keys(a).length!==1){t.push({code:"command_manifest_invalid",plugin:e.name,message:e.manifest.provider===void 0?"a machine transport belongs to a capability provider bundle":"transport has unknown keys",received:JSON.stringify(i),expected:'{ kind: "machine" } on a provider bundle',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"machine"}}const s=Object.keys(a).filter(n=>!["kind","executable"].includes(n));if(a.kind!=="exec"||s.length||a.executable!==void 0&&(typeof a.executable!="string"||a.executable.length===0)){t.push({code:"command_manifest_invalid",plugin:e.name,message:s.length?`transport has unknown keys: ${s.join(", ")}`:"exec transport requires a non-empty executable when declared",received:JSON.stringify(i),expected:'{ kind: "exec", executable?: "plugin-relative path" }',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"exec",...a.executable!==void 0?{executable:a.executable}:{}}}u(X,"transportFor");function w(e){return e.kind==="leaf"||e.children.some(w)}u(w,"hasExecutableLeaf");function M(e){return[...e.roots,...e.coreMounts.map(t=>t.node)]}u(M,"manifestNodes");function z(e,t,i,a){if(t.executable===void 0){if(!M(i).some(w))return t;a.push({code:"command_manifest_invalid",plugin:e.name,message:"exec transport requires executable when commands.json declares executable leaves",received:"(missing)",expected:'{ kind: "exec", executable: "plugin-relative path" }',next:"Add plugin.json.transport.executable.",path:"transport.executable"});return}const s=v(e.root,t.executable);if(s===null){a.push({code:"command_path_unsafe",plugin:e.name,message:"executable escapes the plugin root or is not a regular file",received:t.executable,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.transport.executable.",path:"transport.executable"});return}if((g(s).mode&73)===0){a.push({code:"command_not_executable",plugin:e.name,message:"executable lacks the POSIX exec bit",received:t.executable,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update the plugin.",path:"transport.executable"});return}return{kind:"exec",executable:s}}u(z,"validateExecExecutable");function G(e){return O(e)||e.startsWith(".")||e.includes("/")||e.includes("\\")}u(G,"namesPath");function K(e,t,i){let a=!0;const s=u(n=>{if(n.kind!=="branch")return;const r=n.passthrough;if(r!==void 0&&G(r.bin)){const l=v(e.root,r.bin);l===null?(i.push({code:"command_path_unsafe",plugin:e.name,message:"passthrough binary escapes the plugin root or is not a regular file",received:r.bin,expected:"a relative path to a regular file inside the plugin root",next:"Fix passthrough.bin in commands.json.",path:"passthrough.bin"}),a=!1):(g(l).mode&73)===0?(i.push({code:"command_not_executable",plugin:e.name,message:"passthrough binary lacks the POSIX exec bit",received:r.bin,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update commands.json.",path:"passthrough.bin"}),a=!1):n.passthrough={...r,bin:l}}for(const l of n.children)s(l)},"visit");for(const n of M(t))s(n);return a}u(K,"resolvePassthroughBinaries");function S(e,t=new Set,i,a=new Set){const s=[],n=e.manifest.commands,r=e.manifest.transport;let l=k(e.root,typeof n=="string"?n:"commands.json");const c=u(x=>({plugin:e,manifestPath:l,...x===void 0?{}:{transport:x},contributions:[],coreMounts:[],issues:s}),"empty");if(n===void 0&&r===void 0)return c();if(typeof n!="string"||n.length===0)return s.push({code:"command_manifest_invalid",plugin:e.name,message:"transport requires commands in plugin.json",received:"(missing)",expected:"a plugin-root-relative commands path",next:"Add plugin.json.commands or remove transport.",path:"commands"}),c();const o=X(e,s);if(o===void 0)return c();const d=v(e.root,n);if(d===null)return s.push({code:"command_path_unsafe",plugin:e.name,message:"commands pointer escapes the plugin root or is not a regular file",received:n,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.commands.",path:"commands"}),c(o);l=d;let p;try{p=N(d)}catch{p=null}if(p===null)return s.push({code:"command_manifest_unreadable",plugin:e.name,message:"commands.json is missing or unreadable",received:d,expected:"a readable JSON file",next:"Reinstall or update the plugin."}),c(o);let h;try{h=JSON.parse(Buffer.from(p).toString("utf8"))}catch{return s.push({code:"command_manifest_invalid",plugin:e.name,message:"commands.json is not valid JSON",received:d,expected:"a JSON object",next:"Regenerate commands.json."}),c(o)}const f=I(h,{transport:o.kind==="machine"?"http":o.kind,reservedCoreNames:t,extensibleCoreBranches:a,...i!==void 0?{coreCommandPaths:i}:{}});if(f.manifest===void 0)return f.issues.forEach(W(e,s)),c(o);const m=o.kind==="exec"?z(e,o,f.manifest,s):o;if(m===void 0)return c(o);if(m.kind==="exec"&&!K(e,f.manifest,s))return c(m);const b=e.manifest.provider,y=f.manifest.roots;if(!y.every(x=>x.kind==="branch"))throw new Error("plugin manifest validation returned a top-level leaf");return{plugin:e,manifestPath:l,transport:m,manifest:f.manifest,contributions:y.map(x=>({plugin:e,transport:m,node:x,manifest:f.manifest,manifestName:x.name,...b!==void 0?{provider:b}:{}})),coreMounts:f.manifest.coreMounts.map(x=>({plugin:e,transport:m,parent:x.parent,node:x.node,manifest:f.manifest,...b!==void 0?{provider:b}:{}})),issues:s}}u(S,"validatePluginCommands");function se(e=process.cwd(),t){return _(e,t).map(i=>S(i))}u(se,"discoverPluginCommandCandidates");function P(e,t=process.cwd(),i,a,s=new Set){const n=_(t,i).map(c=>S(c,e,a,s)),r=new Map;for(const c of n)for(const o of c.contributions){const d=r.get(o.node.name);d===void 0?r.set(o.node.name,[o]):d.push(o)}for(const[c,o]of r)if(o.length>1)for(const d of o){const{plugin:p}=d,h=J({name:p.name,sourceMarketplace:p.sourceMarketplace},c),f=n.find(m=>m.plugin.root===p.root);f.contributions=f.contributions.map(m=>m===d?{...m,node:{...m.node,name:h}}:m),f.issues.push({code:"command_collision",plugin:p.name,path:c,message:`top-level command "${c}" is claimed by ${o.map(m=>m.plugin.name).join(", ")} \u2014 mounted as "${h}"`,received:o.map(m=>m.plugin.name).join(", "),expected:"an origin-qualified top-level command for each claimant",next:`Invoke "${h}" to use this plugin command.`})}const l=new Map;for(const c of n)for(const o of c.coreMounts){const d=[...o.parent,o.node.name].join("/"),p=l.get(d);p===void 0?l.set(d,[o]):p.push(o)}for(const[c,o]of l)if(o.length>1)for(const d of o){const p=n.find(h=>h.plugin.root===d.plugin.root);p.coreMounts=p.coreMounts.filter(h=>h!==d),p.issues.push({code:"command_collision",plugin:d.plugin.name,path:c.replace("/","."),message:`contributed command "${d.node.name}" conflicts with another plugin child below the extensible core branch`,received:o.map(h=>h.plugin.name).join(", "),expected:`a unique child name below ${d.parent.join(".")}`,next:"Rename the contributed command or remove this mount."})}return n}u(P,"validateEffectiveCommandPlugins");function Q(e,t){return{...t,contributor:{name:e.name,scope:e.scope,sourceMarketplace:e.sourceMarketplace}}}u(Q,"contributorIssue");function re(e,t=process.cwd(),i,a,s=new Set){const n=P(e,t,i,a,s);return{contributions:n.flatMap(r=>r.contributions),coreMounts:n.flatMap(r=>r.coreMounts),issues:n.flatMap(r=>r.issues)}}u(re,"discoverCommandContributions");function ce(e,t=process.cwd(),i,a,s=new Set){const n=P(e,t,i,a,s),r=T(n.flatMap(o=>o.contributions)).contributions,l=$(r,e);return{contributions:L(l.contributions,t).contributions,coreMounts:B(n.flatMap(o=>o.coreMounts)),issues:[...n.flatMap(o=>o.issues.map(d=>Q(o.plugin,d))),...l.issues]}}u(ce,"buildExternalCommandSnapshot");export{ce as buildExternalCommandSnapshot,re as discoverCommandContributions,se as discoverPluginCommandCandidates,_ as effectiveCommandPlugins,P as validateEffectiveCommandPlugins,S as validatePluginCommands};
|
|
1
|
+
var P=Object.defineProperty;var u=(e,n)=>P(e,"name",{value:n,configurable:!0});import{realpathSync as j,readFileSync as N,statSync as g}from"node:fs";import{isSandboxedNode as F}from"../../shared/env.js";import{isAbsolute as O,resolve as k,sep as R}from"node:path";import{listInstalledPlugins as q,listInstalledPluginsInRoot as A}from"../resolver.js";import{projectScopeRoots as E}from"../scope.js";import{validateCommandManifest as I}from"../../api/command-manifest/manifest.js";import{qualifiedTopLevelCommandName as J,resolveCommandRegistry as $}from"../command-manifests/registry.js";import{adaptPluginContributions as T,adaptPluginCoreMounts as B}from"./compose.js";import{validateHttpPluginTransport as H}from"./endpoint.js";import{providerRootClaims as L}from"../providers/roots.js";import{applyCommandExtensions as W}from"./extensions.js";function _(e=process.cwd(),n){const i=new Set,o=[],r=u(s=>{i.has(s.name)||(i.add(s.name),o.push(s))},"consider");for(const s of E(e,n))for(const m of A("project",s))r(m);if(!F())for(const s of q("user"))r(s);const{skipped:a}=L(o);return o.filter(s=>!a.has(s.name)).filter(s=>s.enabled&&(s.manifest.commands!==void 0||s.manifest.transport!==void 0))}u(_,"effectiveCommandPlugins");function X(e,n){return i=>n.push({...i,plugin:e.name})}u(X,"issueFor");function v(e,n){if(typeof n!="string"||n.length===0)return null;try{const i=j(e),o=j(k(e,n));return(o===i||o.startsWith(i+R))&&g(o).isFile()?o:null}catch{return null}}u(v,"safePath");function z(e,n){const i=e.manifest.transport;if(i===void 0){n.push({code:"command_manifest_invalid",plugin:e.name,message:"commands requires transport in plugin.json",received:"(missing)",expected:"a transport object",next:"Add plugin.json.transport.",path:"transport"});return}if(typeof i!="object"||i===null||Array.isArray(i)){n.push({code:"command_manifest_invalid",plugin:e.name,message:"transport must be an object",received:Array.isArray(i)?"array":typeof i,expected:"an exec or http transport object",next:"Fix plugin.json.transport.",path:"transport"});return}const o=i;if(o.kind==="http"){const a=H(o);if(a.transport!==void 0)return a.transport;n.push({code:"command_manifest_invalid",plugin:e.name,message:a.errors.join("; "),received:JSON.stringify(i),expected:"a valid HTTP transport",next:"Fix plugin.json.transport.",path:"transport"});return}if(o.kind==="machine"){if(e.manifest.provider===void 0||Object.keys(o).length!==1){n.push({code:"command_manifest_invalid",plugin:e.name,message:e.manifest.provider===void 0?"a machine transport belongs to a capability provider bundle":"transport has unknown keys",received:JSON.stringify(i),expected:'{ kind: "machine" } on a provider bundle',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"machine"}}const r=Object.keys(o).filter(a=>!["kind","executable"].includes(a));if(o.kind!=="exec"||r.length||o.executable!==void 0&&(typeof o.executable!="string"||o.executable.length===0)){n.push({code:"command_manifest_invalid",plugin:e.name,message:r.length?`transport has unknown keys: ${r.join(", ")}`:"exec transport requires a non-empty executable when declared",received:JSON.stringify(i),expected:'{ kind: "exec", executable?: "plugin-relative path" }',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"exec",...o.executable!==void 0?{executable:o.executable}:{}}}u(z,"transportFor");function w(e){return e.kind==="leaf"||e.children.some(w)}u(w,"hasExecutableLeaf");function M(e){return[...e.roots,...e.coreMounts.map(n=>n.node)]}u(M,"manifestNodes");function G(e,n,i,o){if(n.executable===void 0){if(!M(i).some(w))return n;o.push({code:"command_manifest_invalid",plugin:e.name,message:"exec transport requires executable when commands.json declares executable leaves",received:"(missing)",expected:'{ kind: "exec", executable: "plugin-relative path" }',next:"Add plugin.json.transport.executable.",path:"transport.executable"});return}const r=v(e.root,n.executable);if(r===null){o.push({code:"command_path_unsafe",plugin:e.name,message:"executable escapes the plugin root or is not a regular file",received:n.executable,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.transport.executable.",path:"transport.executable"});return}if((g(r).mode&73)===0){o.push({code:"command_not_executable",plugin:e.name,message:"executable lacks the POSIX exec bit",received:n.executable,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update the plugin.",path:"transport.executable"});return}return{kind:"exec",executable:r}}u(G,"validateExecExecutable");function K(e){return O(e)||e.startsWith(".")||e.includes("/")||e.includes("\\")}u(K,"namesPath");function Q(e,n,i){let o=!0;const r=u(a=>{if(a.kind!=="branch")return;const s=a.passthrough;if(s!==void 0&&K(s.bin)){const m=v(e.root,s.bin);m===null?(i.push({code:"command_path_unsafe",plugin:e.name,message:"passthrough binary escapes the plugin root or is not a regular file",received:s.bin,expected:"a relative path to a regular file inside the plugin root",next:"Fix passthrough.bin in commands.json.",path:"passthrough.bin"}),o=!1):(g(m).mode&73)===0?(i.push({code:"command_not_executable",plugin:e.name,message:"passthrough binary lacks the POSIX exec bit",received:s.bin,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update commands.json.",path:"passthrough.bin"}),o=!1):a.passthrough={...s,bin:m}}for(const m of a.children)r(m)},"visit");for(const a of M(n))r(a);return o}u(Q,"resolvePassthroughBinaries");function S(e,n=new Set,i,o=new Set){const r=[],a=e.manifest.commands,s=e.manifest.transport;let m=k(e.root,typeof a=="string"?a:"commands.json");const c=u(x=>({plugin:e,manifestPath:m,...x===void 0?{}:{transport:x},contributions:[],coreMounts:[],issues:r}),"empty");if(a===void 0&&s===void 0)return c();if(typeof a!="string"||a.length===0)return r.push({code:"command_manifest_invalid",plugin:e.name,message:"transport requires commands in plugin.json",received:"(missing)",expected:"a plugin-root-relative commands path",next:"Add plugin.json.commands or remove transport.",path:"commands"}),c();const t=z(e,r);if(t===void 0)return c();const d=v(e.root,a);if(d===null)return r.push({code:"command_path_unsafe",plugin:e.name,message:"commands pointer escapes the plugin root or is not a regular file",received:a,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.commands.",path:"commands"}),c(t);m=d;let p;try{p=N(d)}catch{p=null}if(p===null)return r.push({code:"command_manifest_unreadable",plugin:e.name,message:"commands.json is missing or unreadable",received:d,expected:"a readable JSON file",next:"Reinstall or update the plugin."}),c(t);let h;try{h=JSON.parse(Buffer.from(p).toString("utf8"))}catch{return r.push({code:"command_manifest_invalid",plugin:e.name,message:"commands.json is not valid JSON",received:d,expected:"a JSON object",next:"Regenerate commands.json."}),c(t)}const f=I(h,{transport:t.kind==="machine"?"http":t.kind,reservedCoreNames:n,extensibleCoreBranches:o,...i!==void 0?{coreCommandPaths:i}:{}});if(f.manifest===void 0)return f.issues.forEach(X(e,r)),c(t);const l=t.kind==="exec"?G(e,t,f.manifest,r):t;if(l===void 0)return c(t);if(l.kind==="exec"&&!Q(e,f.manifest,r))return c(l);const b=e.manifest.provider,y=f.manifest.roots;if(!y.every(x=>x.kind==="branch"))throw new Error("plugin manifest validation returned a top-level leaf");return{plugin:e,manifestPath:m,transport:l,manifest:f.manifest,contributions:y.map(x=>({plugin:e,transport:l,node:x,manifest:f.manifest,manifestName:x.name,...b!==void 0?{provider:b}:{}})),coreMounts:f.manifest.coreMounts.map(x=>({plugin:e,transport:l,parent:x.parent,node:x.node,manifest:f.manifest,...b!==void 0?{provider:b}:{}})),issues:r}}u(S,"validatePluginCommands");function ce(e=process.cwd(),n){return _(e,n).map(i=>S(i))}u(ce,"discoverPluginCommandCandidates");function C(e,n=process.cwd(),i,o,r=new Set){const a=_(n,i).map(c=>S(c,e,o,r)),s=new Map;for(const c of a)for(const t of c.contributions){const d=s.get(t.node.name);d===void 0?s.set(t.node.name,[t]):d.push(t)}for(const[c,t]of s)if(t.length>1)for(const d of t){const{plugin:p}=d,h=J({name:p.name,sourceMarketplace:p.sourceMarketplace},c),f=a.find(l=>l.plugin.root===p.root);f.contributions=f.contributions.map(l=>l===d?{...l,node:{...l.node,name:h}}:l),f.issues.push({code:"command_collision",plugin:p.name,path:c,message:`top-level command "${c}" is claimed by ${t.map(l=>l.plugin.name).join(", ")} \u2014 mounted as "${h}"`,received:t.map(l=>l.plugin.name).join(", "),expected:"an origin-qualified top-level command for each claimant",next:`Invoke "${h}" to use this plugin command.`})}const m=new Map;for(const c of a)for(const t of c.coreMounts){const d=[...t.parent,t.node.name].join("/"),p=m.get(d);p===void 0?m.set(d,[t]):p.push(t)}for(const[c,t]of m)if(t.length>1)for(const d of t){const p=a.find(h=>h.plugin.root===d.plugin.root);p.coreMounts=p.coreMounts.filter(h=>h!==d),p.issues.push({code:"command_collision",plugin:d.plugin.name,path:c.replace("/","."),message:`contributed command "${d.node.name}" conflicts with another plugin child below the extensible core branch`,received:t.map(h=>h.plugin.name).join(", "),expected:`a unique child name below ${d.parent.join(".")}`,next:"Rename the contributed command or remove this mount."})}return a}u(C,"validateEffectiveCommandPlugins");function U(e,n){return{...n,contributor:{name:e.name,scope:e.scope,sourceMarketplace:e.sourceMarketplace}}}u(U,"contributorIssue");function de(e,n=process.cwd(),i,o,r=new Set){const a=C(e,n,i,o,r);return{contributions:a.flatMap(s=>s.contributions),coreMounts:a.flatMap(s=>s.coreMounts),issues:a.flatMap(s=>s.issues)}}u(de,"discoverCommandContributions");function ue(e,n=process.cwd(),i,o,r=new Set){const a=C(e,n,i,o,r),s=T(a.flatMap(t=>t.contributions)).contributions,m=$(s,e);return{contributions:W(m.contributions,n).contributions,coreMounts:B(a.flatMap(t=>t.coreMounts)),issues:[...a.flatMap(t=>t.issues.map(d=>U(t.plugin,d))),...m.issues]}}u(ue,"buildExternalCommandSnapshot");export{ue as buildExternalCommandSnapshot,de as discoverCommandContributions,ce as discoverPluginCommandCandidates,_ as effectiveCommandPlugins,C as validateEffectiveCommandPlugins,S as validatePluginCommands};
|
package/dist/core/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Ue=Object.defineProperty;var s=(e,n)=>Ue(e,"name",{value:n,configurable:!0});import{envProfileId as Ke}from"../shared/env.js";import{basename as X,join as Q}from"node:path";import{existsSync as qe,mkdirSync as Ge,statSync as Be}from"node:fs";import{isDeepStrictEqual as We}from"node:util";import{CONFIG_FILE as He,STATE_FILE as Je,CONDENSED_HISTORY_MODES as Ze,MOUSE_MODE_DEFAULTS as Ye,WHIP_MESSAGE_MODES as Ve,DEFAULT_WHIP_MESSAGES as ee,defaultScopeConfig as k,defaultScopeState as ne,defaultModelLaddersConfig as Xe,defaultKindsConfig as Qe,defaultRemoteCanvasConfig as en}from"../types.js";import{BINDING_CATALOG as nn,BINDING_IDS as on,isAttachPaneBinding as tn}from"./keybindings/catalog.js";import{notFound as rn}from"./errors.js";import{emitEvent as sn}from"./events/emit.js";import{atomicWriteJson as oe,readJsonIfExists as K,ensureDir as cn}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as w,findProjectScopeRoots as un,userScopeRoot as E}from"./scope.js";import{listInstalledPluginsInRoot as te}from"./installed-plugins.js";import{profileMemoryDir as q,listProfiles as re}from"./profiles/manifest.js";import{canonicalRoot as A,projectStore as dn,userStore as ie}from"./scoped-state/paths.js";import{convertLegacyScopedStore as fn,initializeFreshScopedStore as ln}from"./scoped-state/migrate.js";import{mutateRawSettings as an,readBookkeeping as mn,readRawSettings as pn,readRawSettingsWithRevision as gn,replaceRawSettings as yn,writeBookkeeping as hn,writeRawSettings as bn}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as _n}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as vn}from"./user-settings.js";import{normalizeWorkingGerunds as kn}from"../shared/working-activity.js";import{mergePageComponentLayers as wn,normalizePageComponents as se}from"./human/page-catalog.js";function b(e){return Q(e,He)}s(b,"configPathFor");function ce(e,n){return _n(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ce,"withConfigPathLock");function An(e){return Q(e,Je)}s(An,"statePathFor");function _o(e){const n=y(e);return n?b(n):null}s(_o,"configPath");function vo(e){const n=y(e);return n?An(n):null}s(vo,"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 fn({kind:"project",root:n}),{store:dn(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 pn(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}bn(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}):an(o,t=>n(t))}s(S,"mutateRawAtRoot");const P=globalThis,T=Symbol.for("crtr.broker.config-snapshot");function ko(e){P[T]=e}s(ko,"installBrokerConfigSnapshot");function wo(){return P[T]}s(wo,"brokerConfigSnapshot");function Sn(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?jn(o):k()}s(Sn,"readConfig");function jn(e){const n=I(e);return n?z(n):k()}s(jn,"readConfigAtRoot");function Rn(e){const n=y(e);if(!n)return ne();try{return mn(g(n))}catch(o){if(e==="project"&&!qe(n))return ne();throw o}}s(Rn,"readState");class xn 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 rn(`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 Ao(e){return gn(ue(e))}s(Ao,"readRawSettingsForTarget");function So(e,n,o){return yn(ue(e),n,o,t=>{try{z(t)}catch(r){throw new xn(r)}})}s(So,"replaceRawSettingsForTarget");function jo(e,n){const o=w(e);return S(o,t=>{const r=n(t);return{value:r,next:r}})}s(jo,"updateRawConfigAtomically");function Ro(e,n){G(w(e),n)}s(Ro,"writeConfig");function xo(e,n){G(w(e),n)}s(xo,"writeRawConfig");function On(e,n){const o=w(e);hn(g(o),n)}s(On,"writeState");function Oo(e,n){if(e==="project")try{Ge(n)}catch(t){if(t.code!=="EEXIST"||!Be(n).isDirectory())throw t}else cn(n);const o=g(e==="user"?E():n);ln({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(Oo,"ensureScopeInitialized");function En(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(En,"normalizeKeybindings");const In=new Set(nn.filter(tn).map(e=>e.id));function Pn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&on.has(n)&&In.has(n)))]:[]}s(Pn,"normalizeTmuxPassthrough");function C(e,n=Xe()){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){sn({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 Tn(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(Tn,"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 Cn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Cn,"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(Cn(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}$/,$n=new Set(["crtr","crtrd"]);function F(e,n){if(n==="bin"&&$n.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 Mn(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(Mn,"binDeclarationIssues");function Nn(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(Nn,"normalizeBin");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Ln(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(Ln,"humanActionDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(Ln(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(Fn,"normalizeHumanActions");function Eo(e){return Mn(e).map(n=>n.message)}s(Eo,"invalidPluginBinReasons");function Io(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(Io,"normalizeRequires");function Po(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(Po,"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=Qe()){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 To(){const e=[{origin:"config.json",components:Sn("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 wn(e)}s(To,"resolvePageComponents");const H=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Co(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(Co,"invalidPluginKindsReasons");function zn(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(zn,"normalizeRemoteCanvasTarget");function Dn(e,n=en()){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=zn(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Dn,"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 Un(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(Un,"mergeBrokerThresholds");function Kn(e,n){return{unattendedParkMs:O((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Kn,"mergeLifecycle");function qn(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(qn,"normalizeWhipMessages");function Gn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Gn,"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=Un(e.brokerThresholds,n.brokerThresholds),h=Kn(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]:kn(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=qn(e.whip_messages),we=Ve.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Ae=Ye.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,Se=O(e.live_cycles,n.live_cycles),je=Ze.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=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Pe=En(e.keybindings),Te=Pn(e.tmux_passthrough),Ce=C(e.modelLadders),$e=L(e.providerOptions,n.providerOptions),U=le($(e.modelRoutes)),J=U.complete,Z=M(e.modelRouting,void 0),Me=x(e.kinds),Ne=Dn(e.remoteCanvas),Le=Gn(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 Fe=N(e.spawnEnv,n.spawnEnv?.allow),ze=Nn(e.bin),De=Fn(e.humanActions);return{bin:ze,humanActions:De,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,consolidate_replies:Ie,keybindings:Pe,tmux_passthrough:Te,modelLadders:Ce,providerOptions:$e,...Object.keys(J).length>0?{modelRoutes:J}:{},...Object.keys(U.legacy).length>0?{legacyModelRoutes:U.legacy}:{},...Z!==void 0?{modelRouting:Z}:{},kinds:Me,remoteCanvas:Ne,api:Le,..._?{paths:_}:{},...Y?{store:Y}:{},...v?{runtime:v}:{},spawnEnv:Fe}}s(z,"mergeConfig");function Bn(e){return I(e)}s(Bn,"readRawConfigAtRoot");function Wn(e){const n=y(e);return n?Bn(n):null}s(Wn,"readRawScopeConfig");function Hn(e){if(e===null||e==="")return null;try{return I(q(e))}catch{return null}}s(Hn,"readRawProfileConfig");function Jn(e,n){return[...un(e,n)].reverse().map(r=>({root:r,raw:I(r)}))}s(Jn,"readRawProjectScopeConfigs");function he(e=process.cwd(),n=Ke()||null){const o=P[T];if(o)return o.launch;const t=k(),r=Wn("user"),i=Hn(n),c=Jn(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 $o(e){return he().kinds[e]}s($o,"resolveKindConfig");function Mo(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(Mo,"subKindsAvailableTo");function Zn(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(Zn,"sparseModelLaddersToPersist");function Yn(e,n){return S(e,o=>{const t=z(o),r=z(o);n(r);const i={...o};for(const u of vn)u!=="modelLadders"&&!We(r[u],t[u])&&(i[u]=r[u]);const c=Zn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Yn,"mutateConfigAtRoot");function No(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(No,"persistModelLadders");function Lo(e,n,o){if(o!==void 0)Tn(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(Lo,"persistModelRoute");function Vn(e,n){return Yn(e,n)}s(Vn,"updateConfigAtRoot");function Fo(e,n){return Vn(w(e),n)}s(Fo,"updateConfig");function zo(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(zo,"persistDefaultKindModel");function Do(e,n){const o=Rn(e);return n(o),On(e,o),o}s(Do,"updateState");export{xn as InvalidRawSettingsError,Mn as binDeclarationIssues,wo as brokerConfigSnapshot,_o as configPath,Oo as ensureScopeInitialized,Ln as humanActionDeclarationIssues,ko as installBrokerConfigSnapshot,Eo as invalidPluginBinReasons,Co as invalidPluginKindsReasons,Po as invalidPluginRequiresReasons,Nn as normalizeBin,Fn as normalizeHumanActions,Io as normalizeRequires,Pn as normalizeTmuxPassthrough,zo as persistDefaultKindModel,No as persistModelLadders,Lo as persistModelRoute,Sn as readConfig,jn as readConfigAtRoot,he as readMergedLaunchConfig,Bn as readRawConfigAtRoot,Wn as readRawScopeConfig,Ao as readRawSettingsForTarget,Rn as readState,So as replaceRawSettingsForTarget,$o as resolveKindConfig,To as resolvePageComponents,vo as statePath,Mo as subKindsAvailableTo,Fo as updateConfig,Vn as updateConfigAtRoot,jo as updateRawConfigAtomically,Do as updateState,Ro as writeConfig,xo as writeRawConfig,On as writeState};
|
|
1
|
+
var Ue=Object.defineProperty;var s=(e,n)=>Ue(e,"name",{value:n,configurable:!0});import{envProfileId as Ke}from"../shared/env.js";import{basename as X,join as Q}from"node:path";import{existsSync as qe,mkdirSync as Ge,statSync as Be}from"node:fs";import{isDeepStrictEqual as We}from"node:util";import{CONFIG_FILE as He,STATE_FILE as Je,CONDENSED_HISTORY_MODES as Ze,MOUSE_MODE_DEFAULTS as Ye,WHIP_MESSAGE_MODES as Ve,DEFAULT_WHIP_MESSAGES as ee,defaultScopeConfig as k,defaultScopeState as ne,defaultModelLaddersConfig as Xe,defaultKindsConfig as Qe,defaultRemoteCanvasConfig as en}from"../types.js";import{BINDING_CATALOG as nn,BINDING_IDS as on,isAttachPaneBinding as tn}from"./keybindings/catalog.js";import{notFound as rn}from"./errors.js";import{emitEvent as sn}from"./events/emit.js";import{atomicWriteJson as oe,readJsonIfExists as K,ensureDir as cn}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as w,findProjectScopeRoots as un,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 dn,userStore as ie}from"./scoped-state/paths.js";import{convertLegacyScopedStore as fn,initializeFreshScopedStore as ln}from"./scoped-state/migrate.js";import{mutateRawSettings as an,readBookkeeping as mn,readRawSettings as pn,readRawSettingsWithRevision as gn,replaceRawSettings as yn,writeBookkeeping as hn,writeRawSettings as bn}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as _n}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as vn}from"./user-settings.js";import{normalizeWorkingGerunds as kn}from"../shared/working-activity.js";import{mergePageComponentLayers as wn,normalizePageComponents as se}from"./human/page-catalog.js";function b(e){return Q(e,He)}s(b,"configPathFor");function ce(e,n){return _n(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ce,"withConfigPathLock");function An(e){return Q(e,Je)}s(An,"statePathFor");function _o(e){const n=y(e);return n?b(n):null}s(_o,"configPath");function vo(e){const n=y(e);return n?An(n):null}s(vo,"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 fn({kind:"project",root:n}),{store:dn(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 pn(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}bn(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}):an(o,t=>n(t))}s(S,"mutateRawAtRoot");const P=globalThis,T=Symbol.for("crtr.broker.config-snapshot");function ko(e){P[T]=e}s(ko,"installBrokerConfigSnapshot");function wo(){return P[T]}s(wo,"brokerConfigSnapshot");function Sn(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?jn(o):k()}s(Sn,"readConfig");function jn(e){const n=I(e);return n?z(n):k()}s(jn,"readConfigAtRoot");function Rn(e){const n=y(e);if(!n)return ne();try{return mn(g(n))}catch(o){if(e==="project"&&!qe(n))return ne();throw o}}s(Rn,"readState");class xn 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 rn(`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 Ao(e){return gn(ue(e))}s(Ao,"readRawSettingsForTarget");function So(e,n,o){return yn(ue(e),n,o,t=>{try{z(t)}catch(r){throw new xn(r)}})}s(So,"replaceRawSettingsForTarget");function jo(e,n){const o=w(e);return S(o,t=>{const r=n(t);return{value:r,next:r}})}s(jo,"updateRawConfigAtomically");function Ro(e,n){G(w(e),n)}s(Ro,"writeConfig");function xo(e,n){G(w(e),n)}s(xo,"writeRawConfig");function On(e,n){const o=w(e);hn(g(o),n)}s(On,"writeState");function Oo(e,n){if(e==="project")try{Ge(n)}catch(t){if(t.code!=="EEXIST"||!Be(n).isDirectory())throw t}else cn(n);const o=g(e==="user"?E():n);ln({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(Oo,"ensureScopeInitialized");function En(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(En,"normalizeKeybindings");const In=new Set(nn.filter(tn).map(e=>e.id));function Pn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&on.has(n)&&In.has(n)))]:[]}s(Pn,"normalizeTmuxPassthrough");function C(e,n=Xe()){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){sn({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 Tn(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(Tn,"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 Cn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Cn,"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(Cn(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}$/,$n=new Set(["crtr","crtrd"]);function F(e,n){if(n==="bin"&&$n.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 Mn(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(Mn,"binDeclarationIssues");function Nn(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(Nn,"normalizeBin");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Ln(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(Ln,"humanActionDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(Ln(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(Fn,"normalizeHumanActions");function Eo(e){return Mn(e).map(n=>n.message)}s(Eo,"invalidPluginBinReasons");function Io(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(Io,"normalizeRequires");function Po(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(Po,"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=Qe()){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 To(){const e=[{origin:"config.json",components:Sn("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 wn(e)}s(To,"resolvePageComponents");const H=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Co(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(Co,"invalidPluginKindsReasons");function zn(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(zn,"normalizeRemoteCanvasTarget");function Dn(e,n=en()){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=zn(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Dn,"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 Un(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(Un,"mergeBrokerThresholds");function Kn(e,n){return{unattendedParkMs:O((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Kn,"mergeLifecycle");function qn(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(qn,"normalizeWhipMessages");function Gn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Gn,"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=Un(e.brokerThresholds,n.brokerThresholds),h=Kn(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]:kn(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=qn(e.whip_messages),we=Ve.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Ae=Ye.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,Se=O(e.live_cycles,n.live_cycles),je=Ze.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=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Pe=En(e.keybindings),Te=Pn(e.tmux_passthrough),Ce=C(e.modelLadders),$e=L(e.providerOptions,n.providerOptions),U=le($(e.modelRoutes)),J=U.complete,Z=M(e.modelRouting,void 0),Me=x(e.kinds),Ne=Dn(e.remoteCanvas),Le=Gn(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 Fe=N(e.spawnEnv,n.spawnEnv?.allow),ze=Nn(e.bin),De=Fn(e.humanActions);return{bin:ze,humanActions:De,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,consolidate_replies:Ie,keybindings:Pe,tmux_passthrough:Te,modelLadders:Ce,providerOptions:$e,...Object.keys(J).length>0?{modelRoutes:J}:{},...Object.keys(U.legacy).length>0?{legacyModelRoutes:U.legacy}:{},...Z!==void 0?{modelRouting:Z}:{},kinds:Me,remoteCanvas:Ne,api:Le,..._?{paths:_}:{},...Y?{store:Y}:{},...v?{runtime:v}:{},spawnEnv:Fe}}s(z,"mergeConfig");function Bn(e){return I(e)}s(Bn,"readRawConfigAtRoot");function Wn(e){const n=y(e);return n?Bn(n):null}s(Wn,"readRawScopeConfig");function Hn(e){if(e===null||e==="")return null;try{return I(q(e))}catch{return null}}s(Hn,"readRawProfileConfig");function Jn(e,n){return[...un(e,n)].reverse().map(r=>({root:r,raw:I(r)}))}s(Jn,"readRawProjectScopeConfigs");function he(e=process.cwd(),n=Ke()||null){const o=P[T];if(o)return o.launch;const t=k(),r=Wn("user"),i=Hn(n),c=Jn(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 $o(e){return he().kinds[e]}s($o,"resolveKindConfig");function Mo(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(Mo,"subKindsAvailableTo");function Zn(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(Zn,"sparseModelLaddersToPersist");function Yn(e,n){return S(e,o=>{const t=z(o),r=z(o);n(r);const i={...o};for(const u of vn)u!=="modelLadders"&&!We(r[u],t[u])&&(i[u]=r[u]);const c=Zn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Yn,"mutateConfigAtRoot");function No(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(No,"persistModelLadders");function Lo(e,n,o){if(o!==void 0)Tn(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(Lo,"persistModelRoute");function Vn(e,n){return Yn(e,n)}s(Vn,"updateConfigAtRoot");function Fo(e,n){return Vn(w(e),n)}s(Fo,"updateConfig");function zo(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(zo,"persistDefaultKindModel");function Do(e,n){const o=Rn(e);return n(o),On(e,o),o}s(Do,"updateState");export{xn as InvalidRawSettingsError,Mn as binDeclarationIssues,wo as brokerConfigSnapshot,_o as configPath,Oo as ensureScopeInitialized,Ln as humanActionDeclarationIssues,ko as installBrokerConfigSnapshot,Eo as invalidPluginBinReasons,Co as invalidPluginKindsReasons,Po as invalidPluginRequiresReasons,Nn as normalizeBin,Fn as normalizeHumanActions,Io as normalizeRequires,Pn as normalizeTmuxPassthrough,zo as persistDefaultKindModel,No as persistModelLadders,Lo as persistModelRoute,Sn as readConfig,jn as readConfigAtRoot,he as readMergedLaunchConfig,Bn as readRawConfigAtRoot,Wn as readRawScopeConfig,Ao as readRawSettingsForTarget,Rn as readState,So as replaceRawSettingsForTarget,$o as resolveKindConfig,To as resolvePageComponents,vo as statePath,Mo as subKindsAvailableTo,Fo as updateConfig,Vn as updateConfigAtRoot,jo as updateRawConfigAtomically,Do as updateState,Ro as writeConfig,xo as writeRawConfig,On as writeState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var w=Object.defineProperty;var c=(n,r)=>w(n,"name",{value:r,configurable:!0});import{prepared as v}from"../sqlite-statements.js";import{relative as b,sep as g}from"node:path";import{activeBackgroundBashJobs as x,readJobPgid as y}from"../bash-jobs.js";import{appSpace as S}from"../layout.js";import{getNode as l,recordSettledTurn as k}from"../canvas/index.js";import{transition as E}from"../runtime/lifecycle.js";import{openDb as _}from"../canvas/db.js";import{contextDir as R}from"../canvas/node-agent-paths.js";import{emitEvent as p}from"../events/emit.js";import{closeGrantStreams as C}from"../runs/events.js";import{grantedMounts as G,isGrantedSource as I,mountAllowed as P}from"../spaces/mounts.js";import{permissionsForRun as m}from"../spaces/permissions.js";import{stopNodeSandboxes as O}from"../spaces/stop.js";import{discardChangedGrantTokens as T}from"../providers/token-cache.js";import{activeGrantForApp as F,allGrants as M,mirrorOnly as A}from"./mirror.js";import{runRemovalCascades as D}from"./remove.js";import{notifyGrantChanges as N}from"./watch.js";import{launcherPresent as W,listSandboxes as j,stopSandboxPid as B}from"./sandboxes.js";import{checkCronFire as J}from"../../daemon/cron/authority.js";import{cronExecutionFor as L}from"../../daemon/cron/live-runs.js";import{cronExecutionsReady as U}from"../../daemon/cron/run-socket.js";function h(){return new Map(v(_(),"SELECT uid, app, status FROM app_users").all().map(n=>[n.uid,{app:n.app,status:n.status}]))}c(h,"appUserOwners");function $(n,r=h()){const o=r.get(n.uid),i=n.nodeId.startsWith("cron-"),e=i?L(n.nodeId.slice(5)):void 0;if(i&&(e===void 0||!o))return"permission_revoked";if(e!==void 0&&o.status==="active"){const s=J({grantee:e.grantee,sub:e.sub,grant_id:e.grantId,scopes:e.scopes});if(!s.allowed)return e.refusal??={reason:s.reason,message:s.message},"permission_revoked"}if(!o||o.app==="app:terminal")return null;if(o.status!=="active")return"app_removed";const t=l(n.nodeId);try{let s;if(e!==void 0)s=m(e.grantee,e.sub,e.grantId,e.scopes);else if(t&&t.grantee===o.app)s=m(o.app,t.sub??"user:local",t.grant_id??null,t.scopes??null);else{const d=F(o.app);if(!d)return"permission_revoked";s=m(o.app,d.sub,d.id,null)}const u=G(s),f=S(o.app).root;return n.mounts.every(d=>{const a=b(f,d.source);return a===""||a!==".."&&!a.startsWith(`..${g}`)&&!a.startsWith(g)||!I(o.app,d.source)||P(d,u)})?null:"permission_revoked"}catch{return"permission_revoked"}}c($,"exceeds");async function H(n){const r=l(n);if(!r)return;(r.status==="active"||r.status==="idle")&&E(n,"release");const o=new Date().toISOString();k(n,o),r.run_id&&r.run_id!==n&&v(_(),"UPDATE nodes SET last_settled_at = COALESCE(last_settled_at, ?) WHERE node_id = ?").run(o,r.run_id)}c(H,"afterRevocationStop");function q(n){const r=new Set,o=l(n);o?.pi_pid!=null&&r.add(o.pi_pid);try{const i=R(n,o?.grantee);for(const e of x(i,!0)){const t=y(i,e.jobId);t!==void 0&&r.add(t)}}catch{}return r}c(q,"nodePids");async function z(){if(!W())return{completion:Promise.resolve()};await U();const n=await j(),r=h(),o=n.flatMap(t=>{const s=$(t,r);return s?[{sandbox:t,reason:s}]:[]}),i=[],e=new Map;for(const t of o){p({level:"info",event:"daemon.grants.sandbox_stop",fields:{sandbox_node:t.sandbox.nodeId,pid:t.sandbox.pid,grantee:r.get(t.sandbox.uid).app,reason:t.reason}});const s=e.get(t.sandbox.nodeId)??[];s.push(t),e.set(t.sandbox.nodeId,s)}for(const[t,s]of e){const u=l(t),f=u?q(t):new Set,d=u!==null&&s.some(({sandbox:a})=>f.has(a.pid));i.push((async()=>{if(d){const a=await O(t,"permission_revoked",{holdRecovery:!0,after:c(()=>H(t),"after")});if(!a.confirmed)throw a.error??new Error(`stop of ${t} was not confirmed`)}for(const{sandbox:a}of s)(!d||!f.has(a.pid))&&await B(a.pid)})().catch(a=>{p({level:"error",event:"daemon.grants.sandbox_stop_failed",...u?{node_id:t}:{fields:{sandbox_node:t}},error:a})}))}return{completion:Promise.all(i).then(()=>{})}}c(z,"sweepSandboxes");function K(n,r){try{const{pairs:o,tokens:
|
|
1
|
+
var w=Object.defineProperty;var c=(n,r)=>w(n,"name",{value:r,configurable:!0});import{prepared as v}from"../sqlite-statements.js";import{relative as b,sep as g}from"node:path";import{activeBackgroundBashJobs as x,readJobPgid as y}from"../bash-jobs.js";import{appSpace as S}from"../layout.js";import{getNode as l,recordSettledTurn as k}from"../canvas/index.js";import{transition as E}from"../runtime/lifecycle.js";import{openDb as _}from"../canvas/db.js";import{contextDir as R}from"../canvas/node-agent-paths.js";import{emitEvent as p}from"../events/emit.js";import{closeGrantStreams as C}from"../runs/events.js";import{grantedMounts as G,isGrantedSource as I,mountAllowed as P}from"../spaces/mounts.js";import{permissionsForRun as m}from"../spaces/permissions.js";import{stopNodeSandboxes as O}from"../spaces/stop.js";import{discardChangedGrantTokens as T}from"../providers/token-cache.js";import{activeGrantForApp as F,allGrants as M,mirrorOnly as A}from"./mirror.js";import{runRemovalCascades as D}from"./remove.js";import{notifyGrantChanges as N}from"./watch.js";import{launcherPresent as W,listSandboxes as j,stopSandboxPid as B}from"./sandboxes.js";import{checkCronFire as J}from"../../daemon/cron/authority.js";import{cronExecutionFor as L}from"../../daemon/cron/live-runs.js";import{cronExecutionsReady as U}from"../../daemon/cron/run-socket.js";function h(){return new Map(v(_(),"SELECT uid, app, status FROM app_users").all().map(n=>[n.uid,{app:n.app,status:n.status}]))}c(h,"appUserOwners");function $(n,r=h()){const o=r.get(n.uid),i=n.nodeId.startsWith("cron-"),e=i?L(n.nodeId.slice(5)):void 0;if(i&&(e===void 0||!o))return"permission_revoked";if(e!==void 0&&o.status==="active"){const s=J({grantee:e.grantee,sub:e.sub,grant_id:e.grantId,scopes:e.scopes});if(!s.allowed)return e.refusal??={reason:s.reason,message:s.message},"permission_revoked"}if(!o||o.app==="app:terminal")return null;if(o.status!=="active")return"app_removed";const t=l(n.nodeId);try{let s;if(e!==void 0)s=m(e.grantee,e.sub,e.grantId,e.scopes);else if(t&&t.grantee===o.app)s=m(o.app,t.sub??"user:local",t.grant_id??null,t.scopes??null);else{const d=F(o.app);if(!d)return"permission_revoked";s=m(o.app,d.sub,d.id,null)}const u=G(s),f=S(o.app).root;return n.mounts.every(d=>{const a=b(f,d.source);return a===""||a!==".."&&!a.startsWith(`..${g}`)&&!a.startsWith(g)||!I(o.app,d.source)||P(d,u)})?null:"permission_revoked"}catch{return"permission_revoked"}}c($,"exceeds");async function H(n){const r=l(n);if(!r)return;(r.status==="active"||r.status==="idle")&&E(n,"release");const o=new Date().toISOString();k(n,o),r.run_id&&r.run_id!==n&&v(_(),"UPDATE nodes SET last_settled_at = COALESCE(last_settled_at, ?) WHERE node_id = ?").run(o,r.run_id)}c(H,"afterRevocationStop");function q(n){const r=new Set,o=l(n);o?.pi_pid!=null&&r.add(o.pi_pid);try{const i=R(n,o?.grantee);for(const e of x(i,!0)){const t=y(i,e.jobId);t!==void 0&&r.add(t)}}catch{}return r}c(q,"nodePids");async function z(){if(!W())return{completion:Promise.resolve()};await U();const n=await j(),r=h(),o=n.flatMap(t=>{const s=$(t,r);return s?[{sandbox:t,reason:s}]:[]}),i=[],e=new Map;for(const t of o){p({level:"info",event:"daemon.grants.sandbox_stop",fields:{sandbox_node:t.sandbox.nodeId,pid:t.sandbox.pid,grantee:r.get(t.sandbox.uid).app,reason:t.reason}});const s=e.get(t.sandbox.nodeId)??[];s.push(t),e.set(t.sandbox.nodeId,s)}for(const[t,s]of e){const u=l(t),f=u?q(t):new Set,d=u!==null&&s.some(({sandbox:a})=>f.has(a.pid));i.push((async()=>{if(d){const a=await O(t,"permission_revoked",{holdRecovery:!0,after:c(()=>H(t),"after")});if(!a.confirmed)throw a.error??new Error(`stop of ${t} was not confirmed`)}for(const{sandbox:a}of s)(!d||!f.has(a.pid))&&await B(a.pid)})().catch(a=>{p({level:"error",event:"daemon.grants.sandbox_stop_failed",...u?{node_id:t}:{fields:{sandbox_node:t}},error:a})}))}return{completion:Promise.all(i).then(()=>{})}}c(z,"sweepSandboxes");function K(n,r){try{const{pairs:o,providers:i,tokens:e}=T(n,r);(o||i)&&p({level:"info",event:"daemon.grants.outbound_tokens_discarded",fields:{grants:o,providers:i,tokens:e}})}catch(o){p({level:"error",event:"daemon.grants.outbound_tokens_discard_failed",error:o})}}c(K,"discardOutboundTokens");async function he(n,r=o=>{}){const o=M();try{N(n,o)}catch(e){p({level:"error",event:"daemon.grants.notify_failed",error:e})}K(n,o);for(const e of n){if(e.status!=="active"||o.find(u=>u.id===e.id)?.status==="active")continue;const s=C(e.id);s&&p({level:"info",event:"daemon.grants.streams_closed",fields:{grant:e.id,grantee:e.grantee,streams:s}})}try{const{completion:e}=await z();r(e)}catch(e){p({level:"error",event:"daemon.grants.sweep_failed",error:e})}const i=new Set(o.filter(e=>!A(e)&&e.status==="removed"&&n.find(t=>t.id===e.id)?.status!=="removed").map(e=>e.grantee));r(D(i).catch(()=>{})),r(import("../providers/bundles.js").then(({syncProviderBundles:e})=>e()).catch(e=>{p({level:"error",event:"daemon.providers.bundle_sync_failed",error:e})}))}c(he,"onGrantSync");export{$ as exceeds,he as onGrantSync,z as sweepSandboxes};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
var P=Object.defineProperty;var y=(e,c)=>P(e,"name",{value:c,configurable:!0});import{DatabaseSync as S}from"node:sqlite";import{closeSync as F,existsSync as m,fsyncSync as C,lstatSync as D,openSync as B,readFileSync as $,readdirSync as g,renameSync as J,unlinkSync as x,writeFileSync as q}from"node:fs";import{basename as L,dirname as N,join as a,relative as v,resolve as H,sep as A}from"node:path";import{homedir as G}from"node:os";function M(e,c){return typeof e=="string"?c.map.mapPath(e):Array.isArray(e)?e.map(r=>M(r,c)):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([r,i])=>[r,M(i,c)])):e}y(M,"mappedJson");function b(e,c){const r=JSON.parse(e),i=M(r,c);return JSON.stringify(i)===JSON.stringify(r)?e:JSON.stringify(i)}y(b,"rewriteJson");function O(e,c){return e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(c)!==void 0}y(O,"tableExists");function T(e,c,r){if(!m(e))return;const i=new S(e);try{i.exec("BEGIN IMMEDIATE");try{for(const[f,p]of Object.entries(c)){if(!O(i,f))continue;const u=new Set(i.prepare(`PRAGMA table_info("${f}")`).all().map(o=>o.name)),d=[...(p.paths??[]).filter(o=>u.has(o)),...(p.json??[]).filter(o=>u.has(o))];if(d.length===0)continue;const s=i.prepare(`SELECT rowid AS migration_rowid, ${d.map(o=>`"${o}"`).join(", ")} FROM "${f}"`).all();for(const o of s){const l=[];for(const n of d){const t=o[n];if(typeof t!="string")continue;const h=(p.json??[]).includes(n)?b(t,r):r.map.mapPath(t);h!==t&&l.push([n,h])}l.length&&(i.prepare(`UPDATE "${f}" SET ${l.map(([n])=>`"${n}" = ?`).join(", ")} WHERE rowid = ?`).run(...l.map(([,n])=>n),o.migration_rowid),r.moved+=l.length,r.changes.push(`${e}:${f}:${String(o.migration_rowid)} (${l.map(([n])=>n).join(", ")})`))}}i.exec("COMMIT")}catch(f){throw i.exec("ROLLBACK"),f}}finally{i.close()}}y(T,"rewriteDb");const k={nodes:{paths:["cwd","fork_source_file","pi_session_file"],json:["launch_config_json","review_binding_json","metadata_json","outcome_detail_json"]},sessions:{paths:["transcript_path","fork_source_path"]},worktrees:{paths:["path","repo_root"],json:["sweep_observed_json","abandoned_json","land_intent_json","disposal_json"]},crons:{paths:["cwd"],json:["env_json","sink"]},human_action_deliveries:{paths:["cwd"],json:["argv_json","completion_json","last_failure_json"]},deliveries:{json:["adapter_json"]},reviews:{paths:["origin_session_file","review_dir","branch_file","output_path","file","presentation_dir"],json:["result_json","specification_json"]},human_requests:{paths:["request_dir","file","presentation_dir"],json:["specification_json","action_json","progress_json","feedback_json","result_json"]},run_events:{json:["body_json"]},webhook_deliveries:{json:["payload_json","document_json","last_failure_json","argv_json"]}},W={scope_owners:{paths:["root"]},profiles:{paths:["home"]},profile_projects:{paths:["path"]},profile_defaults:{paths:["directory"]},scope_bookkeeping:{paths:["active_canvas"]},scope_settings:{json:["raw_json"]}};function E(e,c,r){if(!m(e))return;const i=$(e,"utf8"),f=r(i);if(f===i)return;const p=D(e);if(!p.isFile())throw new Error(`migration path is not a regular file: ${e}`);const u=`${e}.migration-tmp`;if(m(u))throw new Error(`migration temporary file already exists: ${u}`);try{q(u,f,{flag:"wx",mode:p.mode});const d=B(u,"r");try{C(d)}finally{F(d)}J(u,e)}finally{m(u)&&x(u)}c.moved++,c.changes.push(`${e} (stored paths)`)}y(E,"rewriteFile");function _(e,c){if(m(e))for(const r of g(e,{withFileTypes:!0})){const i=a(e,r.name);r.isDirectory()?_(i,c):r.isFile()&&c(i)}}y(_,"walk");function U(e,c,r){const{map:i}=e,{old:f}=i,p=new Map,u=new Set,d=new Set;_(c,n=>{if(!n.includes("/conversations/")||!n.endsWith(".jsonl"))return;const t=L(n);p.has(t)?u.add(t):p.set(t,a(f.targetRoot,v(f.root,n)))});const s=y(n=>{if(typeof n=="string"){if(!n.startsWith(f.storedAgent+A+"sessions"+A)||d.has(n)||i.mapPath(n)!==n)return;const t=L(n);if(u.has(t)||!p.has(t)){d.has(n)||e.resolutions.push(`lost-transcript: ${n} is referenced but ${u.has(t)?"matches more than one moved transcript":"exists nowhere"}; left the reference unchanged`),d.add(n);return}i.add(n,p.get(t))}else if(Array.isArray(n))for(const t of n)s(t);else if(n!==null&&typeof n=="object")for(const t of Object.values(n))s(t)},"reference"),o=y(n=>{if(n.endsWith("/meta.json")||n.endsWith(".json")&&(n.includes("/tickets/")||n.includes("/requests/")))s(JSON.parse($(n,"utf8")));else if(n.endsWith(".jsonl")&&n.includes("/conversations/")){const t=$(n,"utf8");s(JSON.parse(t.slice(0,t.indexOf(`
|
|
2
2
|
`)<0?void 0:t.indexOf(`
|
|
3
|
-
`))))}else if(n.endsWith(".md")&&n.includes("/memory/")){const t=$(n,"utf8");if(!t.startsWith(`---
|
|
3
|
+
`))))}else if(n.endsWith(".md")&&(n.includes("/memory/")||n.includes("/profiles/"))){const t=$(n,"utf8");if(!t.startsWith(`---
|
|
4
4
|
`))return;const h=t.indexOf(`
|
|
5
5
|
---`,4);if(h<0)return;for(const j of t.slice(0,h).split(`
|
|
6
|
-
`)){const w=j.match(/^\s*session_file:\s*["']?([^"'\n]+)["']?$/);w&&s(w[1])}}},"inspect");_(c,o),_(a(f.root,"user","memory"),o),_(a(r,"nodes"),o),_(a(r,"tickets"),o),_(a(r,"requests"),o);const l=a(r,"canvas.db");if(m(l)){const n=new S(l,{readOnly:!0});try{for(const[t,h]of Object.entries(k)){if(!O(n,t))continue;const j=new Set(n.prepare(`PRAGMA table_info("${t}")`).all().map(w=>w.name));for(const w of[...h.paths??[],...h.json??[]].filter(R=>j.has(R)))for(const R of n.prepare(`SELECT "${w}" AS value FROM "${t}" WHERE "${w}" LIKE ?`).all(`%${f.storedAgent}/sessions/%`))(h.json??[]).includes(w)?s(JSON.parse(R.value)):s(R.value)}}finally{n.close()}}}y(U,"recoverSessionMappings");function se(e){const{root:c}=e.map.old,r=a(c,"runtime"),i=a(c,"apps");U(e,i,r),T(a(r,"canvas.db"),k,e),T(a(r,"scope","operations.db"),W,e);const f=new Set,p=a(r,"canvas.db");if(m(p)){const s=new S(p,{readOnly:!0});try{if(O(s,"nodes")&&s.prepare("PRAGMA table_info(nodes)").all().some(o=>o.name==="cwd"))for(const o of s.prepare("SELECT cwd FROM nodes").all())f.add(o.cwd)}finally{s.close()}}const u=a(r,"scope","operations.db");if(m(u)){const s=new S(u,{readOnly:!0});try{if(O(s,"profile_projects"))for(const o of s.prepare("SELECT path FROM profile_projects").all())f.add(o.path)}finally{s.close()}}for(const s of f){const o=e.map.old.targetRoot;let l=s.startsWith(o+"/")?H(c,v(o,s)):s;for(;l!==N(l);)T(a(l,".crouter","operations.db"),W,e),l=N(l)}_(a(i),s=>{s.endsWith("/.crouter/operations.db")&&T(s,W,e),s.endsWith("/meta.json")&&E(s,e,o=>b(o,e)),s.endsWith(".md")&&s.includes("/memory/")&&I(s,e),s.endsWith(".jsonl")&&s.includes("/conversations/")&&X(s,e)}),_(a(c,"user","memory"),s=>{s.endsWith(".md")&&I(s,e)}),Y(e);for(const s of e.map.dangling)e.resolutions.push(`dangling-path: ${s} names a file the new layout drops; left the stored path unchanged`);_(a(c,"user","files"),s=>{s.endsWith("/.crouter/operations.db")&&T(s,W,e)}),_(a(r,"nodes"),s=>{s.endsWith("/meta.json")&&E(s,e,o=>b(o,e)),s.endsWith("/session.ptr")&&x(s)}),_(a(r,"tickets"),s=>{s.endsWith(".json")&&E(s,e,o=>b(o,e))}),_(a(r,"requests"),s=>{s.endsWith(".json")&&E(s,e,o=>b(o,e))});const d=a(r,"canvas.db");if(m(d)){const s=new S(d);try{s.exec("DROP TABLE IF EXISTS layout_header_rewrites")}finally{s.close()}}}y(se,"storedPaths");function I(e,c){E(e,c,r=>{if(!r.startsWith(`---
|
|
6
|
+
`)){const w=j.match(/^\s*session_file:\s*["']?([^"'\n]+)["']?$/);w&&s(w[1])}}},"inspect");_(c,o),_(a(f.root,"user","memory"),o),_(a(r,"nodes"),o),_(a(r,"tickets"),o),_(a(r,"requests"),o);const l=a(r,"canvas.db");if(m(l)){const n=new S(l,{readOnly:!0});try{for(const[t,h]of Object.entries(k)){if(!O(n,t))continue;const j=new Set(n.prepare(`PRAGMA table_info("${t}")`).all().map(w=>w.name));for(const w of[...h.paths??[],...h.json??[]].filter(R=>j.has(R)))for(const R of n.prepare(`SELECT "${w}" AS value FROM "${t}" WHERE "${w}" LIKE ?`).all(`%${f.storedAgent}/sessions/%`))(h.json??[]).includes(w)?s(JSON.parse(R.value)):s(R.value)}}finally{n.close()}}}y(U,"recoverSessionMappings");function se(e){const{root:c}=e.map.old,r=a(c,"runtime"),i=a(c,"apps");U(e,i,r),T(a(r,"canvas.db"),k,e),T(a(r,"scope","operations.db"),W,e);const f=new Set,p=a(r,"canvas.db");if(m(p)){const s=new S(p,{readOnly:!0});try{if(O(s,"nodes")&&s.prepare("PRAGMA table_info(nodes)").all().some(o=>o.name==="cwd"))for(const o of s.prepare("SELECT cwd FROM nodes").all())f.add(o.cwd)}finally{s.close()}}const u=a(r,"scope","operations.db");if(m(u)){const s=new S(u,{readOnly:!0});try{if(O(s,"profile_projects"))for(const o of s.prepare("SELECT path FROM profile_projects").all())f.add(o.path)}finally{s.close()}}for(const s of f){const o=e.map.old.targetRoot;let l=s.startsWith(o+"/")?H(c,v(o,s)):s;for(;l!==N(l);)T(a(l,".crouter","operations.db"),W,e),l=N(l)}_(a(i),s=>{s.endsWith("/.crouter/operations.db")&&T(s,W,e),s.endsWith("/meta.json")&&E(s,e,o=>b(o,e)),s.endsWith(".md")&&(s.includes("/memory/")||s.includes("/profiles/"))&&I(s,e),s.endsWith(".jsonl")&&s.includes("/conversations/")&&X(s,e)}),_(a(c,"user","memory"),s=>{s.endsWith(".md")&&I(s,e)}),Y(e);for(const s of e.map.dangling)e.resolutions.push(`dangling-path: ${s} names a file the new layout drops; left the stored path unchanged`);_(a(c,"user","files"),s=>{s.endsWith("/.crouter/operations.db")&&T(s,W,e)}),_(a(r,"nodes"),s=>{s.endsWith("/meta.json")&&E(s,e,o=>b(o,e)),s.endsWith("/session.ptr")&&x(s)}),_(a(r,"tickets"),s=>{s.endsWith(".json")&&E(s,e,o=>b(o,e))}),_(a(r,"requests"),s=>{s.endsWith(".json")&&E(s,e,o=>b(o,e))});const d=a(r,"canvas.db");if(m(d)){const s=new S(d);try{s.exec("DROP TABLE IF EXISTS layout_header_rewrites")}finally{s.close()}}}y(se,"storedPaths");function I(e,c){E(e,c,r=>{if(!r.startsWith(`---
|
|
7
7
|
`))return r;const i=r.indexOf(`
|
|
8
8
|
---`,4);return i<0?r:r.slice(0,i).replace(/^(\s*session_file:\s*)([^\n]+)$/gm,(p,u,d)=>{const s=d.match(/^(["'])(.*)\1$/),o=s?s[2]:d.trim(),l=c.map.mapPath(o);return l===o?p:`${u}${s?s[1]:""}${l}${s?s[1]:""}`})+r.slice(i)})}y(I,"rewriteMemory");function X(e,c){const r=a(c.map.old.root,"runtime","canvas.db");if(!m(r)){E(e,c,f=>{const p=f.indexOf(`
|
|
9
9
|
`),u=p<0?f:f.slice(0,p);return b(u,c)+(p<0?"":f.slice(p))});return}const i=new S(r);try{i.exec("CREATE TABLE IF NOT EXISTS layout_header_rewrites (path TEXT PRIMARY KEY, old_header TEXT NOT NULL, new_header TEXT NOT NULL)");const f=i.prepare("SELECT old_header, new_header FROM layout_header_rewrites WHERE path = ?").get(e),p=$(e,"utf8"),u=p.indexOf(`
|
|
10
10
|
`),d=u<0?p:p.slice(0,u),s=f?.new_header??b(d,c);if(f&&d!==f.old_header&&d!==s)throw new Error(`conversation header changed during migration: ${e}`);if(!f&&s!==d){const o=a(c.map.old.targetRoot,v(c.map.old.root,e)),l=Buffer.byteLength(s)-Buffer.byteLength(d);i.exec("BEGIN IMMEDIATE");try{i.prepare("INSERT INTO layout_header_rewrites (path, old_header, new_header) VALUES (?, ?, ?)").run(e,d,s),l!==0&&O(i,"sessions")&&i.prepare("UPDATE sessions SET event_offset = event_offset + ? WHERE transcript_path = ? AND event_offset > 0").run(l,o),i.exec("COMMIT")}catch(n){throw i.exec("ROLLBACK"),n}}d!==s&&E(e,c,o=>{const l=o.indexOf(`
|
|
11
|
-
`);if((l<0?o:o.slice(0,l))!==d)throw new Error(`conversation header changed during migration: ${e}`);return s+(l<0?"":o.slice(l))}),(f||s!==d)&&i.prepare("DELETE FROM layout_header_rewrites WHERE path = ?").run(e)}finally{i.close()}}y(X,"rewriteHeader");function K(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}y(K,"escape");function Y(e){const c=e.bodyPaths;if(c.length===0)return;const r=G(),i=[];for(const[t,h]of c)i.push([t,h]),t.startsWith(r+A)&&i.push([`~${t.slice(r.length)}`,h.startsWith(r+A)?`~${h.slice(r.length)}`:h]);i.sort((t,h)=>h[0].length-t[0].length);const f=new RegExp(`(${i.map(([t])=>K(t)).join("|")})(?![A-Za-z0-9_-])`,"g"),p=new Map(i),{root:u,scope:d,canvas:s}=e.map.old,o=y(t=>{if(!t.endsWith(".md"))return;if(e.dryRun){const j=$(t,"utf8").match(f)?.length??0;j&&e.resolutions.push(`profile-extra-link: rewrote ${j} link(s) to moved profile files in ${t}`);return}let h=0;E(t,e,j=>j.replace(f,w=>(h++,p.get(w)))),h&&e.resolutions.push(`profile-extra-link: rewrote ${h} link(s) to moved profile files in ${t}`)},"visit"),l=y(t=>{if(m(t))for(const h of g(t))_(a(t,h,"context"),o)},"nodeContexts");if(e.dryRun){_(a(d,"memory"),o),_(a(d,"profiles"),o),l(a(s,"nodes"));return}_(a(u,"user","memory"),o);const n=a(u,"apps");if(m(n))for(const t of g(n))_(a(n,t,"memory"),o),_(a(n,t,"files","profiles"),o),l(a(n,t,"nodes"))}y(Y,"rewriteBodyPaths");export{Y as rewriteBodyPaths,se as storedPaths};
|
|
11
|
+
`);if((l<0?o:o.slice(0,l))!==d)throw new Error(`conversation header changed during migration: ${e}`);return s+(l<0?"":o.slice(l))}),(f||s!==d)&&i.prepare("DELETE FROM layout_header_rewrites WHERE path = ?").run(e)}finally{i.close()}}y(X,"rewriteHeader");function K(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}y(K,"escape");function Y(e){const c=e.bodyPaths;if(c.length===0)return;const r=G(),i=[];for(const[t,h]of c)i.push([t,h]),t.startsWith(r+A)&&i.push([`~${t.slice(r.length)}`,h.startsWith(r+A)?`~${h.slice(r.length)}`:h]);i.sort((t,h)=>h[0].length-t[0].length);const f=new RegExp(`(${i.map(([t])=>K(t)).join("|")})(?![A-Za-z0-9_-])`,"g"),p=new Map(i),{root:u,scope:d,canvas:s}=e.map.old,o=y(t=>{if(!t.endsWith(".md"))return;if(e.dryRun){const j=$(t,"utf8").match(f)?.length??0;j&&e.resolutions.push(`profile-extra-link: rewrote ${j} link(s) to moved profile files in ${t}`);return}let h=0;E(t,e,j=>j.replace(f,w=>(h++,p.get(w)))),h&&e.resolutions.push(`profile-extra-link: rewrote ${h} link(s) to moved profile files in ${t}`)},"visit"),l=y(t=>{if(m(t))for(const h of g(t))_(a(t,h,"context"),o)},"nodeContexts");if(e.dryRun){_(a(d,"memory"),o),_(a(d,"profiles"),o),l(a(s,"nodes"));return}_(a(u,"user","memory"),o);const n=a(u,"apps");if(m(n))for(const t of g(n))_(a(n,t,"memory"),o),_(a(n,t,"profiles"),o),_(a(n,t,"files","profiles"),o),l(a(n,t,"nodes"))}y(Y,"rewriteBodyPaths");export{Y as rewriteBodyPaths,se as storedPaths};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var oe=Object.defineProperty;var h=(e,t)=>oe(e,"name",{value:t,configurable:!0});import{DatabaseSync as z}from"node:sqlite";import{closeSync as se,copyFileSync as re,existsSync as u,realpathSync as ne,fsyncSync as pe,lstatSync as $,mkdirSync as B,openSync as ce,readFileSync as T,readdirSync as E,renameSync as M,rmdirSync as F,unlinkSync as D,writeFileSync as J}from"node:fs";import{execFileSync as Z}from"node:child_process";import{basename as x,dirname as R,isAbsolute as q,join as n,relative as k,resolve as C,sep as P}from"node:path";import{profileSpace as ae}from"../layout.js";import{isJunkFile as j,movePath as S,sameFile as A,setAside as O,setAsidePath as H}from"./index.js";import{rewriteBodyPaths as ie}from"./stored-paths.js";function L(e,t){Z("git",["-c",`safe.directory=${e}`,"-C",e,...t],{stdio:"pipe"})}h(L,"gitInRepo");function _(e,t){const{root:s,targetRoot:p}=t.map.old;return C(s,k(p,e))}h(_,"physical");function N(e,t=!1){const{old:s}=e.map,p=n(s.canvas,"canvas.db"),o=n(s.root,"runtime","canvas.db"),r=u(p)?p:o;return u(r)&&$(r).size>0?new z(r,{readOnly:!t||e.dryRun}):null}h(N,"canvasDb");function W(e){return new Map(e.prepare("SELECT node_id, grantee FROM nodes").all().map(({node_id:t,grantee:s})=>{const p=s==="user:local"?"terminal":s.startsWith("app:")?s.slice(4):"";if(!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(p))throw new Error(`node ${t} has no valid app`);return[t,p]}))}h(W,"nodeApps");function Y(e,t,s){return n(s.map.old.targetRoot,"apps",e,"files","profiles",t)}h(Y,"profileFiles");function G(e,t,s,p){if(!u(e))return;if(!u(t)){S(e,t,p);return}const o=$(e),r=$(t);if(o.isDirectory()&&r.isDirectory()){for(const d of E(e))G(n(e,d),n(t,d),n(s,d),p);F(e);return}if(o.isFile()&&r.isFile()&&A(e,t)){D(e);return}const a=_(s,p);p.dryRun||S(e,a,p),p.resolutions.push(`profile-home: ${t} differs from the profile's ${e}; kept the app home's copy, moved the profile's to ${a}`)}h(G,"mergeHome");function K(e,t,s,p){if(!u(e)||!u(t))return;const o=$(e),r=$(t);if(o.isDirectory()&&r.isDirectory()){for(const a of E(e))K(n(e,a),n(t,a),n(s,a),p);return}o.isFile()&&r.isFile()&&A(e,t)||p.resolutions.push(`profile-home: ${t} differs from the profile's ${e}; kept the app home's copy, moved the profile's to ${_(s,p)}`)}h(K,"previewHome");function Q(e,t,s){e.bodyPaths.some(([p])=>p===t)||e.bodyPaths.push([t,s])}h(Q,"bodyPath");function V(e){const{map:t}=e,s=[n(t.old.scope,"operations.db"),n(t.old.root,"runtime","scope","operations.db")].find(u),p=s?new z(s,{readOnly:!0}):null,o=new Map;try{if(p&&p.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='profiles'").get())for(const i of p.prepare("SELECT id, grantee FROM profiles").all())o.set(i.id,i.grantee)}finally{p?.close()}const r=new Map;for(const[i,c]of o){const w=c==null||c==="user:local"?"terminal":c.startsWith("app:")?c.slice(4):"",f=ae(w,i),y=n(t.old.storedScope,"profiles",i);t.retire(y,f.
|
|
1
|
+
var oe=Object.defineProperty;var h=(e,t)=>oe(e,"name",{value:t,configurable:!0});import{DatabaseSync as z}from"node:sqlite";import{closeSync as se,copyFileSync as re,existsSync as u,realpathSync as ne,fsyncSync as pe,lstatSync as $,mkdirSync as B,openSync as ce,readFileSync as T,readdirSync as E,renameSync as M,rmdirSync as F,unlinkSync as D,writeFileSync as J}from"node:fs";import{execFileSync as Z}from"node:child_process";import{basename as x,dirname as R,isAbsolute as q,join as n,relative as k,resolve as C,sep as P}from"node:path";import{profileSpace as ae}from"../layout.js";import{isJunkFile as j,movePath as S,sameFile as A,setAside as O,setAsidePath as H}from"./index.js";import{rewriteBodyPaths as ie}from"./stored-paths.js";function L(e,t){Z("git",["-c",`safe.directory=${e}`,"-C",e,...t],{stdio:"pipe"})}h(L,"gitInRepo");function _(e,t){const{root:s,targetRoot:p}=t.map.old;return C(s,k(p,e))}h(_,"physical");function N(e,t=!1){const{old:s}=e.map,p=n(s.canvas,"canvas.db"),o=n(s.root,"runtime","canvas.db"),r=u(p)?p:o;return u(r)&&$(r).size>0?new z(r,{readOnly:!t||e.dryRun}):null}h(N,"canvasDb");function W(e){return new Map(e.prepare("SELECT node_id, grantee FROM nodes").all().map(({node_id:t,grantee:s})=>{const p=s==="user:local"?"terminal":s.startsWith("app:")?s.slice(4):"";if(!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(p))throw new Error(`node ${t} has no valid app`);return[t,p]}))}h(W,"nodeApps");function Y(e,t,s){return n(s.map.old.targetRoot,"apps",e,"files","profiles",t)}h(Y,"profileFiles");function G(e,t,s,p){if(!u(e))return;if(!u(t)){S(e,t,p);return}const o=$(e),r=$(t);if(o.isDirectory()&&r.isDirectory()){for(const d of E(e))G(n(e,d),n(t,d),n(s,d),p);F(e);return}if(o.isFile()&&r.isFile()&&A(e,t)){D(e);return}const a=_(s,p);p.dryRun||S(e,a,p),p.resolutions.push(`profile-home: ${t} differs from the profile's ${e}; kept the app home's copy, moved the profile's to ${a}`)}h(G,"mergeHome");function K(e,t,s,p){if(!u(e)||!u(t))return;const o=$(e),r=$(t);if(o.isDirectory()&&r.isDirectory()){for(const a of E(e))K(n(e,a),n(t,a),n(s,a),p);return}o.isFile()&&r.isFile()&&A(e,t)||p.resolutions.push(`profile-home: ${t} differs from the profile's ${e}; kept the app home's copy, moved the profile's to ${_(s,p)}`)}h(K,"previewHome");function Q(e,t,s){e.bodyPaths.some(([p])=>p===t)||e.bodyPaths.push([t,s])}h(Q,"bodyPath");function V(e){const{map:t}=e,s=[n(t.old.scope,"operations.db"),n(t.old.root,"runtime","scope","operations.db")].find(u),p=s?new z(s,{readOnly:!0}):null,o=new Map;try{if(p&&p.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='profiles'").get())for(const i of p.prepare("SELECT id, grantee FROM profiles").all())o.set(i.id,i.grantee)}finally{p?.close()}const r=new Map;for(const[i,c]of o){const w=c==null||c==="user:local"?"terminal":c.startsWith("app:")?c.slice(4):"",f=ae(w,i),y=n(t.old.storedScope,"profiles",i);t.retire(y,f.dir),t.add(n(y,"memory"),f.dir),t.add(n(y,"env.json"),f.env),t.add(n(y,"home"),f.home),r.set(i,{target:f,app:w})}const a=n(t.old.scope,"profiles"),d={folders:[],junk:[],aside:[]};if(!u(a))return d;for(const i of E(a)){const c=n(a,i);if(!$(c).isDirectory()){(j(i)?d.junk:d.aside).push(c);continue}if(i===".locks"){for(const l of E(c)){const v=n(c,l);!(l.endsWith(".lock")&&$(v).isFile())&&!j(l)&&d.aside.push(v)}continue}const w=n(t.old.storedScope,"profiles",i),f=r.get(i);if(!f){const l=Y("terminal",i,e);t.add(w,l),Q(e,w,l),d.folders.push({id:i,source:c,target:null,files:l,extras:[]});continue}const y=Y(f.app,i,e),b=[];for(const l of E(c)){const v=$(n(c,l));(l==="memory"||l==="home"?v.isDirectory():l==="env.json"||l==="profile.json"||l.endsWith(".lock")?v.isFile():j(l))||(b.push(l),t.add(n(w,l),n(y,l)),Q(e,n(w,l),n(y,l)))}d.folders.push({id:i,source:c,target:f.target,files:y,extras:b})}return d}h(V,"profileFolders");function X(e,t){for(const s of e.folders){s.target||t.resolutions.push(`profile-folder: ${s.source} has no profile row; moved whole to ${_(s.files,t)}`);for(const p of s.extras)t.resolutions.push(`profile-extra: ${n(s.source,p)} moved to ${_(n(s.files,p),t)}`)}for(const s of e.junk)t.resolutions.push(`profile-leftover: deleted ${s} (not profile data)`);for(const s of e.aside)t.resolutions.push(`profile-leftover: ${s} is not a profile; moved to ${H(t,"profiles",x(s))}`)}h(X,"profileLines");function Fe(e){const{map:t}=e;S(n(t.old.scope,"memory"),n(t.old.root,"user","memory"),e);const s=N(e);if(s)try{for(const[r,a]of W(s)){const d=n(t.old.root,"apps",a,"memory","nodes",r);S(n(t.old.root,"apps",a,"nodes",r,"context","memory"),d,e),S(n(t.old.canvas,"nodes",r,"context","memory"),d,e)}}finally{s.close()}const p=V(e);X(p,e);for(const{source:r,target:a,files:d,extras:i}of p.folders){if(!a){S(r,_(d,e),e,!0);continue}for(const c of i)S(n(r,c),_(n(d,c),e),e);S(n(r,"memory"),_(a.dir,e),e),S(n(r,"env.json"),_(a.env,e),e),G(n(r,"home"),_(a.home,e),n(d,"home"),e);for(const c of E(r))D(n(r,c));F(r),e.moved++,e.changes.push(`${r} (removed)`)}for(const r of p.junk)D(r);for(const r of p.aside)O(r,"profiles",e);const o=n(t.old.scope,"profiles");if(u(o)){const r=n(o,".locks");if(u(r)){for(const a of E(r))D(n(r,a));F(r)}F(o)}}h(Fe,"memoryAndProfiles");function de(e,t,s,p){if(u(e)){if(!$(e).isFile())throw new Error(`session path is not a file: ${e}`);if(B(R(t),{recursive:!0}),u(t)){if($(t).isFile()&&A(e,t))return;const o=O(t,"replaced",s,k(s.map.old.root,t));s.resolutions.push(`stray-destination: ${t} predates the migration; moved it to ${o} and put ${e} in its place`)}if(p){const o=n(R(t),`.${x(t)}.migrating`);u(o)&&D(o),re(e,o);const r=ce(o,"r");try{pe(r)}finally{se(r)}if(!A(e,o))throw new Error(`session copy verification failed: ${e}`);M(o,t),s.moved++,s.changes.push(`${e} -> ${t} (source retained)`);return}M(e,t),s.moved++,s.changes.push(`${e} -> ${t}`)}}h(de,"moveSession");function le(e,t,s){const p=new Set(t.prepare("SELECT s.transcript_path AS path FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.unbound_at IS NULL AND n.status IN ('active', 'idle') AND s.transcript_path IS NOT NULL").all().map(r=>r.path)),o=e.dryRun?null:t.prepare("UPDATE sessions SET transcript_path = NULL WHERE transcript_path = ?");for(const r of s)if(!(u(r.source)||u(_(r.destination,e)))){if(p.has(r.transcript_path)){e.resolutions.push(`lost-transcript: ${r.transcript_path} is missing but is a live node's current session; kept its path`);continue}o?.run(r.transcript_path),e.resolutions.push(`lost-transcript: ${r.transcript_path} is missing from both paths; cleared the session's transcript path`)}}h(le,"lostTranscripts");function fe(e){const t=N(e,!0);if(t)try{const s=W(t),p=t.prepare("SELECT session_id, node_id, transcript_path FROM sessions WHERE transcript_path IS NOT NULL ORDER BY session_id, (unbound_at IS NULL) DESC, created_at DESC, rowid DESC").all(),o=new Map,r=new Map,a=new Map;for(const c of p){o.has(c.session_id)||o.set(c.session_id,c.node_id),a.set(c.transcript_path,(a.get(c.transcript_path)??0)+1);const w=r.get(c.transcript_path)??new Set;w.add(c.session_id),r.set(c.transcript_path,w)}const d=new Set,i=[];for(const{session_id:c,node_id:w,transcript_path:f}of p){if(d.has(f))continue;if(d.add(f),r.get(f).size!==1)throw new Error(`two conversations share a transcript: ${f}`);const y=a.get(f)>1?o.get(c):w,b=s.get(y);if(!b)throw new Error(`session belongs to unknown node: ${y}`);if(!q(f))throw new Error(`session path is not absolute: ${f}`);const l=n(e.map.old.targetRoot,"apps",b,"conversations",y,x(f));if(f===l)continue;const v=f===e.map.old.storedAgent||f.startsWith(e.map.old.storedAgent+P),m=v?n(e.map.old.agent,k(e.map.old.storedAgent,f)):f;i.push({transcript_path:f,destination:l,source:m,retain:process.platform==="linux"&&v})}le(e,t,i);for(const{transcript_path:c,destination:w}of i)e.map.add(c,w);if(e.dryRun)return;for(const{destination:c,source:w,retain:f}of i)de(w,_(c,e),e,f)}finally{t.close()}}h(fe,"conversations");function De(e){if(process.platform!=="linux")return;const t=N(e);if(t)try{const s=t.prepare("SELECT node_id, path, repo_root FROM worktrees").all(),p=W(t);for(const o of s){const r=e.map.mapPath(o.repo_root);if(r===o.repo_root)continue;const a=p.get(o.node_id);if(!a)throw new Error(`worktree belongs to unknown node: ${o.node_id}`);const d=_(n(e.map.old.targetRoot,"apps",a,"nodes",o.node_id,"worktree"),e);if(!u(d))continue;L(_(r,e),["worktree","repair",d]);const i=o.path.startsWith(e.map.old.storedCanvas+P)?n(e.map.old.canvas,k(e.map.old.storedCanvas,o.path)):o.path;I(i,d,e)}}finally{t.close()}}h(De,"repairMovedRepositories");function I(e,t,s){const p=h(o=>{for(const r of E(o)){const a=n(o,r);if(r===".git"&&a!==n(t,".git")&&$(a).isFile()){const d=T(a,"utf8");if(!d.startsWith("gitdir: "))throw new Error(`invalid submodule git link: ${a}`);const i=d.slice(8).trim(),c=C(R(a),i),w=n(e,k(t,a)),f=C(R(w),i),y=u(c)?c:f;if(!u(y))throw new Error(`submodule git directory missing: ${w}`);const b=s?.map.mapPath(y)??y,l=s&&b!==y?_(b,s):y;if(!u(l))throw new Error(`moved submodule git directory missing: ${l}`);c!==l&&J(a,`gitdir: ${k(R(a),l)}
|
|
2
2
|
`);const v=n(l,"config"),m=T(v,"utf8");if(!/^\s*worktree\s*=.*$/m.test(m))throw new Error(`submodule has no worktree setting: ${v}`);const te=JSON.stringify(k(l,R(a))),U=m.replace(/^(\s*worktree\s*=).*$/m,`$1 ${te}`);U!==m&&J(v,U)}else r!==".git"&&$(a).isDirectory()&&p(a)}},"visit");p(t)}h(I,"repairSubmoduleLinks");function ue(e,t){return Z("git",["-c",`safe.directory=${e}`,"-C",e,...t],{stdio:"pipe",encoding:"utf8"})}h(ue,"gitOut");function g(e){try{return ne(e)}catch{return C(e)}}h(g,"real");function he(e,t){try{const s=g(t);return ue(e,["worktree","list","--porcelain"]).split(`
|
|
3
3
|
`).some(p=>p.startsWith("worktree ")&&g(p.slice(9))===s)}catch{return!1}}h(he,"registered");function we(e,t){if(!u(e))return!1;try{const s=T(n(t,".git"),"utf8");return s.startsWith("gitdir: ")?u(C(t,s.slice(8).trim())):!1}catch{return!1}}h(we,"repairable");function ee(e,t,s){s.dryRun||t.state!=="open"&&t.cleanup_state==="complete"||e.prepare("UPDATE worktrees SET state = CASE WHEN state = 'open' THEN 'closed' ELSE state END, cleanup_state = 'complete', closed_at = COALESCE(closed_at, ?) WHERE node_id = ?").run(new Date().toISOString(),t.node_id)}h(ee,"closeRow");function ye(e){const t=N(e,!0);if(t){try{const s=W(t),p=t.prepare("SELECT node_id, state, cleanup_state, path, repo_root FROM worktrees").all();for(const o of p){const r=s.get(o.node_id);if(!r)throw new Error(`worktree belongs to unknown node: ${o.node_id}`);if(!q(o.path))throw new Error(`worktree path is not absolute: ${o.path}`);const a=n(e.map.old.targetRoot,"apps",r,"nodes",o.node_id,"worktree");if(o.path===a)continue;const d=o.path===e.map.old.storedCanvas||o.path.startsWith(e.map.old.storedCanvas+P)?n(e.map.old.canvas,k(e.map.old.storedCanvas,o.path)):o.path,i=_(a,e);if(!u(d)){e.map.add(o.path,a),u(i)?!e.dryRun&&u(o.repo_root)&&(L(o.repo_root,["worktree","repair",i]),I(d,i)):o.state!=="open"&&o.cleanup_state==="complete"||(ee(t,o,e),e.resolutions.push(`missing-worktree: ${o.path} (node ${o.node_id}) is gone; closed its row`));continue}if(!he(o.repo_root,d))if(o.state==="open"&&we(o.repo_root,d))e.resolutions.push(`unregistered-worktree: ${o.path} (node ${o.node_id}) is not registered in ${o.repo_root}; relinked it with git worktree repair`),e.dryRun||L(o.repo_root,["worktree","repair",d]);else{const c=H(e,"worktrees",x(d));e.resolutions.push(`unregistered-worktree: ${o.path} (node ${o.node_id}${o.state==="open"?"":`, ${o.state}`}) is not a worktree of ${u(o.repo_root)?o.repo_root:`the missing repository ${o.repo_root}`}; ${o.state==="open"?"closed its row and ":""}moved the folder to ${c}`),e.map.redirect(o.path,n(e.map.old.targetRoot,k(e.map.old.root,c))),e.dryRun||(O(d,"worktrees",e),ee(t,o,e));continue}if(e.map.add(o.path,a),u(i)){const c=H(e,"replaced",k(e.map.old.root,i));e.resolutions.push(`stray-destination: ${i} predates the migration; moved it to ${c} and put the worktree ${d} in its place`),e.dryRun||O(i,"replaced",e,k(e.map.old.root,i))}if(!e.dryRun){B(R(i),{recursive:!0});try{L(o.repo_root,["worktree","move",d,i])}catch(c){if(!String(c.stderr??"").includes("submodule"))throw c;M(d,i),L(o.repo_root,["worktree","repair",i])}I(d,i),e.moved++,e.changes.push(`${d} -> ${i} (git worktree move)`)}}}finally{t.close()}e.dryRun||_e(e)}}h(ye,"worktrees");function _e(e){const t=n(e.map.old.canvas,"nodes");if(u(t)){for(const s of E(t)){const p=n(t,s);$(p).isDirectory()&&E(p).length===0&&F(p)}E(t).length===0&&F(t)}}h(_e,"pruneOldNodeFolders");function Ce(e){ye(e);const t=V(e);X(t,e);for(const{source:s,target:p,files:o}of t.folders)p&&K(n(s,"home"),_(p.home,e),n(o,"home"),e);fe(e),ie(e)}h(Ce,"previewStores");export{fe as conversations,Fe as memoryAndProfiles,Ce as previewStores,V as profileFolders,De as repairMovedRepositories,ye as worktrees};
|
package/dist/core/layout.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare function userRoot(): string;
|
|
|
6
6
|
export declare function appsRoot(): string;
|
|
7
7
|
export declare function secretsDir(): string;
|
|
8
8
|
export declare function profileSpace(app: string, id: string): {
|
|
9
|
-
|
|
9
|
+
dir: string;
|
|
10
10
|
env: string;
|
|
11
11
|
home: string;
|
|
12
12
|
};
|
|
@@ -15,7 +15,7 @@ export declare function layoutVersionFile(): string;
|
|
|
15
15
|
export declare function userFilesRoot(): string;
|
|
16
16
|
export declare function appSpace(app: string): {
|
|
17
17
|
root: string;
|
|
18
|
-
|
|
18
|
+
profiles: string;
|
|
19
19
|
conversations: string;
|
|
20
20
|
nodes: string;
|
|
21
21
|
files: string;
|