@gencode/agents 0.3.2 → 0.5.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @gencode/agents
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 970bf39: Subagent artifacts are now recorded in the agent session instead of a separate child session, with new `source` and `sessionId` fields on each operation to distinguish agent vs subagent provenance. CRON tasks no longer generate artifact records.
8
+ - Add `--max-tokens` support to the summarize command and allow agent runs to cap model output tokens.
9
+
10
+ ### Patch Changes
11
+
12
+ - f799cc0: Restore custom agent delegation in prompts and subagent spawning, with stricter validation that only explicitly listed custom agent names may be selected.
13
+
14
+ ## 0.4.0
15
+
16
+ ### Minor Changes
17
+
18
+ - ff2729c: Add a batch_subagent_spawn tool that accepts multiple subagent tasks and runs them with a five-child concurrency limit.
19
+ - 80932da: Restrict subagent nesting depth from 3 to 2 and add depth-aware guardrails: system prompts now include a subagent constraint section discouraging deep nesting, and the subagent_spawn tool description warns subagents to prefer direct tool calls over spawning further subagents.
20
+
21
+ ### Patch Changes
22
+
23
+ - 80932da: Fix sub-subagent session directories being placed at the sessions root instead of nested inside the parent subagent's directory. Added `parentDir` field to `SessionPathOptions` so the session layer can resolve child paths relative to the spawning session's absolute directory, correctly nesting subagents at any depth.
24
+ - f96b5fd: Record successful agent file write and edit operations in per-session artifacts.json files with tool metadata, operation names, move sources, timestamps, and bounded content previews.
25
+ - 7e0ecf4: Stop truncating agent log message previews by default so full task and message text is preserved in logs.
26
+
3
27
  ## 0.3.1
4
28
 
5
29
  ### Patch Changes
