@north-light/crouter 0.3.336 → 0.3.338

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.
@@ -1 +1 @@
1
- var y=Object.defineProperty;var u=(t,n)=>y(t,"name",{value:n,configurable:!0});import{listInstalledPluginsInRoot as b}from"../resolver.js";import{projectScopeRoots as w,userScopeRoot as R}from"../scope.js";import{validatePluginHookArtifact as j}from"./artifact.js";function x(t){return t.manifest.hooks!==void 0||t.manifest.hookExecutable!==void 0}u(x,"hasHookDeclaration");function O(t){const n=new Set,s=[];for(const a of t){const p=b(a.scope,a.root).sort((c,r)=>c.name<r.name?-1:c.name>r.name?1:0);for(const c of p)n.has(c.name)||(n.add(c.name),c.enabled&&x(c)&&s.push(c))}return s}u(O,"orderedPluginsInScopes");function v(t=process.cwd(),n){return[...w(t,n).map(s=>({scope:"project",root:s})),{scope:"user",root:R()}]}u(v,"hookDiscoveryScopes");function z(t=process.cwd(),n){return O(v(t,n))}u(z,"effectiveHookPlugins");function H(t,n=process.cwd(),s){const a=new Set,p=[];for(const c of v(n,s)){const r=t.filter(e=>e.plugin.scope===c.scope&&e.scopeRoot===c.root),i=new Set(r.map(e=>e.plugin.name)),o=[...b(c.scope,c.root).filter(e=>!i.has(e.name)),...r.map(e=>e.plugin)];o.sort((e,l)=>e.name<l.name?-1:e.name>l.name?1:0);for(const e of o)a.has(e.name)||(a.add(e.name),e.enabled&&x(e)&&p.push(e))}return p}u(H,"effectiveHookPluginsWithCandidates");function h(t,n){return{...n,plugin:t.name,scope:t.scope}}u(h,"issue");function k(t,n){return n.map(s=>h(t,s))}u(k,"artifactIssues");function I(t,n,s){const a=[];return n.forEach((p,c)=>{s.has(p.target)||a.push(h(t,{code:"command_hook_target_invalid",path:`hooks[${c}].target`,message:`hook target "${p.target}" is not an eligible core returned-object leaf`,received:p.target,expected:"an exact eligible core leaf path",next:"Choose a current returned-object core leaf; pkg plugin, sys doctor, JSONL, passthrough, and UI/void surfaces are unavailable."}))}),a}u(I,"targetIssues");function g(t,n){const s=[],a=[],p=[];let c=0;for(const o of n){const e=j(o.root,o.manifest),l=k(o,e.issues);let f=[];if(l.length===0&&e.manifest!==void 0&&e.executablePath!==void 0){const d=I(o,e.manifest.hooks,t);l.push(...d),l.length===0&&(f=e.manifest.hooks.map((m,P)=>Object.freeze({executable:e.executablePath,plugin:Object.freeze({name:o.name,scope:o.scope,root:o.root}),target:m.target,phase:m.phase,op:m.op,description:m.description,effects:Object.freeze([...m.effects]),declarationIndex:P,order:c++})),a.push(...f))}s.push(Object.freeze({plugin:o,...e.manifestPath===void 0?{}:{manifestPath:e.manifestPath},...e.executablePath===void 0?{}:{executablePath:e.executablePath},...e.manifest===void 0?{}:{manifest:e.manifest},lifecycleCandidates:Object.freeze([...e.lifecycleCandidates]),hooks:Object.freeze(f),issues:Object.freeze(l)})),p.push(...l)}const r=new Map;for(const o of a){const e=r.get(o.target);e===void 0?r.set(o.target,[o]):e.push(o)}const i=new Map;for(const[o,e]of r){const l=e.filter(f=>f.phase==="replace");if(l.length>1)for(const f of l)p.push(h(f.plugin,{code:"command_hook_collision",path:`hooks[${f.declarationIndex}]`,message:`multiple replacements target "${o}"`,received:l.map(d=>`${d.plugin.name}:${d.op}`).join(", "),expected:"exactly one replacement for this core leaf",next:"Remove or change one replace declaration; before and after hooks may coexist with one replacement."}));i.set(o,Object.freeze({target:o,before:Object.freeze(e.filter(f=>f.phase==="before")),after:Object.freeze(e.filter(f=>f.phase==="after").reverse()),replacements:Object.freeze(l)}))}return Object.freeze({catalog:t,hooks:Object.freeze(a),plans:i,validations:Object.freeze(s),issues:Object.freeze(p),valid:p.length===0})}u(g,"compileHookRegistry");function C(t){const n=[],s=[],a=[];let p=0;for(const r of t){const i=j(r.root,r.manifest),o=k(r,i.issues);let e=[];o.length===0&&i.manifest!==void 0&&i.executablePath!==void 0&&(e=(i.manifest.schemaVersion===2?i.manifest.lifecycle:[]).map((f,d)=>Object.freeze({executable:i.executablePath,plugin:Object.freeze({name:r.name,scope:r.scope,root:r.root}),event:f.event,phase:f.phase,op:f.op,description:f.description,effects:Object.freeze([...f.effects]),declarationIndex:d,order:p++})),s.push(...e)),n.push(Object.freeze({plugin:r,...i.manifestPath===void 0?{}:{manifestPath:i.manifestPath},...i.executablePath===void 0?{}:{executablePath:i.executablePath},...i.manifest===void 0?{}:{manifest:i.manifest},lifecycleCandidates:Object.freeze([...i.lifecycleCandidates]),hooks:Object.freeze([]),issues:Object.freeze(o)})),a.push(...o)}const c=new Map;for(const r of s){const i=c.get(r.event)??[];c.set(r.event,Object.freeze([...i,r]))}return Object.freeze({hooks:Object.freeze(s),plans:c,validations:Object.freeze(n),issues:Object.freeze(a),valid:a.length===0})}u(C,"compileLifecycleHookRegistry");function D(t,n){return C(z(t,n))}u(D,"discoverLifecycleHookRegistry");function E(t,n=process.cwd(),s){return g(t,z(n,s))}u(E,"discoverHookRegistry");function N(t,n,s,a=process.cwd(),p){return S(t,[{plugin:n,scopeRoot:s}],a,p)}u(N,"discoverCandidateHookRegistry");function S(t,n,s=process.cwd(),a){return g(t,H(n,s,a))}u(S,"discoverCandidateHookRegistryForCandidates");function T(t,n){return g(t,O(n))}u(T,"discoverHookRegistryInScopes");export{g as compileHookRegistry,C as compileLifecycleHookRegistry,N as discoverCandidateHookRegistry,S as discoverCandidateHookRegistryForCandidates,E as discoverHookRegistry,T as discoverHookRegistryInScopes,D as discoverLifecycleHookRegistry,z as effectiveHookPlugins,v as hookDiscoveryScopes};
1
+ var R=Object.defineProperty;var u=(t,n)=>R(t,"name",{value:n,configurable:!0});import{listInstalledPluginsInRoot as b}from"../resolver.js";import{projectScopeRoots as w,userScopeRoot as C}from"../scope.js";import{validatePluginHookArtifact as j}from"./artifact.js";function O(t){return t.manifest.hooks!==void 0||t.manifest.hookExecutable!==void 0}u(O,"hasHookDeclaration");function x(t){const n=new Set,s=[];for(const a of t){const p=b(a.scope,a.root).sort((c,r)=>c.name<r.name?-1:c.name>r.name?1:0);for(const c of p)n.has(c.name)||(n.add(c.name),c.enabled&&O(c)&&s.push(c))}return s}u(x,"orderedPluginsInScopes");function v(t=process.cwd(),n){return[...w(t,n).map(s=>({scope:"project",root:s})),{scope:"user",root:C()}]}u(v,"hookDiscoveryScopes");function z(t=process.cwd(),n){return x(v(t,n))}u(z,"effectiveHookPlugins");function I(t,n=process.cwd(),s){const a=new Set,p=[];for(const c of v(n,s)){const r=t.filter(e=>e.plugin.scope===c.scope&&e.scopeRoot===c.root),i=new Set(r.map(e=>e.plugin.name)),o=[...b(c.scope,c.root).filter(e=>!i.has(e.name)),...r.map(e=>e.plugin)];o.sort((e,l)=>e.name<l.name?-1:e.name>l.name?1:0);for(const e of o)a.has(e.name)||(a.add(e.name),e.enabled&&O(e)&&p.push(e))}return p}u(I,"effectiveHookPluginsWithCandidates");function h(t,n){return{...n,plugin:t.name,scope:t.scope}}u(h,"issue");function k(t,n){return n.map(s=>h(t,s))}u(k,"artifactIssues");function H(t,n,s){const a=[];return n.forEach((p,c)=>{s.has(p.target)||a.push(h(t,{code:"command_hook_target_invalid",path:`hooks[${c}].target`,message:`hook target "${p.target}" is not an eligible core returned-object leaf`,received:p.target,expected:"an exact eligible core leaf path",next:"Choose a current returned-object core leaf; pkg plugin, sys doctor, JSONL, passthrough, and UI/void surfaces are unavailable."}))}),a}u(H,"targetIssues");function g(t,n){const s=[],a=[],p=[];let c=0;for(const o of n){const e=j(o.root,o.manifest),l=k(o,e.issues);let f=[];if(l.length===0&&e.manifest!==void 0&&e.executablePath!==void 0){const d=H(o,e.manifest.hooks,t);l.push(...d),l.length===0&&(f=e.manifest.hooks.map((m,y)=>Object.freeze({executable:e.executablePath,plugin:Object.freeze({name:o.name,scope:o.scope,root:o.root}),target:m.target,phase:m.phase,op:m.op,description:m.description,effects:Object.freeze([...m.effects]),declarationIndex:y,order:c++})),a.push(...f))}s.push(Object.freeze({plugin:o,...e.manifestPath===void 0?{}:{manifestPath:e.manifestPath},...e.executablePath===void 0?{}:{executablePath:e.executablePath},...e.manifest===void 0?{}:{manifest:e.manifest},lifecycleCandidates:Object.freeze([...e.lifecycleCandidates]),hooks:Object.freeze(f),issues:Object.freeze(l)})),p.push(...l)}const r=new Map;for(const o of a){const e=r.get(o.target);e===void 0?r.set(o.target,[o]):e.push(o)}const i=new Map;for(const[o,e]of r){const l=e.filter(f=>f.phase==="replace");if(l.length>1)for(const f of l)p.push(h(f.plugin,{code:"command_hook_collision",path:`hooks[${f.declarationIndex}]`,message:`multiple replacements target "${o}"`,received:l.map(d=>`${d.plugin.name}:${d.op}`).join(", "),expected:"exactly one replacement for this core leaf",next:"Remove or change one replace declaration; before and after hooks may coexist with one replacement."}));i.set(o,Object.freeze({target:o,before:Object.freeze(e.filter(f=>f.phase==="before")),after:Object.freeze(e.filter(f=>f.phase==="after").reverse()),replacements:Object.freeze(l)}))}return Object.freeze({catalog:t,hooks:Object.freeze(a),plans:i,validations:Object.freeze(s),issues:Object.freeze(p),valid:p.length===0})}u(g,"compileHookRegistry");function P(t){const n=[],s=[],a=[];let p=0;for(const r of t){const i=j(r.root,r.manifest),o=k(r,i.issues);let e=[];o.length===0&&i.manifest!==void 0&&i.executablePath!==void 0&&(e=(i.manifest.schemaVersion===2?i.manifest.lifecycle:[]).map((f,d)=>Object.freeze({executable:i.executablePath,plugin:Object.freeze({name:r.name,scope:r.scope,root:r.root}),event:f.event,phase:f.phase,op:f.op,description:f.description,effects:Object.freeze([...f.effects]),declarationIndex:d,order:p++})),s.push(...e)),n.push(Object.freeze({plugin:r,...i.manifestPath===void 0?{}:{manifestPath:i.manifestPath},...i.executablePath===void 0?{}:{executablePath:i.executablePath},...i.manifest===void 0?{}:{manifest:i.manifest},lifecycleCandidates:Object.freeze([...i.lifecycleCandidates]),hooks:Object.freeze([]),issues:Object.freeze(o)})),a.push(...o)}const c=new Map;for(const r of s){const i=c.get(r.event)??[];c.set(r.event,Object.freeze([...i,r]))}return Object.freeze({hooks:Object.freeze(s),plans:c,validations:Object.freeze(n),issues:Object.freeze(a),valid:a.length===0})}u(P,"compileLifecycleHookRegistry");function T(t,n){return process.env.CRTR_TEST_DISABLE_LIFECYCLE_HOOK_DISCOVERY==="1"?P([]):P(z(t,n))}u(T,"discoverLifecycleHookRegistry");function D(t,n=process.cwd(),s){return g(t,z(n,s))}u(D,"discoverHookRegistry");function M(t,n,s,a=process.cwd(),p){return S(t,[{plugin:n,scopeRoot:s}],a,p)}u(M,"discoverCandidateHookRegistry");function S(t,n,s=process.cwd(),a){return g(t,I(n,s,a))}u(S,"discoverCandidateHookRegistryForCandidates");function A(t,n){return g(t,x(n))}u(A,"discoverHookRegistryInScopes");export{g as compileHookRegistry,P as compileLifecycleHookRegistry,M as discoverCandidateHookRegistry,S as discoverCandidateHookRegistryForCandidates,D as discoverHookRegistry,A as discoverHookRegistryInScopes,T as discoverLifecycleHookRegistry,z as effectiveHookPlugins,v as hookDiscoveryScopes};
@@ -2,12 +2,11 @@ import { DatabaseSync } from 'node:sqlite';
2
2
  import { type ScopedStore } from './paths.js';
3
3
  export declare const PROFILE_ID_SHAPE: RegExp;
4
4
  export declare function writeOwnerRoot(db: DatabaseSync, key: string, root: string): void;
5
+ export declare function assertScopedStoreReady(store: ScopedStore): void;
6
+ export declare function discardIncompleteScopedStore(store: ScopedStore): void;
7
+ export declare function withProjectStateLock<T>(root: string, run: () => T): T;
5
8
  export declare function scopedStoreExists(store: ScopedStore): boolean;
6
9
  export declare function legacyScopedStorePaths(store: ScopedStore): string[];
7
- /** Acquiring the store on demand races every other process reaching the same
8
- * fresh root at once (e.g. two brokers sharing a fresh agent dir on first
9
- * launch), so the check-then-create runs under a cross-process lock — the
10
- * same primitive worktree-sweep and the plugin-swap path already use. */
11
10
  export declare function initializeFreshScopedStore(input: {
12
11
  kind: 'user' | 'project' | 'provider';
13
12
  root: string;
@@ -1 +1 @@
1
- var m=Object.defineProperty;var c=(o,e)=>m(o,"name",{value:e,configurable:!0});import{DatabaseSync as f}from"node:sqlite";import{chmodSync as a,existsSync as i,mkdirSync as u,readdirSync as y,statSync as w,writeFileSync as E}from"node:fs";import{join as n}from"node:path";import{CONFIG_FILE as h,PROFILE_DIR as x,STATE_FILE as p}from"../../types.js";import{withExclusiveDirectoryLock as A}from"../exclusive-lock.js";import{providerStore as M,projectStore as _,userStore as v}from"./paths.js";import{createScopedSchema as I,SCOPED_SCHEMA_VERSION as S}from"./schema.js";const s=new Map,L=/^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/;function R(o,e,r){o.prepare("UPDATE scope_owners SET root=? WHERE owner_key=?").run(r,e)}c(R,"writeOwnerRoot");function P(o){return Number(o.prepare("PRAGMA user_version").get().user_version)}c(P,"version");function d(o){i(o)&&a(o,384);for(const e of["-wal","-shm"])i(`${o}${e}`)&&a(`${o}${e}`,384)}c(d,"secure");function l(o){return i(o.path)}c(l,"scopedStoreExists");function k(o){if(o.kind==="project")return[n(o.root,p)];if(o.kind==="provider")return[n(o.root,"anthropic-subscriptions.json"),n(o.root,"openai-codex-subscriptions.json"),n(o.root,"provider-rotation.json")];const e=[n(o.root,h),n(o.root,p),n(o.root,"profile-defaults.json")],r=n(o.root,x);if(i(r))for(const t of y(r,{withFileTypes:!0}))t.isDirectory()&&L.test(t.name)&&e.push(n(r,t.name,"profile.json"),n(r,t.name,h),n(r,t.name,p));return e}c(k,"legacyScopedStorePaths");function O(o){const e=o.kind==="user"?v(o.root):o.kind==="project"?_(o.root):M(o.root);l(e)||(u(e.root,{recursive:!0,mode:448}),A(n(e.root,".init.lock"),()=>{if(l(e))return;const r=k(e).find(i);if(r!==void 0)throw new Error(`legacy scoped state exists at ${r}; crtr was updated and \`crtr sys daemon restart\` converts local state`);j(e,t=>{I(t,e.kind),e.kind!=="provider"&&R(t,e.kind,e.root)})}))}c(O,"initializeFreshScopedStore");function $(o){const e=s.get(o.path);if(e!==void 0)return e;i(o.path)||O(o);const r=new f(o.path);r.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");const t=P(r);if(t===0)throw r.close(),new Error(`scoped SQL store is uninitialized: ${o.path}; crtr was updated and \`crtr sys daemon restart\` converts local state`);if(t>S)throw r.close(),new Error(`scoped SQL store ${o.path} uses unsupported schema version ${t}`);if(t!==S)throw r.close(),new Error(`scoped SQL store ${o.path} requires an explicit conversion`);return d(o.path),s.set(o.path,r),r}c($,"openScopedStore");function j(o,e){if(i(o.path))throw new Error(`scoped SQL store already exists: ${o.path}`);if(u(o.root,{recursive:!0,mode:448}),!w(o.root).isDirectory())throw new Error(`scoped SQL root is not a directory: ${o.root}`);a(o.root,448),E(o.path,"",{mode:384});const r=new f(o.path);try{r.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; BEGIN IMMEDIATE;"),e(r),r.exec("COMMIT")}catch(t){try{r.exec("ROLLBACK")}catch{}throw t}finally{d(o.path),r.close()}}c(j,"createScopedStore");function Q(o,e){const r=$(o);if(r.isTransaction)return e(r);r.exec("BEGIN IMMEDIATE");try{const t=e(r);return r.exec("COMMIT"),d(o.path),t}catch(t){try{r.exec("ROLLBACK")}catch{}throw t}}c(Q,"withScopedWrite");function z(){for(const o of s.values())o.close();s.clear()}c(z,"closeScopedStores");export{L as PROFILE_ID_SHAPE,z as closeScopedStores,j as createScopedStore,O as initializeFreshScopedStore,k as legacyScopedStorePaths,$ as openScopedStore,l as scopedStoreExists,Q as withScopedWrite,R as writeOwnerRoot};
1
+ var M=Object.defineProperty;var n=(o,r)=>M(o,"name",{value:r,configurable:!0});import{DatabaseSync as s}from"node:sqlite";import{chmodSync as u,existsSync as a,mkdirSync as m,readdirSync as _,rmSync as I,statSync as L,writeFileSync as v}from"node:fs";import{join as i}from"node:path";import R from"proper-lockfile";import{CONFIG_FILE as S,PROFILE_DIR as j,STATE_FILE as p}from"../../types.js";import{withExclusiveDirectoryLock as w}from"../exclusive-lock.js";import{providerStore as O,projectStore as P,userStore as $}from"./paths.js";import{createScopedSchema as D,SCOPED_SCHEMA_VERSION as E}from"./schema.js";const d=new Map,b=/^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-f]{8}$/;function G(o,r,e){o.prepare("UPDATE scope_owners SET root=? WHERE owner_key=?").run(e,r)}n(G,"writeOwnerRoot");function x(o){return Number(o.prepare("PRAGMA user_version").get().user_version)}n(x,"version");function A(o,r){const e=x(o);if(e===0)throw new Error(`scoped SQL store is uninitialized: ${r.path}; crtr was updated and \`crtr sys daemon restart\` converts local state`);if(e>E)throw new Error(`scoped SQL store ${r.path} uses unsupported schema version ${e}`);if(e!==E)throw new Error(`scoped SQL store ${r.path} requires an explicit conversion`)}n(A,"assertVersion");function X(o){const r=new s(o.path,{readOnly:!0});try{A(r,o)}finally{r.close()}}n(X,"assertScopedStoreReady");function T(o){if(!k(o))return;const r=new s(o.path,{readOnly:!0});let e;try{e=x(r)}finally{r.close()}if(e===0)for(const t of[o.path,`${o.path}-wal`,`${o.path}-shm`])I(t,{force:!0})}n(T,"discardIncompleteScopedStore");function g(o,r){return w(i(o,".init.lock"),()=>{const e=i(o,p),t=Date.now()+5e3;let c=10;for(;;){let h;try{h=R.lockSync(e,{realpath:!1,retries:0,stale:3e4,update:1e4})}catch(f){if(f.code!=="ELOCKED")throw f;const y=t-Date.now();if(y<=0)throw new Error(`timed out waiting for project state conversion lock: ${e}`,{cause:f});Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.min(c,y)),c=Math.min(c*2,250);continue}try{return r()}finally{h()}}})}n(g,"withProjectStateLock");function l(o){a(o)&&u(o,384);for(const r of["-wal","-shm"])a(`${o}${r}`)&&u(`${o}${r}`,384)}n(l,"secure");function k(o){return a(o.path)}n(k,"scopedStoreExists");function C(o){if(o.kind==="project")return[i(o.root,p)];if(o.kind==="provider")return[i(o.root,"anthropic-subscriptions.json"),i(o.root,"openai-codex-subscriptions.json"),i(o.root,"provider-rotation.json")];const r=[i(o.root,S),i(o.root,p),i(o.root,"profile-defaults.json")],e=i(o.root,j);if(a(e))for(const t of _(e,{withFileTypes:!0}))t.isDirectory()&&b.test(t.name)&&r.push(i(e,t.name,"profile.json"),i(e,t.name,S),i(e,t.name,p));return r}n(C,"legacyScopedStorePaths");function F(o){const r=o.kind==="user"?$(o.root):o.kind==="project"?P(o.root):O(o.root);m(r.root,{recursive:!0,mode:448});const e=n(()=>{if(r.kind==="project"&&T(r),k(r))return;const t=C(r).find(a);if(t!==void 0)throw new Error(`legacy scoped state exists at ${t}; crtr was updated and \`crtr sys daemon restart\` converts local state`);z(r,c=>{D(c,r.kind),r.kind!=="provider"&&G(c,r.kind,r.root)})},"initialize");r.kind==="project"?g(r.root,e):w(i(r.root,".init.lock"),e)}n(F,"initializeFreshScopedStore");function N(o){const r=d.get(o.path);if(r!==void 0)return r;F(o);const e=new s(o.path);try{return e.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;"),A(e,o),l(o.path),d.set(o.path,e),e}catch(t){throw e.close(),t}}n(N,"openScopedStore");function z(o,r){if(a(o.path))throw new Error(`scoped SQL store already exists: ${o.path}`);if(m(o.root,{recursive:!0,mode:448}),!L(o.root).isDirectory())throw new Error(`scoped SQL root is not a directory: ${o.root}`);u(o.root,448),v(o.path,"",{mode:384});const e=new s(o.path);try{e.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; BEGIN IMMEDIATE;"),r(e),e.exec("COMMIT")}catch(t){try{e.exec("ROLLBACK")}catch{}throw t}finally{l(o.path),e.close()}}n(z,"createScopedStore");function Y(o,r){const e=N(o);if(e.isTransaction)return r(e);e.exec("BEGIN IMMEDIATE");try{const t=r(e);return e.exec("COMMIT"),l(o.path),t}catch(t){try{e.exec("ROLLBACK")}catch{}throw t}}n(Y,"withScopedWrite");function Z(){for(const o of d.values())o.close();d.clear()}n(Z,"closeScopedStores");export{b as PROFILE_ID_SHAPE,X as assertScopedStoreReady,Z as closeScopedStores,z as createScopedStore,T as discardIncompleteScopedStore,F as initializeFreshScopedStore,C as legacyScopedStorePaths,N as openScopedStore,k as scopedStoreExists,g as withProjectStateLock,Y as withScopedWrite,G as writeOwnerRoot};
@@ -1,3 +1,3 @@
1
- var T=Object.defineProperty;var l=(e,r)=>T(e,"name",{value:r,configurable:!0});import{randomUUID as $}from"node:crypto";import{chmodSync as k,copyFileSync as R,existsSync as d,mkdirSync as E,readFileSync as _,readdirSync as U,statSync as x}from"node:fs";import{dirname as P,join as u,relative as V}from"node:path";import A from"proper-lockfile";import{CONFIG_FILE as I,PROFILE_DIR as J,STATE_FILE as S}from"../../types.js";import{LockedJsonFile as W}from"../locked-file.js";import{createScopedStore as b,legacyScopedStorePaths as L,PROFILE_ID_SHAPE as C,scopedStoreExists as g,writeOwnerRoot as D}from"./db.js";import{providerStore as N,projectStore as q,userStore as z}from"./paths.js";import{createScopedSchema as j}from"./schema.js";function h(e){return JSON.parse(_(e,"utf8"))}l(h,"json");function G(e){return e.some(d)}l(G,"existsLegacy");function O(e,r){const o=u(e,".legacy-scoped-state");E(o,{recursive:!0,mode:448}),k(o,448);for(const a of r)if(d(a)&&x(a).isFile()){const n=V(e,a);if(n===""||n.startsWith(".."))throw new Error(`legacy state is outside its owning root: ${a}`);const t=u(o,n);E(P(t),{recursive:!0,mode:448}),R(a,t),k(t,384)}}l(O,"preserve");function H(e,r){const o=u(e,S),a=A.lockSync(o,{realpath:!1,retries:0,stale:3e4,update:1e4});try{return r()}finally{a()}}l(H,"withLegacyProjectStateLock");import{initializeFreshScopedStore as ue}from"./db.js";function se(e){const r=e.kind==="user"?z(e.root):e.kind==="project"?q(e.root):N(e.root);if(g(r))return;if(e.kind==="provider")throw new Error("provider conversion requires convertLegacyProviderStore() under coordinated shared-agent-dir activation");const o=L(r),a=l(()=>{g(r)||(b(r,n=>{j(n,e.kind);const t=e.kind==="user"?"user":"project";D(n,t,r.root),e.kind==="user"?Q(n,r.root):w(n,t,u(r.root,S))}),G(o)&&O(r.root,o))},"convert");e.kind==="project"?H(r.root,a):a()}l(se,"convertLegacyScopedStore");function K(e){if(!d(e))return[];const r=JSON.parse(_(e,"utf8"));if(!Array.isArray(r))throw new Error(`legacy subscription pool is malformed: ${e}`);const o=new Set;return r.map((a,n)=>{if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy subscription pool entry ${n+1} is malformed: ${e}`);const t=a,s=typeof t.label=="string"?t.label.trim():"",c=typeof t.refresh=="string"?t.refresh.trim():"",i=typeof t.access=="string"?t.access.trim():"",p=Number(t.expires);if(!s||!c||!i||!Number.isFinite(p))throw new Error(`legacy subscription pool entry ${n+1} is incomplete: ${e}`);const m=s.toLowerCase();if(o.has(m))throw new Error(`legacy subscription pool has duplicate label "${s}": ${e}`);o.add(m);const f=l(v=>Number.isFinite(Number(t[v]))?Number(t[v]):0,"timing"),y=typeof t.accountId=="string"&&t.accountId.trim()!==""?t.accountId.trim():void 0;return{label:s,refresh:c,access:i,expires:p,rateLimitedUntil:f("rateLimitedUntil"),lastAttemptAt:f("lastAttemptAt"),lastRateLimitedAt:f("lastRateLimitedAt"),...t.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},...y?{accountId:y}:{}}})}l(K,"parseLegacyProviderPool");function M(e){if(!d(e))return{};const r=JSON.parse(_(e,"utf8"));if(r===null||typeof r!="object"||Array.isArray(r))throw new Error(`legacy provider rotation settings are malformed: ${e}`);const o=r;return{...o.defaultFallbackStrength==="ultra"||o.defaultFallbackStrength==="strong"||o.defaultFallbackStrength==="medium"||o.defaultFallbackStrength==="light"?{defaultFallbackStrength:o.defaultFallbackStrength}:{},...typeof o.revertWhenAvailable=="boolean"?{revertWhenAvailable:o.revertWhenAvailable}:{}}}l(M,"parseLegacyRotation");async function B(e,r){const o=[];try{for(const a of e)d(a)&&o.push(await A.lock(a,{realpath:!1,retries:0,stale:3e4,update:1e4}));return await r()}finally{await Promise.allSettled(o.reverse().map(a=>a()))}}l(B,"withLegacyProviderLocks");async function ce(e){const r=N(e);if(g(r))return;const o=L(r);await B(o,async()=>{if(g(r))return;const a=new Map(o.slice(0,2).map((t,s)=>[s===0?"anthropic":"openai-codex",K(t)])),n=M(o[2]);O(r.root,o);for(const[t,s]of a){const c=Object.fromEntries(s.map(p=>[$(),{refresh:p.refresh,access:p.access,expires:p.expires,...p.accountId?{accountId:p.accountId}:{}}]));await new W(u(r.root,`${t}-credentials.json`),!0,`{"version":1,"accounts":{}}
2
- `).withLockAsync(async(p,m,f)=>(f(`${JSON.stringify({version:1,accounts:c})}
3
- `),{result:void 0}))}b(r,t=>{j(t,"provider");for(const[s,c]of a){const i=JSON.parse(_(u(r.root,`${s}-credentials.json`),"utf8")),p=Object.keys(i.accounts),m=t.prepare("INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)");c.forEach((f,y)=>m.run(s,p[y],f.label,f.label.toLowerCase(),y,f.lastAttemptAt,f.lastRateLimitedAt,f.rateLimitedUntil,f.authFailure??null))}(n.defaultFallbackStrength!==void 0||n.revertWhenAvailable!==void 0)&&t.prepare("INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?)").run(n.defaultFallbackStrength??null,n.revertWhenAvailable===void 0?null:n.revertWhenAvailable?1:0)})})}l(ce,"convertLegacyProviderStore");function F(e,r,o){if(!d(o))return;const a=h(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy config is malformed: ${o}`);e.prepare("INSERT INTO scope_settings(owner_key,raw_json) VALUES(?,?)").run(r,JSON.stringify(a))}l(F,"importSettings");function w(e,r,o){if(!d(o))return;const a=h(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy state is malformed: ${o}`);const n=a;e.prepare("INSERT INTO scope_bookkeeping(owner_key,last_self_check,active_canvas) VALUES(?,?,?)").run(r,n.last_self_check??null,n.activeCanvas??null);const t=e.prepare("INSERT INTO scope_marketplaces(owner_key,name,last_updated) VALUES(?,?,?)");for(const[c,i]of Object.entries(n.marketplaces??{}))t.run(r,c,i.last_updated??null);const s=e.prepare("INSERT INTO scope_plugins(owner_key,name,last_updated,etag,checked_at) VALUES(?,?,?,?,?)");for(const[c,i]of Object.entries(n.plugins??{}))s.run(r,c,i.last_updated??null,i.etag??null,i.checked_at??null)}l(w,"importState");function Q(e,r){F(e,"user",u(r,I)),w(e,"user",u(r,S));const o=u(r,J);if(d(o))for(const n of U(o,{withFileTypes:!0})){if(!n.isDirectory()||!C.test(n.name))continue;const t=n.name,s=u(o,t),c=u(s,"profile.json");if(!d(c))throw new Error(`legacy profile manifest is missing: ${c}`);const i=h(c);if(!i||typeof i!="object"||!Array.isArray(i.projects)||typeof i.name!="string"||typeof i.created_at!="string")throw new Error(`legacy profile manifest is malformed: ${c}`);e.prepare("INSERT INTO profiles(id,name,created_at,last_used_at,paused_at,home,default_kind,metadata_json) VALUES(?,?,?,?,?,?,?,?)").run(t,i.name,i.created_at,i.last_used_at??null,i.paused_at??null,i.home??null,i.default_kind??null,JSON.stringify(i.metadata??{})),e.prepare("INSERT INTO scope_owners(owner_key,kind,root,profile_id) VALUES(?,?,?,?)").run(`profile:${t}`,"profile",s,t);const p=e.prepare("INSERT INTO profile_projects(profile_id,path,position,memory) VALUES(?,?,?,?)");i.projects.forEach((m,f)=>p.run(t,m.path,f,m.memory)),F(e,`profile:${t}`,u(s,I)),w(e,`profile:${t}`,u(s,S))}const a=u(r,"profile-defaults.json");if(d(a)){const n=h(a);if(n===null||typeof n!="object"||Array.isArray(n))throw new Error(`legacy profile defaults are malformed: ${a}`);const t=e.prepare("INSERT INTO profile_defaults(directory,profile_id) VALUES(?,?)");for(const[s,c]of Object.entries(n)){if(typeof c!="string")throw new Error(`legacy profile default is malformed: ${a}`);t.run(s,c)}}}l(Q,"importUser");export{ce as convertLegacyProviderStore,se as convertLegacyScopedStore,ue as initializeFreshScopedStore};
1
+ var T=Object.defineProperty;var f=(e,r)=>T(e,"name",{value:r,configurable:!0});import{randomUUID as R}from"node:crypto";import{chmodSync as E,copyFileSync as $,existsSync as d,mkdirSync as A,readFileSync as S,readdirSync as U,statSync as x}from"node:fs";import{dirname as P,join as p,relative as V}from"node:path";import J from"proper-lockfile";import{CONFIG_FILE as I,PROFILE_DIR as W,STATE_FILE as h}from"../../types.js";import{LockedJsonFile as C}from"../locked-file.js";import{assertScopedStoreReady as D,createScopedStore as b,discardIncompleteScopedStore as q,legacyScopedStorePaths as L,PROFILE_ID_SHAPE as z,scopedStoreExists as _,withProjectStateLock as G,writeOwnerRoot as H}from"./db.js";import{providerStore as N,projectStore as K,userStore as M}from"./paths.js";import{createScopedSchema as j}from"./schema.js";function g(e){return JSON.parse(S(e,"utf8"))}f(g,"json");function O(e){return e.some(d)}f(O,"existsLegacy");function w(e,r){const o=p(e,".legacy-scoped-state");A(o,{recursive:!0,mode:448}),E(o,448);for(const a of r)if(d(a)&&x(a).isFile()){const n=V(e,a);if(n===""||n.startsWith(".."))throw new Error(`legacy state is outside its owning root: ${a}`);const t=p(o,n);A(P(t),{recursive:!0,mode:448}),$(a,t),E(t,384)}}f(w,"preserve");import{initializeFreshScopedStore as de}from"./db.js";function le(e){const r=e.kind==="user"?M(e.root):e.kind==="project"?K(e.root):N(e.root);if(e.kind!=="project"&&_(r))return;if(e.kind==="provider")throw new Error("provider conversion requires convertLegacyProviderStore() under coordinated shared-agent-dir activation");const o=L(r),a=f(()=>{e.kind==="project"&&q(r),!_(r)&&(e.kind==="project"&&O(o)&&w(r.root,o),b(r,n=>{j(n,e.kind);const t=e.kind==="user"?"user":"project";H(n,t,r.root),e.kind==="user"?Y(n,r.root):v(n,t,p(r.root,h))}),e.kind==="user"&&O(o)&&w(r.root,o))},"convert");e.kind==="project"?G(r.root,()=>{a(),D(r)}):a()}f(le,"convertLegacyScopedStore");function B(e){if(!d(e))return[];const r=JSON.parse(S(e,"utf8"));if(!Array.isArray(r))throw new Error(`legacy subscription pool is malformed: ${e}`);const o=new Set;return r.map((a,n)=>{if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy subscription pool entry ${n+1} is malformed: ${e}`);const t=a,s=typeof t.label=="string"?t.label.trim():"",c=typeof t.refresh=="string"?t.refresh.trim():"",i=typeof t.access=="string"?t.access.trim():"",u=Number(t.expires);if(!s||!c||!i||!Number.isFinite(u))throw new Error(`legacy subscription pool entry ${n+1} is incomplete: ${e}`);const m=s.toLowerCase();if(o.has(m))throw new Error(`legacy subscription pool has duplicate label "${s}": ${e}`);o.add(m);const l=f(k=>Number.isFinite(Number(t[k]))?Number(t[k]):0,"timing"),y=typeof t.accountId=="string"&&t.accountId.trim()!==""?t.accountId.trim():void 0;return{label:s,refresh:c,access:i,expires:u,rateLimitedUntil:l("rateLimitedUntil"),lastAttemptAt:l("lastAttemptAt"),lastRateLimitedAt:l("lastRateLimitedAt"),...t.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},...y?{accountId:y}:{}}})}f(B,"parseLegacyProviderPool");function Q(e){if(!d(e))return{};const r=JSON.parse(S(e,"utf8"));if(r===null||typeof r!="object"||Array.isArray(r))throw new Error(`legacy provider rotation settings are malformed: ${e}`);const o=r;return{...o.defaultFallbackStrength==="ultra"||o.defaultFallbackStrength==="strong"||o.defaultFallbackStrength==="medium"||o.defaultFallbackStrength==="light"?{defaultFallbackStrength:o.defaultFallbackStrength}:{},...typeof o.revertWhenAvailable=="boolean"?{revertWhenAvailable:o.revertWhenAvailable}:{}}}f(Q,"parseLegacyRotation");async function X(e,r){const o=[];try{for(const a of e)d(a)&&o.push(await J.lock(a,{realpath:!1,retries:0,stale:3e4,update:1e4}));return await r()}finally{await Promise.allSettled(o.reverse().map(a=>a()))}}f(X,"withLegacyProviderLocks");async function fe(e){const r=N(e);if(_(r))return;const o=L(r);await X(o,async()=>{if(_(r))return;const a=new Map(o.slice(0,2).map((t,s)=>[s===0?"anthropic":"openai-codex",B(t)])),n=Q(o[2]);w(r.root,o);for(const[t,s]of a){const c=Object.fromEntries(s.map(u=>[R(),{refresh:u.refresh,access:u.access,expires:u.expires,...u.accountId?{accountId:u.accountId}:{}}]));await new C(p(r.root,`${t}-credentials.json`),!0,`{"version":1,"accounts":{}}
2
+ `).withLockAsync(async(u,m,l)=>(l(`${JSON.stringify({version:1,accounts:c})}
3
+ `),{result:void 0}))}b(r,t=>{j(t,"provider");for(const[s,c]of a){const i=JSON.parse(S(p(r.root,`${s}-credentials.json`),"utf8")),u=Object.keys(i.accounts),m=t.prepare("INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)");c.forEach((l,y)=>m.run(s,u[y],l.label,l.label.toLowerCase(),y,l.lastAttemptAt,l.lastRateLimitedAt,l.rateLimitedUntil,l.authFailure??null))}(n.defaultFallbackStrength!==void 0||n.revertWhenAvailable!==void 0)&&t.prepare("INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?)").run(n.defaultFallbackStrength??null,n.revertWhenAvailable===void 0?null:n.revertWhenAvailable?1:0)})})}f(fe,"convertLegacyProviderStore");function F(e,r,o){if(!d(o))return;const a=g(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy config is malformed: ${o}`);e.prepare("INSERT INTO scope_settings(owner_key,raw_json) VALUES(?,?)").run(r,JSON.stringify(a))}f(F,"importSettings");function v(e,r,o){if(!d(o))return;const a=g(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy state is malformed: ${o}`);const n=a;e.prepare("INSERT INTO scope_bookkeeping(owner_key,last_self_check,active_canvas) VALUES(?,?,?)").run(r,n.last_self_check??null,n.activeCanvas??null);const t=e.prepare("INSERT INTO scope_marketplaces(owner_key,name,last_updated) VALUES(?,?,?)");for(const[c,i]of Object.entries(n.marketplaces??{}))t.run(r,c,i.last_updated??null);const s=e.prepare("INSERT INTO scope_plugins(owner_key,name,last_updated,etag,checked_at) VALUES(?,?,?,?,?)");for(const[c,i]of Object.entries(n.plugins??{}))s.run(r,c,i.last_updated??null,i.etag??null,i.checked_at??null)}f(v,"importState");function Y(e,r){F(e,"user",p(r,I)),v(e,"user",p(r,h));const o=p(r,W);if(d(o))for(const n of U(o,{withFileTypes:!0})){if(!n.isDirectory()||!z.test(n.name))continue;const t=n.name,s=p(o,t),c=p(s,"profile.json");if(!d(c))throw new Error(`legacy profile manifest is missing: ${c}`);const i=g(c);if(!i||typeof i!="object"||!Array.isArray(i.projects)||typeof i.name!="string"||typeof i.created_at!="string")throw new Error(`legacy profile manifest is malformed: ${c}`);e.prepare("INSERT INTO profiles(id,name,created_at,last_used_at,paused_at,home,default_kind,metadata_json) VALUES(?,?,?,?,?,?,?,?)").run(t,i.name,i.created_at,i.last_used_at??null,i.paused_at??null,i.home??null,i.default_kind??null,JSON.stringify(i.metadata??{})),e.prepare("INSERT INTO scope_owners(owner_key,kind,root,profile_id) VALUES(?,?,?,?)").run(`profile:${t}`,"profile",s,t);const u=e.prepare("INSERT INTO profile_projects(profile_id,path,position,memory) VALUES(?,?,?,?)");i.projects.forEach((m,l)=>u.run(t,m.path,l,m.memory)),F(e,`profile:${t}`,p(s,I)),v(e,`profile:${t}`,p(s,h))}const a=p(r,"profile-defaults.json");if(d(a)){const n=g(a);if(n===null||typeof n!="object"||Array.isArray(n))throw new Error(`legacy profile defaults are malformed: ${a}`);const t=e.prepare("INSERT INTO profile_defaults(directory,profile_id) VALUES(?,?)");for(const[s,c]of Object.entries(n)){if(typeof c!="string")throw new Error(`legacy profile default is malformed: ${a}`);t.run(s,c)}}}f(Y,"importUser");export{fe as convertLegacyProviderStore,le as convertLegacyScopedStore,de as initializeFreshScopedStore};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.336",
3
+ "version": "0.3.338",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.336",
3
+ "version": "0.3.338",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.336",
9
+ "version": "0.3.338",
10
10
  "hasInstallScript": true,