@@ -0,0 +1,71 @@
1
+ import{t as e}from"./rolldown-runtime-CNxR59P3.js";import{createRequire as t}from"node:module";import n from"node:fs/promises";import r,{basename as i}from"node:path";import a from"node:fs";import o,{randomUUID as s}from"node:crypto";import c from"lz-string";const l=`__LZENC__`;function u(e){return`${l}${c.compressToBase64(e)}`}function d(e){if(!f(e))return e;let t=e.slice(9),n=c.decompressFromBase64(t);return n===null?(console.warn(`[session-storage] decompression failed for encrypted content (length=${e.length}), returning raw`),e):n}function f(e){return e.startsWith(l)}async function p(e){try{return d(await n.readFile(e,`utf-8`))}catch(e){if(e.code===`ENOENT`)return null;throw e}}async function m(e,t,r){let i=r?u(t):t;await n.writeFile(e,i,`utf-8`)}async function h(e,t,r){if(!r){await n.appendFile(e,t,`utf-8`);return}let i=await p(e);await m(e,i?i+t:t,!0)}async function g(e,t,r){let i=r?u(t):t,a=`${e}.${process.pid}.${Date.now()}.tmp`;await n.writeFile(a,i,`utf-8`),await n.rename(a,e)}async function ee(e){return p(e)}const _=`sessions`,v=2e3,y=new Map;function b(e){let t=e?.trim()||_;if(!/^[A-Za-z0-9_-]+$/.test(t))throw Error(`Invalid session store name: ${e}. Must match /^[A-Za-z0-9_-]+$/`);return t}function x(e,t){let n=t.trim();if(!/^[A-Za-z0-9_-]+$/.test(n))throw Error(`Invalid ${e}: ${t}. Must match /^[A-Za-z0-9_-]+$/`);return n}function S(e,t){return r.join(e,`.aimax`,b(t?.storeName))}function C(e,t,n){let i=n?.subagent?x(`subagent session id`,t):t;if(n?.subagent){if(n.subagent.parentDir)return r.join(n.subagent.parentDir,`subagents`,i);let t=x(`parent session id`,n.subagent.parentSessionId);return r.join(S(e,n),t,`subagents`,i)}return r.join(S(e,n),i)}function w(e,t,n){return r.join(C(e,t,n),`transcript.jsonl`)}function T(e,t,n){return r.join(C(e,t,n),`artifacts.json`)}function E(e,t,n){return r.join(C(e,t,n),`session.json`)}function D(e,t,n){return r.join(C(e,t,n),`context.json`)}function te(e,t,n){return r.join(C(e,t,n),`session-memory.json`)}function ne(e,t,n){return r.join(C(e,t,n),`collapse-log.jsonl`)}function re(e,t,n){return r.join(C(e,t,n),`tool-results`)}function O(e,t,n){return r.join(C(e,t,n),`cron-executions.jsonl`)}const k={version:2,updatedAt:new Date(0).toISOString(),readStates:[],toolResults:[],compaction:{budgets:[],snips:[],collapseSpans:[],consecutiveAutocompactFailures:0}};async function ie(e,t,i){let a=i?.sessionId??s(),o=C(e,a,i);await n.mkdir(o,{recursive:!0});let c=r.join(o,`.channel`);return await n.writeFile(c,t,`utf-8`),a}async function A(e,t,r){let i=C(e,t,r);await n.mkdir(i,{recursive:!0})}async function j(e,t,n){let r=await p(w(e,t,n));if(r===null)return[];let i=[];for(let e of r.split(`
2
+ `)){let t=e.trim();if(t)try{i.push(JSON.parse(t))}catch{}}return i}async function ae(e,t,n,r){await A(e,t,r);let i=T(e,t,r),a=r?.encryptSessions??!1;await le(i,async()=>{let e=await M(i);await ce(i,{version:1,updatedAt:new Date().toISOString(),operations:[...e.operations,se(n)]},a)})}async function oe(e,t,n){return(await M(T(e,t,n))).operations}function se(e){let t=e.content.length,n=t>v;return{...e,content:n?`${e.content.slice(0,Math.max(0,v-3))}...`:e.content,timestamp:new Date().toISOString(),truncated:n,originalChars:t}}async function M(e){let t=await p(e);if(t===null)return N();try{let e=JSON.parse(t);return e.version!==1||!Array.isArray(e.operations)?N():{version:1,updatedAt:typeof e.updatedAt==`string`?e.updatedAt:new Date(0).toISOString(),operations:e.operations}}catch{return N()}}function N(){return{version:1,updatedAt:new Date(0).toISOString(),operations:[]}}async function ce(e,t,i){await n.mkdir(r.dirname(e),{recursive:!0}),await g(e,`${JSON.stringify(t,null,2)}\n`,i)}async function le(e,t){let n=(y.get(e)??Promise.resolve()).catch(()=>{}).then(t);y.set(e,n);try{await n}finally{y.get(e)===n&&y.delete(e)}}async function ue(e,t,n,i){await A(e,t,i);let a=w(e,t,i);await h(a,JSON.stringify(n)+`
3
+ `,i?.encryptSessions??!1);try{let{resolveMemoryProvider:t}=await import(`./provider-registry-CxtHsHdk.js`).then(e=>e.t),{createBuiltinMemoryProvider:n}=await Promise.resolve().then(()=>$),o=r.join(e,`.aimax`),s=t({providerId:i?.providerId,pluginId:i?.pluginId,dataDir:e,memoryDir:o,sessionStoreName:i?.storeName})?.provider??n({dataDir:e,memoryDir:o,sessionStoreName:i?.storeName});s.noteSessionUpdate&&s.noteSessionUpdate(a)}catch{}i?.onMemoryChanged&&await Promise.resolve(i.onMemoryChanged({reason:`transcript-append`,files:[r.join(b(i.storeName),t,`transcript.jsonl`).replace(/\\/g,`/`)],source:`sessions`,sessionId:t,providerId:i.providerId??i.pluginId,timestamp:new Date().toISOString()})).catch(()=>{})}async function de(e,t,n,i){await A(e,t,i);let a=w(e,t,i),o=n(await j(e,t,i)),s=o.map(e=>JSON.stringify(e)).join(`
4
+ `),c=i?.encryptSessions??!1;await m(a,s.length>0?`${s}\n`:``,c);try{let{resolveMemoryProvider:t}=await import(`./provider-registry-CxtHsHdk.js`).then(e=>e.t),{createBuiltinMemoryProvider:n}=await Promise.resolve().then(()=>$),o=r.join(e,`.aimax`),s=t({providerId:i?.providerId,pluginId:i?.pluginId,dataDir:e,memoryDir:o,sessionStoreName:i?.storeName})?.provider??n({dataDir:e,memoryDir:o,sessionStoreName:i?.storeName});s.noteSessionUpdate&&s.noteSessionUpdate(a)}catch{}return i?.onMemoryChanged&&await Promise.resolve(i.onMemoryChanged({reason:`transcript-rewrite`,files:[r.join(b(i.storeName),t,`transcript.jsonl`).replace(/\\/g,`/`)],source:`sessions`,sessionId:t,providerId:i.providerId??i.pluginId,timestamp:new Date().toISOString()})).catch(()=>{}),o}async function fe(e,t,n,r){await A(e,t,r),await h(O(e,t,r),JSON.stringify(n)+`
5
+ `,r?.encryptSessions??!1)}async function pe(e,t,n){let r=await p(O(e,t,n));if(r===null)return[];let i=[];for(let e of r.split(`
6
+ `)){let t=e.trim();if(t)try{i.push(JSON.parse(t))}catch{}}return i}async function me(e,t){let r=S(e,t);try{return(await n.readdir(r,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name).sort()}catch(e){if(e.code===`ENOENT`)return[];throw e}}async function he(e,t,n){await A(e,t.id,n);let r=E(e,t.id,n),i=n?.encryptSessions??!1;await m(r,JSON.stringify(t,null,2),i)}async function ge(e,t,n,r){let i=await P(e,t,r);if(!i)return null;let a={...i,...n,id:i.id,createdAt:i.createdAt,updatedAt:new Date().toISOString()};return await he(e,a,r),a}async function P(e,t,i){let a=await p(E(e,t,i));if(a===null)return null;try{let o=JSON.parse(a);if(!o.channel){let a=r.join(C(e,t,i),`.channel`);try{o.channel=(await n.readFile(a,`utf-8`)).trim()}catch{o.channel=`WEB`}}return o}catch{return null}}async function _e(e,t,n){let r=await me(e,n),i=await Promise.all(r.map(async t=>{let r=await P(e,t,n);return{id:t,title:r?.title??t,channel:r?.channel??`WEB`,createdAt:r?.createdAt??``,updatedAt:r?.updatedAt??``}}));return t?i.filter(e=>e.channel===t):i}async function ve(e,t,n){let r=await p(D(e,t,n));if(r===null)return k;try{let e=JSON.parse(r),t=typeof e.version==`number`?e.version:void 0;return t!==1&&t!==2?k:{version:2,updatedAt:typeof e.updatedAt==`string`?e.updatedAt:k.updatedAt,readStates:Array.isArray(e.readStates)?e.readStates:[],toolResults:Array.isArray(e.toolResults)?e.toolResults:[],compaction:{sessionMemory:e.compaction?.sessionMemory,modelUsage:e.compaction?.modelUsage,budgets:Array.isArray(e.compaction?.budgets)?e.compaction.budgets:[],snips:Array.isArray(e.compaction?.snips)?e.compaction.snips:[],collapseSpans:Array.isArray(e.compaction?.collapseSpans)?e.compaction.collapseSpans:[],consecutiveAutocompactFailures:typeof e.compaction?.consecutiveAutocompactFailures==`number`?e.compaction.consecutiveAutocompactFailures:0,lastCompactionAt:typeof e.compaction?.lastCompactionAt==`string`?e.compaction.lastCompactionAt:void 0,lastCompactionLayer:e.compaction?.lastCompactionLayer===`L1`||e.compaction?.lastCompactionLayer===`L2`||e.compaction?.lastCompactionLayer===`L3`||e.compaction?.lastCompactionLayer===`L4`||e.compaction?.lastCompactionLayer===`L5`||e.compaction?.lastCompactionLayer===`L6`?e.compaction.lastCompactionLayer:void 0}}}catch{return k}}async function ye(e,t,r){let i=C(e,t,r);try{return(await n.stat(i)).isDirectory()}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function be(e,t,n){let[r,i,a]=await Promise.all([P(e,t,n),j(e,t,n),ve(e,t,n)]);return{id:t,metadata:r,transcriptPath:w(e,t,n),contextSnapshotPath:D(e,t,n),sessionMemoryPath:te(e,t,n),collapseLogPath:ne(e,t,n),toolResultsDir:re(e,t,n),transcriptEntryCount:i.length,readStateCount:a.readStates.length,toolResultRefCount:a.toolResults.length,transcriptEntries:i,context:a}}async function xe(e,t,n){let r=await be(e,t,n);return{id:r.id,metadata:r.metadata,transcript:r.transcriptEntries,context:r.context,paths:{transcriptPath:r.transcriptPath,contextSnapshotPath:r.contextSnapshotPath,sessionMemoryPath:r.sessionMemoryPath,collapseLogPath:r.collapseLogPath,toolResultsDir:r.toolResultsDir}}}function F(e){return!!(e&&typeof e==`object`&&`code`in e&&e.code===`ENOENT`)}async function Se(e){let t;try{t=await n.lstat(e)}catch(e){if(F(e))return{missing:!0};throw e}if(t.isSymbolicLink()||!t.isFile())throw Error(`path required`);return{missing:!1,stat:t}}function Ce(e){try{a.mkdirSync(e,{recursive:!0})}catch{}return e}function we(e){return e.trim().replace(/^[./]+/,``).replace(/\\/g,`/`)}function Te(e){let t=we(e);return t?t===`MEMORY.md`||t===`memory.md`?!0:t.startsWith(`memory/`):!1}async function Ee(e,t){let i=await n.readdir(e,{withFileTypes:!0});for(let n of i){let i=r.join(e,n.name);if(!n.isSymbolicLink()){if(n.isDirectory()){await Ee(i,t);continue}n.isFile()&&n.name.endsWith(`.md`)&&t.push(i)}}}async function I(e){let t=[],i=r.join(e,`MEMORY.md`),a=r.join(e,`memory.md`),o=r.join(e,`memory`),s=async e=>{try{let r=await n.lstat(e);if(r.isSymbolicLink()||!r.isFile()||!e.endsWith(`.md`))return;t.push(e)}catch{}};await s(i),await s(a);try{let e=await n.lstat(o);!e.isSymbolicLink()&&e.isDirectory()&&await Ee(o,t)}catch{}if(t.length<=1)return t;let c=new Set,l=[];for(let e of t){let t=e;try{t=await n.realpath(e)}catch{}c.has(t)||(c.add(t),l.push(e))}return l}function L(e){return o.createHash(`sha256`).update(e).digest(`hex`)}async function De(e,t){let i;try{i=await n.stat(e)}catch(e){if(F(e))return null;throw e}let a;try{a=await n.readFile(e,`utf-8`)}catch(e){if(F(e))return null;throw e}let o=L(a);return{path:r.relative(t,e).replace(/\\/g,`/`),absPath:e,mtimeMs:i.mtimeMs,size:i.size,hash:o}}function Oe(e,t){let n=e.split(`
7
+ `);if(n.length===0)return[];let r=Math.max(32,t.tokens*4),i=Math.max(0,t.overlap*4),a=[],o=[],s=0,c=()=>{if(o.length===0)return;let e=o[0],t=o[o.length-1];if(!e||!t)return;let n=o.map(e=>e.line).join(`
8
+ `),r=e.lineNo,i=t.lineNo;a.push({startLine:r,endLine:i,text:n,hash:L(n)})},l=()=>{if(i<=0||o.length===0){o=[],s=0;return}let e=0,t=[];for(let n=o.length-1;n>=0;--n){let r=o[n];if(r&&(e+=r.line.length+1,t.unshift(r),e>=i))break}o=t,s=t.reduce((e,t)=>e+t.line.length+1,0)};for(let e=0;e<n.length;e+=1){let t=n[e]??``,i=e+1,a=[];if(t.length===0)a.push(``);else for(let e=0;e<t.length;e+=r)a.push(t.slice(e,e+r));for(let e of a){let t=e.length+1;s+t>r&&o.length>0&&(c(),l()),o.push({line:e,lineNo:i}),s+=t}}return c(),a}function ke(e,t){if(!(!t||t.length===0))for(let n of e)n.startLine=t[n.startLine-1]??n.startLine,n.endLine=t[n.endLine-1]??n.endLine}function R(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Ae(e,t){if(e.length===0||t.length===0)return 0;let n=Math.min(e.length,t.length),r=0,i=0,a=0;for(let o=0;o<n;o+=1){let n=e[o]??0,s=t[o]??0;r+=n*s,i+=n*n,a+=s*s}return i===0||a===0?0:r/(Math.sqrt(i)*Math.sqrt(a))}function je(e){return(e.toLowerCase().match(/[\p{L}\p{N}_]+/gu)??[]).filter(Boolean)}function Me(e){return o.createHash(`sha256`).update(e).digest().readUInt32BE(0)}function z(e,t=384){let n=Array(t).fill(0),r=je(e);if(r.length===0)return n;for(let e of r){let r=Me(e)%t;n[r]+=1}let i=Math.sqrt(n.reduce((e,t)=>e+t*t,0));if(i>0)for(let e=0;e<n.length;e+=1)n[e]=n[e]/i;return n}function B(e){let t=e?.model?.trim()||`mock-embedding-v1`,n=e?.dimensions??384;return{id:`external-mock`,model:t,embedQuery:async e=>z(e,n),embedBatch:async e=>e.map(e=>z(e,n))}}const V=new class{providers=new Map;byPluginId=new Map;register(e){this.providers.set(e.id,e),e.pluginId&&this.byPluginId.set(e.pluginId,e.id)}getById(e){return this.providers.get(e)}getByPluginId(e){let t=this.byPluginId.get(e);return t?this.providers.get(t):void 0}clear(){this.providers.clear(),this.byPluginId.clear()}};function Ne(e){let t=e.id?.trim()||e.pluginId;return V.register({id:t,pluginId:e.pluginId,create:e.create,config:e.config,rootDir:e.rootDir,source:e.source}),t}function H(e){let t=e.providerId?.trim(),n=e.pluginId?.trim(),r=(t?V.getById(t):void 0)??(n?V.getByPluginId(n):void 0);return r?{provider:r.create({dataDir:e.dataDir,memoryDir:e.memoryDir,pluginId:r.pluginId,config:r.config,rootDir:r.rootDir,source:r.source}),registration:r}:null}function Pe(){V.clear()}const U={enabled:!1,lambda:.7};function W(e){let t=e.toLowerCase().match(/[a-z0-9_]+/g)??[];return new Set(t)}function Fe(e,t){if(e.size===0&&t.size===0)return 1;if(e.size===0||t.size===0)return 0;let n=0,r=e.size<=t.size?e:t,i=e.size<=t.size?t:e;for(let e of r)i.has(e)&&n++;let a=e.size+t.size-n;return a===0?0:n/a}function Ie(e,t,n){if(t.length===0)return 0;let r=0,i=n.get(e.id)??W(e.content);for(let e of t){let t=Fe(i,n.get(e.id)??W(e.content));t>r&&(r=t)}return r}function Le(e,t,n){return n*e-(1-n)*t}function Re(e,t={}){let{enabled:n=U.enabled,lambda:r=U.lambda}=t;if(!n||e.length<=1)return[...e];let i=Math.max(0,Math.min(1,r));if(i===1)return e.slice().sort((e,t)=>t.score-e.score);let a=new Map;for(let t of e)a.set(t.id,W(t.content));let o=Math.max(...e.map(e=>e.score)),s=Math.min(...e.map(e=>e.score)),c=o-s,l=e=>c===0?1:(e-s)/c,u=[],d=new Set(e);for(;d.size>0;){let e=null,t=-1/0;for(let n of d){let r=Le(l(n.score),Ie(n,u,a),i);(r>t||r===t&&n.score>(e?.score??-1/0))&&(t=r,e=n)}if(e)u.push(e),d.delete(e);else break}return u}function ze(e,t={}){if(e.length===0)return e;let n=new Map;return Re(e.map((e,t)=>{let r=`${e.path}:${e.startLine}:${t}`;return n.set(r,e),{id:r,score:e.score,content:e.snippet}}),t).map(e=>n.get(e.id))}const G={enabled:!1,halfLifeDays:30},K=/(?:^|\/)(?:memory)\/(\d{4})-(\d{2})-(\d{2})\.md$/;function Be(e){return!Number.isFinite(e)||e<=0?0:Math.LN2/e}function Ve(e){let t=Be(e.halfLifeDays),n=Math.max(0,e.ageInDays);return t<=0||!Number.isFinite(n)?1:Math.exp(-t*n)}function He(e){return e.score*Ve(e)}function Ue(e){let t=e.replaceAll(`\\`,`/`).replace(/^\.\//,``),n=K.exec(t);if(!n)return null;let r=Number(n[1]),i=Number(n[2]),a=Number(n[3]);if(!Number.isInteger(r)||!Number.isInteger(i)||!Number.isInteger(a))return null;let o=Date.UTC(r,i-1,a),s=new Date(o);return s.getUTCFullYear()!==r||s.getUTCMonth()!==i-1||s.getUTCDate()!==a?null:s}function We(e){let t=e.replaceAll(`\\`,`/`).replace(/^\.\//,``);return t===`MEMORY.md`||t===`memory.md`?!0:t.startsWith(`memory/`)?!K.test(t):!1}async function Ge(e){let t=Ue(e.filePath);if(t)return t;if(e.source===`memory`&&We(e.filePath)||!e.memoryRoot)return null;let i=r.isAbsolute(e.filePath)?e.filePath:r.resolve(e.memoryRoot,e.filePath);try{let e=await n.stat(i);return Number.isFinite(e.mtimeMs)?new Date(e.mtimeMs):null}catch{return null}}function Ke(e,t){return Math.max(0,t-e.getTime())/864e5}async function qe(e){let t={...G,...e.temporalDecay};if(!t.enabled)return[...e.results];let n=e.nowMs??Date.now(),r=new Map;return Promise.all(e.results.map(async i=>{let a=`${i.source}:${i.path}`,o=r.get(a);o||(o=Ge({filePath:i.path,source:i.source,memoryRoot:e.memoryRoot}),r.set(a,o));let s=await o;if(!s)return i;let c=He({score:i.score,ageInDays:Ke(s,n),halfLifeDays:t.halfLifeDays});return{...i,score:c}}))}function Je(e){let t=e.match(/[\p{L}\p{N}_]+/gu)?.map(e=>e.trim()).filter(Boolean)??[];return t.length===0?null:t.map(e=>`"${e.replaceAll(`"`,``)}"`).join(` AND `)}function Ye(e){return 1/(1+(Number.isFinite(e)?Math.max(0,e):999))}async function Xe(e){let t=new Map;for(let n of e.vector)t.set(n.id,{id:n.id,path:n.path,startLine:n.startLine,endLine:n.endLine,source:n.source,snippet:n.snippet,vectorScore:n.vectorScore,textScore:0});for(let n of e.keyword){let e=t.get(n.id);e?(e.textScore=n.textScore,n.snippet&&n.snippet.length>0&&(e.snippet=n.snippet)):t.set(n.id,{id:n.id,path:n.path,startLine:n.startLine,endLine:n.endLine,source:n.source,snippet:n.snippet,vectorScore:0,textScore:n.textScore})}let n=(await qe({results:Array.from(t.values()).map(t=>{let n=e.vectorWeight*t.vectorScore+e.textWeight*t.textScore;return{path:t.path,startLine:t.startLine,endLine:t.endLine,score:n,snippet:t.snippet,source:t.source}}),temporalDecay:{...G,...e.temporalDecay},memoryRoot:e.memoryRoot,nowMs:e.nowMs})).slice().sort((e,t)=>t.score-e.score),r={...U,...e.mmr};return r.enabled?ze(n,r):n}function Ze(e){e.db.exec(`
9
+ CREATE TABLE IF NOT EXISTS meta (
10
+ key TEXT PRIMARY KEY,
11
+ value TEXT NOT NULL
12
+ );
13
+ `),e.db.exec(`
14
+ CREATE TABLE IF NOT EXISTS files (
15
+ path TEXT PRIMARY KEY,
16
+ source TEXT NOT NULL DEFAULT 'memory',
17
+ hash TEXT NOT NULL,
18
+ mtime INTEGER NOT NULL,
19
+ size INTEGER NOT NULL
20
+ );
21
+ `),e.db.exec(`
22
+ CREATE TABLE IF NOT EXISTS chunks (
23
+ id TEXT PRIMARY KEY,
24
+ path TEXT NOT NULL,
25
+ source TEXT NOT NULL DEFAULT 'memory',
26
+ start_line INTEGER NOT NULL,
27
+ end_line INTEGER NOT NULL,
28
+ hash TEXT NOT NULL,
29
+ model TEXT NOT NULL,
30
+ text TEXT NOT NULL,
31
+ embedding TEXT NOT NULL,
32
+ updated_at INTEGER NOT NULL
33
+ );
34
+ `),e.db.exec(`
35
+ CREATE TABLE IF NOT EXISTS ${e.embeddingCacheTable} (
36
+ provider TEXT NOT NULL,
37
+ model TEXT NOT NULL,
38
+ provider_key TEXT NOT NULL,
39
+ hash TEXT NOT NULL,
40
+ embedding TEXT NOT NULL,
41
+ dims INTEGER,
42
+ updated_at INTEGER NOT NULL,
43
+ PRIMARY KEY (provider, model, provider_key, hash)
44
+ );
45
+ `),e.db.exec(`CREATE INDEX IF NOT EXISTS idx_embedding_cache_updated_at ON ${e.embeddingCacheTable}(updated_at);`);let t=!1,n;if(e.ftsEnabled)try{e.db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.ftsTable} USING fts5(\n text,\n id UNINDEXED,\n path UNINDEXED,\n source UNINDEXED,\n model UNINDEXED,\n start_line UNINDEXED,\n end_line UNINDEXED\n);`),t=!0}catch(e){let r=e instanceof Error?e.message:String(e);t=!1,n=r}return Qe(e.db,`files`,`source`,`TEXT NOT NULL DEFAULT 'memory'`),Qe(e.db,`chunks`,`source`,`TEXT NOT NULL DEFAULT 'memory'`),e.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`),e.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source);`),{ftsAvailable:t,...n?{ftsError:n}:{}}}function Qe(e,t,n,r){e.prepare(`PRAGMA table_info(${t})`).all().some(e=>e.name===n)||e.exec(`ALTER TABLE ${t} ADD COLUMN ${n} ${r}`)}function q(e,t){return e.length<=t?e:e.slice(0,t)}const $e=e=>Buffer.from(new Float32Array(e).buffer);async function et(e){return e.queryVec.length===0||e.limit<=0?[]:await e.ensureVectorReady(e.queryVec.length)?e.db.prepare(`SELECT c.id, c.path, c.start_line, c.end_line, c.text,
46
+ c.source,
47
+ vec_distance_cosine(v.embedding, ?) AS dist
48
+ FROM ${e.vectorTable} v\n JOIN chunks c ON c.id = v.id\n WHERE c.model = ?${e.sourceFilterVec.sql}\n ORDER BY dist ASC\n LIMIT ?`).all($e(e.queryVec),e.providerModel,...e.sourceFilterVec.params,e.limit).map(t=>({id:t.id,path:t.path,startLine:t.start_line,endLine:t.end_line,score:1-t.dist,snippet:q(t.text,e.snippetMaxChars),source:t.source})):tt({db:e.db,providerModel:e.providerModel,sourceFilter:e.sourceFilterChunks}).map(t=>({chunk:t,score:Ae(e.queryVec,t.embedding)})).filter(e=>Number.isFinite(e.score)).slice().sort((e,t)=>t.score-e.score).slice(0,e.limit).map(t=>({id:t.chunk.id,path:t.chunk.path,startLine:t.chunk.startLine,endLine:t.chunk.endLine,score:t.score,snippet:q(t.chunk.text,e.snippetMaxChars),source:t.chunk.source}))}function tt(e){return e.db.prepare(`SELECT id, path, start_line, end_line, text, embedding, source
49
+ FROM chunks
50
+ WHERE model = ?${e.sourceFilter.sql}`).all(e.providerModel,...e.sourceFilter.params).map(e=>({id:e.id,path:e.path,startLine:e.start_line,endLine:e.end_line,text:e.text,embedding:R(e.embedding),source:e.source}))}async function nt(e){if(e.limit<=0)return[];let t=e.buildFtsQuery(e.query);if(!t)return[];let n=e.providerModel?` AND model = ?`:``,r=e.providerModel?[e.providerModel]:[];return e.db.prepare(`SELECT id, path, source, start_line, end_line, text,\n bm25(${e.ftsTable}) AS rank\n FROM ${e.ftsTable}\n WHERE ${e.ftsTable} MATCH ?${n}${e.sourceFilter.sql}\n ORDER BY rank ASC\n LIMIT ?`).all(t,...r,...e.sourceFilter.params,e.limit).map(t=>{let n=e.bm25RankToScore(t.rank);return{id:t.id,path:t.path,startLine:t.start_line,endLine:t.end_line,score:n,textScore:n,snippet:q(t.text,e.snippetMaxChars),source:t.source}})}const rt=t(import.meta.url);function it(){try{return rt(`node:sqlite`)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`SQLite support is unavailable in this Node runtime (missing node:sqlite). ${t}`,{cause:e})}}const at={chunkTokens:400,chunkOverlap:80,maxResults:6,minScore:.2,fallback:{enabled:!0},embedding:{},experimental:{sessionMemory:!1},sources:[`memory`],store:{sessionStoreName:void 0,vector:{enabled:!0}},hybrid:{enabled:!0,vectorWeight:.7,textWeight:.3,candidateMultiplier:4,mmr:{enabled:!1,lambda:.7},temporalDecay:{enabled:!1,halfLifeDays:30}},cache:{enabled:!0,maxEntries:5e4},sync:{onSessionStart:!0,onSearch:!0,watch:!0,watchDebounceMs:1500,sessions:{deltaBytes:1e5,deltaMessages:50}},citations:`auto`};async function ot(e){try{let t=await import(`sqlite-vec`),n=e.extensionPath?.trim()?e.extensionPath.trim():void 0,r=n??t.getLoadablePath();return e.db.enableLoadExtension(!0),n?e.db.loadExtension(r):t.load(e.db),{ok:!0,extensionPath:r}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}function st(e,t,n){let i=S(e,{storeName:n});return r.relative(i,t).replace(/\\/g,`/`)}async function ct(e,t){let i=S(e,{storeName:t});try{let e=await n.readdir(i,{withFileTypes:!0}),t=[];for(let a of e){if(!a.isDirectory())continue;let e=r.join(i,a.name,`transcript.jsonl`);try{(await n.stat(e)).isFile()&&t.push(e)}catch{}}return t}catch(e){if(F(e))return[];throw e}}function lt(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e&&typeof e==`object`&&`text`in e?String(e.text??``):``).filter(Boolean).join(` `):e?String(e):``}async function ut(e,t,i){let a;try{a=await n.stat(t)}catch(e){if(F(e))return null;throw e}let o;try{let e=await p(t);if(e===null)return null;o=e}catch(e){if(F(e))return null;throw e}let s=[],c=[],l=o.split(`
51
+ `);for(let e=0;e<l.length;e+=1){let t=l[e]?.trim();if(t)try{let n=JSON.parse(t),r=n.role??`unknown`,i=lt(n.content);if(!i)continue;let a=i.split(`
52
+ `);for(let t of a)s.push(`[${r}] ${t}`),c.push(e+1)}catch{}}let u=s.join(`
53
+ `),d=L(u);return{path:r.join(b(i),st(e,t,i)).replace(/\\/g,`/`),absPath:t,mtimeMs:a.mtimeMs,size:a.size,hash:d,content:u,lineMap:c}}const J=`chunks_vec`,Y=`chunks_fts`,X=`embedding_cache`,dt=`memory_index_meta_v1`,ft=3e4;function pt(e,t,n){let r=t.split(`
54
+ `);for(let t of r){let n=t.match(/^##\s+(.+)$/);if(n?.[1])return`${e}#${n[1].trim()}`}return`${e}#L${n}`}const Z=new Map;function Q(e,t){let n={...e,...t,hybrid:{...e.hybrid,...t?.hybrid??{}},cache:{...e.cache,...t?.cache??{}},sync:{...e.sync,...t?.sync??{}},experimental:{...e.experimental,...t?.experimental??{}},sources:t?.sources??e.sources,embedding:{...e.embedding,...t?.embedding??{}},store:{...e.store,...t?.store??{},vector:{...e.store.vector,...t?.store?.vector??{}}}};return n.experimental.sessionMemory&&!n.sources.includes(`sessions`)&&(n.sources=[...n.sources,`sessions`]),n}var mt=class e{dataDir;memoryRoot;storePath;config;sessionStoreName;provider;providerKey;embeddingProviderId;db;dirty=!0;ftsAvailable=!1;ftsError;vector={enabled:!0,available:null,extensionPath:void 0,loadError:void 0,dims:void 0};vectorReady=null;watchers=[];watchTimer=null;sessionWatchTimer=null;sessionsDirty=!1;sessionsDirtyFiles=new Set;sessionPendingFiles=new Set;searchFallbackOnly=!1;lastRebuildSummary;sessionDeltas=new Map;static get(t,n){let i=r.join(t,`.aimax`),a=Q(at,n),o=`${i}::${b(a.store.sessionStoreName)}`,s=Z.get(o);if(s)return n&&s.applyConfig(n),s;let c=new e(t,i,a);return Z.set(o,c),c}constructor(e,t,n){this.dataDir=e,this.memoryRoot=t,this.storePath=r.join(t,`.index.sqlite`),this.config=Q(at,n),this.sessionStoreName=b(this.config.store.sessionStoreName),this.provider=B(),this.providerKey=this.computeProviderKey(),this.applyEmbeddingProvider(),this.vector.enabled=this.config.store.vector.enabled,this.vector.extensionPath=this.config.store.vector.extensionPath,this.db=this.openDatabase(),this.ensureSchema(),this.ensureWatcher(),this.ensureSessionListener(),this.dirty=!0}applyConfig(e){this.config=Q(this.config,e),this.sessionStoreName=b(this.config.store.sessionStoreName),this.applyEmbeddingProvider(),this.vector.enabled=this.config.store.vector.enabled,this.vector.extensionPath=this.config.store.vector.extensionPath,this.ensureWatcher(),this.ensureSessionListener()}warmSession(){this.config.sync.onSessionStart&&this.sync({reason:`session-start`}).catch(()=>{})}noteSessionUpdate(e){this.scheduleSessionDirty(e)}status(){let e=this.buildSourceFilter(),t=this.db.prepare(`SELECT COUNT(*) as c FROM files WHERE 1=1${e.sql}`).get(...e.params),n=this.db.prepare(`SELECT COUNT(*) as c FROM chunks WHERE 1=1${e.sql}`).get(...e.params),r=(()=>{let t=Array.from(this.config.sources);if(t.length===0)return[];let n=new Map;for(let e of t)n.set(e,{files:0,chunks:0});let r=this.db.prepare(`SELECT source, COUNT(*) as c FROM files WHERE 1=1${e.sql} GROUP BY source`).all(...e.params);for(let e of r){let t=n.get(e.source)??{files:0,chunks:0};t.files=e.c??0,n.set(e.source,t)}let i=this.db.prepare(`SELECT source, COUNT(*) as c FROM chunks WHERE 1=1${e.sql} GROUP BY source`).all(...e.params);for(let e of i){let t=n.get(e.source)??{files:0,chunks:0};t.chunks=e.c??0,n.set(e.source,t)}return t.map(e=>Object.assign({source:e},n.get(e)))})(),i=this.provider?`hybrid`:`fts-only`,a=this.config.cache.enabled?this.db.prepare(`SELECT COUNT(*) as c FROM ${X}`).get()?.c??0:void 0;return{backend:`builtin`,files:t?.c??0,chunks:n?.c??0,dirty:this.dirty||this.sessionsDirty,workspaceDir:this.memoryRoot,dbPath:this.storePath,provider:this.provider.id,model:this.provider.model,sources:Array.from(this.config.sources),sourceCounts:r,cache:this.config.cache.enabled?{enabled:!0,entries:a,maxEntries:this.config.cache.maxEntries}:{enabled:!1,maxEntries:this.config.cache.maxEntries},fts:{enabled:this.config.hybrid.enabled,available:this.ftsAvailable,error:this.ftsError,rows:this.getFtsRowCount()},vector:{enabled:this.vector.enabled,available:this.vector.available??void 0,extensionPath:this.vector.extensionPath,loadError:this.vector.loadError,dims:this.vector.dims},custom:{searchMode:i,fallbackActive:this.searchFallbackOnly,lastRebuildSummary:this.lastRebuildSummary}}}async probeEmbeddingAvailability(){try{return await this.provider.embedBatch([`ping`]),{ok:!0}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async probeVectorAvailability(){return this.vector.enabled?await this.ensureVectorReady():!1}async search(e){let t=e.trim();if(!t)return[];if(this.readMeta()?this.config.sync.onSearch&&(this.dirty||this.sessionsDirty)&&this.sync({reason:`search`}).catch(()=>{this.searchFallbackOnly=!0}):await this.sync({reason:`boot`}).catch(()=>{this.searchFallbackOnly=!0}),this.searchFallbackOnly)return this.decorateCitations(await this.fileScanSearch(t));let n=this.config.hybrid,r=Math.min(200,Math.max(1,Math.floor(this.config.maxResults*n.candidateMultiplier))),i=n.enabled&&this.ftsAvailable?await this.searchKeyword(t,r).catch(()=>[]):[],a=await this.provider.embedQuery(t).catch(()=>[]),o=a.some(e=>e!==0)?await this.searchVector(a,r).catch(()=>[]):[],s=[];if(!n.enabled||!this.ftsAvailable)s=o.filter(e=>e.score>=this.config.minScore).slice(0,this.config.maxResults);else{let e=await Xe({vector:o.map(e=>({id:`${e.path}:${e.startLine}:${e.endLine}:${e.source}`,path:e.path,startLine:e.startLine,endLine:e.endLine,source:e.source,snippet:e.snippet,vectorScore:e.score})),keyword:i.map(e=>({id:`${e.path}:${e.startLine}:${e.endLine}:${e.source}`,path:e.path,startLine:e.startLine,endLine:e.endLine,source:e.source,snippet:e.snippet,textScore:e.textScore})),vectorWeight:n.vectorWeight,textWeight:n.textWeight,mmr:n.mmr,temporalDecay:n.temporalDecay,memoryRoot:this.memoryRoot}),t=e.filter(e=>e.score>=this.config.minScore);if(t.length>0||i.length===0)s=t.slice(0,this.config.maxResults);else{let t=Math.min(this.config.minScore,n.textWeight);s=e.filter(e=>e.score>=t).slice(0,this.config.maxResults)}}return s.length>0?this.decorateCitations(this.decorateEntryIds(s)):this.config.fallback.enabled?(this.searchFallbackOnly=!0,this.decorateCitations(this.decorateEntryIds(await this.fileScanSearch(t)))):[]}async readFile(e){let{absPath:t,relPath:r}=this.resolveMemoryFilePath(e.relPath);if((await Se(t)).missing)return{text:``,path:r};let i;try{i=await n.readFile(t,`utf-8`)}catch(e){if(F(e))return{text:``,path:r};throw e}if(!e.from&&!e.lines)return{text:i,path:r};let a=i.split(`
55
+ `),o=Math.max(1,e.from??1),s=Math.max(1,e.lines??a.length);return{text:a.slice(o-1,o-1+s).join(`
56
+ `),path:r}}async replaceFile(e){let{absPath:t}=this.resolveMemoryFilePath(e.relPath);await n.mkdir(r.dirname(t),{recursive:!0}),await n.writeFile(t,e.content,`utf-8`),this.dirty=!0,await this.syncAndPostCheck(`replace`)}async deleteFile(e){let{absPath:t}=this.resolveMemoryFilePath(e);try{await n.unlink(t)}catch(e){if(F(e))return;throw e}this.dirty=!0,await this.syncAndPostCheck(`delete`)}async appendToMemory(e){let t=this.memoryRoot;await n.mkdir(t,{recursive:!0});let i=r.join(t,`MEMORY.md`),a=e.endsWith(`
57
+ `)?e:`${e}\n`;await n.appendFile(i,a,`utf-8`),this.dirty=!0,await this.syncAndPostCheck(`append`)}openDatabase(){Ce(r.dirname(this.storePath));let{DatabaseSync:e}=it();return new e(this.storePath,{allowExtension:this.vector.enabled})}ensureSchema(){let e=Ze({db:this.db,embeddingCacheTable:X,ftsTable:Y,ftsEnabled:this.config.hybrid.enabled});this.ftsAvailable=e.ftsAvailable,e.ftsError&&(this.ftsError=e.ftsError)}async ensureVectorReady(e){if(!this.vector.enabled)return!1;this.vectorReady||=this.withTimeout(this.loadVectorExtension(),ft,`sqlite-vec load timed out after ${Math.round(ft/1e3)}s`);let t=!1;try{t=await this.vectorReady||!1}catch(e){let t=e instanceof Error?e.message:String(e);return this.vector.available=!1,this.vector.loadError=t,this.vectorReady=null,!1}return t&&typeof e==`number`&&e>0&&this.ensureVectorTable(e),t}async loadVectorExtension(){if(this.vector.available!==null)return this.vector.available;if(!this.vector.enabled)return this.vector.available=!1,!1;try{let e=this.vector.extensionPath?.trim()?this.vector.extensionPath.trim():void 0,t=await ot({db:this.db,extensionPath:e});if(!t.ok)throw Error(t.error??`unknown sqlite-vec load error`);return this.vector.extensionPath=t.extensionPath,this.vector.available=!0,!0}catch(e){let t=e instanceof Error?e.message:String(e);return this.vector.available=!1,this.vector.loadError=t,!1}}ensureVectorTable(e){this.vector.dims!==e&&(this.vector.dims&&this.vector.dims!==e&&this.dropVectorTable(),this.db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS ${J} USING vec0(\n id TEXT PRIMARY KEY,\n embedding FLOAT[${e}]\n)`),this.vector.dims=e)}dropVectorTable(){try{this.db.exec(`DROP TABLE IF EXISTS ${J}`)}catch{}}async withTimeout(e,t,n){if(!Number.isFinite(t)||t<=0)return await e;let r=null,i=new Promise((e,i)=>{r=setTimeout(()=>i(Error(n)),t)});try{return await Promise.race([e,i])}finally{r&&clearTimeout(r)}}ensureWatcher(){if(!this.config.sync.watch||this.watchers.length>0)return;let e=[r.join(this.memoryRoot,`MEMORY.md`),r.join(this.memoryRoot,`memory.md`),r.join(this.memoryRoot,`memory`)],t=()=>{this.dirty=!0,this.scheduleWatchSync()};for(let n of e)try{let e=a.watch(n,{recursive:!1},t);e.on(`error`,()=>{try{e.close()}catch{}}),this.watchers.push(e)}catch{}}scheduleWatchSync(){this.config.sync.watch&&(this.watchTimer&&clearTimeout(this.watchTimer),this.watchTimer=setTimeout(()=>{this.watchTimer=null,this.sync({reason:`watch`}).catch(()=>{})},this.config.sync.watchDebounceMs))}ensureSessionListener(){if(!this.config.experimental.sessionMemory)return;let e=S(this.dataDir,{storeName:this.sessionStoreName});try{let t=a.watch(e,{recursive:!0},(t,n)=>{if(!n||!n.endsWith(`transcript.jsonl`))return;let i=r.join(e,n);this.scheduleSessionDirty(i)});this.watchers.push(t)}catch{}}scheduleSessionDirty(e){this.config.experimental.sessionMemory&&(this.sessionPendingFiles.add(e),!this.sessionWatchTimer&&(this.sessionWatchTimer=setTimeout(()=>{this.sessionWatchTimer=null,this.processSessionDeltaBatch().catch(()=>{})},5e3)))}async processSessionDeltaBatch(){if(this.sessionPendingFiles.size===0)return;let e=Array.from(this.sessionPendingFiles);this.sessionPendingFiles.clear();let t=!1;for(let n of e){let e=await this.updateSessionDelta(n);if(!e)continue;let r=e.deltaBytes,i=e.deltaMessages,a=r<=0?e.pendingBytes>0:e.pendingBytes>=r,o=i<=0?e.pendingMessages>0:e.pendingMessages>=i;!a&&!o||(this.sessionsDirtyFiles.add(n),this.sessionsDirty=!0,e.pendingBytes=r>0?Math.max(0,e.pendingBytes-r):0,e.pendingMessages=i>0?Math.max(0,e.pendingMessages-i):0,t=!0)}t&&this.sync({reason:`session-delta`}).catch(()=>{})}async updateSessionDelta(e){let t=this.config.sync.sessions;if(!t)return null;let r;try{r=await n.stat(e)}catch{return null}let i=r.size,a=this.sessionDeltas.get(e);a||(a={lastSize:0,pendingBytes:0,pendingMessages:0},this.sessionDeltas.set(e,a));let o=Math.max(0,i-a.lastSize);return o===0&&i===a.lastSize?{deltaBytes:t.deltaBytes,deltaMessages:t.deltaMessages,pendingBytes:a.pendingBytes,pendingMessages:a.pendingMessages}:(i<a.lastSize?(a.lastSize=i,a.pendingBytes+=i,t.deltaMessages>0&&(t.deltaBytes<=0||a.pendingBytes<t.deltaBytes)&&(a.pendingMessages+=await this.countNewlines(e,0,i))):(a.pendingBytes+=o,t.deltaMessages>0&&(t.deltaBytes<=0||a.pendingBytes<t.deltaBytes)&&(a.pendingMessages+=await this.countNewlines(e,a.lastSize,i)),a.lastSize=i),this.sessionDeltas.set(e,a),{deltaBytes:t.deltaBytes,deltaMessages:t.deltaMessages,pendingBytes:a.pendingBytes,pendingMessages:a.pendingMessages})}async countNewlines(e,t,r){if(r<=t)return 0;let i;try{i=await n.open(e,`r`)}catch{return 0}try{let e=t,n=0,a=Buffer.alloc(64*1024);for(;e<r;){let t=Math.min(a.length,r-e),{bytesRead:o}=await i.read(a,0,t,e);if(o<=0)break;for(let e=0;e<o;e+=1)a[e]===10&&(n+=1);e+=o}return n}finally{await i.close()}}computeProviderKey(){return L(JSON.stringify({provider:this.provider.id,model:this.provider.model}))}resolveMemoryFilePath(e){let t=e.trim();if(!t)throw Error(`path required`);let n=r.isAbsolute(t)?r.resolve(t):r.resolve(this.memoryRoot,t),i=r.relative(this.memoryRoot,n).replace(/\\/g,`/`);if(!(i.length>0&&!i.startsWith(`..`)&&!r.isAbsolute(i)&&Te(i))||!n.endsWith(`.md`))throw Error(`path required`);return{absPath:n,relPath:i}}applyEmbeddingProvider(){let e=this.config.embedding?.providerId?.trim();if(e){let t=H({providerId:e,dataDir:this.dataDir,memoryDir:this.memoryRoot});if(!t)throw Error(`Embedding provider not found: ${e}`);this.provider=t.provider,this.embeddingProviderId=e,this.providerKey=this.computeProviderKey(),this.dirty=!0;return}this.embeddingProviderId&&(this.provider=B(),this.embeddingProviderId=void 0,this.providerKey=this.computeProviderKey(),this.dirty=!0)}readMeta(){let e=this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(dt);if(!e?.value)return null;try{return JSON.parse(e.value)}catch{return null}}writeMeta(e){let t=JSON.stringify(e);this.db.prepare(`INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value`).run(dt,t)}loadEmbeddingCache(e){if(!this.config.cache.enabled||e.length===0)return new Map;let t=Array.from(new Set(e.filter(Boolean)));if(t.length===0)return new Map;let n=new Map,r=[this.provider.id,this.provider.model,this.providerKey];for(let e=0;e<t.length;e+=400){let i=t.slice(e,e+400),a=i.map(()=>`?`).join(`, `),o=this.db.prepare(`SELECT hash, embedding FROM ${X}\n WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${a})`).all(...r,...i);for(let e of o)n.set(e.hash,R(e.embedding))}return n}upsertEmbeddingCache(e){if(!this.config.cache.enabled||e.length===0)return;let t=Date.now(),n=this.db.prepare(`INSERT INTO ${X} (provider, model, provider_key, hash, embedding, dims, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(provider, model, provider_key, hash) DO UPDATE SET\n embedding=excluded.embedding,\n dims=excluded.dims,\n updated_at=excluded.updated_at`);for(let r of e){let e=r.embedding??[];n.run(this.provider.id,this.provider.model,this.providerKey,r.hash,JSON.stringify(e),e.length,t)}}async embedChunks(e){if(e.length===0)return[];let t=this.loadEmbeddingCache(e.map(e=>e.hash)),n=Array.from({length:e.length},()=>[]),r=[];for(let i=0;i<e.length;i+=1){let a=e[i],o=a?.hash?t.get(a.hash):void 0;o&&o.length>0?n[i]=o:a&&r.push({index:i,chunk:a})}if(r.length===0)return n;let i=await this.provider.embedBatch(r.map(e=>e.chunk.text)),a=[];for(let e=0;e<r.length;e+=1){let t=r[e],o=i[e]??[];n[t.index]=o,a.push({hash:t.chunk.hash,embedding:o})}return this.upsertEmbeddingCache(a),n}async indexFile(e,t){let r=Oe(t.content??await n.readFile(e.absPath,`utf-8`),{tokens:this.config.chunkTokens,overlap:this.config.chunkOverlap}).filter(e=>e.text.trim().length>0);t.source===`sessions`&&ke(r,t.lineMap);let i=await this.embedChunks(r),a=i.find(e=>e.length>0),o=a?await this.ensureVectorReady(a.length):!1,s=Date.now();if(o)try{this.db.prepare(`DELETE FROM ${J} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`).run(e.path,t.source)}catch{}if(this.ftsAvailable)try{this.db.prepare(`DELETE FROM ${Y} WHERE path = ? AND source = ? AND model = ?`).run(e.path,t.source,this.provider.model)}catch{}this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(e.path,t.source);for(let n=0;n<r.length;n+=1){let a=r[n],c=i[n]??[],l=L(`${t.source}:${e.path}:${a.startLine}:${a.endLine}:${a.hash}:${this.provider.model}`);if(this.db.prepare(`INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)
58
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
59
+ ON CONFLICT(id) DO UPDATE SET
60
+ hash=excluded.hash,
61
+ model=excluded.model,
62
+ text=excluded.text,
63
+ embedding=excluded.embedding,
64
+ updated_at=excluded.updated_at`).run(l,e.path,t.source,a.startLine,a.endLine,a.hash,this.provider.model,a.text,JSON.stringify(c),s),o&&c.length>0){try{this.db.prepare(`DELETE FROM ${J} WHERE id = ?`).run(l)}catch{}this.db.prepare(`INSERT INTO ${J} (id, embedding) VALUES (?, ?)`).run(l,Buffer.from(new Float32Array(c).buffer))}this.ftsAvailable&&this.db.prepare(`INSERT INTO ${Y} (text, id, path, source, model, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?, ?)`).run(a.text,l,e.path,t.source,this.provider.model,a.startLine,a.endLine)}this.db.prepare(`INSERT INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)
65
+ ON CONFLICT(path) DO UPDATE SET
66
+ source=excluded.source,
67
+ hash=excluded.hash,
68
+ mtime=excluded.mtime,
69
+ size=excluded.size`).run(e.path,t.source,e.hash,e.mtimeMs,e.size)}buildSourceFilter(){let e=this.config.sources;return e.length?{sql:` AND source IN (${e.map(()=>`?`).join(`, `)})`,params:e}:{sql:``,params:[]}}async searchVector(e,t){return await et({db:this.db,vectorTable:J,providerModel:this.provider.model,queryVec:e,limit:t,snippetMaxChars:700,ensureVectorReady:async e=>await this.ensureVectorReady(e),sourceFilterVec:this.buildSourceFilter(),sourceFilterChunks:this.buildSourceFilter()})}async searchKeyword(e,t){return this.ftsAvailable?await nt({db:this.db,ftsTable:Y,providerModel:this.provider.model,query:e,limit:t,snippetMaxChars:700,sourceFilter:this.buildSourceFilter(),buildFtsQuery:e=>Je(e),bm25RankToScore:Ye}):[]}resetIndex(){if(this.db.exec(`DELETE FROM files`),this.db.exec(`DELETE FROM chunks`),this.ftsAvailable)try{this.db.exec(`DELETE FROM ${Y}`)}catch{}this.dropVectorTable(),this.vector.dims=void 0,this.sessionsDirtyFiles.clear()}async syncAndPostCheck(e){try{await this.sync({reason:`mutation-postcheck`})}catch{this.searchFallbackOnly=!0;return}this.searchFallbackOnly=!this.indexHasSearchableData()}indexHasSearchableData(){try{if((this.db.prepare(`SELECT COUNT(*) as c FROM chunks`).get()?.c??0)>0)return!0}catch{}try{if(a.readdirSync(this.memoryRoot).filter(e=>e.endsWith(`.md`)).length>0)return!1;let e=r.join(this.memoryRoot,`memory`);return a.existsSync(e)?a.readdirSync(e).filter(e=>e.endsWith(`.md`)).length===0:!0}catch{return!1}}async fileScanSearch(e){let t=e.trim().toLowerCase();if(!t)return[];let a=await I(this.memoryRoot),o=[];for(let e of a){let a=``;try{a=await n.readFile(e,`utf-8`)}catch{continue}let s=r.relative(this.memoryRoot,e).replace(/\\/g,`/`);s.startsWith(`memory/`);let c=a.split(`
70
+ `);for(let n=0;n<c.length;n+=1){let r=c[n]??``,a=r.toLowerCase();if(!a.includes(t))continue;let l=a===t?1:Math.max(.2,t.length/Math.max(r.length,t.length));o.push({path:s||i(e),startLine:n+1,endLine:n+1,score:Number(l.toFixed(4)),snippet:r.slice(0,700),source:`memory`})}}return o.sort((e,t)=>t.score-e.score||e.path.localeCompare(t.path)||e.startLine-t.startLine),o.slice(0,this.config.maxResults)}getFtsRowCount(){if(this.ftsAvailable)try{return this.db.prepare(`SELECT COUNT(*) as c FROM ${Y}`).get()?.c??0}catch{return}}buildRebuildSummary(e){let t=this.db.prepare(`SELECT COUNT(*) as c FROM chunks`).get();return{reason:e.reason,memoryFilesIndexed:e.memoryFilesIndexed,sessionFilesIndexed:e.sessionFilesIndexed,staleMemoryFilesRemoved:e.staleMemoryFilesRemoved,staleSessionFilesRemoved:e.staleSessionFilesRemoved,chunks:t?.c??0,ftsRows:this.getFtsRowCount(),fallbackActive:this.searchFallbackOnly,needsFullReindex:e.needsFullReindex}}async rebuild(e=`manual-rebuild`){return this.resetIndex(),this.dirty=!0,this.sessionsDirty=!0,await this.sync({reason:e,forceFullReindex:!0}),this.lastRebuildSummary??this.buildRebuildSummary({reason:e,memoryFilesIndexed:0,sessionFilesIndexed:0,staleMemoryFilesRemoved:0,staleSessionFilesRemoved:0,needsFullReindex:!0})}async sync(e){let t=this.readMeta(),n=e?.forceFullReindex||!t||t.model!==this.provider.model||t.provider!==this.provider.id||t.providerKey!==this.providerKey||t.chunkTokens!==this.config.chunkTokens||t.chunkOverlap!==this.config.chunkOverlap||this.vector.available&&!t?.vectorDims;n&&this.resetIndex();let r=await I(this.memoryRoot),i=(await Promise.all(r.map(async e=>De(e,this.memoryRoot)))).filter(e=>e!==null),a=new Set(i.map(e=>e.path)),o=0,s=i.map(e=>async()=>{let t=this.db.prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`).get(e.path,`memory`);!n&&t?.hash===e.hash||(await this.indexFile(e,{source:`memory`}),o+=1)});for(let e of s)await e();let c=0,l=this.db.prepare(`SELECT path FROM files WHERE source = ?`).all(`memory`);for(let e of l)if(!a.has(e.path)){this.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(e.path,`memory`),c+=1;try{this.db.prepare(`DELETE FROM ${J} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`).run(e.path,`memory`)}catch{}if(this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(e.path,`memory`),this.ftsAvailable)try{this.db.prepare(`DELETE FROM ${Y} WHERE path = ? AND source = ? AND model = ?`).run(e.path,`memory`,this.provider.model)}catch{}}let u={indexed:0,staleRemoved:0};this.config.experimental.sessionMemory&&(n||this.sessionsDirty)&&(u=await this.syncSessionFiles(n)),this.writeMeta({model:this.provider.model,provider:this.provider.id,providerKey:this.providerKey,chunkTokens:this.config.chunkTokens,chunkOverlap:this.config.chunkOverlap,...this.vector.available&&this.vector.dims?{vectorDims:this.vector.dims}:{}}),this.dirty=!1,this.searchFallbackOnly=!this.indexHasSearchableData(),this.lastRebuildSummary=this.buildRebuildSummary({reason:e?.reason??`sync`,memoryFilesIndexed:o,sessionFilesIndexed:u.indexed,staleMemoryFilesRemoved:c,staleSessionFilesRemoved:u.staleRemoved,needsFullReindex:!!n})}async syncSessionFiles(e){let t=await ct(this.dataDir,this.sessionStoreName),n=(await Promise.all(t.map(async e=>ut(this.dataDir,e,this.sessionStoreName)))).filter(e=>e!==null),r=new Set(n.map(e=>e.path)),i=e||this.sessionsDirtyFiles.size===0,a=0;for(let t of n){if(!i&&!this.sessionsDirtyFiles.has(t.absPath))continue;let n=this.db.prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`).get(t.path,`sessions`);if(!e&&n?.hash===t.hash){this.resetSessionDelta(t.absPath,t.size);continue}await this.indexFile(t,{source:`sessions`,content:t.content,lineMap:t.lineMap}),a+=1,this.resetSessionDelta(t.absPath,t.size)}let o=0,s=this.db.prepare(`SELECT path FROM files WHERE source = ?`).all(`sessions`);for(let e of s)if(!r.has(e.path)){this.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(e.path,`sessions`),o+=1;try{this.db.prepare(`DELETE FROM ${J} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`).run(e.path,`sessions`)}catch{}if(this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(e.path,`sessions`),this.ftsAvailable)try{this.db.prepare(`DELETE FROM ${Y} WHERE path = ? AND source = ? AND model = ?`).run(e.path,`sessions`,this.provider.model)}catch{}}return this.sessionsDirty=!1,this.sessionsDirtyFiles.clear(),{indexed:a,staleRemoved:o}}resetSessionDelta(e,t){let n=this.sessionDeltas.get(e);n&&(n.lastSize=t,n.pendingBytes=0,n.pendingMessages=0)}decorateCitations(e){return this.config.citations===`off`?e:e.map(e=>{let t=`Source: ${e.path}#L${e.startLine}-L${e.endLine}`;return this.config.citations===`on`?{...e,citation:t,snippet:`${e.snippet}\n\n${t}`}:{...e,citation:t}})}decorateEntryIds(e){return e.map(e=>{if(e.id)return e;let t=pt(e.path,e.snippet,e.startLine);return{...e,id:t}})}},$=e({createBuiltinMemoryProvider:()=>ht});function ht(e,t){let n=mt.get(e.dataDir,t?.includeSessions?{experimental:{sessionMemory:!0},sources:[`memory`,`sessions`],store:{sessionStoreName:e.sessionStoreName,vector:{enabled:!0}}}:e.sessionStoreName?{store:{sessionStoreName:e.sessionStoreName,vector:{enabled:!0}}}:void 0),i=e.memoryDir;return{id:`builtin-memory`,name:`Builtin Memory Provider`,status:()=>n.status(),search:async(e,t)=>n.search(e),getLines:async(e,t,r)=>{let i=Math.max(1,r-t+1),a=await n.readFile({relPath:e,from:t,lines:i});return a.text?a.text.split(`
71
+ `):[]},listFiles:async()=>I(i),append:async e=>n.appendToMemory(e),updateFile:async(e,t)=>{await n.replaceFile({relPath:e,content:t})},deleteFile:async e=>{await n.deleteFile(e)},sync:async e=>{if(e===`cli-rebuild`){await n.rebuild(e);return}await n.sync({reason:e??`provider-sync`})},noteSessionUpdate:e=>{let t=r.isAbsolute(e)?e:r.resolve(e);n.noteSessionUpdate(t)}}}export{de as A,g as B,oe as C,j as D,P as E,S as F,ee as G,u as H,re as I,m as K,w as L,C as M,ye as N,E as O,te as P,ge as R,me as S,ve as T,f as U,d as V,p as W,O as _,Pe as a,be as b,_ as c,fe as d,ue as f,ie as g,D as h,Ne as i,he as j,b as k,v as l,ne as m,ht as n,H as o,T as p,mt as r,I as s,$ as t,ae as u,A as v,pe as w,_e as x,xe as y,h as z};
package/dist/index.d.ts CHANGED
@@ -217,6 +217,12 @@ type SubagentContext = {
217
217
  type SessionPathScope = {
218
218
  subagent?: {
219
219
  parentSessionId: string;
220
+ /**
221
+ * Absolute filesystem path of the parent session's directory.
222
+ * Required for correctly nesting sub-subagents (depth ≥ 2).
223
+ * See SessionPathOptions.subagent.parentDir for details.
224
+ */
225
+ parentDir?: string;
220
226
  };
221
227
  };
222
228
  type AgentRunParamsBase = {
@@ -231,7 +237,8 @@ type AgentRunParamsBase = {
231
237
  /** vLLM/OpenAI-compatible API base URL */baseUrl: string;
232
238
  apiKey: string;
233
239
  model: string; /** Context window size; defaults to 200000 */
234
- contextWindow?: number; /** Flash model for lightweight tasks (e.g. title generation) */
240
+ contextWindow?: number; /** Maximum number of tokens for LLM output; defaults to 32768 */
241
+ maxTokens?: number; /** Flash model for lightweight tasks (e.g. title generation) */
235
242
  flashModel?: string;
236
243
  }; /** In-process progress callback */
237
244
  onProgress?: (event: AgentProgressEvent$1) => Promise<void>; /** Execution timeout in milliseconds; defaults to 600000 (10 min) */
@@ -260,7 +267,8 @@ type AgentRunParamsBase = {
260
267
  * Additional skill registry directories supplied by the CLI.
261
268
  * Each directory contains skill child directories such as <dir>/<skill-name>/SKILL.md.
262
269
  */
263
- skillsLoadPaths?: string[]; /** Memory system options (optional) */
270
+ skillsLoadPaths?: string[]; /** Whether to encrypt session data at rest using lz-string compression. */
271
+ encryptSessions?: boolean; /** Memory system options (optional) */
264
272
  memory?: {
265
273
  /** Explicit memory provider id (overrides plugins.slots.memory) */providerId?: string; /** Explicit plugin id for memory provider (used when providerId not set) */
266
274
  pluginId?: string; /** Whether memory replies should include source path/line hints */
@@ -370,7 +378,7 @@ type SubagentRunRecord = {
370
378
  };
371
379
  //#endregion
372
380
  //#region src/subagent/registry.d.ts
373
- declare const MAX_SUBAGENT_DEPTH = 3;
381
+ declare const MAX_SUBAGENT_DEPTH = 2;
374
382
  declare const MAX_CHILDREN_PER_SESSION = 5;
375
383
  /**
376
384
  * In-memory registry for subagent runs scoped to a single parent runAgent call.
@@ -864,9 +872,17 @@ declare function runAgent(params: AgentRunParams, _registryForTesting?: Subagent
864
872
  //#region src/session/session.d.ts
865
873
  declare const DEFAULT_SESSION_STORE_NAME = "sessions";
866
874
  type SessionPathOptions = {
867
- storeName?: string;
875
+ storeName?: string; /** Whether session data should be encrypted at rest. */
876
+ encryptSessions?: boolean;
868
877
  subagent?: {
869
878
  parentSessionId: string;
879
+ /**
880
+ * Absolute filesystem path of the parent session's directory.
881
+ * When set, the child path is resolved as `path.join(parentDir, "subagents", childSessionId)`
882
+ * rather than anchoring at `sessionsDir`. This is required for correctly nesting
883
+ * sub-subagents (depth ≥ 2) inside their parent subagent's own directory.
884
+ */
885
+ parentDir?: string;
870
886
  };
871
887
  };
872
888
  type SessionInspection = {
@@ -903,6 +919,27 @@ type CronExecutionRecord = {
903
919
  childSessionId?: string;
904
920
  createdAt: string;
905
921
  };
922
+ declare const MAX_ARTIFACT_CONTENT_CHARS = 2000;
923
+ type ArtifactOperationType = "write" | "edit" | "delete" | "move";
924
+ type ArtifactOperationName = "write_file" | "edit_file" | "patch_add" | "patch_update" | "patch_delete" | "patch_move";
925
+ type ArtifactOperationInput = {
926
+ type: ArtifactOperationType;
927
+ operation: ArtifactOperationName;
928
+ file: string;
929
+ sourceFile?: string;
930
+ content: string;
931
+ toolCallId: string;
932
+ toolName: string; /** Whether this operation was performed by the agent itself or a subagent */
933
+ source: "agent" | "subagent"; /** The session that actually performed this operation */
934
+ sessionId: string;
935
+ };
936
+ /** Operation shape that tool implementations provide before the recorder enriches it with source/sessionId. */
937
+ type ArtifactOpInput = Omit<ArtifactOperationInput, "source" | "sessionId">;
938
+ type ArtifactOperation = ArtifactOperationInput & {
939
+ timestamp: string;
940
+ truncated: boolean;
941
+ originalChars: number;
942
+ };
906
943
  /** Resolves the sessions directory path within a data directory */
907
944
  declare function normalizeSessionStoreName(storeName?: string): string;
908
945
  /** Resolves the sessions directory path within a data directory */
@@ -911,6 +948,8 @@ declare function sessionsDir(dataDir: string, options?: SessionPathOptions): str
911
948
  declare function sessionDir(dataDir: string, sessionId: string, options?: SessionPathOptions): string;
912
949
  /** Resolves the transcript file path for a session */
913
950
  declare function transcriptPath(dataDir: string, sessionId: string, options?: SessionPathOptions): string;
951
+ /** Resolves the artifact operation log path for a session */
952
+ declare function artifactsPath(dataDir: string, sessionId: string, options?: SessionPathOptions): string;
914
953
  /** Resolves the metadata file path for a session */
915
954
  declare function metadataPath(dataDir: string, sessionId: string, options?: SessionPathOptions): string;
916
955
  /** Resolves the persisted context snapshot path for a session */
@@ -928,6 +967,8 @@ declare function createSession(dataDir: string, channel: Channel, options?: Sess
928
967
  declare function ensureSession(dataDir: string, sessionId: string, options?: SessionPathOptions): Promise<void>;
929
968
  /** Loads all transcript entries from a session */
930
969
  declare function loadTranscript(dataDir: string, sessionId: string, options?: SessionPathOptions): Promise<TranscriptEntry[]>;
970
+ declare function appendArtifactOperation(dataDir: string, sessionId: string, operation: ArtifactOperationInput, options?: SessionPathOptions): Promise<void>;
971
+ declare function loadArtifactOperations(dataDir: string, sessionId: string, options?: SessionPathOptions): Promise<ArtifactOperation[]>;
931
972
  /** Appends a single entry to the transcript file */
932
973
  declare function appendTranscriptEntry(dataDir: string, sessionId: string, entry: TranscriptEntry, options?: SessionPathOptions & {
933
974
  providerId?: string;
@@ -956,6 +997,48 @@ declare function loadSessionContextSnapshot(dataDir: string, sessionId: string,
956
997
  declare function inspectSession(dataDir: string, sessionId: string, options?: SessionPathOptions): Promise<SessionInspection>;
957
998
  declare function exportSession(dataDir: string, sessionId: string, options?: SessionPathOptions): Promise<SessionExport>;
958
999
  //#endregion
1000
+ //#region src/session/session-storage.d.ts
1001
+ /**
1002
+ * Unified session storage layer.
1003
+ *
1004
+ * When encryption is enabled, all session file content is compressed/encoded
1005
+ * via lz-string before writing and decompressed/decoded on read.
1006
+ * The marker prefix `__LZENC__` lets readers distinguish encrypted content
1007
+ * from plain-text even after a configuration change.
1008
+ */
1009
+ /** Compress + encode a UTF-8 string into a base64-safe encrypted payload. */
1010
+ declare function encryptContent(plain: string): string;
1011
+ /** Detect whether a payload is encrypted, then decode + decompress. */
1012
+ declare function decryptContent(raw: string): string;
1013
+ /** Returns `true` when the raw string starts with the encryption marker. */
1014
+ declare function isEncryptedContent(raw: string): boolean;
1015
+ /**
1016
+ * Read a session file, transparently decrypting if the content is encrypted.
1017
+ * Returns `null` when the file does not exist (ENOENT).
1018
+ */
1019
+ declare function readSessionFile(filePath: string): Promise<string | null>;
1020
+ /**
1021
+ * Write content to a session file, optionally encrypting it.
1022
+ */
1023
+ declare function writeSessionFile(filePath: string, content: string, encrypt?: boolean): Promise<void>;
1024
+ /**
1025
+ * Append content to a session file, optionally encrypting the *entire* file.
1026
+ *
1027
+ * For JSONL files in encrypted mode we must read-decrypt-append-encrypt-write
1028
+ * because lz-string output is not append-friendly.
1029
+ */
1030
+ declare function appendSessionFile(filePath: string, line: string, encrypt?: boolean): Promise<void>;
1031
+ /**
1032
+ * Atomically write content via a temp file + rename, optionally encrypting.
1033
+ */
1034
+ declare function atomicWriteSessionFile(filePath: string, content: string, encrypt?: boolean): Promise<void>;
1035
+ /**
1036
+ * Read a session file and return its content as a string, transparently
1037
+ * handling encrypted files. This replaces direct `fs.createReadStream` usage
1038
+ * for session transcript scanning.
1039
+ */
1040
+ declare function readSessionFileContent(filePath: string): Promise<string | null>;
1041
+ //#endregion
959
1042
  //#region src/context/session-context-store.d.ts
960
1043
  type PersistedToolResult = {
961
1044
  content: string;
@@ -1308,6 +1391,12 @@ type SystemPromptParams = {
1308
1391
  presetSystemPrompt?: string; /** Custom agent prompt body used for a named subagent. */
1309
1392
  activeAgentSystemPrompt?: string; /** Custom agents visible to the main agent for delegation decisions. */
1310
1393
  availableAgents?: AgentDefinition[];
1394
+ /**
1395
+ * Nesting depth of this agent run (0 = root, 1 = first-level subagent, …).
1396
+ * When > 0, an explicit constraint section is injected to discourage further
1397
+ * subagent spawning.
1398
+ */
1399
+ subagentDepth?: number;
1311
1400
  /**
1312
1401
  * Summary of prior conversation history produced by compaction.
1313
1402
  * When provided, it is appended to the system prompt so the agent
@@ -1455,6 +1544,30 @@ type UnionLast<U> = UnionToIntersect<U extends unknown ? (x: U) => 0 : never> ex
1455
1544
  type UnionToTuple<U, Acc extends unknown[] = [], R = UnionLast<U>> = [U] extends [never] ? Acc : UnionToTuple<Exclude<U, R>, [Extract<U, R>, ...Acc]>;
1456
1545
  type Assert<T, E> = T extends E ? T : never;
1457
1546
  type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
1547
+ type Ensure<T> = T extends infer U ? U : never;
1548
+ //#endregion
1549
+ //#region ../../node_modules/.pnpm/@sinclair+typebox@0.34.48/node_modules/@sinclair/typebox/build/cjs/type/array/array.d.ts
1550
+ interface ArrayOptions extends SchemaOptions {
1551
+ /** The minimum number of items in this array */
1552
+ minItems?: number;
1553
+ /** The maximum number of items in this array */
1554
+ maxItems?: number;
1555
+ /** Should this schema contain unique items */
1556
+ uniqueItems?: boolean;
1557
+ /** A schema for which some elements should match */
1558
+ contains?: TSchema;
1559
+ /** A minimum number of contains schema matches */
1560
+ minContains?: number;
1561
+ /** A maximum number of contains schema matches */
1562
+ maxContains?: number;
1563
+ }
1564
+ type ArrayStatic<T extends TSchema, P extends unknown[]> = Ensure<Static<T, P>[]>;
1565
+ interface TArray<T extends TSchema = TSchema> extends TSchema, ArrayOptions {
1566
+ [Kind]: 'Array';
1567
+ static: ArrayStatic<T, this['params']>;
1568
+ type: 'array';
1569
+ items: T;
1570
+ }
1458
1571
  //#endregion
1459
1572
  //#region ../../node_modules/.pnpm/@sinclair+typebox@0.34.48/node_modules/@sinclair/typebox/build/cjs/type/schema/schema.d.ts
1460
1573
  interface SchemaOptions {
@@ -1683,6 +1796,7 @@ declare function createProcessTool(options: ProcessToolOptions): AgentTool<typeo
1683
1796
  declare function createBashTool(workspaceDir: string): AgentTool;
1684
1797
  //#endregion
1685
1798
  //#region src/tools/files.d.ts
1799
+ type ArtifactRecorder = (operation: ArtifactOpInput) => Promise<void>;
1686
1800
  declare const readFileSchema: TObject<{
1687
1801
  path: TString;
1688
1802
  offset: TOptional<TNumber>;
@@ -1698,7 +1812,7 @@ declare const writeFileSchema: TObject<{
1698
1812
  path: TString;
1699
1813
  content: TString;
1700
1814
  }>;
1701
- declare function createWriteFileTool(workspaceDir: string, contextManager?: ContextManager): AgentTool<typeof writeFileSchema, {
1815
+ declare function createWriteFileTool(workspaceDir: string, contextManager?: ContextManager, artifactRecorder?: ArtifactRecorder): AgentTool<typeof writeFileSchema, {
1702
1816
  path: string;
1703
1817
  }>;
1704
1818
  declare const editFileSchema: TObject<{
@@ -1706,7 +1820,7 @@ declare const editFileSchema: TObject<{
1706
1820
  old_string: TString;
1707
1821
  new_string: TString;
1708
1822
  }>;
1709
- declare function createEditFileTool(workspaceDir: string, contextManager?: ContextManager): AgentTool<typeof editFileSchema, {
1823
+ declare function createEditFileTool(workspaceDir: string, contextManager?: ContextManager, artifactRecorder?: ArtifactRecorder): AgentTool<typeof editFileSchema, {
1710
1824
  path: string;
1711
1825
  occurrences: number;
1712
1826
  }>;
@@ -1732,6 +1846,7 @@ declare const applyPatchSchema: TObject<{
1732
1846
  type ApplyPatchToolOptions = {
1733
1847
  sessionId?: string;
1734
1848
  hitlResume?: AgentRunParams["hitlResume"];
1849
+ artifactRecorder?: (operation: ArtifactOpInput) => Promise<void>;
1735
1850
  };
1736
1851
  declare function createApplyPatchTool(workspaceDir: string, options?: ApplyPatchToolOptions): AgentTool<typeof applyPatchSchema, ApplyPatchDetails>;
1737
1852
  //#endregion
@@ -1806,9 +1921,18 @@ type ImageResult = {
1806
1921
  declare function createImageTool(): AgentTool<typeof imageSchema, ImageResult>;
1807
1922
  //#endregion
1808
1923
  //#region src/tools/subagent-spawn.d.ts
1924
+ declare const spawnTaskSchema: TObject<{
1925
+ task: TString;
1926
+ label: TOptional<TString>;
1927
+ agent: TOptional<TString>;
1928
+ }>;
1809
1929
  declare const spawnSchema: TObject<{
1810
1930
  task: TString;
1811
1931
  label: TOptional<TString>;
1932
+ agent: TOptional<TString>;
1933
+ }>;
1934
+ declare const batchSpawnSchema: TObject<{
1935
+ tasks: TArray<typeof spawnTaskSchema>;
1812
1936
  }>;
1813
1937
  type SpawnResult = {
1814
1938
  status: "done";
@@ -1829,6 +1953,16 @@ type SpawnResult = {
1829
1953
  runId: string;
1830
1954
  error: string;
1831
1955
  };
1956
+ type BatchSpawnItemResult = SpawnResult & {
1957
+ index: number;
1958
+ task: string;
1959
+ label?: string;
1960
+ };
1961
+ type BatchSpawnResult = {
1962
+ status: "done" | "partial_error" | "error";
1963
+ results: BatchSpawnItemResult[];
1964
+ };
1965
+ type InheritedRunParams = Pick<AgentRunParams, "plugins" | "skillsLoadPaths" | "memory" | "messaging" | "historyLimit" | "onProgress" | "messageId" | "sessionStoreName" | "agentPolicy">;
1832
1966
  /** Formats the announce message injected into the parent session when a subagent completes. */
1833
1967
  declare function buildSubagentAnnounceMessage(params: {
1834
1968
  task: string;
@@ -1842,6 +1976,8 @@ declare function buildSubagentAnnounceMessage(params: {
1842
1976
  *
1843
1977
  * @param registry The parent session's subagent registry.
1844
1978
  * @param parentSessionId Session ID of the agent doing the spawning.
1979
+ * @param parentSessionDir Absolute filesystem path of the spawning session's directory.
1980
+ * Used to correctly nest child session directories under the parent.
1845
1981
  * @param depth Current nesting depth of the spawning agent (child will be depth+1).
1846
1982
  * @param dataDir User data directory (shared between parent and child).
1847
1983
  * @param channel Channel inherited from the parent session.
@@ -1849,7 +1985,8 @@ declare function buildSubagentAnnounceMessage(params: {
1849
1985
  * @param loopDetection Tool-loop detection config inherited from the parent.
1850
1986
  * @param spawnFn Function that actually runs a child agent (injected to avoid circular imports).
1851
1987
  */
1852
- declare function createSubagentSpawnTool(registry: SubagentRegistry, parentSessionId: string, depth: number, dataDir: string, channel: AgentRunParams["channel"], llm: AgentRunParams["llm"], loopDetection: ToolLoopDetectionConfig | undefined, inheritedRunParams: Pick<AgentRunParams, "plugins" | "skillsLoadPaths" | "memory" | "messaging" | "historyLimit" | "onProgress" | "messageId" | "sessionStoreName" | "agentPolicy">, spawnFn: (params: AgentRunParams) => Promise<AgentRunResult>): AgentTool<typeof spawnSchema, SpawnResult>;
1988
+ declare function createSubagentSpawnTool(registry: SubagentRegistry, parentSessionId: string, parentSessionDir: string, depth: number, dataDir: string, channel: AgentRunParams["channel"], llm: AgentRunParams["llm"], loopDetection: ToolLoopDetectionConfig | undefined, inheritedRunParams: InheritedRunParams, spawnFn: (params: AgentRunParams) => Promise<AgentRunResult>): AgentTool<typeof spawnSchema, SpawnResult>;
1989
+ declare function createBatchSubagentSpawnTool(registry: SubagentRegistry, parentSessionId: string, parentSessionDir: string, depth: number, dataDir: string, channel: AgentRunParams["channel"], llm: AgentRunParams["llm"], loopDetection: ToolLoopDetectionConfig | undefined, inheritedRunParams: InheritedRunParams, spawnFn: (params: AgentRunParams) => Promise<AgentRunResult>): AgentTool<typeof batchSpawnSchema, BatchSpawnResult>;
1853
1990
  //#endregion
1854
1991
  //#region src/tools/subagents.d.ts
1855
1992
  declare const ACTIONS: readonly ["list", "kill"];
@@ -1956,6 +2093,17 @@ declare function isUiToolPauseSignal(error: unknown): error is UiToolPauseSignal
1956
2093
  /** Optional context for enabling subagent tools */
1957
2094
  type SubagentToolsContext = {
1958
2095
  sessionId: string;
2096
+ /**
2097
+ * Runtime-local session id, used to record which session actually performed
2098
+ * an artifact operation. Always refers to the currently executing session.
2099
+ */
2100
+ runtimeSessionId?: string;
2101
+ /**
2102
+ * Absolute filesystem path of the current (spawning) session's directory.
2103
+ * Passed to createSubagentSpawnTool so it can correctly nest child sessions
2104
+ * under the parent's directory at any depth.
2105
+ */
2106
+ currentSessionDir: string;
1959
2107
  registry: SubagentRegistry;
1960
2108
  parentSessionId: string; /** Depth of the current agent (root = 0) */
1961
2109
  depth: number;
@@ -2431,4 +2579,4 @@ declare function formatClarifyResolution(resolution: HitlResolution): string;
2431
2579
  declare function formatReviewResolution(resolution: HitlResolution): string;
2432
2580
  declare function buildResumeNarration(resolution: HitlResolution, kind: string): string;
2433
2581
  //#endregion
2434
- export { AgentBinding, AgentConfig, type AgentConfigSource, type AgentCustomProgressEvent, type AgentDefinition, type AgentDirectoryCandidate, AgentModelConfig, type AgentProgressEvent, type AgentRunParams, type AgentRunResult, type AgentRuntimePolicy, type AgentScanOptions, AgentsConfig, BOOTSTRAP_FILE_NAMES, BOOTSTRAP_MAX_CHARS, BOOTSTRAP_TOTAL_MAX_CHARS, type BootstrapContextFile, type BootstrapEnsureResult, type BootstrapFile, type BootstrapMountResult, type BootstrapMountStatus, type CallbackEventPayload, type CallbackPayload, type Channel, type ContextManager, type CronExecutionRecord, DEFAULT_SESSION_STORE_NAME, type EmbeddingProvider, type EmbeddingProviderContext, type EmbeddingProviderFactory, type EmbeddingProviderRegistration, HITL_MESSAGES, type HitlPauseContext, HitlPauseSignal, type HitlToolContext, MAX_CHILDREN_PER_SESSION, MAX_SUBAGENT_DEPTH, type MemoryCallOptions, type MemoryChangeSource, type MemoryChangedEvent, type MemoryChangedHandler, MemoryIndexManager, type MemoryProvider, type MemoryProviderContext, type MemoryProviderFactory, type MemoryProviderRegistration, type MemoryProviderStatus, type MemoryRebuildSummary, type MemorySearchOptions, type MemorySearchResult, type NormalizedPluginsConfig, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PersistedSubagentRunRecord, type PersistedToolResult, type PluginApi, type PluginCandidate, type PluginConfigUiHint, type PluginCustomProgressInput, type PluginDiagnostic, type PluginDiscoveryOptions, type PluginDiscoveryResult, type PluginEntryConfig, type PluginExecutionRuntime, type PluginHookAfterCompactionEvent, type PluginHookAfterPromptBuildEvent, type PluginHookAfterToolCallEvent, type PluginHookAgentContext, type PluginHookAgentEndEvent, type PluginHookAssistantMessageEndEvent, type PluginHookBeforeCompactionEvent, type PluginHookBeforeCompactionResult, type PluginHookBeforeModelResolveEvent, type PluginHookBeforeModelResolveResult, type PluginHookBeforePromptBuildEvent, type PluginHookBeforePromptBuildResult, type PluginHookBeforeToolCallEvent, type PluginHookBeforeToolCallResult, type PluginHookDreamGateEvent, type PluginHookDreamGateResult, type PluginHookHandlerMap, type PluginHookLlmInputEvent, type PluginHookLlmOutputEvent, type PluginHookMemoryChangedEvent, type PluginHookName, PluginHookRegistry, type PluginHookSessionEndEvent, type PluginHookSessionResetEvent, type PluginHookSessionStartEvent, type PluginKind, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRegistry, type PluginOrigin, type PluginProgressEmitter, type PluginRecord, type PluginRegistry, type PluginRuntime, type PluginRuntimeContext, type PluginSystem, type PluginSystemOptions, type PluginToolOptions, PluginToolRegistry, type PluginUiToolDescriptor, type PluginUiToolOptions, type PluginsConfig, type PluginsConfigValidationResult, type RegisteredPluginTool, type ResumeOptions, type ResumeValidationResult, type RunResultPayload, SYSTEM_AGENTS_DIR, type SessionContextStore, type SessionExport, type SessionInspection, type SessionMetadata, type SessionMetadataUpdate, type SessionSummary, type Skill, type SkillDirectory, type SkillViewResult, type SlashCommandList, type SubagentContext, SubagentRegistry, type SubagentRunRecord, type SubagentStatus, type SubagentToolsContext, type SystemPromptParams, type ToolLoopDetectionConfig, type TranscriptEntry, type UiToolInputSchema, type UiToolOptions, UiToolPauseSignal, addAgent, addBinding, agentDirCandidates, aimaxDir, appendCronExecutionRecord, appendRecentToMemory, appendToMemory, appendTranscriptEntry, approvalSummaryFromResolution, bootstrapMountLayout, buildAgentDelegationPrompt, buildAgentTaskPrompt, buildBootstrapContextFiles, buildResumeNarration, buildSkillsPrompt, buildSubagentAnnounceMessage, buildSystemPrompt, cleanupOldSubagentRecords, clearPendingHitl, clearPendingUiTool, collapseLogPath, contextSnapshotPath, createAgentTools, createApplyPatchTool, createBashTool, createBuiltinMemoryProvider, createContextManager, createEditFileTool, createExecTool, createImageTool, createListDirTool, createMemoryAppendTool, createMemoryForgetTool, createMemoryGetTool, createMemoryListTool, createMemoryLogTool, createMemorySearchTool, createMemoryUpdateTool, createMemoryWriteTool, createPendingHitl, createPendingUiTool, createPluginProgressEmitter, createPluginRuntime, createProcessTool, createReadFileTool, createSession, createSessionContextStore, createSessionSearchTool, createSkillListTool, createSkillLoadTool, createSubagentSpawnTool, createSubagentsTool, createUiTool, createWriteFileTool, cronExecutionsPath, defaultUiToolInputSchema, deleteMemoryFile, discoverAIMaxPlugins, ensureBootstrapMountLayout, ensureSession, exportSession, filterSkillsForAgent, filterToolsForAgent, findAgentDefinition, findSkillByName, formatApprovalResolution, formatClarifyResolution, formatReviewResolution, generateSessionTitle, getAgentConfig, getMemoryLines, hasBootstrapSentinel, hitlHistoryPath, initializePluginSystem, inspectBootstrapMountLayout, inspectSession, isBootstrapMountLayoutReady, isHitlPauseSignal, isUiToolPauseSignal, listAgents, listAvailableSlashCommands, listBindings, listMemoryFiles, listSessionSummaries, listSessions, listSubagentRunsFromDisk, loadAgentDefinitionsFromDir, loadAgentsConfig, loadBootstrapFiles, loadCronExecutionRecords, readPendingHitl as loadPendingHitl, readPendingHitl, readPendingUiTool as loadPendingUiTool, readPendingUiTool, loadPluginManifest, loadPluginManifestRegistry, loadPlugins, loadSessionContextSnapshot, loadSessionMetadata, loadSkillView, loadSkills, loadSkillsFromDirs, loadSkillsWithPluginDirs, loadSubagentRegistryFromDisk, loadTranscript, memoryDir, metadataPath, normalizeAgentId, normalizePluginsConfig, normalizeSessionStoreName, parseAgentDefinition, pendingHitlPath, pendingUiToolPath, primaryMemoryPath, readHitlHistory, readMemoryFile, readPrimaryMemory, registerEmbeddingProvider, registerMemoryProvider, removeAgent, removeBindings, replaceMemoryFile, resetEmbeddingProviderRegistryForTests, resetMemoryProviderRegistryForTests, resolveAgentDir, resolveAgentIdByBinding, resolveAgentsConfigPath, resolveDefaultAgentId, resolveEmbeddingProvider, resolveHitlRequest, resolveHitlRequest as resolvePendingHitl, resolveMemoryProvider, resolveModelFallbacks, resolveModelString, resolvePendingUiTool, resolvePluginManifestPath, rewriteTranscript, runAgent, saveAgentsConfig, saveSessionMetadata, saveSubagentRegistryToDisk, scanAgentDefinitions, searchMemory, sessionDir, sessionMemoryPath, sessionsDir, skillsDir, toolResultsDir, transcriptPath, transitionHitlStatus, updateAgentIdentity, updateSessionMetadata, validatePluginsConfig, validateResume, wrapToolsWithHooks };
2582
+ export { AgentBinding, AgentConfig, type AgentConfigSource, type AgentCustomProgressEvent, type AgentDefinition, type AgentDirectoryCandidate, AgentModelConfig, type AgentProgressEvent, type AgentRunParams, type AgentRunResult, type AgentRuntimePolicy, type AgentScanOptions, AgentsConfig, type ArtifactOpInput, type ArtifactOperation, type ArtifactOperationInput, type ArtifactOperationName, type ArtifactOperationType, BOOTSTRAP_FILE_NAMES, BOOTSTRAP_MAX_CHARS, BOOTSTRAP_TOTAL_MAX_CHARS, type BootstrapContextFile, type BootstrapEnsureResult, type BootstrapFile, type BootstrapMountResult, type BootstrapMountStatus, type CallbackEventPayload, type CallbackPayload, type Channel, type ContextManager, type CronExecutionRecord, DEFAULT_SESSION_STORE_NAME, type EmbeddingProvider, type EmbeddingProviderContext, type EmbeddingProviderFactory, type EmbeddingProviderRegistration, HITL_MESSAGES, type HitlPauseContext, HitlPauseSignal, type HitlToolContext, MAX_ARTIFACT_CONTENT_CHARS, MAX_CHILDREN_PER_SESSION, MAX_SUBAGENT_DEPTH, type MemoryCallOptions, type MemoryChangeSource, type MemoryChangedEvent, type MemoryChangedHandler, MemoryIndexManager, type MemoryProvider, type MemoryProviderContext, type MemoryProviderFactory, type MemoryProviderRegistration, type MemoryProviderStatus, type MemoryRebuildSummary, type MemorySearchOptions, type MemorySearchResult, type NormalizedPluginsConfig, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PersistedSubagentRunRecord, type PersistedToolResult, type PluginApi, type PluginCandidate, type PluginConfigUiHint, type PluginCustomProgressInput, type PluginDiagnostic, type PluginDiscoveryOptions, type PluginDiscoveryResult, type PluginEntryConfig, type PluginExecutionRuntime, type PluginHookAfterCompactionEvent, type PluginHookAfterPromptBuildEvent, type PluginHookAfterToolCallEvent, type PluginHookAgentContext, type PluginHookAgentEndEvent, type PluginHookAssistantMessageEndEvent, type PluginHookBeforeCompactionEvent, type PluginHookBeforeCompactionResult, type PluginHookBeforeModelResolveEvent, type PluginHookBeforeModelResolveResult, type PluginHookBeforePromptBuildEvent, type PluginHookBeforePromptBuildResult, type PluginHookBeforeToolCallEvent, type PluginHookBeforeToolCallResult, type PluginHookDreamGateEvent, type PluginHookDreamGateResult, type PluginHookHandlerMap, type PluginHookLlmInputEvent, type PluginHookLlmOutputEvent, type PluginHookMemoryChangedEvent, type PluginHookName, PluginHookRegistry, type PluginHookSessionEndEvent, type PluginHookSessionResetEvent, type PluginHookSessionStartEvent, type PluginKind, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRegistry, type PluginOrigin, type PluginProgressEmitter, type PluginRecord, type PluginRegistry, type PluginRuntime, type PluginRuntimeContext, type PluginSystem, type PluginSystemOptions, type PluginToolOptions, PluginToolRegistry, type PluginUiToolDescriptor, type PluginUiToolOptions, type PluginsConfig, type PluginsConfigValidationResult, type RegisteredPluginTool, type ResumeOptions, type ResumeValidationResult, type RunResultPayload, SYSTEM_AGENTS_DIR, type SessionContextStore, type SessionExport, type SessionInspection, type SessionMetadata, type SessionMetadataUpdate, type SessionSummary, type Skill, type SkillDirectory, type SkillViewResult, type SlashCommandList, type SubagentContext, SubagentRegistry, type SubagentRunRecord, type SubagentStatus, type SubagentToolsContext, type SystemPromptParams, type ToolLoopDetectionConfig, type TranscriptEntry, type UiToolInputSchema, type UiToolOptions, UiToolPauseSignal, addAgent, addBinding, agentDirCandidates, aimaxDir, appendArtifactOperation, appendCronExecutionRecord, appendRecentToMemory, appendSessionFile, appendToMemory, appendTranscriptEntry, approvalSummaryFromResolution, artifactsPath, atomicWriteSessionFile, bootstrapMountLayout, buildAgentDelegationPrompt, buildAgentTaskPrompt, buildBootstrapContextFiles, buildResumeNarration, buildSkillsPrompt, buildSubagentAnnounceMessage, buildSystemPrompt, cleanupOldSubagentRecords, clearPendingHitl, clearPendingUiTool, collapseLogPath, contextSnapshotPath, createAgentTools, createApplyPatchTool, createBashTool, createBatchSubagentSpawnTool, createBuiltinMemoryProvider, createContextManager, createEditFileTool, createExecTool, createImageTool, createListDirTool, createMemoryAppendTool, createMemoryForgetTool, createMemoryGetTool, createMemoryListTool, createMemoryLogTool, createMemorySearchTool, createMemoryUpdateTool, createMemoryWriteTool, createPendingHitl, createPendingUiTool, createPluginProgressEmitter, createPluginRuntime, createProcessTool, createReadFileTool, createSession, createSessionContextStore, createSessionSearchTool, createSkillListTool, createSkillLoadTool, createSubagentSpawnTool, createSubagentsTool, createUiTool, createWriteFileTool, cronExecutionsPath, decryptContent, defaultUiToolInputSchema, deleteMemoryFile, discoverAIMaxPlugins, encryptContent, ensureBootstrapMountLayout, ensureSession, exportSession, filterSkillsForAgent, filterToolsForAgent, findAgentDefinition, findSkillByName, formatApprovalResolution, formatClarifyResolution, formatReviewResolution, generateSessionTitle, getAgentConfig, getMemoryLines, hasBootstrapSentinel, hitlHistoryPath, initializePluginSystem, inspectBootstrapMountLayout, inspectSession, isBootstrapMountLayoutReady, isEncryptedContent, isHitlPauseSignal, isUiToolPauseSignal, listAgents, listAvailableSlashCommands, listBindings, listMemoryFiles, listSessionSummaries, listSessions, listSubagentRunsFromDisk, loadAgentDefinitionsFromDir, loadAgentsConfig, loadArtifactOperations, loadBootstrapFiles, loadCronExecutionRecords, readPendingHitl as loadPendingHitl, readPendingHitl, readPendingUiTool as loadPendingUiTool, readPendingUiTool, loadPluginManifest, loadPluginManifestRegistry, loadPlugins, loadSessionContextSnapshot, loadSessionMetadata, loadSkillView, loadSkills, loadSkillsFromDirs, loadSkillsWithPluginDirs, loadSubagentRegistryFromDisk, loadTranscript, memoryDir, metadataPath, normalizeAgentId, normalizePluginsConfig, normalizeSessionStoreName, parseAgentDefinition, pendingHitlPath, pendingUiToolPath, primaryMemoryPath, readHitlHistory, readMemoryFile, readPrimaryMemory, readSessionFile, readSessionFileContent, registerEmbeddingProvider, registerMemoryProvider, removeAgent, removeBindings, replaceMemoryFile, resetEmbeddingProviderRegistryForTests, resetMemoryProviderRegistryForTests, resolveAgentDir, resolveAgentIdByBinding, resolveAgentsConfigPath, resolveDefaultAgentId, resolveEmbeddingProvider, resolveHitlRequest, resolveHitlRequest as resolvePendingHitl, resolveMemoryProvider, resolveModelFallbacks, resolveModelString, resolvePendingUiTool, resolvePluginManifestPath, rewriteTranscript, runAgent, saveAgentsConfig, saveSessionMetadata, saveSubagentRegistryToDisk, scanAgentDefinitions, searchMemory, sessionDir, sessionMemoryPath, sessionsDir, skillsDir, toolResultsDir, transcriptPath, transitionHitlStatus, updateAgentIdentity, updateSessionMetadata, validatePluginsConfig, validateResume, wrapToolsWithHooks, writeSessionFile };