11
11
  "license": "GPL-3.0-only",
12
12
  "workspaces": [
@@ -10859,28 +10859,28 @@
10859
10859
  },
10860
10860
  "packages/crouter-api": {
10861
10861
  "name": "@north-light/crouter-api",
10862
- "version": "0.3.336",
10862
+ "version": "0.3.338",
10863
10863
  "license": "GPL-3.0-only"
10864
10864
  },
10865
10865
  "packages/crouter-env-docker": {
10866
10866
  "name": "@north-light/crouter-env-docker",
10867
- "version": "0.3.336",
10867
+ "version": "0.3.338",
10868
10868
  "license": "GPL-3.0-only"
10869
10869
  },
10870
10870
  "packages/crouter-plugin": {
10871
10871
  "name": "@north-light/crouter-plugin",
10872
- "version": "0.3.336",
10872
+ "version": "0.3.338",
10873
10873
  "license": "GPL-3.0-only",
10874
10874
  "dependencies": {
10875
- "@north-light/crouter-api": "^0.3.336"
10875
+ "@north-light/crouter-api": "^0.3.338"
10876
10876
  }
10877
10877
  },
10878
10878
  "packages/crouter-sdk": {
10879
10879
  "name": "@north-light/crouter-sdk",
10880
- "version": "0.3.336",
10880
+ "version": "0.3.338",
10881
10881
  "license": "GPL-3.0-only",
10882
10882
  "dependencies": {
10883
- "@north-light/crouter-api": "^0.3.336"
10883
+ "@north-light/crouter-api": "^0.3.338"
10884
10884
  }
10885
10885
  }
10886
10886
  }