@gencode/cli 0.12.1 → 0.13.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,30 @@
1
1
  # @gencode/cli
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5af5e22: Add an opt-out switch for LLM session title generation. New sessions now generate a conversational title via the flash model by default (unchanged), but you can skip that LLM call for runs that don't need it — for example batch/one-shot jobs, embedded API usage, or CI.
8
+
9
+ - CLI: pass `--disable-title` on `aimax run` or `aimax resume`. It overrides the new env var `AIMAX_DISABLE_TITLE=true`.
10
+ - Programmatic: set `titleGeneration: { enabled: false }` on `AgentRunParams`.
11
+
12
+ When the switch is off, the session still gets a title — it falls back to a truncated version of the first user message, so the session list is never blank. No token cost and no network call happen. The switch controls only title generation; topic segmentation is unaffected. Start-up logs now show the resolved state as `titleGen: enabled|disabled`.
13
+
14
+ ### Patch Changes
15
+
16
+ - cbd1dba: AIMax now treats `LLMRequestError` model failures as retryable transient LLM failures even when the upstream gateway also reports non-retryable-looking metadata such as `BadRequestError` or HTTP 400. Runs still avoid replaying an attempt after assistant text or tool results have already been produced, and the agent log now records why a retry was skipped with fields such as `reason`, `retryableError`, `attemptRecordCount`, `recordsWithToolResults`, and `recordsWithAssistantText`.
17
+ - cbd1dba: AIMax now retries LLM turns when the streaming connection is torn down mid-response by the network or upstream, instead of failing the whole run on the first attempt.
18
+
19
+ Previously, if the HTTP socket was closed while the model was still streaming (for example an upstream gateway or load balancer dropping the connection, surfacing in logs as `streamErrorType="TypeError"`, `streamErrorMessage="terminated"`, `streamErrorCauseCode="UND_ERR_SOCKET"`, or Node errno codes such as `ECONNRESET`/`EPIPE`/`ETIMEDOUT`), the error reached the turn-retry loop without any retryable metadata, so it was treated as a final failure and the run stopped at `attempt=1` even though `maxAttempts` was higher.
20
+
21
+ Such transport-level failures are now recognized as transient and replayed within the existing turn-retry budget (default 3 attempts, exponential backoff). No configuration is required — the new behavior is on by default. User-initiated aborts and genuine non-retryable provider errors (e.g. HTTP 4xx with a real status code) are still not retried, and an attempt is still never replayed once assistant text or tool results have been produced.
22
+
23
+ - Updated dependencies [cbd1dba]
24
+ - Updated dependencies [cbd1dba]
25
+ - Updated dependencies [5af5e22]
26
+ - @gencode/agents@0.15.0
27
+
3
28
  ## 0.12.1
4
29
 
5
30
  ### Patch Changes
package/dist/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{a as e,i as t,o as n,t as r}from"./program-D2WYTclJ.js";function i(){globalThis.getPkgPath||(globalThis.getPkgPath=()=>`@wizard/aimax`)}i();function a(e){return e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e)}function o(e){let t=e.shutdownTimeoutMs??2e3,n=!1,r=(r,i)=>{if(e.logError(`Fatal ${r}: ${a(i)}`),n)return;n=!0;let o=setTimeout(()=>e.exit(1),t);typeof o.unref==`function`&&o.unref(),Promise.resolve().then(()=>e.shutdown()).catch(()=>{}).finally(()=>{clearTimeout(o),e.exit(1)})};e.proc.on(`uncaughtException`,e=>r(`uncaughtException`,e)),e.proc.on(`unhandledRejection`,e=>r(`unhandledRejection`,e))}const s=Date.now(),c=process.env.AIMAX_DATA_DIR,l=process.argv.includes(`run`)&&process.argv.includes(`--encrypt-sessions`),u=process.argv.includes(`run`)||process.argv.includes(`resume`);function d(e){for(let t=0;t<e.length;t++){let n=e[t];if(n===`--message-id`||n===`--messageId`)return e[t+1];if(n?.startsWith(`--message-id=`))return n.slice(13);if(n?.startsWith(`--messageId=`))return n.slice(12)}}c&&!l&&!u&&t(c,{messageId:d(process.argv)}),o({proc:process,logError:t=>e.error(t),shutdown:n,exit:e=>process.exit(e)}),e.info(`AIMax CLI starting (pid=${process.pid})`,{dataDir:c,encryptedRun:l,loggerDeferred:!!(c&&(l||u))}),r().parseAsync(process.argv).catch(t=>{e.error(`Unexpected error: ${t.message}`),process.exit(1)}).finally(()=>{let t=Date.now()-s;return e.info(`AIMax CLI exited (total uptime: ${t}ms)`),n()});export{};
2
+ import{a as e,i as t,o as n,t as r}from"./program-CcXFTFcR.js";function i(){globalThis.getPkgPath||(globalThis.getPkgPath=()=>`@wizard/aimax`)}i();function a(e){return e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e)}function o(e){let t=e.shutdownTimeoutMs??2e3,n=!1,r=(r,i)=>{if(e.logError(`Fatal ${r}: ${a(i)}`),n)return;n=!0;let o=setTimeout(()=>e.exit(1),t);typeof o.unref==`function`&&o.unref(),Promise.resolve().then(()=>e.shutdown()).catch(()=>{}).finally(()=>{clearTimeout(o),e.exit(1)})};e.proc.on(`uncaughtException`,e=>r(`uncaughtException`,e)),e.proc.on(`unhandledRejection`,e=>r(`unhandledRejection`,e))}const s=Date.now(),c=process.env.AIMAX_DATA_DIR,l=process.argv.includes(`run`)&&process.argv.includes(`--encrypt-sessions`),u=process.argv.includes(`run`)||process.argv.includes(`resume`);function d(e){for(let t=0;t<e.length;t++){let n=e[t];if(n===`--message-id`||n===`--messageId`)return e[t+1];if(n?.startsWith(`--message-id=`))return n.slice(13);if(n?.startsWith(`--messageId=`))return n.slice(12)}}c&&!l&&!u&&t(c,{messageId:d(process.argv)}),o({proc:process,logError:t=>e.error(t),shutdown:n,exit:e=>process.exit(e)}),e.info(`AIMax CLI starting (pid=${process.pid})`,{dataDir:c,encryptedRun:l,loggerDeferred:!!(c&&(l||u))}),r().parseAsync(process.argv).catch(t=>{e.error(`Unexpected error: ${t.message}`),process.exit(1)}).finally(()=>{let t=Date.now()-s;return e.info(`AIMax CLI exited (total uptime: ${t}ms)`),n()});export{};
package/dist/index.d.ts CHANGED
@@ -46,7 +46,8 @@ type RunOptions = {
46
46
  tokenBudget?: string;
47
47
  force?: boolean;
48
48
  encryptSessions?: boolean;
49
- disableTopicSegmentation?: boolean;
49
+ disableTopicSegmentation?: boolean; /** Skip LLM session title generation for new sessions. */
50
+ disableTitle?: boolean;
50
51
  };
51
52
  declare function executeRun(options: RunOptions): Promise<void>;
52
53
  //#endregion
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{n as e,r as t,t as n}from"./program-D2WYTclJ.js";export{n as createProgram,t as executeRun,e as getDataDir};
1
+ import{n as e,r as t,t as n}from"./program-CcXFTFcR.js";export{n as createProgram,t as executeRun,e as getDataDir};
@@ -0,0 +1,40 @@
1
+ import{createRequire as e}from"node:module";import{Command as t}from"commander";import{GoalConflictError as n,applyCliGoalBeforeRun as r,bootstrapMountLayout as i,buildAimaxGoalCliHelpExtra as a,buildResumeNarration as o,clearPendingUiTool as s,deleteGoal as c,ensureBootstrapMountLayout as l,exportSession as u,formatApprovalResolution as d,formatClarifyResolution as f,formatReviewResolution as p,hasBootstrapSentinel as m,initializePluginSystem as h,inspectSession as g,listAvailableSlashCommands as _,listSessionSummaries as v,loadPendingHitl as ee,loadPendingUiTool as te,loadSessionExportSnapshots as ne,loadSkillsWithPluginDirs as re,loadTranscript as ie,normalizePluginsConfig as ae,normalizeSessionStoreName as y,readGoal as b,resolveGoalObjective as oe,resolveMemoryProviderOrDefault as se,resolvePendingHitl as ce,resolvePendingUiTool as le,rewriteTranscript as ue,runAgent as de,sessionsDir as fe,transcriptPath as pe,updateGoal as me,writeGoal as he}from"@gencode/agents";import{formatTaskForDisplay as ge,isAgentDiagnosticEvent as _e,isHitlTool as ve,parseMatchedTextToResolution as ye,parseTextToResolution as be}from"@gencode/shared";import x,{existsSync as S,mkdirSync as xe,readFileSync as Se,statSync as Ce,writeFileSync as we}from"node:fs";import C,{basename as Te,dirname as w,join as T,resolve as E}from"node:path";import Ee from"log4js";import D,{glob as De,readdir as Oe}from"node:fs/promises";import ke from"node:os";import{execFile as Ae,execFileSync as je}from"node:child_process";import Me from"gensign-node";import{fileURLToPath as Ne}from"node:url";import{addAgent as Pe,addBinding as Fe,getAgentConfig as O,listAgents as Ie,listBindings as Le,loadAgentsConfig as k,normalizeAgentId as Re,removeAgent as ze,removeBindings as Be,resolveAgentDir as Ve,resolveDefaultAgentId as He,updateAgentIdentity as Ue}from"@gencode/agents/config";import{createHash as We,randomUUID as Ge}from"node:crypto";function Ke(e){let t=new Intl.DateTimeFormat(`en-CA`,{timeZone:`Asia/Shanghai`,year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}).formatToParts(e);return Object.fromEntries(t.map(e=>[e.type,e.value]))}function qe(e=new Date){let t=Ke(e),n=String(e.getMilliseconds()).padStart(3,`0`);return`${t.year}-${t.month}-${t.day} ${t.hour}:${t.minute}:${t.second}.${n}`}let A=function(e){return e.INFO=`INFO`,e.ERROR=`ERROR`,e.WARN=`WARN`,e}({}),j=null,M=[];function Je(){return qe()}function Ye(e){if(!e)return``;let t=Object.entries(e).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${Xe(t)}`);return t.length>0?` ${t.join(` `)}`:``}function Xe(e){return JSON.stringify(Ze(e,new WeakSet))??`undefined`}function Ze(e,t){return typeof e==`bigint`?e.toString():e==null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:typeof e!=`object`&&typeof e!=`function`?String(e):t.has(e)?`[Circular]`:(t.add(e),Array.isArray(e)?e.map(e=>Ze(e,t)):Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0).map(([e,n])=>[e,Ze(n,t)])))}function Qe(e){return C.join(e,`.aimax`)}function $e(e){let t=e?.trim();return t&&t.replace(/[^A-Za-z0-9_.-]/g,`_`)||`no-message-${process.pid}`}function et(e,t){let n=$e(t?.messageId),r=t?.sessionStoreName?.trim()||`sessions`;return t?.sessionId?{runLogId:n,logDir:C.join(Qe(e),r,t.sessionId,`logs`,n)}:{runLogId:n,logDir:C.join(Qe(e),`logs`,n)}}function tt(e){return{appLogPath:C.join(e,`app.log`),errorLogPath:C.join(e,`errors.log`)}}function nt(e){let{appLogPath:t,errorLogPath:n}=tt(e);Ee.configure({appenders:{appFile:{type:`file`,filename:t,maxLogSize:5*1024*1024,backups:3,compress:!0,keepFileExt:!0,layout:{type:`messagePassThrough`}},errorFile:{type:`file`,filename:n,maxLogSize:5*1024*1024,backups:3,compress:!0,keepFileExt:!0,layout:{type:`messagePassThrough`}},errorsOnly:{type:`logLevelFilter`,appender:`errorFile`,level:`error`,maxLevel:`fatal`}},categories:{default:{appenders:[`appFile`,`errorsOnly`],level:`info`}}})}function rt(e,t,n){return`[${Je()}] [${e}] ${t}${Ye(n)}`}function it(e,t,n){try{process.stderr.write(`${rt(e,t,n)}\n`)}catch{}}function at(e,t,n){if(!j){M.push({level:e,message:t,context:n}),M.length>200&&(M=M.slice(-200)),it(e,t,n);return}let r=rt(e,t,n),i=Ee.getLogger();if(e===A.ERROR){i.error(r);return}if(e===A.WARN){i.warn(r);return}i.info(r)}function N(e,t){let{logDir:n,runLogId:r}=et(e,t);if(j?.dataDir===e&&j.runLogId===r&&j.logDir===n)return;x.mkdirSync(n,{recursive:!0}),nt(n),j={dataDir:e,logDir:n,runLogId:r};let i=M;M=[];for(let e of i)at(e.level,e.message,e.context)}function ot(){return j?{...j}:null}async function st(){await Ee.shutdown()}const P={info:(e,t)=>at(A.INFO,e,t),warn:(e,t)=>at(A.WARN,e,t),error:(e,t)=>at(A.ERROR,e,t)};var ct=class{startTime;name;constructor(e){this.name=e,this.startTime=Date.now()}end(){let e=Date.now()-this.startTime;return P.info(`${this.name} completed in ${e}ms`),e}};function lt(e){if(typeof e==`string`)return e;let t=JSON.stringify(e);return t===void 0?String(e):t}const ut=new Set;function dt(e){return e instanceof Error?{name:e.name,message:e.message,code:e.code}:{message:String(e)}}function ft(e,t){try{P.warn(`CLI ${e} write failed; suppressing further ${e} writes`,{stream:e,...dt(t)})}catch{}}function pt(e,t){if(ut.has(e))return;let n=e===`stdout`?process.stdout:process.stderr;try{n.write(t)}catch(t){ut.add(e),ft(e,t)}}function mt(e){pt(`stdout`,e)}function F(e){pt(`stdout`,e+`
2
+ `)}function I(e){pt(`stderr`,e+`
3
+ `)}function L(e){switch(e.type){case`start`:F(`\n[start] ${e.message}`);break;case`text`:mt(e.text);break;case`stream_text_delta`:mt(e.text);break;case`bootstrap`:F(`\n[bootstrap:${e.phase}] ${e.dataDir}`);break;case`session_reset`:F(`\n[session:${e.action}] ${e.message}`);break;case`tool_start`:F(`\n[tool:${e.name}] ${JSON.stringify(e.input??{})}`);break;case`tool_end`:{let t=lt(e.output);F(`[tool:${e.name}] ${e.isError?`ERROR`:`OK`} ${t.slice(0,200)}`);break}case`compaction`:F(`\n[compaction${e.layer?`:${e.layer}`:``}] ${e.reason}${e.strategy?` (${e.strategy})`:``}`);break;case`skill_used`:F(`\n[skill] ${e.skillName} agent=${e.agent} task=${e.taskId}`);break;case`custom`:F(`\n[plugin:${e.pluginId}] ${e.name}${e.label?` ${e.label}`:``}${e.data?` ${JSON.stringify(e.data)}`:``}`);break;case`error`:I(`\n[error] ${e.message}`);break;case`diagnostic`:break;case`subagent_spawn`:F(`\n[subagent:spawn]${e.label?` "${e.label}"`:``} ${ge(e.task)}`);break;case`subagent_complete`:F(`[subagent:${e.status}] ${ge(e.task)}`);break;case`hitl_requested`:if(F(`\n[hitl:${e.request.kind}] ${e.request.title}`),F(` prompt: ${e.request.prompt}`),F(` requestId: ${e.request.requestId}`),e.request.input.mode===`choice`)for(let t of e.request.input.choices)F(` - [${t.id}] ${t.label}`);break;case`hitl_resumed`:F(`\n[hitl:resumed] requestId=${e.requestId} action=${e.resolution.action}`);break;case`hitl_expired`:F(`\n[hitl:expired] requestId=${e.requestId} reason=${e.reason}`);break;case`hitl_cancelled`:F(`\n[hitl:cancelled] requestId=${e.requestId}${e.reason?` reason=${e.reason}`:``}`);break;case`ui_tool_request`:F(`\n[ui-tool:${e.request.toolName}] ${e.request.outputSchema.title}`),F(` requestId: ${e.request.requestId}`),F(` toolCallId: ${e.request.toolCallId}`);break;case`ui_tool_result`:F(`\n[ui-tool:resumed] requestId=${e.requestId} tool=${e.toolName}`);break}}function ht(e,t){if(t===`json`){e&&F(JSON.stringify(e,null,2));return}F(`
4
+ `),F(`session: ${e.sessionId}`),F(`duration: ${e.durationMs}ms`),F(`tokens: input=${e.usage.input} output=${e.usage.output} total=${e.usage.total}`),e.context&&(F(`context: ${e.context.snapshotPath}`),F(`tool-results: ${e.context.toolResultsDir}`)),e.error&&I(`error: ${e.error}`)}function gt(e,t){if(t===`json`){F(JSON.stringify(e,null,2));return}if(e.length===0){F(`No sessions found.`);return}for(let t of e){let e=t.createdAt?new Date(t.createdAt).toLocaleString():`unknown`,n=t.goalStatus?` [GOAL:${t.goalStatus}]`:` [GOAL:—]`;F(`${t.id} ${e} [${t.channel}]${n} ${t.title}`)}}function _t(e,t){if(t===`json`){F(JSON.stringify(e,null,2));return}F(`session: ${e.id}`),e.metadata&&(F(`title: ${e.metadata.title}`),F(`channel: ${e.metadata.channel}`),F(`created: ${e.metadata.createdAt}`),F(`updated: ${e.metadata.updatedAt}`)),F(`transcript: ${e.transcriptPath}`),F(`entries: ${e.transcriptEntryCount}`),F(`context: ${e.contextSnapshotPath}`),F(`session-memory: ${e.sessionMemoryPath}`),F(`collapse-log: ${e.collapseLogPath}`),F(`read-states: ${e.readStateCount}`),F(`tool-results: ${e.toolResultRefCount}`),F(`tool-results-dir: ${e.toolResultsDir}`)}function vt(e,t){if(t===`json`){F(JSON.stringify(e,null,2));return}F(`session: ${e.id}`),F(`transcript: ${e.paths.transcriptPath}`),F(`context: ${e.paths.contextSnapshotPath}`),F(`session-memory: ${e.paths.sessionMemoryPath}`),F(`collapse-log: ${e.paths.collapseLogPath}`),F(`tool-results-dir: ${e.paths.toolResultsDir}`),F(`transcript-entries: ${e.transcript.length}`),F(`read-states: ${e.context.readStates.length}`),F(`tool-results: ${e.context.toolResults.length}`),F(`collapse-spans: ${e.context.compaction.collapseSpans.length}`)}function yt(e,t){if(t===`json`){F(JSON.stringify(e,null,2));return}F(`Bootstrap completed.`),F(`dataDir: ${e.dataDir}`),F(`created dirs: ${e.createdDirs.length}`),F(`created files: ${e.createdFiles.length}`),F(`skipped dirs: ${e.skippedDirs.length}`),F(`skipped files: ${e.skippedFiles.length}`)}const bt=`.aimax`,xt=`${bt}.pre-gocryptfs.`,St=[`app.log`,`errors.log`],Ct=[`logs`],wt=[`fusermount3`,`fusermount`,`umount`],Tt=[{command:`fusermount3`,args:[`-u`],label:`fusermount3 -u`},{command:`fusermount3`,args:[`-uz`],label:`fusermount3 -uz`},{command:`fusermount`,args:[`-u`],label:`fusermount -u`},{command:`fusermount`,args:[`-uz`],label:`fusermount -uz`},{command:`umount`,args:[],label:`umount`},{command:`umount`,args:[`-l`],label:`umount -l`}];function Et(e){return C.join(e,`.aimax.enc`)}function Dt(e){return C.join(e,bt)}function Ot(e){return C.join(e,`${xt}${process.pid}.${Date.now()}`)}function kt(e){return C.join(e,`${bt}.plaintext-restore.${process.pid}.${Date.now()}`)}function At(e){return e.replace(/\\([0-7]{3})/g,(e,t)=>String.fromCharCode(Number.parseInt(t,8)))}async function R(e){try{let t=await Nt.read(),n=C.resolve(e);for(let e of t.split(`
5
+ `)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&C.resolve(At(t[4]??``))===n)return!0}return!1}catch{return!1}}function jt(e){try{let t=x.readFileSync(`/proc/self/mountinfo`,`utf-8`),n=C.resolve(e);for(let e of t.split(`
6
+ `)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&C.resolve(At(t[4]??``))===n)return!0}return!1}catch{return!1}}async function Mt(){return await D.readFile(`/proc/self/mountinfo`,`utf-8`)}const Nt={read:Mt};async function z(e){try{return await D.stat(e),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function B(e){await D.mkdir(e,{recursive:!0})}async function Pt(e){if(await B(e),(await D.readdir(e)).length>0)throw Error(`Refusing to mount encrypted .aimax over non-empty directory: ${e}. Clear stale plaintext files or disable --encrypt-sessions for this run.`)}async function Ft(e){return await z(e)?(await D.readdir(e)).length===0:!0}async function V(e){if(await z(e))return(await D.readdir(e)).length}async function It(e){if(!await z(e))return!1;let t=await D.readdir(e,{withFileTypes:!0});for(let e of t)if(!(e.isDirectory()&&Ct.includes(e.name))&&!(e.isFile()&&St.some(t=>e.name.startsWith(t))))return!0;return!1}async function Lt(e){let t=await D.readdir(e,{withFileTypes:!0});for(let n of t){if(n.isDirectory()&&Ct.includes(n.name)){await D.rm(C.join(e,n.name),{recursive:!0,force:!0}).catch(()=>{});continue}n.isFile()&&St.some(e=>n.name.startsWith(e))&&await D.rm(C.join(e,n.name),{force:!0}).catch(()=>{})}}async function Rt(e){if(!await z(C.join(e,`gocryptfs.conf`)))throw Error(`Encrypted .aimax directory exists but is not initialized: ${e}. Remove the incomplete .aimax.enc directory or restore it from backup before retrying --encrypt-sessions.`)}async function zt(e){return(await D.readdir(e,{withFileTypes:!0})).filter(e=>e.isDirectory()&&e.name.startsWith(xt)).map(t=>C.join(e,t.name)).sort()}async function Bt(e,t){if(!await z(t))return null;let n=Ot(e);return P.info(`--encrypt-sessions moving plaintext .aimax aside before migration`,{plainDir:t,backupDir:n}),await D.rename(t,n),n}async function H(e,t,n){P.info(`--encrypt-sessions copying plaintext backup into encrypted mount`,{backupDir:e,plainDir:t,force:n}),await D.cp(e,t,{recursive:!0,force:n})}async function Vt(e,t){if(e.length===0)return[];await B(t);let n=[];for(let r of e)await z(r)&&(await H(r,t,!0),await D.rm(r,{recursive:!0,force:!0}),P.info(`--encrypt-sessions restored interrupted plaintext backup after failed migration`,{backupDir:r,plainDir:t}),n.push(r));return n}async function Ht(e){let t=Et(e),n=Dt(e),r=await z(t);if(!r)return;let i=r&&await z(C.join(t,`gocryptfs.conf`)),a=await z(n),o=a?await R(n):!1,s=await Ft(n);if(P.info(`plaintext .aimax restore check for disabled --encrypt-sessions`,{dataDir:e,encryptedDir:t,plainDir:n,encryptedDirExists:r,encryptedDirInitialized:i,plainDirExists:a,plainDirMountPoint:o,plainDirEntryCount:await V(n)}),!i){P.warn(`plaintext .aimax restore skipped because .aimax.enc is not initialized`,{encryptedDir:t,plainDir:n}),await B(n);return}if(o){P.warn(`plaintext .aimax restore skipped because .aimax is already a mount point`,{plainDir:n,encryptedDir:t});return}if(await It(n)){P.info(`plaintext .aimax restore skipped because plaintext .aimax already contains data`,{plainDir:n,encryptedDir:t,plainDirEntryCount:await V(n)});return}s||(P.info(`plaintext .aimax clearing ephemeral files before restore`,{plainDir:n,encryptedDir:t,plainDirEntryCount:await V(n)}),await Lt(n));try{await Gt()}catch(e){P.warn(`plaintext .aimax restore unavailable; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t}),await B(n);return}let c=kt(e),l=!1;try{await Pt(n),await Kt(t,n),l=!0,await D.rm(c,{recursive:!0,force:!0}),await B(c),await D.cp(n,c,{recursive:!0,force:!0}),P.info(`plaintext .aimax restore copied encrypted history to staging directory`,{plainDir:n,encryptedDir:t,restoreDir:c,restoredEntryCount:await V(c)}),await Jt(n),l=!1,await D.rm(n,{recursive:!0,force:!0}),await D.rename(c,n),P.info(`plaintext .aimax restore completed for disabled --encrypt-sessions`,{plainDir:n,encryptedDir:t})}catch(e){l&&await Jt(n).catch(e=>{P.warn(`plaintext .aimax restore failed to unmount during rollback`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}),await D.rm(c,{recursive:!0,force:!0}).catch(()=>{}),await B(n).catch(()=>{}),P.warn(`plaintext .aimax restore failed; continuing with existing plaintext .aimax`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}}async function Ut(e){let t=C.join(ke.tmpdir(),`aimax-gocryptfs-pass.${process.pid}.${Date.now()}`);await D.writeFile(t,`wizard_aimax@2026
7
+ `,{mode:384});try{return await e(t)}finally{await D.rm(t,{force:!0})}}async function Wt(e){let t=e.includes(`-init`)?`init`:`mount`;P.info(`--encrypt-sessions starting gocryptfs ${t}`);try{await Qt(`gocryptfs`,e),P.info(`--encrypt-sessions completed gocryptfs ${t}`)}catch(n){let r=n instanceof Error?n.message:String(n);throw P.warn(`--encrypt-sessions failed gocryptfs ${t}`,{error:r}),Error(`gocryptfs ${e.join(` `)} failed: ${r}`)}}async function Gt(){P.info(`--encrypt-sessions checking encryption dependencies`),await en(`gocryptfs`,`required for --encrypt-sessions`),P.info(`--encrypt-sessions dependency available`,{command:`gocryptfs`});for(let e of wt)if(await $t(e)){P.info(`--encrypt-sessions unmount dependency available`,{command:e});return}throw Error(`--encrypt-sessions requires one of ${wt.join(`, `)} to be installed for secure unmount cleanup.`)}async function Kt(e,t){P.info(`--encrypt-sessions mounting encrypted .aimax`,{encryptedDir:e,plainDir:t}),await Ut(async n=>{await Wt([`-q`,`-passfile`,n,e,t])})}async function qt(e){P.info(`--encrypt-sessions initializing encrypted .aimax directory`,{encryptedDir:e}),await Ut(async t=>{await Wt([`-q`,`-init`,`-passfile`,t,e])})}async function Jt(e){let t=[];P.info(`--encrypt-sessions unmounting encrypted .aimax`,{plainDir:e});for(let n of Tt)try{if(P.info(`--encrypt-sessions attempting encrypted .aimax unmount`,{command:n.label,plainDir:e}),await Qt(n.command,[...n.args,e]),!await R(e)){P.info(`--encrypt-sessions unmounted encrypted .aimax`,{command:n.label,plainDir:e});return}let r=`${n.label} returned success but ${e} is still mounted`;t.push(r),P.warn(`--encrypt-sessions unmount command returned success but mountpoint remains`,{command:n.label,plainDir:e})}catch(r){let i=tn(n.label,r);t.push(i),P.warn(`--encrypt-sessions unmount attempt failed`,{command:n.label,plainDir:e,error:r instanceof Error?r.message:String(r)})}throw Error(`Failed to unmount ${e}: ${t.join(`; `)}`)}function Yt(e){for(let t of Tt)try{if(je(t.command,[...t.args,e],{stdio:`ignore`}),!jt(e))return}catch{}}function Xt(e){let t=!1,n=()=>{t||(t=!0,Yt(e))},r=()=>n(),i=()=>{n(),process.exit(130)},a=()=>{n(),process.exit(143)};return process.once(`exit`,r),process.once(`SIGINT`,i),process.once(`SIGTERM`,a),{release(){process.removeListener(`exit`,r),process.removeListener(`SIGINT`,i),process.removeListener(`SIGTERM`,a)}}}async function Zt(e){let t=Et(e),n=Dt(e),r=await z(n),i=await z(t),a=i&&await z(C.join(t,`gocryptfs.conf`)),o=r?await R(n):!1;P.info(`--encrypt-sessions preparing encrypted .aimax mount`,{dataDir:e,encryptedDir:t,plainDir:n,plainDirExists:r,encryptedDirExists:i,encryptedDirInitialized:a,plainDirMountPoint:o,plainDirEntryCount:await V(n),encryptedDirEntryCount:await V(t)});let s=()=>({mounted:!1,plainDir:n,encryptedDir:t,async cleanup(){}});try{await Gt()}catch(e){return P.warn(`--encrypt-sessions is unavailable; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e)}),await B(n),s()}if(await R(n))return P.warn(`--encrypt-sessions found existing .aimax mount; continuing without taking ownership`,{plainDir:n}),s();let c=null,l=[],u=null,d=null,f=!1;try{if(l=await zt(e),l.length>0&&P.warn(`--encrypt-sessions found interrupted pre-gocryptfs migration backups`,{count:l.length}),!await z(t))if(P.info(`--encrypt-sessions encrypted .aimax directory does not exist; starting first-time migration`,{encryptedDir:t,plainDir:n,resumedBackupCount:l.length}),l.length>0?u=await Bt(e,n):c=await Bt(e,n),await B(t),await qt(t),await B(n),await Kt(t,n),f=!0,d=Xt(n),P.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),l.length>0){for(let e of l)await H(e,n,!0);u&&=(await H(u,n,!1),await D.rm(u,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:u}),null);for(let e of l)await D.rm(e,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await H(c,n,!0),await D.rm(c,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:c}),null);else if(P.info(`--encrypt-sessions encrypted .aimax directory exists; mounting existing encrypted data`,{encryptedDir:t,plainDir:n,resumedBackupCount:l.length,plainDirEntryCount:await V(n)}),await Rt(t),l.length>0?u=await Bt(e,n):await Ft(n)||(c=await Bt(e,n)),await Pt(n),await Kt(t,n),f=!0,d=Xt(n),P.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),l.length>0){for(let e of l)await H(e,n,!0);u&&=(await H(u,n,!1),await D.rm(u,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:u}),null);for(let e of l)await D.rm(e,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await H(c,n,!0),await D.rm(c,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:c}),null);return P.info(`--encrypt-sessions prepared encrypted .aimax mount result`,{mounted:f,plainDir:n,encryptedDir:t,plainDirMountPoint:await R(n),plainDirEntryCount:await V(n),encryptedDirEntryCount:await V(t)}),{mounted:f,plainDir:n,encryptedDir:t,async cleanup(){if(d?.release(),!f){P.info(`--encrypt-sessions cleanup skipped because encrypted .aimax is not mounted`,{plainDir:n,encryptedDir:t});return}f=!1,P.info(`--encrypt-sessions cleanup started`,{plainDir:n,encryptedDir:t});try{await Jt(n),P.info(`--encrypt-sessions cleanup completed`,{plainDir:n,encryptedDir:t})}catch(e){P.warn(`--encrypt-sessions failed to unmount encrypted .aimax; continuing shutdown`,{error:e instanceof Error?e.message:String(e)})}}}}catch(e){d?.release(),f&&await Jt(n).catch(e=>{P.warn(`--encrypt-sessions failed to unmount during mount rollback`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}),c&&await z(c)&&await Ft(n)&&(await D.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await D.rename(c,n).catch(()=>{}),P.info(`--encrypt-sessions restored plaintext backup after failed migration`,{backupDir:c,plainDir:n})),u&&await z(u)&&await Ft(n)&&(await D.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await D.rename(u,n).catch(()=>{}),P.info(`--encrypt-sessions restored residual plaintext backup after failed migration`,{backupDir:u,plainDir:n}));let r=await Vt(l,n).catch(e=>(P.warn(`--encrypt-sessions failed to restore interrupted plaintext backups after failed migration`,{error:e instanceof Error?e.message:String(e),plainDir:n,backupCount:l.length}),[]));return l=l.filter(e=>!r.includes(e)),P.warn(`--encrypt-sessions failed; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e),mountedBeforeFailure:f,plainDir:n,encryptedDir:t,backupDir:c,residualPlainBackupDir:u,resumedBackupCount:l.length}),await B(n),s()}}async function U(e,t,n){if(!t.encryptSessions)return await Ht(e),n();P.info(`--encrypt-sessions wrapper starting encrypted .aimax preparation`,{dataDir:e});let r=await Zt(e);P.info(`--encrypt-sessions wrapper prepared encrypted .aimax state`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir});try{return P.info(`--encrypt-sessions wrapper entering protected operation`,{dataDir:e,mounted:r.mounted}),await n(r)}finally{P.info(`--encrypt-sessions wrapper starting cleanup`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir}),await r.cleanup(),P.info(`--encrypt-sessions wrapper finished cleanup`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir})}}async function Qt(e,t){await new Promise((n,r)=>{Ae(e,t,{encoding:`utf-8`},e=>{if(e){r(e);return}n()})})}async function $t(e){try{return await Qt(`sh`,[`-c`,`command -v "${e}" >/dev/null 2>&1`]),!0}catch{return!1}}async function en(e,t){if(!await $t(e))throw Error(`--encrypt-sessions requires ${e}: ${t}.`)}function tn(e,t){return`${e} failed: ${t instanceof Error?t.message:String(t)}`}function nn(e){e.command(`bootstrap`).description(`Initialize the data directory with required directories and templates`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{yt(await U(e.dataDir,e,async()=>i(e.dataDir)),t)}catch(e){I(`Error bootstrapping data directory: ${e.message}`),process.exit(1)}})}function rn(e){return Me.sm4_encrypt_ecb(e)}function an(e){return rn(e)}const on=[`minimal`,`low`,`medium`,`high`,`xhigh`];function sn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(on.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of ${on.join(`, `)}.`)}}function cn(e={}){let t=ln(e.apiFormat??process.env.AIMAX_API_FORMAT),n=e.baseUrl??process.env.AIMAX_BASE_URL,r=process.env.AIMAX_AUTH_TOKEN,i=e.authToken?an(e.authToken):r?an(r):e.apiKey??process.env.AIMAX_API_KEY,a=e.model??process.env.AIMAX_MODEL,o=[];if(n||o.push(`--base-url / AIMAX_BASE_URL`),i||o.push(`--api-key / AIMAX_API_KEY`),a||o.push(`--model / AIMAX_MODEL`),o.length>0)throw Error(`Missing required LLM configuration: ${o.join(`, `)}`);return{apiFormat:t,baseUrl:n,apiKey:i,model:a,contextWindow:e.contextWindow??(process.env.AIMAX_CONTEXT_WINDOW?Number(process.env.AIMAX_CONTEXT_WINDOW):void 0),flashModel:e.flashModel??process.env.AIMAX_FLASH_MODEL,thinking:e.thinking===void 0?sn(process.env.AIMAX_THINKING,`AIMAX_THINKING`):sn(e.thinking,`--thinking`)}}function ln(e){if(!e||e===`openai-completions`||e===`anthropic-messages`)return e;throw Error(`Unsupported LLM API format: ${e}`)}const un=[`off`,`fallback`];function dn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function fn(e,t){if(e===void 0)return;let n=e.trim();if(!n)return;let r=Number(n);if(!Number.isFinite(r))throw Error(`Invalid ${t}: ${e}. Must be a number.`);return r}function pn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(un.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of ${un.join(`, `)}.`)}}function mn(){return[`AIMAX_MEMORY_KC_ENABLED`,`AIMAX_MEMORY_KC_BASE_URL`,`AIMAX_MEMORY_KC_BASE_PATH`,`AIMAX_MEMORY_KC_AUTH_TOKEN`,`AIMAX_MEMORY_KC_SEARCH_MODE`,`AIMAX_MEMORY_KC_TOP_K`,`AIMAX_MEMORY_KC_SCORE_THRESHOLD`,`AIMAX_MEMORY_KC_TIMEOUT_MS`,`AIMAX_MEMORY_KC_SYNC_ENABLED`].some(e=>process.env[e]!==void 0)}function hn(e){return Object.values(e).some(e=>e!==void 0)}function gn(e={}){if(!(!hn(e)&&!mn()))return{knowledgeController:{enabled:e.kcEnabled??dn(process.env.AIMAX_MEMORY_KC_ENABLED,`AIMAX_MEMORY_KC_ENABLED`),baseUrl:e.kcBaseUrl??process.env.AIMAX_MEMORY_KC_BASE_URL,basePath:e.kcBasePath??process.env.AIMAX_MEMORY_KC_BASE_PATH,authToken:e.kcAuthToken??process.env.AIMAX_MEMORY_KC_AUTH_TOKEN,searchMode:e.kcSearchMode===void 0?pn(process.env.AIMAX_MEMORY_KC_SEARCH_MODE,`AIMAX_MEMORY_KC_SEARCH_MODE`)??`off`:pn(e.kcSearchMode,`kcSearchMode`),topK:e.kcTopK??fn(process.env.AIMAX_MEMORY_KC_TOP_K,`AIMAX_MEMORY_KC_TOP_K`),scoreThreshold:e.kcScoreThreshold??fn(process.env.AIMAX_MEMORY_KC_SCORE_THRESHOLD,`AIMAX_MEMORY_KC_SCORE_THRESHOLD`),timeoutMs:e.kcTimeoutMs??fn(process.env.AIMAX_MEMORY_KC_TIMEOUT_MS,`AIMAX_MEMORY_KC_TIMEOUT_MS`),syncEnabled:e.kcSyncEnabled??dn(process.env.AIMAX_MEMORY_KC_SYNC_ENABLED,`AIMAX_MEMORY_KC_SYNC_ENABLED`)}}}function _n(e,t){return t?C.resolve(t):C.join(e,`.aimax`,`plugins.json`)}async function W(e,t){let n=_n(e,t);try{let e=await D.readFile(n,`utf-8`);return JSON.parse(e)}catch(e){if(e.code===`ENOENT`)return;throw e}}async function G(e,t,n){let r=_n(e,n);await D.mkdir(C.dirname(r),{recursive:!0}),await D.writeFile(r,JSON.stringify(t,null,2),`utf-8`)}function K(e){return typeof e==`object`&&!!e}function vn(e){return K(e)&&e.type===`text`&&typeof e.text==`string`&&(e.textSignature===void 0||typeof e.textSignature==`string`)}function yn(e){return K(e)&&e.type===`image`&&typeof e.data==`string`&&typeof e.mimeType==`string`}function bn(e){return K(e)&&e.type===`thinking`&&typeof e.thinking==`string`&&(e.thinkingSignature===void 0||typeof e.thinkingSignature==`string`)&&(e.redacted===void 0||typeof e.redacted==`boolean`)}function xn(e){return K(e)&&e.type===`toolCall`&&typeof e.id==`string`&&typeof e.name==`string`&&K(e.arguments)&&(e.thoughtSignature===void 0||typeof e.thoughtSignature==`string`)}function Sn(e){return typeof e==`string`||Array.isArray(e)&&e.every(e=>vn(e)||yn(e))}function Cn(e){return Array.isArray(e)&&e.every(e=>vn(e)||bn(e)||xn(e))}function wn(e){return K(e)&&typeof e.input==`number`&&typeof e.output==`number`&&typeof e.cacheRead==`number`&&typeof e.cacheWrite==`number`&&typeof e.totalTokens==`number`&&K(e.cost)&&typeof e.cost.input==`number`&&typeof e.cost.output==`number`&&typeof e.cost.cacheRead==`number`&&typeof e.cost.cacheWrite==`number`&&typeof e.cost.total==`number`}function Tn(e){return!K(e)||typeof e.role!=`string`?!1:e.role===`user`?Sn(e.content):e.role===`assistant`?Cn(e.content)&&typeof e.api==`string`&&typeof e.provider==`string`&&typeof e.model==`string`&&wn(e.usage)&&(e.stopReason===`stop`||e.stopReason===`length`||e.stopReason===`toolUse`||e.stopReason===`error`||e.stopReason===`aborted`)&&(e.errorMessage===void 0||typeof e.errorMessage==`string`):e.role===`toolResult`?typeof e.toolCallId==`string`&&typeof e.toolName==`string`&&Array.isArray(e.content)&&e.content.every(e=>vn(e)||yn(e))&&typeof e.isError==`boolean`:!1}async function En(e){let t;try{t=await D.readFile(e,`utf-8`)}catch(e){throw Error(`Failed to read message file: ${e.message}`)}let n;try{n=JSON.parse(t)}catch(e){throw Error(`Invalid JSON in message file: ${e.message}`)}let r=Array.isArray(n)?n:[n];if(r.length===0||!r.every(e=>Tn(e)))throw Error(`Message file must contain one Message object or an array of Message objects`);return r}async function Dn(e){if(!!e.message==!!e.fromFile)throw Error(`Exactly one of --message or --from-file must be provided`);return e.fromFile?{kind:`messages`,messages:await En(e.fromFile)}:{kind:`text`,message:e.message}}var On=class{constructor(e){this.sinks=e}async send(e){await Promise.allSettled(this.sinks.map(async t=>{await t.send(e)}))}async close(){await Promise.allSettled(this.sinks.map(async e=>{await e.close()}))}},kn=class{constructor(e){this.url=e}async send(e){await this.post(this.toPayload(e))}async close(){}async post(e){let t=Date.now(),n=An(e);P.info(`sending callback event`,{callbackUrl:this.url,...n});let r=new AbortController,i=!1,a=setTimeout(()=>{i=!0,r.abort()},5e3);try{let a=await fetch(this.url,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e),signal:r.signal}),o=Date.now()-t;if(!a.ok){P.error(`callback event failed`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,timedOut:i,...n});return}P.info(`callback event delivered`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,...n})}catch(e){let r=Date.now()-t;P.error(`callback event failed`,{callbackUrl:this.url,error:e instanceof Error?e.message:String(e),durationMs:r,timedOut:i,...n})}finally{clearTimeout(a)}}toPayload(e){switch(e.type){case`start`:return e;case`progress`:return e;case`done`:return e;case`error`:return e;case`session_reset`:return e;case`hitl`:return e;case`title_updated`:return e;default:{let t=e;throw Error(`Unsupported callback event: ${JSON.stringify(t)}`)}}}};function An(e){return{eventType:e.type,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,progressType:e.type===`progress`?e.event.type:void 0}}function jn(e,t){if(t.kind===`none`)return e;let n=new URL(e);return n.searchParams.set(`authToken`,t.token),n.toString()}const Mn=5e3,Nn=5e3;function Pn(){let e=globalThis.WebSocket;if(!e)throw Error(`WebSocket is not available in this runtime`);return e}function Fn(e){return e?{kind:`query_token`,token:e}:{kind:`none`}}function In(e,t,n){if(typeof e.once==`function`){e.once(t,n);return}if(typeof e.addEventListener==`function`&&typeof e.removeEventListener==`function`){let r=(...i)=>{e.removeEventListener?.(t,r),n(...i)};e.addEventListener(t,r);return}throw Error(`WebSocket does not support one-time listener registration for "${t}"`)}function Ln(e,t,n){if(typeof e.on==`function`){e.on(t,n);return}if(typeof e.addEventListener==`function`){e.addEventListener(t,n);return}throw Error(`WebSocket does not support listener registration for "${t}"`)}var Rn=class{socket=null;connectPromise=null;enabled=!0;textSequence=0;constructor(e,t,n){this.url=e,this.events=t,this.authToken=n}async send(e){let t=this.toEnvelope(e);if(!(!t||!this.enabled))try{await zn(this.ensureConnected(),Mn,`WebSocket connection timed out after ${Mn}ms`);let e=Pn();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){P.warn(`websocket sink disabled after send failure`,{url:this.url,error:e instanceof Error?e.message:String(e)}),this.enabled=!1}}async sendTextDelta(e){if(!this.enabled||!this.events.has(`text`))return;this.textSequence+=1;let t={type:`text`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:new Date().toISOString(),sequence:this.textSequence,delta:e.text};try{await zn(this.ensureConnected(),Mn,`WebSocket connection timed out after ${Mn}ms`);let e=Pn();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){P.warn(`websocket sink disabled after text delta send failure`,{url:this.url,error:e instanceof Error?e.message:String(e)}),this.enabled=!1}}async close(){this.enabled=!1;let e=this.socket;if(this.socket=null,this.connectPromise=null,!e)return;let t=Pn();if(e.readyState!==t.CLOSED)try{await zn(new Promise(t=>{In(e,`close`,()=>t()),e.close()}),Nn,`WebSocket close timed out after ${Nn}ms`)}catch(e){P.warn(`websocket sink close timed out`,{url:this.url,error:e instanceof Error?e.message:String(e)})}}async ensureConnected(){if(!this.enabled)return;let e=Pn();if(this.socket&&this.socket.readyState===e.OPEN)return;if(this.connectPromise){await this.connectPromise;return}let t=new e(jn(this.url,Fn(this.authToken)));this.connectPromise=new Promise((e,n)=>{In(t,`open`,()=>{this.socket=t,Ln(t,`close`,()=>{this.socket===t&&(this.socket=null)}),e()}),In(t,`error`,e=>{n(e)})});try{await this.connectPromise}finally{this.connectPromise=null}}toEnvelope(e){let t=new Date().toISOString();switch(e.type){case`start`:return this.events.has(`start`)?{...e,timestamp:t}:null;case`done`:return this.events.has(`done`)?{...e,timestamp:t}:null;case`error`:return this.events.has(`error`)?{...e,timestamp:t}:null;case`hitl`:return this.events.has(`hitl`)?{...e,timestamp:t}:null;case`title_updated`:return this.events.has(`title_updated`)?{type:`title_updated`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,title:e.title}:null;case`session_reset`:return null;case`progress`:return e.event.type===`text`?this.events.has(`text`)?(this.textSequence+=1,{type:`text`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,sequence:this.textSequence,delta:e.event.text}):null:e.event.type===`stream_text_delta`||!this.events.has(`progress`)?null:{type:`progress`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,event:e.event};default:{let t=e;throw Error(`Unsupported stream event: ${JSON.stringify(t)}`)}}}};function zn(e,t,n){return new Promise((r,i)=>{let a=setTimeout(()=>i(Error(n)),t);e.then(e=>{clearTimeout(a),r(e)},e=>{clearTimeout(a),i(e)})})}function Bn(e){let t=e.trim();if(!t)throw Error(`Goal objective cannot be empty`);return t}function Vn(e,t){if(t.action===`unchanged`)return null;if(t.action===`created`||t.action===`replaced`)return t.action;if(e?.status!==t.goal.status)switch(t.goal.status){case`active`:return e?.status===`paused`?`resumed`:`updated`;case`paused`:return`paused`;case`complete`:return`completed`;case`budget_limited`:return`budget_limited`;default:return`updated`}return`updated`}function Hn(e){let t=Vn(e.before,e.result);return t?{type:`goal_updated`,sessionId:e.sessionId,action:t,goalId:e.result.goal.goalId,goalStatus:e.result.goal.status}:null}function Un(e){let t=e?.packageRoot??Wn(),n=C.join(t,`models`),r=C.join(n,...`Xenova/bge-small-zh-v1.5`.split(`/`));if(x.existsSync(C.join(r,`config.json`)))return n}function Wn(){let e=C.dirname(Ne(import.meta.url));return C.basename(e)===`src`||C.basename(e)===`dist`?C.resolve(e,`..`):e}function Gn(e){return{text:e.text,usage:e.usage,durationMs:e.durationMs,...e.error?{error:e.error}:{},...e.paused?{paused:e.paused}:{},...e.uiToolPending?{uiToolPending:e.uiToolPending}:{},...e.artifacts&&e.artifacts.length>0?{artifacts:e.artifacts}:{}}}function Kn(e){if(!e?.trim())return;let t=new Set,n=[];for(let r of e.split(`,`)){let e=r.trim();if(!e)continue;let i=qn(e);if(!i)throw Error(`Invalid --artifacts-url-whitelist entry: ${e}. Expected a domain or URL with a valid hostname.`);t.has(i)||(t.add(i),n.push(i))}return n.length>0?n:void 0}function qn(e){try{let t=/^[a-z][a-z\d+.-]*:\/\//i.test(e)?e:`http://${e}`,n=new URL(t);return n.username||n.password?null:n.hostname.trim().toLowerCase()||null}catch{return null}}const Jn=[`start`,`text`,`done`,`error`,`hitl`],Yn=[`off`,`gate`,`dry_run`,`write`];function Xn(e){if(!e?.trim())return new Set(Jn);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl`);r.add(e)}return r.size>0?r:new Set(Jn)}function Zn(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=Un();return t?{embeddingModelDir:t}:void 0}function Qn(e){return e.disableTitle===!0||process.env.AIMAX_DISABLE_TITLE===`true`?{enabled:!1}:void 0}function $n(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir or AIMAX_DATA_DIR`);return t}function er(e){return e?.trim()||void 0}function tr(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!C.isAbsolute(t)){let n=e.systemAgentsDir===void 0?`AIMAX_SYSTEM_AGENTS_DIR`:`--system-agents-dir`;throw Error(`Invalid ${n}: ${t}. Path must be absolute.`)}return t}}function nr(e){return e?y(e):void 0}function rr(e){if(!e?.trim())return[];let t=e.split(`,`).map(e=>e.trim()).filter(Boolean),n=new Set,r=[];for(let e of t){if(!C.isAbsolute(e))throw Error(`Invalid --skillsLoadPaths entry: ${e}. Each path must be absolute.`);n.has(e)||(n.add(e),r.push(e))}return r}function ir(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function ar(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(Yn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function or(e){let t=e.autoSkillsLoadEnabled===void 0?ir(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):ir(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?ar(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):ar(e.autoSkillsReviewMode,`--auto-skills-review-mode`),r={};return t!==void 0&&(r.load={enabled:t}),n!==void 0&&(r.review={mode:n}),r.load||r.review?r:void 0}function sr(e,t){if(e.inputText&&t){let n=be(e.inputText,t);return n.submittedBy={userId:e.user,channel:e.channel??`IM`},n}if(!e.inputJson&&!e.inputText)throw Error(`Either --input-json or --input-text must be provided for the resume command`);try{let t=JSON.parse(e.inputJson);return{requestId:e.requestId,sessionId:e.sessionId,action:t.action??`submit`,values:t.values,submittedBy:t.submittedBy,idempotencyKey:t.idempotencyKey,submittedAt:t.submittedAt??new Date().toISOString()}}catch(e){throw Error(`Invalid --input-json: ${e.message}`)}}function cr(e,t){if(!e.inputJson)throw Error(`UI tool resume requires --input-json`);try{let n=JSON.parse(e.inputJson),r=n&&typeof n==`object`&&`values`in n&&n.values&&typeof n.values==`object`&&!Array.isArray(n.values)?n.values:n;return{requestId:t.request.requestId,sessionId:t.sessionId,toolCallId:t.request.toolCallId,toolName:t.request.toolName,values:r,submittedAt:new Date().toISOString()}}catch(e){throw Error(`Invalid --input-json: ${e.message}`)}}async function lr(e){let t=await ie(e.dataDir,e.sessionId,{storeName:e.sessionStoreName,encryptSessions:e.encryptSessions});for(let n=t.length-1;n>=0;--n){let r=t[n];if(r?.role!==`assistant`||!Array.isArray(r.toolCalls))continue;let i=r.toolCalls.find(t=>t.id===e.toolCallId&&t.name===e.toolName);if(i)return i.arguments}}async function ur(e){let t=$n(e),n=e.channel??`WEB`,r=cn({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow?Number(e.contextWindow):void 0,flashModel:e.flashModel,thinking:e.thinking});return{dataDir:t,systemAgentsDir:tr(e),channel:n,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:r,skillsLoadPaths:rr(e.skillsLoadPaths),artifactsUrlWhitelist:Kn(e.artifactsUrlWhitelist),autoSkills:or(e)}}function dr(e){let t=[],n=null;return e.callbackUrl&&t.push(new kn(e.callbackUrl)),e.streamUrl&&(n=new Rn(e.streamUrl,Xn(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new On(t),websocketSink:n}}async function fr(e){let{dataDir:t,sessionId:n,sessionStoreName:r,toolCallId:i,toolName:a,resolution:o,encryptSessions:s}=e;if(!i||!a||!ve(a))return;let c=(e,t)=>{switch(e){case`request_approval`:return d(t);case`clarify`:return f(t);case`request_review`:return p(t);default:return JSON.stringify({action:t.action,values:t.values})}};await ue(t,n,e=>{let t=e.findIndex(e=>e.role===`tool_result`&&e.toolCallId===i&&e.toolName===a);if(t===-1)return e;let n=e.slice(0,t+1);return n[t]={...n[t],content:c(a,o),isError:!1},n},{storeName:r,encryptSessions:s})}async function pr(e){let{dataDir:t,sessionId:n,sessionStoreName:r,result:i,encryptSessions:a}=e;await ue(t,n,e=>{let t=e.findIndex(e=>e.role===`assistant`&&Array.isArray(e.toolCalls)&&e.toolCalls.some(e=>e.id===i.toolCallId&&e.name===i.toolName));if(t===-1)return e;let n=e.slice(0,t+1);return n.push({role:`tool_result`,toolCallId:i.toolCallId,toolName:i.toolName,content:JSON.stringify({submitted:!0,values:i.values}),isError:!1,timestamp:i.submittedAt}),n},{storeName:r,encryptSessions:a})}function mr(){let e=gn();return e?{core:e}:void 0}async function hr(e){let t=$n(e);await U(t,e,async()=>{N(t,{messageId:e.messageId,sessionId:e.sessionId,sessionStoreName:nr(e.sessionStore)});let i=new ct(`resume command`),a=null;try{let t=await ur(e),o=nr(e.sessionStore),c=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await D.readFile(e.goalFile,`utf-8`):e.goal;let a=Bn(i),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(I(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));try{let n=await b(t.dataDir,e.sessionId,{storeName:o}),i=await r({dataDir:t.dataDir,sessionId:e.sessionId,objective:a,tokenBudget:s,force:e.force,storeName:o});c=Hn({sessionId:e.sessionId,before:n,result:i})}catch(e){throw e instanceof n&&(I(e.message),I(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}P.info(`resume command started`,{sessionId:e.sessionId,requestId:e.requestId,channel:t.channel,dataDir:t.dataDir});let l=await ee(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),u=l?null:await te(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions});if(!l&&!u)throw Error(`No pending HITL or UI tool request found for session "${e.sessionId}"`);if(l){if(l.request.requestId!==e.requestId)throw Error(`Request ID mismatch: pending is "${l.request.requestId}", got "${e.requestId}"`);if(l.status===`expired`)throw Error(`HITL request has expired`);if(l.status===`cancelled`)throw Error(`HITL request has been cancelled`)}else if(u){if(u.request.requestId!==e.requestId)throw Error(`Request ID mismatch: pending is "${u.request.requestId}", got "${e.requestId}"`);if(u.status!==`pending`)throw Error(`UI tool request is already "${u.status}", cannot resume`)}if(l){let n=sr(e,l.request),r=await ce({dataDir:t.dataDir,sessionStoreName:o,sessionId:e.sessionId,requestId:e.requestId,resolution:n}),s=r.state;if(!s)throw Error(`Resolved HITL state was not persisted`);let u=gr(n,s.request.kind);await fr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:s.toolContext?.toolCallId,toolName:s.toolContext?.toolName,resolution:n,encryptSessions:e.encryptSessions});let d=dr(e);a=d.sink;let f=e.sessionId,p=async n=>{if(f=n.sessionId??f,!_e(n)){if(n.type===`stream_text_delta`){t.format===`text`&&L(n),await d.websocketSink?.sendTextDelta({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}t.format===`text`&&L(n),await a?.send({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,type:`progress`,event:n})}};c&&await p(c),await p({type:`hitl_resumed`,requestId:e.requestId,resolution:n,sessionId:e.sessionId}),`idempotentReplay`in r&&r.idempotentReplay&&(P.info(`resume command treated as idempotent replay`,{sessionId:e.sessionId,requestId:e.requestId,idempotencyKey:n.idempotencyKey}),ht({sessionId:e.sessionId,text:`Resume request already processed.`,usage:{input:0,output:0,total:0},durationMs:0},t.format),i.end(),process.exit(0));let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await W(t.dataDir,m),g;try{g=await de({dataDir:t.dataDir,projectDir:er(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:u,encryptSessions:e.encryptSessions??!1,topicSegmentation:Zn(e),titleGeneration:Qn(e),memory:mr(),hitlResume:{request:s.request,resolution:n,checkpoint:s.checkpoint,toolContext:s.toolContext},plugins:h?{config:h,dataDir:t.dataDir,workspaceDir:C.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:h.llmAllowlist}:void 0,onProgress:p})}finally{}g.error?await a?.send({sessionId:g.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`error`,message:g.error}):await a?.send({sessionId:g.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`done`,result:Gn(g)}),ht(g,t.format),g.error?P.error(`resume command failed: ${g.error}`):P.info(`resume command succeeded`),i.end(),process.exit(g.error?1:0);return}let d=cr(e,u);if(!await le(t.dataDir,e.sessionId,e.requestId,d,{storeName:o,encryptSessions:e.encryptSessions}))throw Error(`UI tool resume validation failed`);await pr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,result:d,encryptSessions:e.encryptSessions});let f=dr(e);a=f.sink;let p=e.sessionId,m=async n=>{if(p=n.sessionId??p,!_e(n)){if(n.type===`stream_text_delta`){t.format===`text`&&L(n),await f.websocketSink?.sendTextDelta({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}if(t.format===`text`&&L(n),n.type===`start`){await a?.send({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,type:`start`,message:n.message});return}await a?.send({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,type:`progress`,event:n})}},h=await lr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:d.toolCallId,toolName:d.toolName,encryptSessions:e.encryptSessions});c&&await m(c),await m({type:`tool_end`,sessionId:e.sessionId,toolCallId:d.toolCallId,name:d.toolName,input:h,output:JSON.stringify({submitted:!0,values:d.values}),isError:!1});let g=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,_=await W(t.dataDir,g),v=await de({dataDir:t.dataDir,projectDir:er(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:`[UI_TOOL_RESUME]
8
+ The pending UI tool result has been written into the transcript. Continue from the latest tool result without repeating the same form request.`,encryptSessions:e.encryptSessions??!1,topicSegmentation:Zn(e),titleGeneration:Qn(e),memory:mr(),uiToolResume:d,plugins:_?{config:_,dataDir:t.dataDir,workspaceDir:C.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:_.llmAllowlist}:void 0,onProgress:m});await s(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),v.error?await a?.send({sessionId:v.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`error`,message:v.error}):await a?.send({sessionId:v.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`done`,result:Gn(v)}),ht(v,t.format),v.error?P.error(`resume command failed: ${v.error}`):P.info(`resume command succeeded`),i.end(),process.exit(v.error?1:0)}catch(t){let n=t;a&&(n.message.includes(`expired`)&&await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`progress`,event:{type:`hitl_expired`,sessionId:e.sessionId,requestId:e.requestId,reason:n.message}}),n.message.includes(`cancelled`)&&await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`progress`,event:{type:`hitl_cancelled`,sessionId:e.sessionId,requestId:e.requestId,reason:n.message}}),await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`error`,message:`Resume failed: ${n.message}`})),P.error(`resume command error: ${n.message}`),I(`Fatal: ${n.message}`),i.end(),process.exit(1)}finally{await a?.close()}})}function gr(e,t){return o(e,t)}function _r(e){e.command(`resume`).description(`Resume a paused HITL session with user input`).requiredOption(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--project-dir <path>`,`Current project directory used as the default cwd context`).option(`--system-agents-dir <path>`,`System agent definition directory (overrides AIMAX_SYSTEM_AGENTS_DIR, default: /aimax/agents)`).requiredOption(`-s, --session-id <id>`,`Session ID to resume`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).requiredOption(`--request-id <id>`,`HITL request ID to resolve`).option(`--input-json <json>`,`JSON string with the resolution (action, values, etc.)`).option(`--input-text <text>`,`Plain text response for IM channels without rich UI (e.g. '同意', '拒绝')`).option(`--skillsLoadPaths <paths>`,`Comma-separated absolute skill load paths`).option(`--auto-skills-load-enabled <boolean>`,`Enable learned auto-skill loading for the main agent (overrides AIMAX_AUTO_SKILLS_LOAD_ENABLED)`).option(`--auto-skills-review-mode <mode>`,`Auto-skill review mode: off, gate, dry_run, or write (overrides AIMAX_AUTO_SKILLS_REVIEW_MODE)`).option(`--message-id <id>`,`Message ID for correlating events`).option(`--user <id>`,`User identifier propagated to external callback and stream payloads`).option(`-c, --channel <channel>`,`Channel name (default: WEB)`,`WEB`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--auth-token <token>`,`Auth token used to generate the API key`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--context-window <n>`,`LLM context window size`).option(`--thinking <level>`,`Explicit thinking level: minimal, low, medium, high, or xhigh (overrides AIMAX_THINKING)`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--plugins-config <path>`,`Plugins config file path`).option(`--goal <text>`,`Set or replace the thread goal objective before resuming`).option(`--goal-file <path>`,`Read goal objective from a file`).option(`--token-budget <n>`,`Token budget for the goal (positive integer, or 0 for unlimited)`).option(`--force`,`Replace existing goal with a different objective`).option(`--encrypt-sessions`,`Enable encryption for the .aimax data directory`).option(`--disable-topic-segmentation`,`Disable smart topic segmentation for this resume run`).option(`--disable-title`,`Skip LLM session title generation for new sessions (overrides AIMAX_DISABLE_TITLE)`).action(async e=>{await hr(e)})}function vr(e,t){return{notify:(n,r=`info`)=>{t?.readyState===1?t.send(JSON.stringify({type:`diagnostic`,sessionId:e,level:r,message:n})):console.log(`[${r}] ${n}`)},confirm:async n=>!t||t.readyState!==1?!1:new Promise(r=>{let i=`confirm-${Date.now()}`;t.send(JSON.stringify({type:`hitl_confirm`,sessionId:e,id:i,message:n}));let a=e=>{try{let t=JSON.parse(String(e));r(t.id===i&&t.confirmed===!0)}catch{r(!1)}};typeof t.once==`function`?t.once(`message`,a):t.addEventListener(`message`,e=>a(e.data),{once:!0})}),select:async(n,r)=>{if(!(!t||t.readyState!==1))return new Promise(i=>{let a=`select-${Date.now()}`;t.send(JSON.stringify({type:`hitl_select`,sessionId:e,id:a,title:n,options:r}));let o=e=>{try{let t=JSON.parse(String(e));i(t.id===a?t.selected:void 0)}catch{i(void 0)}};typeof t.once==`function`?t.once(`message`,o):t.addEventListener(`message`,e=>o(e.data),{once:!0})})},setStatus:n=>{t?.readyState===1?t.send(JSON.stringify({type:`diagnostic`,sessionId:e,level:`info`,message:n})):console.log(`[status] ${n}`)}}}const yr=[`start`,`text`,`done`,`error`],br=[`off`,`gate`,`dry_run`,`write`];function xr(e){if(!e?.trim())return new Set(yr);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl,title_updated`);r.add(e)}return r.size>0?r:new Set(yr)}function Sr(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=Un();return t?{embeddingModelDir:t}:void 0}function Cr(e){return e.disableTitle===!0||process.env.AIMAX_DISABLE_TITLE===`true`?{enabled:!1}:void 0}function wr(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function Tr(e){return e?.trim()||void 0}function Er(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!C.isAbsolute(t)){let n=e.systemAgentsDir===void 0?`AIMAX_SYSTEM_AGENTS_DIR`:`--system-agents-dir`;throw Error(`Invalid ${n}: ${t}. Path must be absolute.`)}return t}}function Dr(e){return e?.trim()||void 0}function Or(e){return e??`WEB`}function q(e){return e?y(e):void 0}function kr(e){if(!e?.trim())return[];let t=e.split(`,`).map(e=>e.trim()).filter(Boolean),n=new Set,r=[];for(let e of t){if(!C.isAbsolute(e))throw Error(`Invalid --skillsLoadPaths entry: ${e}. Each path must be absolute.`);n.has(e)||(n.add(e),r.push(e))}return r}function Ar(e){let t=``;for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`\\`&&n+1<e.length){let r=e[n+1];if(r===`,`||r===`\\`||r===`=`){t+=r,n+=1;continue}}t+=r}return t}function jr(e){let t=[],n=``;for(let r=0;r<e.length;r+=1){let i=e[r];if(i===`\\`&&r+1<e.length){let t=e[r+1];if(t===`,`||t===`\\`){n+=t,r+=1;continue}}if(i===`,`){t.push(n),n=``;continue}n+=i}return t.push(n),t}function Mr(e){if(!e?.trim())return{};let t=[],n=new Set;for(let r of jr(e)){let e=r.trim();if(!e)continue;let i=e.indexOf(`=`);if(i<=0)throw Error(`Invalid --env entry: ${e}. Expected KEY=VALUE (use \\= to embed an equals sign in the value).`);let a=e.slice(0,i).trim(),o=e.slice(i+1).trim();if(!a)throw Error(`Invalid --env entry: ${e}. Key must not be empty.`);if(n.has(a))throw Error(`Invalid --env entry: duplicate key ${a}.`);n.add(a),t.push([a,Ar(o)])}return Object.fromEntries(t)}function Nr(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function Pr(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(br.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function Fr(e){let t=e.autoSkillsLoadEnabled===void 0?Nr(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):Nr(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?Pr(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):Pr(e.autoSkillsReviewMode,`--auto-skills-review-mode`),r={};return t!==void 0&&(r.load={enabled:t}),n!==void 0&&(r.review={mode:n}),r.load||r.review?r:void 0}function Ir(e,t){return e.length<=t?e:t<=3?e.slice(0,t):`${e.slice(0,t-3)}...`}function Lr(e,t){if(t<=0)return[``];let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n.length>0?n:[``]}function Rr(e,t,n=78){let r=Math.max(0,n-4),i=e?e.length+2:0,a=Math.max(r,i,...t.map(e=>e.length)),o=a+2,s=e?` ${Ir(e,Math.max(0,a-2))} `:``,c=e?`┌${s}${`─`.repeat(Math.max(0,o-s.length))}┐`:`┌${`─`.repeat(o)}┐`,l=`└${`─`.repeat(o)}┘`;return[c,...t.flatMap(e=>Lr(e,a).map(e=>`│ ${e.padEnd(a,` `)} │`)),l].join(`
9
+ `)}function zr(e){return e.kind===`text`?`inline message (${e.message.length} chars)`:`message file (${e.messages.length} messages)`}function J(e,t=`-`){return e==null||e===``?t:String(e)}function Br(e){return e?`set`:`unset`}function Vr(e){return e?`true`:`false`}function Hr(e,t){let n=q(e.sessionStore)??`sessions`,r=t.timeoutMs===void 0?`default`:`${t.timeoutMs}`,i=e.callbackUrl?`enabled`:`disabled`,a=e.streamUrl?`enabled`:`disabled`,o=zr(t.input),s=t.input.kind===`text`?`inline`:e.fromFile??`file`,c=qe(),l=Sr(e)?.enabled===!1?`disabled`:`enabled`,u=Cr(e)?.enabled===!1?`disabled`:`enabled`,d=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,f=[...xr(e.streamEvents)].join(`,`),p=t.autoSkills?.load?.enabled,m=t.autoSkills?.review?.mode,h=e.tokenBudget===`0`?`unlimited`:J(e.tokenBudget),g=t.artifactsUrlWhitelist?.join(`,`)??`-`,_=e.env?Object.keys(Mr(e.env)):[],v=_.length===0?`-`:`${_.length} key${_.length===1?``:`s`}`;return{banner:Rr(void 0,[`AIMax CLI`,`Stateless Agent Runner`]),contextBox:Rr(`Run Context`,[`time : ${c}`,`dataDir : ${t.dataDir}`,`projectDir : ${Tr(e.projectDir)??`-`}`,`systemAgents : ${t.systemAgentsDir??`/aimax/agents`}`,`agent : ${Dr(e.agent)??`-`}`,`channel : ${t.channel}`,`user : ${e.user??`-`}`,`message : ${e.message===void 0?`-`:`inline (${e.message.length} chars)`}`,`fromFile : ${J(e.fromFile)}`,`input : ${o}`,`skillsPaths : ${t.skillsLoadPaths.length>0?t.skillsLoadPaths.join(`,`):`-`}`,`autoSkillLoad: ${p===void 0?`-`:String(p)}`,`autoSkillRev : ${m??`-`}`,`sessionId : ${e.sessionId??`new`}`,`sessionStore : ${n}`,`messageId : ${e.messageId??`-`}`,`workspace : ${C.join(t.dataDir,`workspace`)}`,`baseUrl : ${t.llm.baseUrl}`,`apiKey : ${Br(t.llm.apiKey)}`,`authToken : ${Br(e.authToken)}`,`model : ${t.llm.model}`,`contextWindow: ${J(t.llm.contextWindow)}`,`flashModel : ${J(t.llm.flashModel)}`,`thinking : ${J(t.llm.thinking)}`,`callbackUrl : ${J(e.callbackUrl)}`,`streamUrl : ${J(e.streamUrl)}`,`streamAuth : ${Br(e.streamAuthToken)}`,`streamEvents : ${f}`,`artifactUrls : ${g}`,`output : ${t.format}`,`callback : ${i}`,`websocket : ${a}`,`timeoutMs : ${r}`,`pluginsConfig: ${J(d)}`,`env : ${v}`,`goal : ${e.goal===void 0?`-`:`inline (${e.goal.length} chars)`}`,`goalFile : ${J(e.goalFile)}`,`tokenBudget : ${h}`,`force : ${Vr(e.force)}`,`resumeReqId : ${J(e.resumeRequestId)}`,`resumeInput : ${e.resumeInputJson===void 0?`-`:`inline (${e.resumeInputJson.length} chars)`}`,`resumeFile : ${J(e.resumeFromFile)}`,`encryptSess : ${Vr(e.encryptSessions)}`,`topicSegment : ${l}`,`titleGen : ${u}`]),logContext:{time:c,channel:t.channel,user:e.user,dataDir:t.dataDir,projectDir:Tr(e.projectDir),systemAgentsDir:t.systemAgentsDir,agent:Dr(e.agent),workspaceDir:C.join(t.dataDir,`workspace`),sessionId:e.sessionId??`new`,sessionStore:n,messageId:e.messageId,hasMessage:e.message!==void 0,fromFile:e.fromFile,skillsLoadPaths:t.skillsLoadPaths.join(`,`)||void 0,autoSkillsLoadEnabled:p,autoSkillsReviewMode:m,baseUrl:t.llm.baseUrl,hasApiKey:!!t.llm.apiKey,hasAuthToken:!!e.authToken,model:t.llm.model,contextWindow:t.llm.contextWindow,flashModel:t.llm.flashModel,thinking:t.llm.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,hasStreamAuthToken:!!e.streamAuthToken,streamEvents:f,artifactsUrlWhitelist:t.artifactsUrlWhitelist?.join(`,`)||void 0,output:t.format,hasCallback:!!e.callbackUrl,hasStream:!!e.streamUrl,timeoutMs:t.timeoutMs,pluginsConfig:d,envKeys:_.length>0?_.join(`,`):void 0,hasGoal:e.goal!==void 0,goalFile:e.goalFile,tokenBudget:h===`-`?void 0:h,force:!!e.force,resumeRequestId:e.resumeRequestId,hasResumeInputJson:e.resumeInputJson!==void 0,resumeFromFile:e.resumeFromFile,encryptSessions:!!e.encryptSessions,topicSegmentation:l,titleGeneration:u,inputKind:t.input.kind,inputSource:s,inputSummary:o}}}async function Ur(e,t){let n=wr(e),r=Or(e.channel),i=cn({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow?Number(e.contextWindow):void 0,flashModel:e.flashModel,thinking:e.thinking});return{dataDir:n,systemAgentsDir:Er(e),channel:r,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:i,input:t,skillsLoadPaths:kr(e.skillsLoadPaths),artifactsUrlWhitelist:Kn(e.artifactsUrlWhitelist),autoSkills:Fr(e)}}function Wr(e){if(e.kind===`text`)return e.message;if(e.messages.length!==1)return null;let[t]=e.messages;if(t.role!==`user`)return null;if(typeof t.content==`string`)return t.content;if(t.content.length===0)return null;let n=[];for(let e of t.content){if(e.type!==`text`)return null;n.push(e.text)}return n.join(`
10
+ `)}async function Gr(e,t){if(!e.sessionId)return null;let n=Wr(t);if(!n)return null;let r=await ee(wr(e),e.sessionId,{storeName:q(e.sessionStore),encryptSessions:e.encryptSessions});return!r||r.status!==`pending`||!ye(n,r.request)?null:{requestId:r.request.requestId,inputText:n}}function Kr(e){let t=[],n=null;return e.callbackUrl&&t.push(new kn(e.callbackUrl)),e.streamUrl&&(n=new Rn(e.streamUrl,xr(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new On(t),websocketSink:n}}async function Y(e,t){P.info(`dispatching external event`,pi(t)),await e.sink.send(t)}function qr(e){let t={sessionId:e.sessionId,messageId:e.messageId,parentSessionId:e.parentSessionId,depth:e.depth,scope:e.scope,phase:e.phase,...e.details};if(e.level===`error`){P.error(e.message,t);return}if(e.level===`warn`){P.warn(e.message,t);return}P.info(e.message,t)}function Jr(e,t,n,r,i){return{sink:e,websocketSink:t,channel:n,defaultMessageId:r,user:i}}function Yr(e){let t=new AbortController,n=n=>{P.warn(`run abort signal received`,{signal:n,uptimeMs:Math.round(process.uptime()*1e3),alreadyAborted:t.signal.aborted,...e?.()}),t.abort()},r=()=>n(`SIGTERM`),i=()=>n(`SIGINT`);return process.once(`SIGTERM`,r),process.once(`SIGINT`,i),{controller:t,cleanup:()=>{process.off(`SIGTERM`,r),process.off(`SIGINT`,i)}}}function Xr(e){return{activeSessionId:e??`pending`,finalResult:null,loggerSessionId:void 0}}function Zr(e,t,n,r){!r||n.loggerSessionId===r||(N(e,{messageId:t.messageId,sessionId:r,sessionStoreName:q(t.sessionStore)}),n.loggerSessionId=r)}function Qr(e,t){e.activeSessionId=t.sessionId??e.activeSessionId}function $r(e,t){return e.messageId??t}async function ei(e,t,n){if(!await m(e.dataDir)){if(await ti(t,e.format,n.activeSessionId,e.dataDir,`checking`),(await l(e.dataDir)).performedBootstrap){await ti(t,e.format,n.activeSessionId,e.dataDir,`initializing`),await ti(t,e.format,n.activeSessionId,e.dataDir,`initialized`);return}await ti(t,e.format,n.activeSessionId,e.dataDir,`ready`)}}async function ti(e,t,n,r,i){let a={type:`bootstrap`,phase:i,dataDir:r};t===`text`&&L(a),await Y(e,{sessionId:n,channel:e.channel,messageId:e.defaultMessageId,user:e.user,type:`progress`,event:a})}function ni(e,t,n,r){return async i=>{if(Qr(n,i),Zr(e.dataDir,r,n,i.sessionId),_e(i)){qr(i);return}if(i.type===`stream_text_delta`){e.format===`text`&&L(i),await t.websocketSink?.sendTextDelta({sessionId:n.activeSessionId,channel:e.channel,messageId:$r(i,t.defaultMessageId),user:t.user,text:i.text});return}e.format===`text`&&L(i);let a=$r(i,t.defaultMessageId);if(i.type===`hitl_requested`){await Y(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`hitl`,request:i.request}),await Y(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`progress`,event:i});return}if(i.type===`start`){await Y(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`start`,message:i.message});return}if(i.type===`session_reset`){await Y(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`session_reset`,action:i.action,previousSessionId:i.previousSessionId,message:i.message});return}await Y(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`progress`,event:i})}}function ri(e){let t=vr(e);return{confirm:(e,n)=>t.confirm(e),select:(e,n,r)=>t.select?t.select(e,n):Promise.resolve(void 0)}}function ii(e,t,n,r,i,a){let o=gn(),s={dataDir:t.dataDir,projectDir:Tr(e.projectDir),systemAgentsDir:t.systemAgentsDir,agentPolicy:Dr(e.agent)?{requestedAgentName:Dr(e.agent)}:void 0,sessionStoreName:q(e.sessionStore),sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,abortSignal:n.signal,pendingGoal:a,encryptSessions:e.encryptSessions??!1,topicSegmentation:Sr(e),titleGeneration:Cr(e),env:Mr(e.env),...o?{memory:{core:o}}:{},plugins:i?{config:i,dataDir:t.dataDir,workspaceDir:C.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:i.llmAllowlist}:void 0,onProgress:r,createPiExtensionDialogBridge:ri};return t.input.kind===`messages`?{...s,messages:t.input.messages}:{...s,message:t.input.message}}async function ai(e,t,n,r){if(t.activeSessionId=r.sessionId,t.finalResult=r,r.error){await Y(e,{sessionId:r.sessionId,channel:e.channel,messageId:n,user:e.user,type:`error`,message:r.error});return}await Y(e,{sessionId:r.sessionId,channel:e.channel,messageId:n,user:e.user,type:`done`,result:Gn(r)})}async function oi(e,t,n,r){await Y(e,{sessionId:t.finalResult?.sessionId??t.activeSessionId,channel:e.channel,messageId:n,user:e.user,type:`error`,message:`Fatal: ${r.message}`})}function si(e,t){let n=Hr(e,t);P.info([`run command started`,n.banner,n.contextBox].join(`
11
+ `),n.logContext),t.format===`text`&&(F(n.banner),F(``),F(n.contextBox),F(``))}function ci(e,t,n){return ht(t,n),t.error?P.error(`run command failed: ${t.error}`):P.info(`run command succeeded`),e.end(),t.error?1:0}function li(e){let t=ot();if(!t)return;let n=`[${qe()}] [ERROR] ${e}\n`;try{x.appendFileSync(C.join(t.logDir,`app.log`),n),x.appendFileSync(C.join(t.logDir,`errors.log`),n)}catch{}}async function ui(e,t){let n=`run command error: ${t.message}`;P.error(n),li(n),I(`Fatal: ${t.message}`),e.end(),await st(),process.exit(1)}async function di(e){if(e.resumeInputJson&&e.resumeFromFile)throw Error(`--resume-input-json and --resume-from-file are mutually exclusive`);if(!e.resumeFromFile)return e.resumeInputJson;try{return await D.readFile(e.resumeFromFile,`utf-8`)}catch(e){throw Error(`Failed to read resume input file: ${e.message}`)}}async function fi(e){let t=wr(e);await U(t,e,async i=>{let a=Xr(e.sessionId);Zr(t,e,a,e.sessionId),e.encryptSessions&&P.info(`--encrypt-sessions run mount state after logger initialization`,{dataDir:t,mounted:i?.mounted??!1,plainDir:i?.plainDir,encryptedDir:i?.encryptedDir});let o=new ct(`run command`),s=await di(e);if(e.resumeRequestId||s||e.resumeFromFile){if(!e.sessionId||!e.resumeRequestId||!s)throw Error(`--session-id, --resume-request-id, and exactly one of --resume-input-json or --resume-from-file must be provided together`);await hr({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:e.resumeRequestId,inputJson:s,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,thinking:e.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,artifactsUrlWhitelist:e.artifactsUrlWhitelist,skillsLoadPaths:e.skillsLoadPaths,autoSkillsLoadEnabled:e.autoSkillsLoadEnabled,autoSkillsReviewMode:e.autoSkillsReviewMode,messageId:e.messageId,user:e.user,goal:e.goal,goalFile:e.goalFile,tokenBudget:e.tokenBudget,force:e.force,encryptSessions:e.encryptSessions,disableTopicSegmentation:e.disableTopicSegmentation,disableTitle:e.disableTitle});return}let c;try{c=await Dn({message:e.message,fromFile:e.fromFile})}catch(e){await ui(o,e);return}let l=await Gr(e,c);if(l){await hr({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:l.requestId,inputText:l.inputText,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,thinking:e.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,artifactsUrlWhitelist:e.artifactsUrlWhitelist,skillsLoadPaths:e.skillsLoadPaths,autoSkillsLoadEnabled:e.autoSkillsLoadEnabled,autoSkillsReviewMode:e.autoSkillsReviewMode,messageId:e.messageId,user:e.user,goal:e.goal,goalFile:e.goalFile,tokenBudget:e.tokenBudget,force:e.force,encryptSessions:e.encryptSessions,disableTopicSegmentation:e.disableTopicSegmentation,disableTitle:e.disableTitle});return}let u=e.channel??`WEB`,{controller:d,cleanup:f}=Yr(()=>({activeSessionId:a.activeSessionId,finalSessionId:a.finalResult?.sessionId,messageId:e.messageId,channel:u,user:e.user})),p=null;try{let t=await Ur(e,c);u=t.channel,si(e,t);let i=Kr(e);p=i.sink,P.info(`external sink configured`,{callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamEvents:e.streamEvents});let s=Jr(p,i.websocketSink,t.channel,e.messageId,e.user);await ei(t,s,a);let l,f=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await D.readFile(e.goalFile,`utf-8`):e.goal;let a=Bn(i),o=q(e.sessionStore),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(I(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));try{if(e.sessionId){let n=await b(t.dataDir,e.sessionId,{storeName:o}),i=await r({dataDir:t.dataDir,sessionId:e.sessionId,objective:a,tokenBudget:s,force:e.force,storeName:o});f=Hn({sessionId:e.sessionId,before:n,result:i})}else l={objective:a,tokenBudget:s??null}}catch(e){throw e instanceof n&&(I(e.message),I(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await W(t.dataDir,m),g=ni(t,s,a,e);f&&await g(f);let _=await de(ii(e,t,d,g,h,l));Zr(t.dataDir,e,a,_.sessionId),await ai(s,a,e.messageId,_),process.exitCode=ci(o,_,t.format)}catch(t){let n=t;p&&await oi(Jr(p,null,u,e.messageId,e.user),a,e.messageId,n),await ui(o,n)}finally{await p?.close(),f()}})}function pi(e){return{eventType:e.type,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,progressType:e.type===`progress`?e.event.type:void 0,textLength:e.type===`done`?e.result.text.length:void 0,hasError:e.type===`error`?!0:e.type===`done`?!!e.result.error:void 0}}function mi(e){e.command(`run`).description(`Run an agent task`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--project-dir <path>`,`Current project directory used as the default cwd context`).option(`--system-agents-dir <path>`,`System agent definition directory (overrides AIMAX_SYSTEM_AGENTS_DIR, default: /aimax/agents)`).option(`--agent <name>`,`Custom agent name to run as the root agent`).option(`--user <id>`,`User identifier propagated to external callback and stream payloads`).option(`--message <text>`,`User message to send to the agent`).option(`--from-file <path>`,`Load structured Message JSON from a file`).option(`--skillsLoadPaths <paths>`,`Comma-separated absolute skill load paths`).option(`--auto-skills-load-enabled <boolean>`,`Enable learned auto-skill loading for the main agent (overrides AIMAX_AUTO_SKILLS_LOAD_ENABLED)`).option(`--auto-skills-review-mode <mode>`,`Auto-skill review mode: off, gate, dry_run, or write (overrides AIMAX_AUTO_SKILLS_REVIEW_MODE)`).option(`-s, --session-id <id>`,`Resume an existing session by ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--message-id <id>`,`Message ID for correlating events`).option(`-c, --channel <channel>`,`Channel name (default: WEB)`,`WEB`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--auth-token <token>`,`Auth token used to generate the API key (highest priority)`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--context-window <n>`,`LLM context window size`).option(`--flash-model <name>`,`Flash model for lightweight tasks like title generation (overrides AIMAX_FLASH_MODEL)`).option(`--thinking <level>`,`Explicit thinking level: minimal, low, medium, high, or xhigh (overrides AIMAX_THINKING)`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events: start,text,progress,done,error`).option(`--artifacts-url-whitelist <urls>`,`Comma-separated URL artifact hostnames or URLs to collect; unset collects all URL artifacts`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--plugins-config <path>`,`Plugins config file path`).option(`--env <kvlist>`,`Session-scoped env vars injected into the run. Comma-separated KEY=VALUE pairs. Backslash-escape "," and "=" inside values. Available to plugins via api.runtime.session.env and merged into child process environments spawned by the exec/process tools.`).option(`--goal <text>`,`Set or replace the thread goal objective before running`).option(`--goal-file <path>`,`Read goal objective from a file`).option(`--token-budget <n>`,`Token budget for the goal (positive integer, or 0 for unlimited)`).option(`--force`,`Replace existing goal with a different objective`).option(`--resume-request-id <id>`,`Resume a pending HITL request from aimax run`).option(`--resume-input-json <json>`,`Structured HITL resume payload used with --resume-request-id`).option(`--resume-from-file <path>`,`Load structured HITL resume payload from a file (alternative to --resume-input-json)`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).option(`--disable-topic-segmentation`,`Disable smart topic segmentation for this run`).option(`--disable-title`,`Skip LLM session title generation for new sessions (title falls back to a truncated first message; overrides AIMAX_DISABLE_TITLE)`).action(async e=>{await fi(e)})}function hi(e){e.command(`sessions`).description(`List or inspect sessions for a data directory`).argument(`[action]`,`Action: list (default) | inspect | export`).option(`-d, --data-dir <path>`,`Data directory path`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`-c, --channel <channel>`,`Filter by channel type: H5 | WEB | KLPA | TASK | CRON | EIP_ASSISTANT`).option(`-s, --session-id <id>`,`Session ID for inspect/export`).option(`--output <format>`,`Output format: text or json`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t,n)=>{let r=n.opts(),i=e??`list`,a=i===`export`?r.output===`text`?`text`:`json`:r.output===`json`?`json`:`text`;r.dataDir||(I(`error: required option '-d, --data-dir <path>' not specified`),process.exit(1)),r.channel&&r.channel!==`H5`&&r.channel!==`WEB`&&r.channel!==`KLPA`&&r.channel!==`TASK`&&r.channel!==`CRON`&&r.channel!==`EIP_ASSISTANT`&&(I(`Invalid channel: ${r.channel}. Must be 'H5', 'WEB', 'KLPA', 'TASK', 'CRON', or 'EIP_ASSISTANT'`),process.exit(1));try{await U(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;if(i===`list`){gt(await v(r.dataDir,r.channel,{storeName:e}),a);return}if(r.sessionId||(I(`error: required option '-s, --session-id <id>' not specified`),process.exit(1)),i===`inspect`){_t(await g(r.dataDir,r.sessionId,{storeName:e}),a);return}if(i===`export`){vt(await u(r.dataDir,r.sessionId,{storeName:e}),a);return}I(`Invalid sessions action: ${i}. Must be 'list', 'inspect', or 'export'`),process.exit(1)})}catch(e){I(`${i===`inspect`?`Error inspecting session`:i===`export`?`Error exporting session`:`Error listing sessions`}: ${e.message}`),process.exit(1)}})}function gi(e){return C.join(e,`workspace`)}function _i(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function vi(e,t){let n=[];n.push(`backend: ${e.backend}`),n.push(`provider: ${e.provider}${e.model?` (${e.model})`:``}`);let r=typeof e.custom?.providerSource==`string`?e.custom.providerSource:void 0,i=typeof e.custom?.providerId==`string`?e.custom.providerId:void 0,a=typeof e.custom?.pluginId==`string`?e.custom.pluginId:void 0;r&&n.push(`provider_source: ${r}`),i&&n.push(`provider_id: ${i}`),a&&n.push(`plugin_id: ${a}`),typeof e.files==`number`&&n.push(`files: ${e.files}`),typeof e.chunks==`number`&&n.push(`chunks: ${e.chunks}`),typeof e.dirty==`boolean`&&n.push(`dirty: ${e.dirty}`),e.dbPath&&n.push(`db: ${e.dbPath}`),e.sources?.length&&n.push(`sources: ${e.sources.join(`, `)}`),t&&(e.fts&&(n.push(`fts: enabled=${e.fts.enabled} available=${e.fts.available}`),e.fts.error&&n.push(`fts_error: ${e.fts.error}`)),e.vector&&(n.push(`vector: enabled=${e.vector.enabled} available=${e.vector.available??`unknown`}`),e.vector.dims&&n.push(`vector_dims: ${e.vector.dims}`),e.vector.loadError&&n.push(`vector_error: ${e.vector.loadError}`)),e.cache&&n.push(`cache: enabled=${e.cache.enabled} entries=${e.cache.entries??0}`));let o=Array.isArray(e.custom?.cliWarnings)?e.custom.cliWarnings.filter(e=>typeof e==`string`&&e.length>0):[];for(let e of o)n.push(`warning: ${e}`);return n.join(`
12
+ `)}function yi(e){let t=e.level===`error`?`plugin error`:`plugin warning`;return e.pluginId?`${t} (${e.pluginId}): ${e.message}`:`${t}: ${e.message}`}function bi(e){if(!e||e===`cli`)return`cli`;if(e===`cron`)return`cron`;throw Error(`Unsupported dream trigger: ${e}. Expected "cli" or "cron".`)}async function xi(e){let t=[],n;try{n=await W(e.dataDir,e.pluginsConfig)}catch(e){t.push(`failed to load plugins config: ${e.message}`)}if(!e.shouldInitialize&&!n)return{warnings:t};try{let r=h({config:n,dataDir:e.dataDir,workspaceDir:gi(e.dataDir),bundledDir:_i()});return t.push(...r.diagnostics.map(yi)),{pluginSystem:r,warnings:t}}catch(e){return t.push(`failed to initialize plugin system: ${e.message}`),{warnings:t}}}async function Si(e){let t=C.join(e.dataDir,`.aimax`),{pluginSystem:n,warnings:r}=await xi({dataDir:e.dataDir,pluginsConfig:e.pluginsConfig,shouldInitialize:!!(e.requirePluginSystem||e.provider||e.providerPlugin)}),i=n?.normalizedConfig.slots.memory,a=e.providerPlugin?.trim()||(e.provider?void 0:i),o=se({providerId:e.provider,pluginId:a,dataDir:e.dataDir,memoryDir:t,includeSessions:e.includeSessions});return o.providerSource===`plugin`?{provider:o.provider,providerId:o.providerId,pluginId:o.pluginId,providerOrigin:`plugin`,warnings:r,pluginSystem:n}:((a||e.provider)&&r.push(`requested memory provider was not resolved; falling back to builtin provider`),{provider:o.provider,providerId:`builtin`,providerOrigin:`builtin`,warnings:r,pluginSystem:n})}function Ci(e,t,n){let r={...e.custom??{},providerSource:t.providerOrigin,providerId:t.providerId,pluginId:t.pluginId,cliWarnings:t.warnings},i={...e,custom:r};return n&&t.providerOrigin===`plugin`?i.custom={...r,note:`deep probe details are provider-defined for plugin memory providers`}:n&&(i.custom={...r,note:`deep probe is only supported by builtin provider`}),i}function wi(e){let t=e.command(`memory`).description(`Manage semantic memory indexing and search`),n=e=>e.option(`--plugins-config <path>`,`Plugins config file path`);n(t.command(`status`)).description(`Show memory index status`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--deep`,`Probe embedding/vector availability`).option(`--index`,`Run a refresh before reporting status`).option(`--include-sessions`,`Include session transcripts in indexing`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--verbose`,`Verbose output`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await U(e.dataDir,e,async()=>{let n=await Si({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,includeSessions:e.includeSessions});e.index&&n.provider.sync&&await n.provider.sync(`cli-status`);let r=Ci(n.provider.status(),n,e.deep);F(t===`json`?JSON.stringify(r,null,2):vi(r,e.deep))})}catch(e){I(`Error getting memory status: ${e.message}`),process.exit(1)}}),n(t.command(`index`)).description(`Reindex memory files`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--include-sessions`,`Include session transcripts in indexing`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--rebuild`,`Force full rebuild from Markdown source`).option(`--verbose`,`Verbose output`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{try{await U(e.dataDir,e,async()=>{let t=await Si({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,includeSessions:e.includeSessions}),n;if(t.provider.sync&&(await t.provider.sync(e.rebuild?`cli-rebuild`:`cli-index`),n=t.provider.status().custom?.lastRebuildSummary),t.warnings.length>0)for(let e of t.warnings)I(`Warning: ${e}`);e.verbose&&n&&F(JSON.stringify(n,null,2)),F(e.rebuild?`Memory index rebuilt.`:`Memory index refreshed.`)})}catch(e){I(`Error indexing memory: ${e.message}`),process.exit(1)}}),n(t.command(`search [query]`)).description(`Search semantic memory`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--query <text>`,`Search query`).option(`--include-sessions`,`Include session transcripts in search`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t)=>{let n=t.output===`json`?`json`:`text`,r=t.query?.trim()||e?.trim();r||(I(`Query is required: provide [query] or --query <text>`),process.exit(1));try{await U(t.dataDir,t,async()=>{let e=await(await Si({dataDir:t.dataDir,provider:t.provider,providerPlugin:t.providerPlugin,pluginsConfig:t.pluginsConfig,includeSessions:t.includeSessions})).provider.search(r);if(n===`json`){F(JSON.stringify(e,null,2));return}if(e.length===0){F(`No results found for: ${r}`);return}F(e.map(e=>{let t=`${e.path}:${e.startLine}-${e.endLine} (${e.score.toFixed(4)}) ${e.snippet}`;return e.citation?`${t}\n${e.citation}`:t}).join(`
13
+ `))})}catch(e){I(`Error searching memory: ${e.message}`),process.exit(1)}}),n(t.command(`dream`)).description(`Trigger Dream Gate host hook for memory plugins`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--trigger <mode>`,`Dream Gate trigger mode: cli (default) or cron`,`cli`).option(`--dry-run`,`Return hook results without plugin-side mutation`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await U(e.dataDir,e,async()=>{let n=bi(e.trigger),r=await Si({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,requirePluginSystem:!0}),i=r.pluginSystem?await r.pluginSystem.registry.hooks.dispatch(`dream_gate`,{dataDir:e.dataDir,memoryDir:C.join(e.dataDir,`.aimax`),providerId:r.providerId,pluginId:r.pluginId,trigger:n,dryRun:!!e.dryRun},{workspaceDir:gi(e.dataDir)}):[],a={ok:!0,trigger:n,providerSource:r.providerOrigin,providerId:r.providerId,pluginId:r.pluginId,resultCount:i.length,results:i,warnings:r.warnings};if(t===`json`){F(JSON.stringify(a,null,2));return}F(`trigger: ${a.trigger}`),F(`provider_source: ${a.providerSource}`),F(`provider_id: ${a.providerId}`),a.pluginId&&F(`plugin_id: ${a.pluginId}`),F(`result_count: ${a.resultCount}`),a.results.length===0?F(`note: no dream_gate hook registered`):F(`results: ${JSON.stringify(a.results)}`);for(let e of a.warnings)F(`warning: ${e}`)})}catch(e){I(`Error running dream gate: ${e.message}`),process.exit(1)}})}function Ti(e){return`${e.match.accountId?`${e.match.channel}:${e.match.accountId}`:e.match.channel} -> ${e.agentId}`}function Ei(e){return async t=>{let n=await k(t),r=Ie(n),i=Le(n);if(He(n),e.json){console.log(JSON.stringify({agents:r,bindings:i},null,2));return}console.log(`Agents:`);for(let e of r){let n=e.default?` (default)`:``,r=e.name&&e.name!==e.id?`${e.id}${n} (${e.name})`:`${e.id}${n}`;if(console.log(` - ${r}`),e.identity?.emoji||e.identity?.name){let t=[e.identity.emoji,e.identity.name].filter(Boolean).join(` `);console.log(` Identity: ${t}`)}let a=Ve(t,e.id);if(console.log(` Agent dir: ${a}`),e.model){let t=typeof e.model==`string`?e.model:e.model.primary;console.log(` Model: ${t}`)}let o=i.filter(t=>t.agentId===e.id);if(o.length>0){console.log(` Routing rules:`);for(let e of o)console.log(` - ${Ti(e)}`)}}}}function Di(e,t){return async n=>{O(await k(n),Re(e))&&(console.error(`Agent "${e}" already exists.`),process.exit(1)),await Pe(n,{id:e,name:t.name,model:t.model,default:t.default})||(console.error(`Agent "${e}" already exists.`),process.exit(1));let r=Ve(n,e);console.log(`Agent "${e}" added successfully.`),console.log(` Agent dir: ${r}`)}}function Oi(e){return async t=>{let n=O(await k(t),Re(e));n||(console.error(`Agent "${e}" not found.`),process.exit(1)),n.default===!0&&(console.error(`Cannot delete default agent "${e}".`),process.exit(1)),await ze(t,e)||(console.error(`Failed to delete agent "${e}".`),process.exit(1)),console.log(`Agent "${e}" deleted.`)}}function ki(e){return async t=>{let n=await k(t),r=e.agent??He(n);O(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),(!e.bind||e.bind.length===0)&&(console.error(`Please specify --bind <channel>[:<account>]`),process.exit(1));for(let n of e.bind){let[e,...i]=n.split(`:`),a=i.join(`:`),o=[`H5`,`WEB`,`KLPA`,`TASK`,`CRON`,`EIP_ASSISTANT`];o.includes(e)||(console.error(`Invalid channel: ${e}`),console.error(`Valid channels: ${o.join(`, `)}`),process.exit(1)),await Fe(t,{agentId:r,match:{channel:e,accountId:a||void 0}}),console.log(`Binding added: ${n} -> ${r}`)}}}function Ai(e){return async t=>{let n=await k(t),r=e.agent??He(n);if(O(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),e.all){let e=await Be(t,r,`*`);console.log(`Removed ${e} binding(s) for agent "${r}".`)}else if(e.bind&&e.bind.length>0){let n=0;for(let i of e.bind){let[e,...a]=i.split(`:`),o=await Be(t,r,e,a.join(`:`)||void 0);o>0?(console.log(`Binding removed: ${i} -> ${r}`),n+=o):console.log(`No binding found: ${i} -> ${r}`)}}else console.error(`Please specify --bind <channel>[:<account>] or --all`),process.exit(1)}}function ji(e){return async t=>{let n=Le(await k(t));if(e.agent&&(n=n.filter(t=>t.agentId===e.agent)),e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(`No bindings configured.`);return}console.log(`Routing bindings:`);for(let e of n)console.log(` ${Ti(e)}`)}}function Mi(e){return async t=>{let n=await k(t),r=e.agent??He(n);O(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),await Ue(t,r,{name:e.name,emoji:e.emoji,avatar:e.avatar})||(console.error(`Failed to update identity for agent "${r}".`),process.exit(1)),console.log(`Identity updated for agent "${r}".`)}}function Ni(e,t){let n=e.command(`agents`).description(`Manage agents`),r=e=>e.option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`);r(n.command(`list`).description(`List all configured agents`).option(`-j, --json`,`Output as JSON`).option(`-b, --bindings`,`Show detailed binding rules`)).action(async e=>{let n=t();await U(n,e,async()=>{await Ei(e)(n)})}),r(n.command(`add <id>`).description(`Add a new agent`).option(`-n, --name <name>`,`Display name`).option(`-m, --model <model>`,`Model identifier`).option(`--default`,`Mark as default agent`)).action(async(e,n)=>{let r=t();await U(r,n,async()=>{await Di(e,n)(r)})}),r(n.command(`delete <id>`).description(`Delete an agent`)).action(async(e,n)=>{let r=t();await U(r,n,async()=>{await Oi(e)(r)})}),r(n.command(`bind`).description(`Bind a channel to an agent`).option(`-a, --agent <id>`,`Target agent ID`).option(`-b, --bind <channel...>`,`Channel binding (e.g., WEB, KLPA:ops)`)).action(async e=>{let n=t();await U(n,e,async()=>{await ki(e)(n)})}),r(n.command(`unbind`).description(`Unbind a channel from an agent`).option(`-a, --agent <id>`,`Target agent ID`).option(`-b, --bind <channel...>`,`Channel binding to remove`).option(`--all`,`Remove all bindings for the agent`)).action(async e=>{let n=t();await U(n,e,async()=>{await Ai(e)(n)})}),r(n.command(`bindings`).description(`List routing bindings`).option(`-a, --agent <id>`,`Filter by agent ID`).option(`-j, --json`,`Output as JSON`)).action(async e=>{let n=t();await U(n,e,async()=>{await ji(e)(n)})}),r(n.command(`set-identity`).description(`Set agent identity`).option(`-a, --agent <id>`,`Target agent ID`).option(`-n, --name <name>`,`Agent name`).option(`-e, --emoji <emoji>`,`Agent emoji`).option(`--avatar <path>`,`Avatar path`)).action(async e=>{let n=t();await U(n,e,async()=>{await Mi(e)(n)})})}function X(e){return C.join(e,`workspace`)}function Z(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function Pi(e){if(e.length===0){F(`No plugins discovered.`);return}for(let t of e){let e=t.status.padEnd(8,` `);F(`${t.id} ${e} ${t.origin} ${t.source}`)}}function Fi(e){F(`id: ${e.id}`),F(`status: ${e.status}`),F(`origin: ${e.origin}`),F(`source: ${e.source}`),F(`enabled: ${e.enabled}`),e.error&&F(`error: ${e.error}`),F(`tools: ${e.toolCount}`),F(`hooks: ${e.hookCount}`),e.skills.length>0&&F(`skills: ${e.skills.join(`, `)}`)}function Ii(e){return Array.from(new Set((e??[]).map(e=>e.trim()).filter(Boolean)))}function Li(e){if(e.length===0){F(`LLM allowlist is empty.`);return}for(let t of e)F(t)}function Ri(e,t){let n=e.command(`plugins`).description(`Manage AIMax plugins`),r=e=>e.option(`--plugins-config <path>`,`Plugins config file path`),i=e=>e.option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`);i(r(n.command(`list`))).description(`List discovered plugins`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await U(n,e,async()=>{Pi(h({config:await W(n,e.pluginsConfig),dataDir:n,workspaceDir:X(n),bundledDir:Z()}).registry.plugins)})}),i(r(n.command(`info`))).description(`Show plugin details`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await U(r,n,async()=>{let t=h({config:await W(r,n.pluginsConfig),dataDir:r,workspaceDir:X(r),bundledDir:Z()}).registry.plugins.find(t=>t.id===e);t||(I(`Plugin not found: ${e}`),process.exit(1)),Fi(t)})}),i(r(n.command(`enable`))).description(`Enable a plugin`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await U(r,n,async()=>{let t=await W(r,n.pluginsConfig)??{},i=ae(t);h({config:t,dataDir:r,workspaceDir:X(r),bundledDir:Z()}).registry.plugins.some(t=>t.id===e)||(I(`Plugin not found: ${e}`),process.exit(1)),await G(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!0}}},n.pluginsConfig),F(`Enabled ${e}`),i.allow.length>0&&!i.allow.includes(e)&&F(`Note: plugins.allow is set; add this plugin id to allowlist if needed.`)})}),i(r(n.command(`disable`))).description(`Disable a plugin`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await U(r,n,async()=>{let t=await W(r,n.pluginsConfig)??{};h({config:t,dataDir:r,workspaceDir:X(r),bundledDir:Z()}).registry.plugins.some(t=>t.id===e)||(I(`Plugin not found: ${e}`),process.exit(1)),await G(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!1}}},n.pluginsConfig),F(`Disabled ${e}`)})}),i(r(n.command(`doctor`))).description(`Validate plugin configuration`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await U(n,e,async()=>{let t=h({config:await W(n,e.pluginsConfig),dataDir:n,workspaceDir:X(n),bundledDir:Z()});if(t.diagnostics.length===0){F(`No plugin issues detected.`);return}for(let e of t.diagnostics)F(`${e.level===`error`?`ERROR`:`WARN`}${e.pluginId?` ${e.pluginId}`:``}: ${e.message}`);t.diagnostics.some(e=>e.level===`error`)&&process.exit(1)})});let a=n.command(`llm-allow`).description(`Manage plugin LLM allowlist`);i(r(a.command(`list`))).description(`List LLM allowlist entries`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await U(n,e,async()=>{Li(Ii((await W(n,e.pluginsConfig))?.llmAllowlist))})}),i(r(a.command(`add`))).description(`Add entries to the LLM allowlist (plugin id or tool name)`).argument(`<entry...>`,`Plugin id or tool name`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await U(r,n,async()=>{let t=await W(r,n.pluginsConfig)??{},i=Ii([...t.llmAllowlist??[],...e]);await G(r,{...t,llmAllowlist:i},n.pluginsConfig),F(`LLM allowlist updated (${i.length} entries).`)})}),i(r(a.command(`remove`))).description(`Remove entries from the LLM allowlist`).argument(`<entry...>`,`Plugin id or tool name`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await U(r,n,async()=>{let t=await W(r,n.pluginsConfig)??{},i=new Set(e.map(e=>e.trim()).filter(Boolean)),a=Ii(t.llmAllowlist).filter(e=>!i.has(e));await G(r,{...t,llmAllowlist:a},n.pluginsConfig),F(`LLM allowlist updated (${a.length} entries).`)})}),i(r(a.command(`clear`))).description(`Clear the LLM allowlist`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await U(n,e,async()=>{await G(n,{...await W(n,e.pluginsConfig)??{},llmAllowlist:[]},e.pluginsConfig),F(`LLM allowlist cleared.`)})})}function zi(e){e.command(`commands`).description(`List available slash commands for a data directory`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await U(e.dataDir,e,async()=>{let n=_(await re(e.dataDir,[]));if(t===`json`){F(JSON.stringify(n,null,2));return}F(`Commands`),F(` builtin: ${n.builtin.map(e=>e.name).join(` | `)}`),n.skillCommands.length>0?F(` skills: ${n.skillCommands.map(e=>e.name).join(` | `)}`):F(` skills: (none)`)})}catch(e){I(`Error listing commands: ${e.message}`),process.exit(1)}})}function Q(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function $(e){if(!e.sessionId)throw Error(`Session ID is required (--session-id or -s)`);return e.sessionId}function Bi(e){return e?y(e):void 0}async function Vi(e){let t={storeName:e.sessionStoreName},n=e.objective.trim(),r=await b(e.dataDir,e.sessionId,t);if(!r||(await oe(e.dataDir,e.sessionId,r,t)).trim()!==n)return he(e.dataDir,e.sessionId,{goalId:Ge(),objective:n,status:`active`,tokenBudget:e.tokenBudget??null,tokensUsed:0,timeUsedSeconds:0},{...t,eventSource:`cli`});if(r.status===`complete`)return r;let i={};return r.status===`paused`&&(i.status=`active`),e.tokenBudget!==void 0&&e.tokenBudget!==r.tokenBudget&&(i.tokenBudget=e.tokenBudget),Object.keys(i).length===0?r:await me(e.dataDir,e.sessionId,i,{...t,eventSource:`cli`})}async function Hi(e,t){let n=Q(t),r=$(t),i=Bi(t.sessionStore),a=e.trim();a||(I(`error: objective cannot be empty`),process.exit(1));let o=t.tokenBudget===void 0||t.tokenBudget===`0`||t.tokenBudget===``?null:Number(t.tokenBudget);o!==null&&(Number.isNaN(o)||o<=0)&&(I(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));let s=await Vi({dataDir:n,sessionId:r,sessionStoreName:i,objective:a,tokenBudget:o});F(JSON.stringify({goal:s},null,2))}async function Ui(e){let t=Q(e),n=$(e),r=Bi(e.sessionStore),i=await b(t,n,{storeName:r});if(!i){F(JSON.stringify({goal:null},null,2));return}let a=await oe(t,n,i,{storeName:r});F(JSON.stringify({goal:{...i,objective:a}},null,2))}async function Wi(e){let t=Q(e),n=$(e),r=Bi(e.sessionStore),i=await b(t,n,{storeName:r});i||(I(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(I(`error: cannot pause a completed goal`),process.exit(1));let a=await me(t,n,{status:`paused`},{storeName:r,eventSource:`cli`});F(JSON.stringify({goal:a},null,2))}async function Gi(e){let t=Q(e),n=$(e),r=Bi(e.sessionStore),i=await b(t,n,{storeName:r});if(i||(I(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(I(`error: cannot resume a completed goal`),process.exit(1)),i.status===`budget_limited`&&(I(`error: cannot resume a budget-limited goal; clear or replace it instead`),process.exit(1)),i.status===`active`){F(JSON.stringify({goal:i},null,2));return}let a=await me(t,n,{status:`active`},{storeName:r,eventSource:`cli`});F(JSON.stringify({goal:a},null,2))}async function Ki(e){let t=await c(Q(e),$(e),{storeName:Bi(e.sessionStore),eventSource:`cli`});F(JSON.stringify({cleared:t},null,2))}function qi(e){let t=e.command(`goal`).description(`Manage thread goals for a session`).addHelpText(`after`,a());t.command(`set <objective>`).description(`Set or replace the thread goal (creates new goalId)`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--token-budget <n>`,`Optional token budget (positive integer, or 0 for unlimited)`).action(async(e,t)=>{try{await Hi(e,t)}catch(e){I(`error: ${e.message}`),process.exit(1)}}),t.command(`get`).description(`Get the current goal as JSON`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Ui(e)}catch(e){I(`error: ${e.message}`),process.exit(1)}}),t.command(`pause`).description(`Pause the current goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Wi(e)}catch(e){I(`error: ${e.message}`),process.exit(1)}}),t.command(`resume`).description(`Resume a paused goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Gi(e)}catch(e){I(`error: ${e.message}`),process.exit(1)}}),t.command(`clear`).description(`Clear the current goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Ki(e)}catch(e){I(`error: ${e.message}`),process.exit(1)}})}const Ji=[`progress`,`error`,`hitl`];function Yi(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir or AIMAX_DATA_DIR`);return t}function Xi(e){if(!e?.trim())return new Set(Ji);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl`);r.add(e)}return r.size>0?r:new Set(Ji)}function Zi(e){return e?y(e):void 0}function Qi(e){let t=[];return e.callbackUrl&&t.push(new kn(e.callbackUrl)),e.streamUrl&&t.push(new Rn(e.streamUrl,Xi(e.streamEvents),e.streamAuthToken)),new On(t)}async function $i(e){let t=Yi(e);await U(t,e,async()=>{N(t,{messageId:e.messageId});let n=new ct(`cancel command`),r=e.channel??`WEB`,i=e.output===`json`?`json`:`text`,a=Qi(e),o=Zi(e.sessionStore);try{let s=await ee(t,e.sessionId,{storeName:o});if(!s)throw Error(`No pending HITL request found for session "${e.sessionId}"`);let c=e.requestId??s.request.requestId;if(s.request.requestId!==c)throw Error(`Request ID mismatch: pending is "${s.request.requestId}", got "${c}"`);if(!(await ce({dataDir:t,sessionStoreName:o,sessionId:e.sessionId,requestId:c,resolution:{requestId:c,sessionId:e.sessionId,action:`cancel`,submittedAt:new Date().toISOString(),submittedBy:{channel:r}}})).state)throw Error(`Failed to cancel HITL request`);let l={type:`hitl_cancelled`,sessionId:e.sessionId,requestId:c,reason:e.reason??`cancelled by operator`};i===`text`&&L(l),await a.send({type:`progress`,sessionId:e.sessionId,channel:r,messageId:e.messageId,event:l}),n.end(),process.exit(0)}catch(t){let i=t;await a.send({type:`error`,sessionId:e.sessionId,channel:r,messageId:e.messageId,message:i.message}),P.error(`cancel command error: ${i.message}`),I(`Fatal: ${i.message}`),n.end(),process.exit(1)}finally{await a.close()}})}function ea(e){e.command(`cancel`).description(`Cancel a pending HITL request`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).requiredOption(`-s, --session-id <id>`,`Session ID containing the pending HITL request`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--request-id <id>`,`HITL request ID to cancel`).option(`--reason <text>`,`Human-readable cancel reason`).option(`-c, --channel <channel>`,`Channel type (default: WEB)`,`WEB`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events`).option(`--message-id <id>`,`Message ID for correlating events`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{await $i(e)})}function ta(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function na(e){return e.query?.trim()||void 0}function ra(e){if(!e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error(`--timeout must be a positive number of milliseconds`);return t}function ia(e){if(!e)return;let t=Number(e);if(!Number.isInteger(t)||t<=0)throw Error(`--max-tokens must be a positive integer`);return t}async function aa(e){if(e.filePath){if(!C.isAbsolute(e.filePath))throw Error(`--file-path must be an absolute path`);try{await D.access(e.filePath)}catch(e){throw Error(`Failed to access --file-path: ${e.message}`)}return{source:`file`,filePath:e.filePath}}let t=e.content;if(!t||!t.trim())throw Error(`Either --file-path or --content must be provided`);return{source:`content`,content:t}}async function oa(e){let t=null;try{let n=ta(e);N(n,{messageId:e.messageId}),t=new ct(`summarize command`);let r=na(e),i=await aa(e),a=cn({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,model:e.model,contextWindow:2e5}),o=ra(e.timeout),s=ia(e.maxTokens);P.info(`summarize command started`,{dataDir:n,source:i.source,filePath:i.source===`file`?i.filePath:void 0,queryLength:r?.length,contentLength:i.source===`content`?i.content.length:void 0,timeoutMs:o,maxTokens:s});let c=await de({dataDir:n,channel:`WEB`,messageId:e.messageId,message:sa(i,r),llm:{...a,maxTokens:s},timeoutMs:o});F(c.text.trim()),P.info(`summarize command succeeded`,{source:i.source,summaryLength:c.text.length,durationMs:c.durationMs}),t.end()}catch(e){P.error(`summarize command error: ${e.message}`),I(`Fatal: ${e.message}`),t?.end(),process.exit(1)}}function sa(e,t){return e.source===`file`?[t?`Summarize exactly one file for the query below.`:`Summarize exactly one file.`,`Read only the absolute file path provided here. Do not search, browse, read other files, execute commands, modify files, or perform any other processing.`,`Return only the summary text.`,``,...t?[`Query:\n${t}`,``]:[],`Input source: file`,`File path: ${e.filePath}`].join(`
14
+ `):[t?`Summarize the provided content for the query below.`:`Summarize the provided content.`,t?`Use only the provided content and query. Do not search, browse, read files, execute commands, modify files, or perform any other processing.`:`Use only the provided content. Do not search, browse, read files, execute commands, modify files, or perform any other processing.`,`Return only the summary text.`,``,...t?[`Query:\n${t}`,``]:[],`Input source: content`,`Source content:`,`<source>`,e.content,`</source>`].join(`
15
+ `)}function ca(e){e.command(`summarize`).description(`Summarize one absolute file path or inline content`).option(`--file-path <path>`,`Absolute file path to summarize`).option(`--content <text>`,`Inline text content to summarize when --file-path is not provided`).option(`--query <text>`,`Optional search target or current description to focus the summary`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--max-tokens <number>`,`Maximum number of tokens for model output`).option(`--message-id <id>`,`Message ID for log correlation`).action(async e=>{await oa(e)})}const la={accent:`#8abeb7`,border:`#5f87ff`,borderAccent:`#00d7ff`,borderMuted:`#505050`,success:`#b5bd68`,error:`#cc6666`,warning:`#ffff00`,muted:`#808080`,dim:`#666666`,text:`#d4d4d4`,thinkingText:`#808080`,selectedBg:`#3a3a4a`,userMessageBg:`#343541`,userMessageText:`#d4d4d4`,customMessageBg:`#2d2838`,customMessageText:`#d4d4d4`,customMessageLabel:`#9575cd`,toolPendingBg:`#282832`,toolSuccessBg:`#283228`,toolErrorBg:`#3c2828`,toolTitle:`#d4d4d4`,toolOutput:`#808080`,mdHeading:`#f0c674`,mdLink:`#81a2be`,mdLinkUrl:`#666666`,mdCode:`#8abeb7`,mdCodeBlock:`#b5bd68`,mdCodeBlockBorder:`#808080`,mdQuote:`#808080`,mdQuoteBorder:`#808080`,mdHr:`#808080`,mdListBullet:`#8abeb7`,toolDiffAdded:`#b5bd68`,toolDiffRemoved:`#cc6666`,toolDiffContext:`#808080`,syntaxComment:`#6A9955`,syntaxKeyword:`#569CD6`,syntaxFunction:`#DCDCAA`,syntaxVariable:`#9CDCFE`,syntaxString:`#CE9178`,syntaxNumber:`#B5CEA8`,syntaxType:`#4EC9B0`,syntaxOperator:`#D4D4D4`,syntaxPunctuation:`#D4D4D4`,thinkingOff:`#505050`,thinkingMinimal:`#6e6e6e`,thinkingLow:`#5f87af`,thinkingMedium:`#81a2be`,thinkingHigh:`#b294bb`,thinkingXhigh:`#d183e8`,bashMode:`#b5bd68`},ua=`#18181e`,da=`#1e1e24`,fa=`#3c3728`;function pa(e){if(!e||typeof e!=`object`)return!1;let t=e.role;return t===`user`||t===`assistant`||t===`tool_result`||t===`compaction`}function ma(e){return!e||typeof e!=`object`?!1:typeof e.type==`string`}function ha(e){return{type:`text`,text:e}}function ga(e){return{type:`thinking`,thinking:e}}function _a(e,t){let n=e.timestamp,r=typeof n==`string`&&n?n:e.content;return`${e.role}\0${r}\0${t}`}function va(e,t,n){let r=_a(e,t);for(let e=0;e<100;e++){let t=We(`sha256`).update(`${r}\0${e}`).digest(`hex`).slice(0,8);if(!n.has(t))return n.add(t),t}let i=We(`sha256`).update(`${r}\0fallback`).digest(`hex`);return n.add(i),i}function ya(e,t){let n=new Set,r=null,i=[],a={type:`session`,version:3,id:t?.sessionId??Ge(),timestamp:e.find(e=>e.timestamp)?.timestamp??new Date().toISOString(),cwd:t?.cwd??process.cwd()};for(let[t,a]of e.entries()){let e=va(a,t,n),o={id:e,parentId:r,timestamp:a.timestamp};if(a.role===`user`)i.push({type:`message`,...o,message:{role:`user`,content:[ha(a.content)]}});else if(a.role===`assistant`){let e=[];a.thinking?.trim()&&e.push(ga(a.thinking.trim())),a.content.trim()&&e.push(ha(a.content));for(let t of a.toolCalls??[])e.push({type:`toolCall`,id:t.id,name:t.name,arguments:t.arguments});a.errorMessage&&e.push(ha(a.errorMessage)),i.push({type:`message`,...o,message:{role:`assistant`,content:e,...a.stopReason?{stopReason:a.stopReason}:{}}})}else if(a.role===`tool_result`){let e=a.content;a.toolResultRef?.preview&&!e.includes(a.toolResultRef.preview)&&(e=`${e}\n\nPreview:\n${a.toolResultRef.preview}`),a.toolResultRef?.storagePath&&(e=`${e}\n\n[Full output: ${a.toolResultRef.storagePath}]`),i.push({type:`message`,...o,message:{role:`toolResult`,toolCallId:a.toolCallId,toolName:a.toolName,content:[ha(e)],isError:a.isError}})}else a.role===`compaction`&&i.push({type:`compaction`,...o,summary:a.content,firstKeptEntryId:r??e,tokensBefore:0});r=e}return{header:a,entries:i,leafId:r}}function ba(e,t){let n=e.trim().split(`
16
+ `).filter(e=>e.trim()),r=[],i=0;for(let e of n)try{r.push(JSON.parse(e))}catch{i+=1}if(r.length===0)return{data:ya([],t),skippedLines:i};let a=r[0];if(ma(a)&&a.type===`session`){let e=a,t=r.slice(1).filter(ma);return{data:{header:e,entries:t,leafId:t.length>0?t[t.length-1].id:null},skippedLines:i}}if(r.every(ma)){let e=r;return{data:{header:{type:`session`,version:3,id:t?.sessionId??Ge(),timestamp:e[0]?.timestamp??new Date().toISOString(),cwd:t?.cwd??process.cwd()},entries:e,leafId:e.length>0?e[e.length-1].id:null},skippedLines:i}}return{data:ya(r.filter(pa),t),skippedLines:i}}function xa(e){let t=e;for(;t!==w(t);){if(S(T(t,`package.json`)))return t;t=w(t)}throw Error(`Could not find @gencode/cli package root`)}function Sa(){let e=xa(w(Ne(import.meta.url))),t=[T(e,`dist`,`export-html`),T(e,`src`,`export-html`)];for(let e of t)if(S(T(e,`template.html`)))return e;throw Error(`export-html template directory not found under ${e}`)}function Ca(e){let t=C.resolve(e),n=`${C.sep}.aimax${C.sep}`,r=t.indexOf(n);if(!(r<0))return t.slice(0,r)}function wa(e){let t=C.dirname(C.resolve(e));return C.basename(t)}async function Ta(e){let t=e.dataDir??(e.transcriptPath?Ca(e.transcriptPath):void 0),n=e.sessionId??(e.transcriptPath?wa(e.transcriptPath):void 0);return!t||!n?{}:ne(t,n,e.sessionPathOptions)}const Ea=new Map;function Da(e){let t=Ea.get(e);if(t!==void 0)return t;let n=Se(T(Sa(),e),`utf-8`);return Ea.set(e,n),n}function Oa(){let e=[];for(let[t,n]of Object.entries(la))e.push(`--${t}: ${n};`);return e.push(`--exportPageBg: ${ua};`),e.push(`--exportCardBg: ${da};`),e.push(`--exportInfoBg: ${fa};`),e.join(`
17
+ `)}function ka(e){return e.replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&amp;`;case`<`:return`&lt;`;case`>`:return`&gt;`;case`"`:return`&quot;`;case`'`:return`&#39;`;default:return e}})}function Aa(e){let t=Da(`template.html`),n=Da(`template.css`),r=Da(`template.js`),i=Buffer.from(JSON.stringify(e)).toString(`base64`),a=n.replace(`{{THEME_VARS}}`,Oa()).replace(`{{BODY_BG}}`,ua).replace(`{{CONTAINER_BG}}`,da).replace(`{{INFO_BG}}`,fa);return t.replace(`{{CSS}}`,a).replace(`{{JS}}`,r).replace(`{{SESSION_DATA}}`,i)}function ja(e,t){return t||`aimax-session-${Te(e,`.jsonl`)}.html`}function Ma(e,t){return`Skipped ${t} malformed JSONL line(s) while exporting ${e}`}function Na(e){for(let t of e)console.warn(t)}async function Pa(e,t){if(t.options?.includeSnapshots===!1)return e;let n=await Ta({dataDir:t.options?.dataDir,sessionId:t.options?.sessionId??e.header.id,transcriptPath:t.inputLabel,sessionPathOptions:t.options?.sessionPathOptions});return!n.systemPrompt&&!n.tools?.length?e:{...e,...n.systemPrompt?{systemPrompt:n.systemPrompt}:{},...n.tools?.length?{tools:n.tools}:{}}}async function Fa(e,t,n){let r=ba(e,{sessionId:n?.sessionId,cwd:n?.cwd}),i=r.skippedLines>0?[Ma(t,r.skippedLines)]:[],a=r.data;a=await Pa(a,{inputLabel:t,options:n});let o=Aa(a),s=ja(t,n?.outputPath);return we(s,o,`utf8`),{outputPath:s,warnings:i}}async function Ia(e,t){if(!S(e))throw Error(`File not found: ${e}`);return Fa(Se(e,`utf-8`),e,t)}async function La(e,t){let n=await Ia(e,t);return Na(n.warnings),n.outputPath}async function Ra(e,t,n){let r=pe(e,t,n);if(!S(r))throw Error(`Transcript not found: ${r}`);if((await ie(e,t,n)).length===0&&!Se(r,`utf-8`).trim())throw Error(`Nothing to export yet - transcript is empty`);let i=Se(r,`utf-8`),{outputPath:a,sessionId:o,cwd:s,dataDir:c,includeSnapshots:l,...u}=n??{};return Fa(i,r,{outputPath:n?.outputPath,sessionId:t,cwd:n?.cwd,dataDir:e,sessionPathOptions:u,includeSnapshots:n?.includeSnapshots})}async function za(e,t,n){let r=await Ra(e,t,n);return Na(r.warnings),r.outputPath}function Ba(e,t){let n=t.map(t=>{let n=S(T(e,t.fileName))?Ce(T(e,t.fileName)):void 0,r=n?`${Math.round(n.size/1024)} KB`:``,i=t.sourcePath?`<span class="muted">${ka(t.sourcePath)}</span>`:``;return`<tr><td><a href="${ka(t.fileName)}">${ka(t.sessionId)}</a></td><td>${r}</td><td>${i}</td></tr>`}).join(`
18
+ `),r=`<!DOCTYPE html>
19
+ <html lang="zh-CN">
20
+ <head>
21
+ <meta charset="UTF-8">
22
+ <title>AIMax Session Exports</title>
23
+ <style>
24
+ body { font-family: system-ui, sans-serif; margin: 2rem; background: #18181e; color: #d4d4d4; }
25
+ table { border-collapse: collapse; width: 100%; }
26
+ th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid #333; }
27
+ a { color: #81a2be; }
28
+ .muted { color: #808080; font-size: 0.85em; }
29
+ </style>
30
+ </head>
31
+ <body>
32
+ <h1>AIMax Session Exports (${t.length})</h1>
33
+ <table>
34
+ <thead><tr><th>Session</th><th>Size</th><th>Source</th></tr></thead>
35
+ <tbody>
36
+ ${n}
37
+ </tbody>
38
+ </table>
39
+ </body>
40
+ </html>`,i=T(e,`index.html`);return we(i,r,`utf8`),i}async function Va(e,t,n){xe(t,{recursive:!0});let r=fe(e,n),i=[],a=[],o=[],s=[],c;try{c=await Oe(r)}catch(e){throw e.code===`ENOENT`?Error(`Sessions directory not found: ${r}`):e}for(let r of c.sort()){let c=pe(e,r,n);if(!S(c)){a.push({sessionId:r,reason:`no transcript.jsonl`});continue}try{let a=T(t,`${r}.html`),l=await Ra(e,r,{...n,outputPath:a});o.push(...l.warnings),i.push({sessionId:r,path:l.outputPath}),s.push({sessionId:r,fileName:`${r}.html`,sourcePath:c})}catch(e){a.push({sessionId:r,reason:e.message})}}let l;return n?.writeIndex!==!1&&s.length>0&&(l=Ba(t,s)),{exported:i,skipped:a,warnings:o,indexPath:l}}async function Ha(e,t,n){xe(t,{recursive:!0});let r=[],i=[],a=[],o=[],s=[];for await(let t of De(e,{cwd:process.cwd()}))s.push(t);if(s.sort(),s.length===0)throw Error(`No files matched glob: ${e}`);for(let e of s){let n=E(e),s=Te(w(n));if(!S(n)){i.push({sessionId:s,reason:`file missing`});continue}try{let e=await Ia(n,{outputPath:T(t,`${s}.html`),sessionId:s,dataDir:Ca(n)});a.push(...e.warnings),r.push({sessionId:s,path:e.outputPath}),o.push({sessionId:s,fileName:`${s}.html`,sourcePath:n})}catch(e){i.push({sessionId:s,reason:e.message})}}let c;return n?.writeIndex!==!1&&o.length>0&&(c=Ba(t,o)),{exported:r,skipped:i,warnings:a,indexPath:c}}function Ua(e){e.command(`export-html`).description(`Export transcript.jsonl to standalone HTML files for browsing`).argument(`[transcript]`,`Path to transcript.jsonl (or use -d/-s, --all, or --glob)`).option(`-d, --data-dir <path>`,`Data directory containing .aimax/sessions`).option(`-s, --session-id <id>`,`Session ID under the data directory`).option(`--session-store <name>`,`Session store under .aimax (default: sessions)`).option(`-o, --output <path>`,`Output HTML path for a single export`).option(`--output-dir <path>`,`Output directory for batch export`).option(`--all`,`Export all sessions under --data-dir (requires --output-dir)`).option(`--glob <pattern>`,`Export transcripts matching a glob (requires --output-dir)`).option(`--no-index`,`Skip writing index.html in batch mode`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t,n)=>{let r=n.opts();try{if(r.glob){r.outputDir||(I(`error: --glob requires --output-dir`),process.exit(1)),Ga(await Ha(r.glob,E(r.outputDir),{writeIndex:!r.noIndex}));return}if(r.all){(!r.dataDir||!r.outputDir)&&(I(`error: --all requires --data-dir and --output-dir`),process.exit(1)),await U(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;Ga(await Va(r.dataDir,E(r.outputDir),{storeName:e,writeIndex:!r.noIndex}))});return}if(e){let t=E(e);S(t)||(I(`File not found: ${t}`),process.exit(1)),r.outputDir&&xe(E(r.outputDir),{recursive:!0});let n=await La(t,{outputPath:r.outputDir?T(E(r.outputDir),`${Te(w(t))}.html`):r.output});console.log(n);return}(!r.dataDir||!r.sessionId)&&(I(`error: specify <transcript.jsonl>, --glob, (-d --all --output-dir), or (-d -s)`),process.exit(1)),Wa(r.sessionId),await U(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;r.outputDir&&xe(E(r.outputDir),{recursive:!0});let t=r.outputDir?E(r.outputDir,`${r.sessionId}.html`):r.output,n=await za(r.dataDir,r.sessionId,{outputPath:t,storeName:e});console.log(n)})}catch(e){I(`Error exporting HTML: ${e.message}`),process.exit(1)}})}function Wa(e){if(e.includes(`..`)||e.startsWith(`/`))throw Error(`Invalid session id: ${e}`)}function Ga(e){for(let t of e.exported)console.log(t.path);for(let t of e.warnings??[])I(`warning: ${t}`);for(let t of e.skipped)I(`skipped ${t.sessionId}: ${t.reason}`);e.indexPath&&console.log(e.indexPath),console.log(`exported ${e.exported.length}, skipped ${e.skipped.length}`)}const Ka=e(import.meta.url)(`../package.json`);function qa(){return process.env.AIMAX_DATA_DIR||process.cwd()}function Ja(){let e=new t;return e.name(`aimax`).description(`AIMax CLI — runs agent tasks in a containerized environment`).version(Ka.version),mi(e),_r(e),qi(e),ea(e),hi(e),Ua(e),ca(e),zi(e),nn(e),wi(e),Ni(e,qa),Ri(e,qa),e}export{P as a,N as i,qa as n,st as o,fi as r,Ja as t};
package/dist/program.js CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./program-D2WYTclJ.js";export{t as createProgram,e as getDataDir};
1
+ import{n as e,t}from"./program-CcXFTFcR.js";export{t as createProgram,e as getDataDir};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gencode/cli",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aimax": "./dist/bin.js"
@@ -28,8 +28,8 @@
28
28
  "commander": "^14.0.3",
29
29
  "gensign-node": "latest",
30
30
  "log4js": "^6.9.1",
31
- "@gencode/agents": "0.14.0",
32
- "@gencode/shared": "0.3.0"
31
+ "@gencode/shared": "0.3.0",
32
+ "@gencode/agents": "0.15.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^22.0.0",
@@ -1,40 +0,0 @@
1
- import{createRequire as e}from"node:module";import{Command as t}from"commander";import{GoalConflictError as n,applyCliGoalBeforeRun as r,bootstrapMountLayout as i,buildAimaxGoalCliHelpExtra as a,buildResumeNarration as o,clearPendingUiTool as s,deleteGoal as c,ensureBootstrapMountLayout as l,exportSession as u,formatApprovalResolution as d,formatClarifyResolution as f,formatReviewResolution as p,hasBootstrapSentinel as m,initializePluginSystem as h,inspectSession as g,listAvailableSlashCommands as _,listSessionSummaries as v,loadPendingHitl as ee,loadPendingUiTool as te,loadSessionExportSnapshots as ne,loadSkillsWithPluginDirs as re,loadTranscript as ie,normalizePluginsConfig as ae,normalizeSessionStoreName as y,readGoal as b,resolveGoalObjective as oe,resolveMemoryProviderOrDefault as se,resolvePendingHitl as ce,resolvePendingUiTool as le,rewriteTranscript as ue,runAgent as de,sessionsDir as fe,transcriptPath as pe,updateGoal as me,writeGoal as he}from"@gencode/agents";import{formatTaskForDisplay as ge,isAgentDiagnosticEvent as _e,isHitlTool as ve,parseMatchedTextToResolution as ye,parseTextToResolution as be}from"@gencode/shared";import xe,{existsSync as x,mkdirSync as Se,readFileSync as Ce,statSync as we,writeFileSync as Te}from"node:fs";import S,{basename as Ee,dirname as C,join as w,resolve as T}from"node:path";import De from"log4js";import E,{glob as Oe,readdir as ke}from"node:fs/promises";import Ae from"node:os";import{execFile as je,execFileSync as Me}from"node:child_process";import Ne from"gensign-node";import{fileURLToPath as Pe}from"node:url";import{addAgent as Fe,addBinding as Ie,getAgentConfig as D,listAgents as Le,listBindings as Re,loadAgentsConfig as O,normalizeAgentId as ze,removeAgent as Be,removeBindings as Ve,resolveAgentDir as He,resolveDefaultAgentId as Ue,updateAgentIdentity as We}from"@gencode/agents/config";import{createHash as Ge,randomUUID as Ke}from"node:crypto";function qe(e){let t=new Intl.DateTimeFormat(`en-CA`,{timeZone:`Asia/Shanghai`,year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}).formatToParts(e);return Object.fromEntries(t.map(e=>[e.type,e.value]))}function Je(e=new Date){let t=qe(e),n=String(e.getMilliseconds()).padStart(3,`0`);return`${t.year}-${t.month}-${t.day} ${t.hour}:${t.minute}:${t.second}.${n}`}let k=function(e){return e.INFO=`INFO`,e.ERROR=`ERROR`,e.WARN=`WARN`,e}({}),A=null,j=[];function Ye(){return Je()}function Xe(e){if(!e)return``;let t=Object.entries(e).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${Ze(t)}`);return t.length>0?` ${t.join(` `)}`:``}function Ze(e){return JSON.stringify(Qe(e,new WeakSet))??`undefined`}function Qe(e,t){return typeof e==`bigint`?e.toString():e==null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:typeof e!=`object`&&typeof e!=`function`?String(e):t.has(e)?`[Circular]`:(t.add(e),Array.isArray(e)?e.map(e=>Qe(e,t)):Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0).map(([e,n])=>[e,Qe(n,t)])))}function $e(e){return S.join(e,`.aimax`)}function et(e){let t=e?.trim();return t&&t.replace(/[^A-Za-z0-9_.-]/g,`_`)||`no-message-${process.pid}`}function tt(e,t){let n=et(t?.messageId),r=t?.sessionStoreName?.trim()||`sessions`;return t?.sessionId?{runLogId:n,logDir:S.join($e(e),r,t.sessionId,`logs`,n)}:{runLogId:n,logDir:S.join($e(e),`logs`,n)}}function nt(e){return{appLogPath:S.join(e,`app.log`),errorLogPath:S.join(e,`errors.log`)}}function rt(e){let{appLogPath:t,errorLogPath:n}=nt(e);De.configure({appenders:{appFile:{type:`file`,filename:t,maxLogSize:5*1024*1024,backups:3,compress:!0,keepFileExt:!0,layout:{type:`messagePassThrough`}},errorFile:{type:`file`,filename:n,maxLogSize:5*1024*1024,backups:3,compress:!0,keepFileExt:!0,layout:{type:`messagePassThrough`}},errorsOnly:{type:`logLevelFilter`,appender:`errorFile`,level:`error`,maxLevel:`fatal`}},categories:{default:{appenders:[`appFile`,`errorsOnly`],level:`info`}}})}function it(e,t,n){return`[${Ye()}] [${e}] ${t}${Xe(n)}`}function at(e,t,n){try{process.stderr.write(`${it(e,t,n)}\n`)}catch{}}function ot(e,t,n){if(!A){j.push({level:e,message:t,context:n}),j.length>200&&(j=j.slice(-200)),at(e,t,n);return}let r=it(e,t,n),i=De.getLogger();if(e===k.ERROR){i.error(r);return}if(e===k.WARN){i.warn(r);return}i.info(r)}function M(e,t){let{logDir:n,runLogId:r}=tt(e,t);if(A?.dataDir===e&&A.runLogId===r&&A.logDir===n)return;xe.mkdirSync(n,{recursive:!0}),rt(n),A={dataDir:e,logDir:n,runLogId:r};let i=j;j=[];for(let e of i)ot(e.level,e.message,e.context)}function st(){return A?{...A}:null}async function ct(){await De.shutdown()}const N={info:(e,t)=>ot(k.INFO,e,t),warn:(e,t)=>ot(k.WARN,e,t),error:(e,t)=>ot(k.ERROR,e,t)};var lt=class{startTime;name;constructor(e){this.name=e,this.startTime=Date.now()}end(){let e=Date.now()-this.startTime;return N.info(`${this.name} completed in ${e}ms`),e}};function ut(e){if(typeof e==`string`)return e;let t=JSON.stringify(e);return t===void 0?String(e):t}const dt=new Set;function ft(e){return e instanceof Error?{name:e.name,message:e.message,code:e.code}:{message:String(e)}}function pt(e,t){try{N.warn(`CLI ${e} write failed; suppressing further ${e} writes`,{stream:e,...ft(t)})}catch{}}function mt(e,t){if(dt.has(e))return;let n=e===`stdout`?process.stdout:process.stderr;try{n.write(t)}catch(t){dt.add(e),pt(e,t)}}function ht(e){mt(`stdout`,e)}function P(e){mt(`stdout`,e+`
2
- `)}function F(e){mt(`stderr`,e+`
3
- `)}function I(e){switch(e.type){case`start`:P(`\n[start] ${e.message}`);break;case`text`:ht(e.text);break;case`stream_text_delta`:ht(e.text);break;case`bootstrap`:P(`\n[bootstrap:${e.phase}] ${e.dataDir}`);break;case`session_reset`:P(`\n[session:${e.action}] ${e.message}`);break;case`tool_start`:P(`\n[tool:${e.name}] ${JSON.stringify(e.input??{})}`);break;case`tool_end`:{let t=ut(e.output);P(`[tool:${e.name}] ${e.isError?`ERROR`:`OK`} ${t.slice(0,200)}`);break}case`compaction`:P(`\n[compaction${e.layer?`:${e.layer}`:``}] ${e.reason}${e.strategy?` (${e.strategy})`:``}`);break;case`skill_used`:P(`\n[skill] ${e.skillName} agent=${e.agent} task=${e.taskId}`);break;case`custom`:P(`\n[plugin:${e.pluginId}] ${e.name}${e.label?` ${e.label}`:``}${e.data?` ${JSON.stringify(e.data)}`:``}`);break;case`error`:F(`\n[error] ${e.message}`);break;case`diagnostic`:break;case`subagent_spawn`:P(`\n[subagent:spawn]${e.label?` "${e.label}"`:``} ${ge(e.task)}`);break;case`subagent_complete`:P(`[subagent:${e.status}] ${ge(e.task)}`);break;case`hitl_requested`:if(P(`\n[hitl:${e.request.kind}] ${e.request.title}`),P(` prompt: ${e.request.prompt}`),P(` requestId: ${e.request.requestId}`),e.request.input.mode===`choice`)for(let t of e.request.input.choices)P(` - [${t.id}] ${t.label}`);break;case`hitl_resumed`:P(`\n[hitl:resumed] requestId=${e.requestId} action=${e.resolution.action}`);break;case`hitl_expired`:P(`\n[hitl:expired] requestId=${e.requestId} reason=${e.reason}`);break;case`hitl_cancelled`:P(`\n[hitl:cancelled] requestId=${e.requestId}${e.reason?` reason=${e.reason}`:``}`);break;case`ui_tool_request`:P(`\n[ui-tool:${e.request.toolName}] ${e.request.outputSchema.title}`),P(` requestId: ${e.request.requestId}`),P(` toolCallId: ${e.request.toolCallId}`);break;case`ui_tool_result`:P(`\n[ui-tool:resumed] requestId=${e.requestId} tool=${e.toolName}`);break}}function gt(e,t){if(t===`json`){e&&P(JSON.stringify(e,null,2));return}P(`
4
- `),P(`session: ${e.sessionId}`),P(`duration: ${e.durationMs}ms`),P(`tokens: input=${e.usage.input} output=${e.usage.output} total=${e.usage.total}`),e.context&&(P(`context: ${e.context.snapshotPath}`),P(`tool-results: ${e.context.toolResultsDir}`)),e.error&&F(`error: ${e.error}`)}function _t(e,t){if(t===`json`){P(JSON.stringify(e,null,2));return}if(e.length===0){P(`No sessions found.`);return}for(let t of e){let e=t.createdAt?new Date(t.createdAt).toLocaleString():`unknown`,n=t.goalStatus?` [GOAL:${t.goalStatus}]`:` [GOAL:—]`;P(`${t.id} ${e} [${t.channel}]${n} ${t.title}`)}}function vt(e,t){if(t===`json`){P(JSON.stringify(e,null,2));return}P(`session: ${e.id}`),e.metadata&&(P(`title: ${e.metadata.title}`),P(`channel: ${e.metadata.channel}`),P(`created: ${e.metadata.createdAt}`),P(`updated: ${e.metadata.updatedAt}`)),P(`transcript: ${e.transcriptPath}`),P(`entries: ${e.transcriptEntryCount}`),P(`context: ${e.contextSnapshotPath}`),P(`session-memory: ${e.sessionMemoryPath}`),P(`collapse-log: ${e.collapseLogPath}`),P(`read-states: ${e.readStateCount}`),P(`tool-results: ${e.toolResultRefCount}`),P(`tool-results-dir: ${e.toolResultsDir}`)}function yt(e,t){if(t===`json`){P(JSON.stringify(e,null,2));return}P(`session: ${e.id}`),P(`transcript: ${e.paths.transcriptPath}`),P(`context: ${e.paths.contextSnapshotPath}`),P(`session-memory: ${e.paths.sessionMemoryPath}`),P(`collapse-log: ${e.paths.collapseLogPath}`),P(`tool-results-dir: ${e.paths.toolResultsDir}`),P(`transcript-entries: ${e.transcript.length}`),P(`read-states: ${e.context.readStates.length}`),P(`tool-results: ${e.context.toolResults.length}`),P(`collapse-spans: ${e.context.compaction.collapseSpans.length}`)}function bt(e,t){if(t===`json`){P(JSON.stringify(e,null,2));return}P(`Bootstrap completed.`),P(`dataDir: ${e.dataDir}`),P(`created dirs: ${e.createdDirs.length}`),P(`created files: ${e.createdFiles.length}`),P(`skipped dirs: ${e.skippedDirs.length}`),P(`skipped files: ${e.skippedFiles.length}`)}const xt=`.aimax`,St=`${xt}.pre-gocryptfs.`,Ct=[`app.log`,`errors.log`],wt=[`logs`],Tt=[`fusermount3`,`fusermount`,`umount`],Et=[{command:`fusermount3`,args:[`-u`],label:`fusermount3 -u`},{command:`fusermount3`,args:[`-uz`],label:`fusermount3 -uz`},{command:`fusermount`,args:[`-u`],label:`fusermount -u`},{command:`fusermount`,args:[`-uz`],label:`fusermount -uz`},{command:`umount`,args:[],label:`umount`},{command:`umount`,args:[`-l`],label:`umount -l`}];function Dt(e){return S.join(e,`.aimax.enc`)}function Ot(e){return S.join(e,xt)}function kt(e){return S.join(e,`${St}${process.pid}.${Date.now()}`)}function At(e){return S.join(e,`${xt}.plaintext-restore.${process.pid}.${Date.now()}`)}function jt(e){return e.replace(/\\([0-7]{3})/g,(e,t)=>String.fromCharCode(Number.parseInt(t,8)))}async function L(e){try{let t=await Pt.read(),n=S.resolve(e);for(let e of t.split(`
5
- `)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&S.resolve(jt(t[4]??``))===n)return!0}return!1}catch{return!1}}function Mt(e){try{let t=xe.readFileSync(`/proc/self/mountinfo`,`utf-8`),n=S.resolve(e);for(let e of t.split(`
6
- `)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&S.resolve(jt(t[4]??``))===n)return!0}return!1}catch{return!1}}async function Nt(){return await E.readFile(`/proc/self/mountinfo`,`utf-8`)}const Pt={read:Nt};async function R(e){try{return await E.stat(e),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function z(e){await E.mkdir(e,{recursive:!0})}async function Ft(e){if(await z(e),(await E.readdir(e)).length>0)throw Error(`Refusing to mount encrypted .aimax over non-empty directory: ${e}. Clear stale plaintext files or disable --encrypt-sessions for this run.`)}async function It(e){return await R(e)?(await E.readdir(e)).length===0:!0}async function B(e){if(await R(e))return(await E.readdir(e)).length}async function Lt(e){if(!await R(e))return!1;let t=await E.readdir(e,{withFileTypes:!0});for(let e of t)if(!(e.isDirectory()&&wt.includes(e.name))&&!(e.isFile()&&Ct.some(t=>e.name.startsWith(t))))return!0;return!1}async function Rt(e){let t=await E.readdir(e,{withFileTypes:!0});for(let n of t){if(n.isDirectory()&&wt.includes(n.name)){await E.rm(S.join(e,n.name),{recursive:!0,force:!0}).catch(()=>{});continue}n.isFile()&&Ct.some(e=>n.name.startsWith(e))&&await E.rm(S.join(e,n.name),{force:!0}).catch(()=>{})}}async function zt(e){if(!await R(S.join(e,`gocryptfs.conf`)))throw Error(`Encrypted .aimax directory exists but is not initialized: ${e}. Remove the incomplete .aimax.enc directory or restore it from backup before retrying --encrypt-sessions.`)}async function Bt(e){return(await E.readdir(e,{withFileTypes:!0})).filter(e=>e.isDirectory()&&e.name.startsWith(St)).map(t=>S.join(e,t.name)).sort()}async function Vt(e,t){if(!await R(t))return null;let n=kt(e);return N.info(`--encrypt-sessions moving plaintext .aimax aside before migration`,{plainDir:t,backupDir:n}),await E.rename(t,n),n}async function V(e,t,n){N.info(`--encrypt-sessions copying plaintext backup into encrypted mount`,{backupDir:e,plainDir:t,force:n}),await E.cp(e,t,{recursive:!0,force:n})}async function Ht(e,t){if(e.length===0)return[];await z(t);let n=[];for(let r of e)await R(r)&&(await V(r,t,!0),await E.rm(r,{recursive:!0,force:!0}),N.info(`--encrypt-sessions restored interrupted plaintext backup after failed migration`,{backupDir:r,plainDir:t}),n.push(r));return n}async function Ut(e){let t=Dt(e),n=Ot(e),r=await R(t);if(!r)return;let i=r&&await R(S.join(t,`gocryptfs.conf`)),a=await R(n),o=a?await L(n):!1,s=await It(n);if(N.info(`plaintext .aimax restore check for disabled --encrypt-sessions`,{dataDir:e,encryptedDir:t,plainDir:n,encryptedDirExists:r,encryptedDirInitialized:i,plainDirExists:a,plainDirMountPoint:o,plainDirEntryCount:await B(n)}),!i){N.warn(`plaintext .aimax restore skipped because .aimax.enc is not initialized`,{encryptedDir:t,plainDir:n}),await z(n);return}if(o){N.warn(`plaintext .aimax restore skipped because .aimax is already a mount point`,{plainDir:n,encryptedDir:t});return}if(await Lt(n)){N.info(`plaintext .aimax restore skipped because plaintext .aimax already contains data`,{plainDir:n,encryptedDir:t,plainDirEntryCount:await B(n)});return}s||(N.info(`plaintext .aimax clearing ephemeral files before restore`,{plainDir:n,encryptedDir:t,plainDirEntryCount:await B(n)}),await Rt(n));try{await Kt()}catch(e){N.warn(`plaintext .aimax restore unavailable; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t}),await z(n);return}let c=At(e),l=!1;try{await Ft(n),await qt(t,n),l=!0,await E.rm(c,{recursive:!0,force:!0}),await z(c),await E.cp(n,c,{recursive:!0,force:!0}),N.info(`plaintext .aimax restore copied encrypted history to staging directory`,{plainDir:n,encryptedDir:t,restoreDir:c,restoredEntryCount:await B(c)}),await Yt(n),l=!1,await E.rm(n,{recursive:!0,force:!0}),await E.rename(c,n),N.info(`plaintext .aimax restore completed for disabled --encrypt-sessions`,{plainDir:n,encryptedDir:t})}catch(e){l&&await Yt(n).catch(e=>{N.warn(`plaintext .aimax restore failed to unmount during rollback`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}),await E.rm(c,{recursive:!0,force:!0}).catch(()=>{}),await z(n).catch(()=>{}),N.warn(`plaintext .aimax restore failed; continuing with existing plaintext .aimax`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}}async function Wt(e){let t=S.join(Ae.tmpdir(),`aimax-gocryptfs-pass.${process.pid}.${Date.now()}`);await E.writeFile(t,`wizard_aimax@2026
7
- `,{mode:384});try{return await e(t)}finally{await E.rm(t,{force:!0})}}async function Gt(e){let t=e.includes(`-init`)?`init`:`mount`;N.info(`--encrypt-sessions starting gocryptfs ${t}`);try{await $t(`gocryptfs`,e),N.info(`--encrypt-sessions completed gocryptfs ${t}`)}catch(n){let r=n instanceof Error?n.message:String(n);throw N.warn(`--encrypt-sessions failed gocryptfs ${t}`,{error:r}),Error(`gocryptfs ${e.join(` `)} failed: ${r}`)}}async function Kt(){N.info(`--encrypt-sessions checking encryption dependencies`),await tn(`gocryptfs`,`required for --encrypt-sessions`),N.info(`--encrypt-sessions dependency available`,{command:`gocryptfs`});for(let e of Tt)if(await en(e)){N.info(`--encrypt-sessions unmount dependency available`,{command:e});return}throw Error(`--encrypt-sessions requires one of ${Tt.join(`, `)} to be installed for secure unmount cleanup.`)}async function qt(e,t){N.info(`--encrypt-sessions mounting encrypted .aimax`,{encryptedDir:e,plainDir:t}),await Wt(async n=>{await Gt([`-q`,`-passfile`,n,e,t])})}async function Jt(e){N.info(`--encrypt-sessions initializing encrypted .aimax directory`,{encryptedDir:e}),await Wt(async t=>{await Gt([`-q`,`-init`,`-passfile`,t,e])})}async function Yt(e){let t=[];N.info(`--encrypt-sessions unmounting encrypted .aimax`,{plainDir:e});for(let n of Et)try{if(N.info(`--encrypt-sessions attempting encrypted .aimax unmount`,{command:n.label,plainDir:e}),await $t(n.command,[...n.args,e]),!await L(e)){N.info(`--encrypt-sessions unmounted encrypted .aimax`,{command:n.label,plainDir:e});return}let r=`${n.label} returned success but ${e} is still mounted`;t.push(r),N.warn(`--encrypt-sessions unmount command returned success but mountpoint remains`,{command:n.label,plainDir:e})}catch(r){let i=nn(n.label,r);t.push(i),N.warn(`--encrypt-sessions unmount attempt failed`,{command:n.label,plainDir:e,error:r instanceof Error?r.message:String(r)})}throw Error(`Failed to unmount ${e}: ${t.join(`; `)}`)}function Xt(e){for(let t of Et)try{if(Me(t.command,[...t.args,e],{stdio:`ignore`}),!Mt(e))return}catch{}}function Zt(e){let t=!1,n=()=>{t||(t=!0,Xt(e))},r=()=>n(),i=()=>{n(),process.exit(130)},a=()=>{n(),process.exit(143)};return process.once(`exit`,r),process.once(`SIGINT`,i),process.once(`SIGTERM`,a),{release(){process.removeListener(`exit`,r),process.removeListener(`SIGINT`,i),process.removeListener(`SIGTERM`,a)}}}async function Qt(e){let t=Dt(e),n=Ot(e),r=await R(n),i=await R(t),a=i&&await R(S.join(t,`gocryptfs.conf`)),o=r?await L(n):!1;N.info(`--encrypt-sessions preparing encrypted .aimax mount`,{dataDir:e,encryptedDir:t,plainDir:n,plainDirExists:r,encryptedDirExists:i,encryptedDirInitialized:a,plainDirMountPoint:o,plainDirEntryCount:await B(n),encryptedDirEntryCount:await B(t)});let s=()=>({mounted:!1,plainDir:n,encryptedDir:t,async cleanup(){}});try{await Kt()}catch(e){return N.warn(`--encrypt-sessions is unavailable; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e)}),await z(n),s()}if(await L(n))return N.warn(`--encrypt-sessions found existing .aimax mount; continuing without taking ownership`,{plainDir:n}),s();let c=null,l=[],u=null,d=null,f=!1;try{if(l=await Bt(e),l.length>0&&N.warn(`--encrypt-sessions found interrupted pre-gocryptfs migration backups`,{count:l.length}),!await R(t))if(N.info(`--encrypt-sessions encrypted .aimax directory does not exist; starting first-time migration`,{encryptedDir:t,plainDir:n,resumedBackupCount:l.length}),l.length>0?u=await Vt(e,n):c=await Vt(e,n),await z(t),await Jt(t),await z(n),await qt(t,n),f=!0,d=Zt(n),N.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),l.length>0){for(let e of l)await V(e,n,!0);u&&=(await V(u,n,!1),await E.rm(u,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:u}),null);for(let e of l)await E.rm(e,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await V(c,n,!0),await E.rm(c,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:c}),null);else if(N.info(`--encrypt-sessions encrypted .aimax directory exists; mounting existing encrypted data`,{encryptedDir:t,plainDir:n,resumedBackupCount:l.length,plainDirEntryCount:await B(n)}),await zt(t),l.length>0?u=await Vt(e,n):await It(n)||(c=await Vt(e,n)),await Ft(n),await qt(t,n),f=!0,d=Zt(n),N.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),l.length>0){for(let e of l)await V(e,n,!0);u&&=(await V(u,n,!1),await E.rm(u,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:u}),null);for(let e of l)await E.rm(e,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await V(c,n,!0),await E.rm(c,{recursive:!0,force:!0}),N.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:c}),null);return N.info(`--encrypt-sessions prepared encrypted .aimax mount result`,{mounted:f,plainDir:n,encryptedDir:t,plainDirMountPoint:await L(n),plainDirEntryCount:await B(n),encryptedDirEntryCount:await B(t)}),{mounted:f,plainDir:n,encryptedDir:t,async cleanup(){if(d?.release(),!f){N.info(`--encrypt-sessions cleanup skipped because encrypted .aimax is not mounted`,{plainDir:n,encryptedDir:t});return}f=!1,N.info(`--encrypt-sessions cleanup started`,{plainDir:n,encryptedDir:t});try{await Yt(n),N.info(`--encrypt-sessions cleanup completed`,{plainDir:n,encryptedDir:t})}catch(e){N.warn(`--encrypt-sessions failed to unmount encrypted .aimax; continuing shutdown`,{error:e instanceof Error?e.message:String(e)})}}}}catch(e){d?.release(),f&&await Yt(n).catch(e=>{N.warn(`--encrypt-sessions failed to unmount during mount rollback`,{error:e instanceof Error?e.message:String(e),plainDir:n,encryptedDir:t})}),c&&await R(c)&&await It(n)&&(await E.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await E.rename(c,n).catch(()=>{}),N.info(`--encrypt-sessions restored plaintext backup after failed migration`,{backupDir:c,plainDir:n})),u&&await R(u)&&await It(n)&&(await E.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await E.rename(u,n).catch(()=>{}),N.info(`--encrypt-sessions restored residual plaintext backup after failed migration`,{backupDir:u,plainDir:n}));let r=await Ht(l,n).catch(e=>(N.warn(`--encrypt-sessions failed to restore interrupted plaintext backups after failed migration`,{error:e instanceof Error?e.message:String(e),plainDir:n,backupCount:l.length}),[]));return l=l.filter(e=>!r.includes(e)),N.warn(`--encrypt-sessions failed; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e),mountedBeforeFailure:f,plainDir:n,encryptedDir:t,backupDir:c,residualPlainBackupDir:u,resumedBackupCount:l.length}),await z(n),s()}}async function H(e,t,n){if(!t.encryptSessions)return await Ut(e),n();N.info(`--encrypt-sessions wrapper starting encrypted .aimax preparation`,{dataDir:e});let r=await Qt(e);N.info(`--encrypt-sessions wrapper prepared encrypted .aimax state`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir});try{return N.info(`--encrypt-sessions wrapper entering protected operation`,{dataDir:e,mounted:r.mounted}),await n(r)}finally{N.info(`--encrypt-sessions wrapper starting cleanup`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir}),await r.cleanup(),N.info(`--encrypt-sessions wrapper finished cleanup`,{dataDir:e,mounted:r.mounted,plainDir:r.plainDir,encryptedDir:r.encryptedDir})}}async function $t(e,t){await new Promise((n,r)=>{je(e,t,{encoding:`utf-8`},e=>{if(e){r(e);return}n()})})}async function en(e){try{return await $t(`sh`,[`-c`,`command -v "${e}" >/dev/null 2>&1`]),!0}catch{return!1}}async function tn(e,t){if(!await en(e))throw Error(`--encrypt-sessions requires ${e}: ${t}.`)}function nn(e,t){return`${e} failed: ${t instanceof Error?t.message:String(t)}`}function rn(e){e.command(`bootstrap`).description(`Initialize the data directory with required directories and templates`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{bt(await H(e.dataDir,e,async()=>i(e.dataDir)),t)}catch(e){F(`Error bootstrapping data directory: ${e.message}`),process.exit(1)}})}function an(e){return Ne.sm4_encrypt_ecb(e)}function on(e){return an(e)}const sn=[`minimal`,`low`,`medium`,`high`,`xhigh`];function cn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(sn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of ${sn.join(`, `)}.`)}}function ln(e={}){let t=un(e.apiFormat??process.env.AIMAX_API_FORMAT),n=e.baseUrl??process.env.AIMAX_BASE_URL,r=process.env.AIMAX_AUTH_TOKEN,i=e.authToken?on(e.authToken):r?on(r):e.apiKey??process.env.AIMAX_API_KEY,a=e.model??process.env.AIMAX_MODEL,o=[];if(n||o.push(`--base-url / AIMAX_BASE_URL`),i||o.push(`--api-key / AIMAX_API_KEY`),a||o.push(`--model / AIMAX_MODEL`),o.length>0)throw Error(`Missing required LLM configuration: ${o.join(`, `)}`);return{apiFormat:t,baseUrl:n,apiKey:i,model:a,contextWindow:e.contextWindow??(process.env.AIMAX_CONTEXT_WINDOW?Number(process.env.AIMAX_CONTEXT_WINDOW):void 0),flashModel:e.flashModel??process.env.AIMAX_FLASH_MODEL,thinking:e.thinking===void 0?cn(process.env.AIMAX_THINKING,`AIMAX_THINKING`):cn(e.thinking,`--thinking`)}}function un(e){if(!e||e===`openai-completions`||e===`anthropic-messages`)return e;throw Error(`Unsupported LLM API format: ${e}`)}const dn=[`off`,`fallback`];function fn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function pn(e,t){if(e===void 0)return;let n=e.trim();if(!n)return;let r=Number(n);if(!Number.isFinite(r))throw Error(`Invalid ${t}: ${e}. Must be a number.`);return r}function mn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(dn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of ${dn.join(`, `)}.`)}}function hn(){return[`AIMAX_MEMORY_KC_ENABLED`,`AIMAX_MEMORY_KC_BASE_URL`,`AIMAX_MEMORY_KC_BASE_PATH`,`AIMAX_MEMORY_KC_AUTH_TOKEN`,`AIMAX_MEMORY_KC_SEARCH_MODE`,`AIMAX_MEMORY_KC_TOP_K`,`AIMAX_MEMORY_KC_SCORE_THRESHOLD`,`AIMAX_MEMORY_KC_TIMEOUT_MS`,`AIMAX_MEMORY_KC_SYNC_ENABLED`].some(e=>process.env[e]!==void 0)}function gn(e){return Object.values(e).some(e=>e!==void 0)}function _n(e={}){if(!(!gn(e)&&!hn()))return{knowledgeController:{enabled:e.kcEnabled??fn(process.env.AIMAX_MEMORY_KC_ENABLED,`AIMAX_MEMORY_KC_ENABLED`),baseUrl:e.kcBaseUrl??process.env.AIMAX_MEMORY_KC_BASE_URL,basePath:e.kcBasePath??process.env.AIMAX_MEMORY_KC_BASE_PATH,authToken:e.kcAuthToken??process.env.AIMAX_MEMORY_KC_AUTH_TOKEN,searchMode:e.kcSearchMode===void 0?mn(process.env.AIMAX_MEMORY_KC_SEARCH_MODE,`AIMAX_MEMORY_KC_SEARCH_MODE`)??`off`:mn(e.kcSearchMode,`kcSearchMode`),topK:e.kcTopK??pn(process.env.AIMAX_MEMORY_KC_TOP_K,`AIMAX_MEMORY_KC_TOP_K`),scoreThreshold:e.kcScoreThreshold??pn(process.env.AIMAX_MEMORY_KC_SCORE_THRESHOLD,`AIMAX_MEMORY_KC_SCORE_THRESHOLD`),timeoutMs:e.kcTimeoutMs??pn(process.env.AIMAX_MEMORY_KC_TIMEOUT_MS,`AIMAX_MEMORY_KC_TIMEOUT_MS`),syncEnabled:e.kcSyncEnabled??fn(process.env.AIMAX_MEMORY_KC_SYNC_ENABLED,`AIMAX_MEMORY_KC_SYNC_ENABLED`)}}}function vn(e,t){return t?S.resolve(t):S.join(e,`.aimax`,`plugins.json`)}async function U(e,t){let n=vn(e,t);try{let e=await E.readFile(n,`utf-8`);return JSON.parse(e)}catch(e){if(e.code===`ENOENT`)return;throw e}}async function W(e,t,n){let r=vn(e,n);await E.mkdir(S.dirname(r),{recursive:!0}),await E.writeFile(r,JSON.stringify(t,null,2),`utf-8`)}function G(e){return typeof e==`object`&&!!e}function yn(e){return G(e)&&e.type===`text`&&typeof e.text==`string`&&(e.textSignature===void 0||typeof e.textSignature==`string`)}function bn(e){return G(e)&&e.type===`image`&&typeof e.data==`string`&&typeof e.mimeType==`string`}function xn(e){return G(e)&&e.type===`thinking`&&typeof e.thinking==`string`&&(e.thinkingSignature===void 0||typeof e.thinkingSignature==`string`)&&(e.redacted===void 0||typeof e.redacted==`boolean`)}function Sn(e){return G(e)&&e.type===`toolCall`&&typeof e.id==`string`&&typeof e.name==`string`&&G(e.arguments)&&(e.thoughtSignature===void 0||typeof e.thoughtSignature==`string`)}function Cn(e){return typeof e==`string`||Array.isArray(e)&&e.every(e=>yn(e)||bn(e))}function wn(e){return Array.isArray(e)&&e.every(e=>yn(e)||xn(e)||Sn(e))}function Tn(e){return G(e)&&typeof e.input==`number`&&typeof e.output==`number`&&typeof e.cacheRead==`number`&&typeof e.cacheWrite==`number`&&typeof e.totalTokens==`number`&&G(e.cost)&&typeof e.cost.input==`number`&&typeof e.cost.output==`number`&&typeof e.cost.cacheRead==`number`&&typeof e.cost.cacheWrite==`number`&&typeof e.cost.total==`number`}function En(e){return!G(e)||typeof e.role!=`string`?!1:e.role===`user`?Cn(e.content):e.role===`assistant`?wn(e.content)&&typeof e.api==`string`&&typeof e.provider==`string`&&typeof e.model==`string`&&Tn(e.usage)&&(e.stopReason===`stop`||e.stopReason===`length`||e.stopReason===`toolUse`||e.stopReason===`error`||e.stopReason===`aborted`)&&(e.errorMessage===void 0||typeof e.errorMessage==`string`):e.role===`toolResult`?typeof e.toolCallId==`string`&&typeof e.toolName==`string`&&Array.isArray(e.content)&&e.content.every(e=>yn(e)||bn(e))&&typeof e.isError==`boolean`:!1}async function Dn(e){let t;try{t=await E.readFile(e,`utf-8`)}catch(e){throw Error(`Failed to read message file: ${e.message}`)}let n;try{n=JSON.parse(t)}catch(e){throw Error(`Invalid JSON in message file: ${e.message}`)}let r=Array.isArray(n)?n:[n];if(r.length===0||!r.every(e=>En(e)))throw Error(`Message file must contain one Message object or an array of Message objects`);return r}async function On(e){if(!!e.message==!!e.fromFile)throw Error(`Exactly one of --message or --from-file must be provided`);return e.fromFile?{kind:`messages`,messages:await Dn(e.fromFile)}:{kind:`text`,message:e.message}}var kn=class{constructor(e){this.sinks=e}async send(e){await Promise.allSettled(this.sinks.map(async t=>{await t.send(e)}))}async close(){await Promise.allSettled(this.sinks.map(async e=>{await e.close()}))}},An=class{constructor(e){this.url=e}async send(e){await this.post(this.toPayload(e))}async close(){}async post(e){let t=Date.now(),n=jn(e);N.info(`sending callback event`,{callbackUrl:this.url,...n});let r=new AbortController,i=!1,a=setTimeout(()=>{i=!0,r.abort()},5e3);try{let a=await fetch(this.url,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e),signal:r.signal}),o=Date.now()-t;if(!a.ok){N.error(`callback event failed`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,timedOut:i,...n});return}N.info(`callback event delivered`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,...n})}catch(e){let r=Date.now()-t;N.error(`callback event failed`,{callbackUrl:this.url,error:e instanceof Error?e.message:String(e),durationMs:r,timedOut:i,...n})}finally{clearTimeout(a)}}toPayload(e){switch(e.type){case`start`:return e;case`progress`:return e;case`done`:return e;case`error`:return e;case`session_reset`:return e;case`hitl`:return e;case`title_updated`:return e;default:{let t=e;throw Error(`Unsupported callback event: ${JSON.stringify(t)}`)}}}};function jn(e){return{eventType:e.type,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,progressType:e.type===`progress`?e.event.type:void 0}}function Mn(e,t){if(t.kind===`none`)return e;let n=new URL(e);return n.searchParams.set(`authToken`,t.token),n.toString()}const Nn=5e3,Pn=5e3;function Fn(){let e=globalThis.WebSocket;if(!e)throw Error(`WebSocket is not available in this runtime`);return e}function In(e){return e?{kind:`query_token`,token:e}:{kind:`none`}}function Ln(e,t,n){if(typeof e.once==`function`){e.once(t,n);return}if(typeof e.addEventListener==`function`&&typeof e.removeEventListener==`function`){let r=(...i)=>{e.removeEventListener?.(t,r),n(...i)};e.addEventListener(t,r);return}throw Error(`WebSocket does not support one-time listener registration for "${t}"`)}function Rn(e,t,n){if(typeof e.on==`function`){e.on(t,n);return}if(typeof e.addEventListener==`function`){e.addEventListener(t,n);return}throw Error(`WebSocket does not support listener registration for "${t}"`)}var zn=class{socket=null;connectPromise=null;enabled=!0;textSequence=0;constructor(e,t,n){this.url=e,this.events=t,this.authToken=n}async send(e){let t=this.toEnvelope(e);if(!(!t||!this.enabled))try{await Bn(this.ensureConnected(),Nn,`WebSocket connection timed out after ${Nn}ms`);let e=Fn();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){N.warn(`websocket sink disabled after send failure`,{url:this.url,error:e instanceof Error?e.message:String(e)}),this.enabled=!1}}async sendTextDelta(e){if(!this.enabled||!this.events.has(`text`))return;this.textSequence+=1;let t={type:`text`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:new Date().toISOString(),sequence:this.textSequence,delta:e.text};try{await Bn(this.ensureConnected(),Nn,`WebSocket connection timed out after ${Nn}ms`);let e=Fn();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){N.warn(`websocket sink disabled after text delta send failure`,{url:this.url,error:e instanceof Error?e.message:String(e)}),this.enabled=!1}}async close(){this.enabled=!1;let e=this.socket;if(this.socket=null,this.connectPromise=null,!e)return;let t=Fn();if(e.readyState!==t.CLOSED)try{await Bn(new Promise(t=>{Ln(e,`close`,()=>t()),e.close()}),Pn,`WebSocket close timed out after ${Pn}ms`)}catch(e){N.warn(`websocket sink close timed out`,{url:this.url,error:e instanceof Error?e.message:String(e)})}}async ensureConnected(){if(!this.enabled)return;let e=Fn();if(this.socket&&this.socket.readyState===e.OPEN)return;if(this.connectPromise){await this.connectPromise;return}let t=new e(Mn(this.url,In(this.authToken)));this.connectPromise=new Promise((e,n)=>{Ln(t,`open`,()=>{this.socket=t,Rn(t,`close`,()=>{this.socket===t&&(this.socket=null)}),e()}),Ln(t,`error`,e=>{n(e)})});try{await this.connectPromise}finally{this.connectPromise=null}}toEnvelope(e){let t=new Date().toISOString();switch(e.type){case`start`:return this.events.has(`start`)?{...e,timestamp:t}:null;case`done`:return this.events.has(`done`)?{...e,timestamp:t}:null;case`error`:return this.events.has(`error`)?{...e,timestamp:t}:null;case`hitl`:return this.events.has(`hitl`)?{...e,timestamp:t}:null;case`title_updated`:return this.events.has(`title_updated`)?{type:`title_updated`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,title:e.title}:null;case`session_reset`:return null;case`progress`:return e.event.type===`text`?this.events.has(`text`)?(this.textSequence+=1,{type:`text`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,sequence:this.textSequence,delta:e.event.text}):null:e.event.type===`stream_text_delta`||!this.events.has(`progress`)?null:{type:`progress`,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,timestamp:t,event:e.event};default:{let t=e;throw Error(`Unsupported stream event: ${JSON.stringify(t)}`)}}}};function Bn(e,t,n){return new Promise((r,i)=>{let a=setTimeout(()=>i(Error(n)),t);e.then(e=>{clearTimeout(a),r(e)},e=>{clearTimeout(a),i(e)})})}function Vn(e){let t=e.trim();if(!t)throw Error(`Goal objective cannot be empty`);return t}function Hn(e,t){if(t.action===`unchanged`)return null;if(t.action===`created`||t.action===`replaced`)return t.action;if(e?.status!==t.goal.status)switch(t.goal.status){case`active`:return e?.status===`paused`?`resumed`:`updated`;case`paused`:return`paused`;case`complete`:return`completed`;case`budget_limited`:return`budget_limited`;default:return`updated`}return`updated`}function Un(e){let t=Hn(e.before,e.result);return t?{type:`goal_updated`,sessionId:e.sessionId,action:t,goalId:e.result.goal.goalId,goalStatus:e.result.goal.status}:null}function Wn(e){let t=e?.packageRoot??Gn(),n=S.join(t,`models`),r=S.join(n,...`Xenova/bge-small-zh-v1.5`.split(`/`));if(xe.existsSync(S.join(r,`config.json`)))return n}function Gn(){let e=S.dirname(Pe(import.meta.url));return S.basename(e)===`src`||S.basename(e)===`dist`?S.resolve(e,`..`):e}function Kn(e){return{text:e.text,usage:e.usage,durationMs:e.durationMs,...e.error?{error:e.error}:{},...e.paused?{paused:e.paused}:{},...e.uiToolPending?{uiToolPending:e.uiToolPending}:{},...e.artifacts&&e.artifacts.length>0?{artifacts:e.artifacts}:{}}}function qn(e){if(!e?.trim())return;let t=new Set,n=[];for(let r of e.split(`,`)){let e=r.trim();if(!e)continue;let i=Jn(e);if(!i)throw Error(`Invalid --artifacts-url-whitelist entry: ${e}. Expected a domain or URL with a valid hostname.`);t.has(i)||(t.add(i),n.push(i))}return n.length>0?n:void 0}function Jn(e){try{let t=/^[a-z][a-z\d+.-]*:\/\//i.test(e)?e:`http://${e}`,n=new URL(t);return n.username||n.password?null:n.hostname.trim().toLowerCase()||null}catch{return null}}const Yn=[`start`,`text`,`done`,`error`,`hitl`],Xn=[`off`,`gate`,`dry_run`,`write`];function Zn(e){if(!e?.trim())return new Set(Yn);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl`);r.add(e)}return r.size>0?r:new Set(Yn)}function Qn(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=Wn();return t?{embeddingModelDir:t}:void 0}function $n(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir or AIMAX_DATA_DIR`);return t}function er(e){return e?.trim()||void 0}function tr(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!S.isAbsolute(t)){let n=e.systemAgentsDir===void 0?`AIMAX_SYSTEM_AGENTS_DIR`:`--system-agents-dir`;throw Error(`Invalid ${n}: ${t}. Path must be absolute.`)}return t}}function nr(e){return e?y(e):void 0}function rr(e){if(!e?.trim())return[];let t=e.split(`,`).map(e=>e.trim()).filter(Boolean),n=new Set,r=[];for(let e of t){if(!S.isAbsolute(e))throw Error(`Invalid --skillsLoadPaths entry: ${e}. Each path must be absolute.`);n.has(e)||(n.add(e),r.push(e))}return r}function ir(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function ar(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(Xn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function or(e){let t=e.autoSkillsLoadEnabled===void 0?ir(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):ir(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?ar(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):ar(e.autoSkillsReviewMode,`--auto-skills-review-mode`),r={};return t!==void 0&&(r.load={enabled:t}),n!==void 0&&(r.review={mode:n}),r.load||r.review?r:void 0}function sr(e,t){if(e.inputText&&t){let n=be(e.inputText,t);return n.submittedBy={userId:e.user,channel:e.channel??`IM`},n}if(!e.inputJson&&!e.inputText)throw Error(`Either --input-json or --input-text must be provided for the resume command`);try{let t=JSON.parse(e.inputJson);return{requestId:e.requestId,sessionId:e.sessionId,action:t.action??`submit`,values:t.values,submittedBy:t.submittedBy,idempotencyKey:t.idempotencyKey,submittedAt:t.submittedAt??new Date().toISOString()}}catch(e){throw Error(`Invalid --input-json: ${e.message}`)}}function cr(e,t){if(!e.inputJson)throw Error(`UI tool resume requires --input-json`);try{let n=JSON.parse(e.inputJson),r=n&&typeof n==`object`&&`values`in n&&n.values&&typeof n.values==`object`&&!Array.isArray(n.values)?n.values:n;return{requestId:t.request.requestId,sessionId:t.sessionId,toolCallId:t.request.toolCallId,toolName:t.request.toolName,values:r,submittedAt:new Date().toISOString()}}catch(e){throw Error(`Invalid --input-json: ${e.message}`)}}async function lr(e){let t=await ie(e.dataDir,e.sessionId,{storeName:e.sessionStoreName,encryptSessions:e.encryptSessions});for(let n=t.length-1;n>=0;--n){let r=t[n];if(r?.role!==`assistant`||!Array.isArray(r.toolCalls))continue;let i=r.toolCalls.find(t=>t.id===e.toolCallId&&t.name===e.toolName);if(i)return i.arguments}}async function ur(e){let t=$n(e),n=e.channel??`WEB`,r=ln({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow?Number(e.contextWindow):void 0,flashModel:e.flashModel,thinking:e.thinking});return{dataDir:t,systemAgentsDir:tr(e),channel:n,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:r,skillsLoadPaths:rr(e.skillsLoadPaths),artifactsUrlWhitelist:qn(e.artifactsUrlWhitelist),autoSkills:or(e)}}function dr(e){let t=[],n=null;return e.callbackUrl&&t.push(new An(e.callbackUrl)),e.streamUrl&&(n=new zn(e.streamUrl,Zn(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new kn(t),websocketSink:n}}async function fr(e){let{dataDir:t,sessionId:n,sessionStoreName:r,toolCallId:i,toolName:a,resolution:o,encryptSessions:s}=e;if(!i||!a||!ve(a))return;let c=(e,t)=>{switch(e){case`request_approval`:return d(t);case`clarify`:return f(t);case`request_review`:return p(t);default:return JSON.stringify({action:t.action,values:t.values})}};await ue(t,n,e=>{let t=e.findIndex(e=>e.role===`tool_result`&&e.toolCallId===i&&e.toolName===a);if(t===-1)return e;let n=e.slice(0,t+1);return n[t]={...n[t],content:c(a,o),isError:!1},n},{storeName:r,encryptSessions:s})}async function pr(e){let{dataDir:t,sessionId:n,sessionStoreName:r,result:i,encryptSessions:a}=e;await ue(t,n,e=>{let t=e.findIndex(e=>e.role===`assistant`&&Array.isArray(e.toolCalls)&&e.toolCalls.some(e=>e.id===i.toolCallId&&e.name===i.toolName));if(t===-1)return e;let n=e.slice(0,t+1);return n.push({role:`tool_result`,toolCallId:i.toolCallId,toolName:i.toolName,content:JSON.stringify({submitted:!0,values:i.values}),isError:!1,timestamp:i.submittedAt}),n},{storeName:r,encryptSessions:a})}function mr(){let e=_n();return e?{core:e}:void 0}async function hr(e){let t=$n(e);await H(t,e,async()=>{M(t,{messageId:e.messageId,sessionId:e.sessionId,sessionStoreName:nr(e.sessionStore)});let i=new lt(`resume command`),a=null;try{let t=await ur(e),o=nr(e.sessionStore),c=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await E.readFile(e.goalFile,`utf-8`):e.goal;let a=Vn(i),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(F(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));try{let n=await b(t.dataDir,e.sessionId,{storeName:o}),i=await r({dataDir:t.dataDir,sessionId:e.sessionId,objective:a,tokenBudget:s,force:e.force,storeName:o});c=Un({sessionId:e.sessionId,before:n,result:i})}catch(e){throw e instanceof n&&(F(e.message),F(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}N.info(`resume command started`,{sessionId:e.sessionId,requestId:e.requestId,channel:t.channel,dataDir:t.dataDir});let l=await ee(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),u=l?null:await te(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions});if(!l&&!u)throw Error(`No pending HITL or UI tool request found for session "${e.sessionId}"`);if(l){if(l.request.requestId!==e.requestId)throw Error(`Request ID mismatch: pending is "${l.request.requestId}", got "${e.requestId}"`);if(l.status===`expired`)throw Error(`HITL request has expired`);if(l.status===`cancelled`)throw Error(`HITL request has been cancelled`)}else if(u){if(u.request.requestId!==e.requestId)throw Error(`Request ID mismatch: pending is "${u.request.requestId}", got "${e.requestId}"`);if(u.status!==`pending`)throw Error(`UI tool request is already "${u.status}", cannot resume`)}if(l){let n=sr(e,l.request),r=await ce({dataDir:t.dataDir,sessionStoreName:o,sessionId:e.sessionId,requestId:e.requestId,resolution:n}),s=r.state;if(!s)throw Error(`Resolved HITL state was not persisted`);let u=gr(n,s.request.kind);await fr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:s.toolContext?.toolCallId,toolName:s.toolContext?.toolName,resolution:n,encryptSessions:e.encryptSessions});let d=dr(e);a=d.sink;let f=e.sessionId,p=async n=>{if(f=n.sessionId??f,!_e(n)){if(n.type===`stream_text_delta`){t.format===`text`&&I(n),await d.websocketSink?.sendTextDelta({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}t.format===`text`&&I(n),await a?.send({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,type:`progress`,event:n})}};c&&await p(c),await p({type:`hitl_resumed`,requestId:e.requestId,resolution:n,sessionId:e.sessionId}),`idempotentReplay`in r&&r.idempotentReplay&&(N.info(`resume command treated as idempotent replay`,{sessionId:e.sessionId,requestId:e.requestId,idempotencyKey:n.idempotencyKey}),gt({sessionId:e.sessionId,text:`Resume request already processed.`,usage:{input:0,output:0,total:0},durationMs:0},t.format),i.end(),process.exit(0));let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await U(t.dataDir,m),g;try{g=await de({dataDir:t.dataDir,projectDir:er(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:u,encryptSessions:e.encryptSessions??!1,topicSegmentation:Qn(e),memory:mr(),hitlResume:{request:s.request,resolution:n,checkpoint:s.checkpoint,toolContext:s.toolContext},plugins:h?{config:h,dataDir:t.dataDir,workspaceDir:S.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:h.llmAllowlist}:void 0,onProgress:p})}finally{}g.error?await a?.send({sessionId:g.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`error`,message:g.error}):await a?.send({sessionId:g.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`done`,result:Kn(g)}),gt(g,t.format),g.error?N.error(`resume command failed: ${g.error}`):N.info(`resume command succeeded`),i.end(),process.exit(g.error?1:0);return}let d=cr(e,u);if(!await le(t.dataDir,e.sessionId,e.requestId,d,{storeName:o,encryptSessions:e.encryptSessions}))throw Error(`UI tool resume validation failed`);await pr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,result:d,encryptSessions:e.encryptSessions});let f=dr(e);a=f.sink;let p=e.sessionId,m=async n=>{if(p=n.sessionId??p,!_e(n)){if(n.type===`stream_text_delta`){t.format===`text`&&I(n),await f.websocketSink?.sendTextDelta({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}if(t.format===`text`&&I(n),n.type===`start`){await a?.send({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,type:`start`,message:n.message});return}await a?.send({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,type:`progress`,event:n})}},h=await lr({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:d.toolCallId,toolName:d.toolName,encryptSessions:e.encryptSessions});c&&await m(c),await m({type:`tool_end`,sessionId:e.sessionId,toolCallId:d.toolCallId,name:d.toolName,input:h,output:JSON.stringify({submitted:!0,values:d.values}),isError:!1});let g=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,_=await U(t.dataDir,g),v=await de({dataDir:t.dataDir,projectDir:er(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:`[UI_TOOL_RESUME]
8
- The pending UI tool result has been written into the transcript. Continue from the latest tool result without repeating the same form request.`,encryptSessions:e.encryptSessions??!1,topicSegmentation:Qn(e),memory:mr(),uiToolResume:d,plugins:_?{config:_,dataDir:t.dataDir,workspaceDir:S.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:_.llmAllowlist}:void 0,onProgress:m});await s(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),v.error?await a?.send({sessionId:v.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`error`,message:v.error}):await a?.send({sessionId:v.sessionId,channel:t.channel,messageId:e.messageId,user:e.user,type:`done`,result:Kn(v)}),gt(v,t.format),v.error?N.error(`resume command failed: ${v.error}`):N.info(`resume command succeeded`),i.end(),process.exit(v.error?1:0)}catch(t){let n=t;a&&(n.message.includes(`expired`)&&await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`progress`,event:{type:`hitl_expired`,sessionId:e.sessionId,requestId:e.requestId,reason:n.message}}),n.message.includes(`cancelled`)&&await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`progress`,event:{type:`hitl_cancelled`,sessionId:e.sessionId,requestId:e.requestId,reason:n.message}}),await a.send({sessionId:e.sessionId,channel:e.channel??`WEB`,messageId:e.messageId,user:e.user,type:`error`,message:`Resume failed: ${n.message}`})),N.error(`resume command error: ${n.message}`),F(`Fatal: ${n.message}`),i.end(),process.exit(1)}finally{await a?.close()}})}function gr(e,t){return o(e,t)}function _r(e){e.command(`resume`).description(`Resume a paused HITL session with user input`).requiredOption(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--project-dir <path>`,`Current project directory used as the default cwd context`).option(`--system-agents-dir <path>`,`System agent definition directory (overrides AIMAX_SYSTEM_AGENTS_DIR, default: /aimax/agents)`).requiredOption(`-s, --session-id <id>`,`Session ID to resume`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).requiredOption(`--request-id <id>`,`HITL request ID to resolve`).option(`--input-json <json>`,`JSON string with the resolution (action, values, etc.)`).option(`--input-text <text>`,`Plain text response for IM channels without rich UI (e.g. '同意', '拒绝')`).option(`--skillsLoadPaths <paths>`,`Comma-separated absolute skill load paths`).option(`--auto-skills-load-enabled <boolean>`,`Enable learned auto-skill loading for the main agent (overrides AIMAX_AUTO_SKILLS_LOAD_ENABLED)`).option(`--auto-skills-review-mode <mode>`,`Auto-skill review mode: off, gate, dry_run, or write (overrides AIMAX_AUTO_SKILLS_REVIEW_MODE)`).option(`--message-id <id>`,`Message ID for correlating events`).option(`--user <id>`,`User identifier propagated to external callback and stream payloads`).option(`-c, --channel <channel>`,`Channel name (default: WEB)`,`WEB`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--auth-token <token>`,`Auth token used to generate the API key`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--context-window <n>`,`LLM context window size`).option(`--thinking <level>`,`Explicit thinking level: minimal, low, medium, high, or xhigh (overrides AIMAX_THINKING)`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--plugins-config <path>`,`Plugins config file path`).option(`--goal <text>`,`Set or replace the thread goal objective before resuming`).option(`--goal-file <path>`,`Read goal objective from a file`).option(`--token-budget <n>`,`Token budget for the goal (positive integer, or 0 for unlimited)`).option(`--force`,`Replace existing goal with a different objective`).option(`--encrypt-sessions`,`Enable encryption for the .aimax data directory`).option(`--disable-topic-segmentation`,`Disable smart topic segmentation for this resume run`).action(async e=>{await hr(e)})}function vr(e,t){return{notify:(n,r=`info`)=>{t?.readyState===1?t.send(JSON.stringify({type:`diagnostic`,sessionId:e,level:r,message:n})):console.log(`[${r}] ${n}`)},confirm:async n=>!t||t.readyState!==1?!1:new Promise(r=>{let i=`confirm-${Date.now()}`;t.send(JSON.stringify({type:`hitl_confirm`,sessionId:e,id:i,message:n}));let a=e=>{try{let t=JSON.parse(String(e));r(t.id===i&&t.confirmed===!0)}catch{r(!1)}};typeof t.once==`function`?t.once(`message`,a):t.addEventListener(`message`,e=>a(e.data),{once:!0})}),select:async(n,r)=>{if(!(!t||t.readyState!==1))return new Promise(i=>{let a=`select-${Date.now()}`;t.send(JSON.stringify({type:`hitl_select`,sessionId:e,id:a,title:n,options:r}));let o=e=>{try{let t=JSON.parse(String(e));i(t.id===a?t.selected:void 0)}catch{i(void 0)}};typeof t.once==`function`?t.once(`message`,o):t.addEventListener(`message`,e=>o(e.data),{once:!0})})},setStatus:n=>{t?.readyState===1?t.send(JSON.stringify({type:`diagnostic`,sessionId:e,level:`info`,message:n})):console.log(`[status] ${n}`)}}}const yr=[`start`,`text`,`done`,`error`],br=[`off`,`gate`,`dry_run`,`write`];function xr(e){if(!e?.trim())return new Set(yr);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl,title_updated`);r.add(e)}return r.size>0?r:new Set(yr)}function Sr(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=Wn();return t?{embeddingModelDir:t}:void 0}function Cr(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function wr(e){return e?.trim()||void 0}function Tr(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!S.isAbsolute(t)){let n=e.systemAgentsDir===void 0?`AIMAX_SYSTEM_AGENTS_DIR`:`--system-agents-dir`;throw Error(`Invalid ${n}: ${t}. Path must be absolute.`)}return t}}function Er(e){return e?.trim()||void 0}function Dr(e){return e??`WEB`}function K(e){return e?y(e):void 0}function Or(e){if(!e?.trim())return[];let t=e.split(`,`).map(e=>e.trim()).filter(Boolean),n=new Set,r=[];for(let e of t){if(!S.isAbsolute(e))throw Error(`Invalid --skillsLoadPaths entry: ${e}. Each path must be absolute.`);n.has(e)||(n.add(e),r.push(e))}return r}function kr(e){let t=``;for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`\\`&&n+1<e.length){let r=e[n+1];if(r===`,`||r===`\\`||r===`=`){t+=r,n+=1;continue}}t+=r}return t}function Ar(e){let t=[],n=``;for(let r=0;r<e.length;r+=1){let i=e[r];if(i===`\\`&&r+1<e.length){let t=e[r+1];if(t===`,`||t===`\\`){n+=t,r+=1;continue}}if(i===`,`){t.push(n),n=``;continue}n+=i}return t.push(n),t}function jr(e){if(!e?.trim())return{};let t=[],n=new Set;for(let r of Ar(e)){let e=r.trim();if(!e)continue;let i=e.indexOf(`=`);if(i<=0)throw Error(`Invalid --env entry: ${e}. Expected KEY=VALUE (use \\= to embed an equals sign in the value).`);let a=e.slice(0,i).trim(),o=e.slice(i+1).trim();if(!a)throw Error(`Invalid --env entry: ${e}. Key must not be empty.`);if(n.has(a))throw Error(`Invalid --env entry: duplicate key ${a}.`);n.add(a),t.push([a,kr(o)])}return Object.fromEntries(t)}function Mr(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if([`true`,`1`,`yes`,`on`].includes(n))return!0;if([`false`,`0`,`no`,`off`].includes(n))return!1;throw Error(`Invalid ${t}: ${e}. Must be true or false.`)}}function Nr(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(br.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function Pr(e){let t=e.autoSkillsLoadEnabled===void 0?Mr(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):Mr(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?Nr(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):Nr(e.autoSkillsReviewMode,`--auto-skills-review-mode`),r={};return t!==void 0&&(r.load={enabled:t}),n!==void 0&&(r.review={mode:n}),r.load||r.review?r:void 0}function Fr(e,t){return e.length<=t?e:t<=3?e.slice(0,t):`${e.slice(0,t-3)}...`}function Ir(e,t){if(t<=0)return[``];let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n.length>0?n:[``]}function Lr(e,t,n=78){let r=Math.max(0,n-4),i=e?e.length+2:0,a=Math.max(r,i,...t.map(e=>e.length)),o=a+2,s=e?` ${Fr(e,Math.max(0,a-2))} `:``,c=e?`┌${s}${`─`.repeat(Math.max(0,o-s.length))}┐`:`┌${`─`.repeat(o)}┐`,l=`└${`─`.repeat(o)}┘`;return[c,...t.flatMap(e=>Ir(e,a).map(e=>`│ ${e.padEnd(a,` `)} │`)),l].join(`
9
- `)}function Rr(e){return e.kind===`text`?`inline message (${e.message.length} chars)`:`message file (${e.messages.length} messages)`}function q(e,t=`-`){return e==null||e===``?t:String(e)}function zr(e){return e?`set`:`unset`}function Br(e){return e?`true`:`false`}function Vr(e,t){let n=K(e.sessionStore)??`sessions`,r=t.timeoutMs===void 0?`default`:`${t.timeoutMs}`,i=e.callbackUrl?`enabled`:`disabled`,a=e.streamUrl?`enabled`:`disabled`,o=Rr(t.input),s=t.input.kind===`text`?`inline`:e.fromFile??`file`,c=Je(),l=Sr(e)?.enabled===!1?`disabled`:`enabled`,u=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,d=[...xr(e.streamEvents)].join(`,`),f=t.autoSkills?.load?.enabled,p=t.autoSkills?.review?.mode,m=e.tokenBudget===`0`?`unlimited`:q(e.tokenBudget),h=t.artifactsUrlWhitelist?.join(`,`)??`-`,g=e.env?Object.keys(jr(e.env)):[],_=g.length===0?`-`:`${g.length} key${g.length===1?``:`s`}`;return{banner:Lr(void 0,[`AIMax CLI`,`Stateless Agent Runner`]),contextBox:Lr(`Run Context`,[`time : ${c}`,`dataDir : ${t.dataDir}`,`projectDir : ${wr(e.projectDir)??`-`}`,`systemAgents : ${t.systemAgentsDir??`/aimax/agents`}`,`agent : ${Er(e.agent)??`-`}`,`channel : ${t.channel}`,`user : ${e.user??`-`}`,`message : ${e.message===void 0?`-`:`inline (${e.message.length} chars)`}`,`fromFile : ${q(e.fromFile)}`,`input : ${o}`,`skillsPaths : ${t.skillsLoadPaths.length>0?t.skillsLoadPaths.join(`,`):`-`}`,`autoSkillLoad: ${f===void 0?`-`:String(f)}`,`autoSkillRev : ${p??`-`}`,`sessionId : ${e.sessionId??`new`}`,`sessionStore : ${n}`,`messageId : ${e.messageId??`-`}`,`workspace : ${S.join(t.dataDir,`workspace`)}`,`baseUrl : ${t.llm.baseUrl}`,`apiKey : ${zr(t.llm.apiKey)}`,`authToken : ${zr(e.authToken)}`,`model : ${t.llm.model}`,`contextWindow: ${q(t.llm.contextWindow)}`,`flashModel : ${q(t.llm.flashModel)}`,`thinking : ${q(t.llm.thinking)}`,`callbackUrl : ${q(e.callbackUrl)}`,`streamUrl : ${q(e.streamUrl)}`,`streamAuth : ${zr(e.streamAuthToken)}`,`streamEvents : ${d}`,`artifactUrls : ${h}`,`output : ${t.format}`,`callback : ${i}`,`websocket : ${a}`,`timeoutMs : ${r}`,`pluginsConfig: ${q(u)}`,`env : ${_}`,`goal : ${e.goal===void 0?`-`:`inline (${e.goal.length} chars)`}`,`goalFile : ${q(e.goalFile)}`,`tokenBudget : ${m}`,`force : ${Br(e.force)}`,`resumeReqId : ${q(e.resumeRequestId)}`,`resumeInput : ${e.resumeInputJson===void 0?`-`:`inline (${e.resumeInputJson.length} chars)`}`,`resumeFile : ${q(e.resumeFromFile)}`,`encryptSess : ${Br(e.encryptSessions)}`,`topicSegment : ${l}`]),logContext:{time:c,channel:t.channel,user:e.user,dataDir:t.dataDir,projectDir:wr(e.projectDir),systemAgentsDir:t.systemAgentsDir,agent:Er(e.agent),workspaceDir:S.join(t.dataDir,`workspace`),sessionId:e.sessionId??`new`,sessionStore:n,messageId:e.messageId,hasMessage:e.message!==void 0,fromFile:e.fromFile,skillsLoadPaths:t.skillsLoadPaths.join(`,`)||void 0,autoSkillsLoadEnabled:f,autoSkillsReviewMode:p,baseUrl:t.llm.baseUrl,hasApiKey:!!t.llm.apiKey,hasAuthToken:!!e.authToken,model:t.llm.model,contextWindow:t.llm.contextWindow,flashModel:t.llm.flashModel,thinking:t.llm.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,hasStreamAuthToken:!!e.streamAuthToken,streamEvents:d,artifactsUrlWhitelist:t.artifactsUrlWhitelist?.join(`,`)||void 0,output:t.format,hasCallback:!!e.callbackUrl,hasStream:!!e.streamUrl,timeoutMs:t.timeoutMs,pluginsConfig:u,envKeys:g.length>0?g.join(`,`):void 0,hasGoal:e.goal!==void 0,goalFile:e.goalFile,tokenBudget:m===`-`?void 0:m,force:!!e.force,resumeRequestId:e.resumeRequestId,hasResumeInputJson:e.resumeInputJson!==void 0,resumeFromFile:e.resumeFromFile,encryptSessions:!!e.encryptSessions,topicSegmentation:l,inputKind:t.input.kind,inputSource:s,inputSummary:o}}}async function Hr(e,t){let n=Cr(e),r=Dr(e.channel),i=ln({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow?Number(e.contextWindow):void 0,flashModel:e.flashModel,thinking:e.thinking});return{dataDir:n,systemAgentsDir:Tr(e),channel:r,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:i,input:t,skillsLoadPaths:Or(e.skillsLoadPaths),artifactsUrlWhitelist:qn(e.artifactsUrlWhitelist),autoSkills:Pr(e)}}function Ur(e){if(e.kind===`text`)return e.message;if(e.messages.length!==1)return null;let[t]=e.messages;if(t.role!==`user`)return null;if(typeof t.content==`string`)return t.content;if(t.content.length===0)return null;let n=[];for(let e of t.content){if(e.type!==`text`)return null;n.push(e.text)}return n.join(`
10
- `)}async function Wr(e,t){if(!e.sessionId)return null;let n=Ur(t);if(!n)return null;let r=await ee(Cr(e),e.sessionId,{storeName:K(e.sessionStore),encryptSessions:e.encryptSessions});return!r||r.status!==`pending`||!ye(n,r.request)?null:{requestId:r.request.requestId,inputText:n}}function Gr(e){let t=[],n=null;return e.callbackUrl&&t.push(new An(e.callbackUrl)),e.streamUrl&&(n=new zn(e.streamUrl,xr(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new kn(t),websocketSink:n}}async function J(e,t){N.info(`dispatching external event`,fi(t)),await e.sink.send(t)}function Kr(e){let t={sessionId:e.sessionId,messageId:e.messageId,parentSessionId:e.parentSessionId,depth:e.depth,scope:e.scope,phase:e.phase,...e.details};if(e.level===`error`){N.error(e.message,t);return}if(e.level===`warn`){N.warn(e.message,t);return}N.info(e.message,t)}function qr(e,t,n,r,i){return{sink:e,websocketSink:t,channel:n,defaultMessageId:r,user:i}}function Jr(e){let t=new AbortController,n=n=>{N.warn(`run abort signal received`,{signal:n,uptimeMs:Math.round(process.uptime()*1e3),alreadyAborted:t.signal.aborted,...e?.()}),t.abort()},r=()=>n(`SIGTERM`),i=()=>n(`SIGINT`);return process.once(`SIGTERM`,r),process.once(`SIGINT`,i),{controller:t,cleanup:()=>{process.off(`SIGTERM`,r),process.off(`SIGINT`,i)}}}function Yr(e){return{activeSessionId:e??`pending`,finalResult:null,loggerSessionId:void 0}}function Xr(e,t,n,r){!r||n.loggerSessionId===r||(M(e,{messageId:t.messageId,sessionId:r,sessionStoreName:K(t.sessionStore)}),n.loggerSessionId=r)}function Zr(e,t){e.activeSessionId=t.sessionId??e.activeSessionId}function Qr(e,t){return e.messageId??t}async function $r(e,t,n){if(!await m(e.dataDir)){if(await ei(t,e.format,n.activeSessionId,e.dataDir,`checking`),(await l(e.dataDir)).performedBootstrap){await ei(t,e.format,n.activeSessionId,e.dataDir,`initializing`),await ei(t,e.format,n.activeSessionId,e.dataDir,`initialized`);return}await ei(t,e.format,n.activeSessionId,e.dataDir,`ready`)}}async function ei(e,t,n,r,i){let a={type:`bootstrap`,phase:i,dataDir:r};t===`text`&&I(a),await J(e,{sessionId:n,channel:e.channel,messageId:e.defaultMessageId,user:e.user,type:`progress`,event:a})}function ti(e,t,n,r){return async i=>{if(Zr(n,i),Xr(e.dataDir,r,n,i.sessionId),_e(i)){Kr(i);return}if(i.type===`stream_text_delta`){e.format===`text`&&I(i),await t.websocketSink?.sendTextDelta({sessionId:n.activeSessionId,channel:e.channel,messageId:Qr(i,t.defaultMessageId),user:t.user,text:i.text});return}e.format===`text`&&I(i);let a=Qr(i,t.defaultMessageId);if(i.type===`hitl_requested`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`hitl`,request:i.request}),await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`progress`,event:i});return}if(i.type===`start`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`start`,message:i.message});return}if(i.type===`session_reset`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`session_reset`,action:i.action,previousSessionId:i.previousSessionId,message:i.message});return}await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:a,user:t.user,type:`progress`,event:i})}}function ni(e){let t=vr(e);return{confirm:(e,n)=>t.confirm(e),select:(e,n,r)=>t.select?t.select(e,n):Promise.resolve(void 0)}}function ri(e,t,n,r,i,a){let o=_n(),s={dataDir:t.dataDir,projectDir:wr(e.projectDir),systemAgentsDir:t.systemAgentsDir,agentPolicy:Er(e.agent)?{requestedAgentName:Er(e.agent)}:void 0,sessionStoreName:K(e.sessionStore),sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,artifactsUrlWhitelist:t.artifactsUrlWhitelist,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,abortSignal:n.signal,pendingGoal:a,encryptSessions:e.encryptSessions??!1,topicSegmentation:Sr(e),env:jr(e.env),...o?{memory:{core:o}}:{},plugins:i?{config:i,dataDir:t.dataDir,workspaceDir:S.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:i.llmAllowlist}:void 0,onProgress:r,createPiExtensionDialogBridge:ni};return t.input.kind===`messages`?{...s,messages:t.input.messages}:{...s,message:t.input.message}}async function ii(e,t,n,r){if(t.activeSessionId=r.sessionId,t.finalResult=r,r.error){await J(e,{sessionId:r.sessionId,channel:e.channel,messageId:n,user:e.user,type:`error`,message:r.error});return}await J(e,{sessionId:r.sessionId,channel:e.channel,messageId:n,user:e.user,type:`done`,result:Kn(r)})}async function ai(e,t,n,r){await J(e,{sessionId:t.finalResult?.sessionId??t.activeSessionId,channel:e.channel,messageId:n,user:e.user,type:`error`,message:`Fatal: ${r.message}`})}function oi(e,t){let n=Vr(e,t);N.info([`run command started`,n.banner,n.contextBox].join(`
11
- `),n.logContext),t.format===`text`&&(P(n.banner),P(``),P(n.contextBox),P(``))}function si(e,t,n){return gt(t,n),t.error?N.error(`run command failed: ${t.error}`):N.info(`run command succeeded`),e.end(),t.error?1:0}function ci(e){let t=st();if(!t)return;let n=`[${Je()}] [ERROR] ${e}\n`;try{xe.appendFileSync(S.join(t.logDir,`app.log`),n),xe.appendFileSync(S.join(t.logDir,`errors.log`),n)}catch{}}async function li(e,t){let n=`run command error: ${t.message}`;N.error(n),ci(n),F(`Fatal: ${t.message}`),e.end(),await ct(),process.exit(1)}async function ui(e){if(e.resumeInputJson&&e.resumeFromFile)throw Error(`--resume-input-json and --resume-from-file are mutually exclusive`);if(!e.resumeFromFile)return e.resumeInputJson;try{return await E.readFile(e.resumeFromFile,`utf-8`)}catch(e){throw Error(`Failed to read resume input file: ${e.message}`)}}async function di(e){let t=Cr(e);await H(t,e,async i=>{let a=Yr(e.sessionId);Xr(t,e,a,e.sessionId),e.encryptSessions&&N.info(`--encrypt-sessions run mount state after logger initialization`,{dataDir:t,mounted:i?.mounted??!1,plainDir:i?.plainDir,encryptedDir:i?.encryptedDir});let o=new lt(`run command`),s=await ui(e);if(e.resumeRequestId||s||e.resumeFromFile){if(!e.sessionId||!e.resumeRequestId||!s)throw Error(`--session-id, --resume-request-id, and exactly one of --resume-input-json or --resume-from-file must be provided together`);await hr({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:e.resumeRequestId,inputJson:s,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,thinking:e.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,artifactsUrlWhitelist:e.artifactsUrlWhitelist,skillsLoadPaths:e.skillsLoadPaths,autoSkillsLoadEnabled:e.autoSkillsLoadEnabled,autoSkillsReviewMode:e.autoSkillsReviewMode,messageId:e.messageId,user:e.user,goal:e.goal,goalFile:e.goalFile,tokenBudget:e.tokenBudget,force:e.force,encryptSessions:e.encryptSessions,disableTopicSegmentation:e.disableTopicSegmentation});return}let c;try{c=await On({message:e.message,fromFile:e.fromFile})}catch(e){await li(o,e);return}let l=await Wr(e,c);if(l){await hr({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:l.requestId,inputText:l.inputText,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,thinking:e.thinking,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,artifactsUrlWhitelist:e.artifactsUrlWhitelist,skillsLoadPaths:e.skillsLoadPaths,autoSkillsLoadEnabled:e.autoSkillsLoadEnabled,autoSkillsReviewMode:e.autoSkillsReviewMode,messageId:e.messageId,user:e.user,goal:e.goal,goalFile:e.goalFile,tokenBudget:e.tokenBudget,force:e.force,encryptSessions:e.encryptSessions,disableTopicSegmentation:e.disableTopicSegmentation});return}let u=e.channel??`WEB`,{controller:d,cleanup:f}=Jr(()=>({activeSessionId:a.activeSessionId,finalSessionId:a.finalResult?.sessionId,messageId:e.messageId,channel:u,user:e.user})),p=null;try{let t=await Hr(e,c);u=t.channel,oi(e,t);let i=Gr(e);p=i.sink,N.info(`external sink configured`,{callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamEvents:e.streamEvents});let s=qr(p,i.websocketSink,t.channel,e.messageId,e.user);await $r(t,s,a);let l,f=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await E.readFile(e.goalFile,`utf-8`):e.goal;let a=Vn(i),o=K(e.sessionStore),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(F(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));try{if(e.sessionId){let n=await b(t.dataDir,e.sessionId,{storeName:o}),i=await r({dataDir:t.dataDir,sessionId:e.sessionId,objective:a,tokenBudget:s,force:e.force,storeName:o});f=Un({sessionId:e.sessionId,before:n,result:i})}else l={objective:a,tokenBudget:s??null}}catch(e){throw e instanceof n&&(F(e.message),F(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await U(t.dataDir,m),g=ti(t,s,a,e);f&&await g(f);let _=await de(ri(e,t,d,g,h,l));Xr(t.dataDir,e,a,_.sessionId),await ii(s,a,e.messageId,_),process.exitCode=si(o,_,t.format)}catch(t){let n=t;p&&await ai(qr(p,null,u,e.messageId,e.user),a,e.messageId,n),await li(o,n)}finally{await p?.close(),f()}})}function fi(e){return{eventType:e.type,sessionId:e.sessionId,messageId:e.messageId,channel:e.channel,user:e.user,progressType:e.type===`progress`?e.event.type:void 0,textLength:e.type===`done`?e.result.text.length:void 0,hasError:e.type===`error`?!0:e.type===`done`?!!e.result.error:void 0}}function pi(e){e.command(`run`).description(`Run an agent task`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--project-dir <path>`,`Current project directory used as the default cwd context`).option(`--system-agents-dir <path>`,`System agent definition directory (overrides AIMAX_SYSTEM_AGENTS_DIR, default: /aimax/agents)`).option(`--agent <name>`,`Custom agent name to run as the root agent`).option(`--user <id>`,`User identifier propagated to external callback and stream payloads`).option(`--message <text>`,`User message to send to the agent`).option(`--from-file <path>`,`Load structured Message JSON from a file`).option(`--skillsLoadPaths <paths>`,`Comma-separated absolute skill load paths`).option(`--auto-skills-load-enabled <boolean>`,`Enable learned auto-skill loading for the main agent (overrides AIMAX_AUTO_SKILLS_LOAD_ENABLED)`).option(`--auto-skills-review-mode <mode>`,`Auto-skill review mode: off, gate, dry_run, or write (overrides AIMAX_AUTO_SKILLS_REVIEW_MODE)`).option(`-s, --session-id <id>`,`Resume an existing session by ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--message-id <id>`,`Message ID for correlating events`).option(`-c, --channel <channel>`,`Channel name (default: WEB)`,`WEB`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--auth-token <token>`,`Auth token used to generate the API key (highest priority)`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--context-window <n>`,`LLM context window size`).option(`--flash-model <name>`,`Flash model for lightweight tasks like title generation (overrides AIMAX_FLASH_MODEL)`).option(`--thinking <level>`,`Explicit thinking level: minimal, low, medium, high, or xhigh (overrides AIMAX_THINKING)`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events: start,text,progress,done,error`).option(`--artifacts-url-whitelist <urls>`,`Comma-separated URL artifact hostnames or URLs to collect; unset collects all URL artifacts`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--plugins-config <path>`,`Plugins config file path`).option(`--env <kvlist>`,`Session-scoped env vars injected into the run. Comma-separated KEY=VALUE pairs. Backslash-escape "," and "=" inside values. Available to plugins via api.runtime.session.env and merged into child process environments spawned by the exec/process tools.`).option(`--goal <text>`,`Set or replace the thread goal objective before running`).option(`--goal-file <path>`,`Read goal objective from a file`).option(`--token-budget <n>`,`Token budget for the goal (positive integer, or 0 for unlimited)`).option(`--force`,`Replace existing goal with a different objective`).option(`--resume-request-id <id>`,`Resume a pending HITL request from aimax run`).option(`--resume-input-json <json>`,`Structured HITL resume payload used with --resume-request-id`).option(`--resume-from-file <path>`,`Load structured HITL resume payload from a file (alternative to --resume-input-json)`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).option(`--disable-topic-segmentation`,`Disable smart topic segmentation for this run`).action(async e=>{await di(e)})}function mi(e){e.command(`sessions`).description(`List or inspect sessions for a data directory`).argument(`[action]`,`Action: list (default) | inspect | export`).option(`-d, --data-dir <path>`,`Data directory path`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`-c, --channel <channel>`,`Filter by channel type: H5 | WEB | KLPA | TASK | CRON | EIP_ASSISTANT`).option(`-s, --session-id <id>`,`Session ID for inspect/export`).option(`--output <format>`,`Output format: text or json`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t,n)=>{let r=n.opts(),i=e??`list`,a=i===`export`?r.output===`text`?`text`:`json`:r.output===`json`?`json`:`text`;r.dataDir||(F(`error: required option '-d, --data-dir <path>' not specified`),process.exit(1)),r.channel&&r.channel!==`H5`&&r.channel!==`WEB`&&r.channel!==`KLPA`&&r.channel!==`TASK`&&r.channel!==`CRON`&&r.channel!==`EIP_ASSISTANT`&&(F(`Invalid channel: ${r.channel}. Must be 'H5', 'WEB', 'KLPA', 'TASK', 'CRON', or 'EIP_ASSISTANT'`),process.exit(1));try{await H(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;if(i===`list`){_t(await v(r.dataDir,r.channel,{storeName:e}),a);return}if(r.sessionId||(F(`error: required option '-s, --session-id <id>' not specified`),process.exit(1)),i===`inspect`){vt(await g(r.dataDir,r.sessionId,{storeName:e}),a);return}if(i===`export`){yt(await u(r.dataDir,r.sessionId,{storeName:e}),a);return}F(`Invalid sessions action: ${i}. Must be 'list', 'inspect', or 'export'`),process.exit(1)})}catch(e){F(`${i===`inspect`?`Error inspecting session`:i===`export`?`Error exporting session`:`Error listing sessions`}: ${e.message}`),process.exit(1)}})}function hi(e){return S.join(e,`workspace`)}function gi(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function _i(e,t){let n=[];n.push(`backend: ${e.backend}`),n.push(`provider: ${e.provider}${e.model?` (${e.model})`:``}`);let r=typeof e.custom?.providerSource==`string`?e.custom.providerSource:void 0,i=typeof e.custom?.providerId==`string`?e.custom.providerId:void 0,a=typeof e.custom?.pluginId==`string`?e.custom.pluginId:void 0;r&&n.push(`provider_source: ${r}`),i&&n.push(`provider_id: ${i}`),a&&n.push(`plugin_id: ${a}`),typeof e.files==`number`&&n.push(`files: ${e.files}`),typeof e.chunks==`number`&&n.push(`chunks: ${e.chunks}`),typeof e.dirty==`boolean`&&n.push(`dirty: ${e.dirty}`),e.dbPath&&n.push(`db: ${e.dbPath}`),e.sources?.length&&n.push(`sources: ${e.sources.join(`, `)}`),t&&(e.fts&&(n.push(`fts: enabled=${e.fts.enabled} available=${e.fts.available}`),e.fts.error&&n.push(`fts_error: ${e.fts.error}`)),e.vector&&(n.push(`vector: enabled=${e.vector.enabled} available=${e.vector.available??`unknown`}`),e.vector.dims&&n.push(`vector_dims: ${e.vector.dims}`),e.vector.loadError&&n.push(`vector_error: ${e.vector.loadError}`)),e.cache&&n.push(`cache: enabled=${e.cache.enabled} entries=${e.cache.entries??0}`));let o=Array.isArray(e.custom?.cliWarnings)?e.custom.cliWarnings.filter(e=>typeof e==`string`&&e.length>0):[];for(let e of o)n.push(`warning: ${e}`);return n.join(`
12
- `)}function vi(e){let t=e.level===`error`?`plugin error`:`plugin warning`;return e.pluginId?`${t} (${e.pluginId}): ${e.message}`:`${t}: ${e.message}`}function yi(e){if(!e||e===`cli`)return`cli`;if(e===`cron`)return`cron`;throw Error(`Unsupported dream trigger: ${e}. Expected "cli" or "cron".`)}async function bi(e){let t=[],n;try{n=await U(e.dataDir,e.pluginsConfig)}catch(e){t.push(`failed to load plugins config: ${e.message}`)}if(!e.shouldInitialize&&!n)return{warnings:t};try{let r=h({config:n,dataDir:e.dataDir,workspaceDir:hi(e.dataDir),bundledDir:gi()});return t.push(...r.diagnostics.map(vi)),{pluginSystem:r,warnings:t}}catch(e){return t.push(`failed to initialize plugin system: ${e.message}`),{warnings:t}}}async function xi(e){let t=S.join(e.dataDir,`.aimax`),{pluginSystem:n,warnings:r}=await bi({dataDir:e.dataDir,pluginsConfig:e.pluginsConfig,shouldInitialize:!!(e.requirePluginSystem||e.provider||e.providerPlugin)}),i=n?.normalizedConfig.slots.memory,a=e.providerPlugin?.trim()||(e.provider?void 0:i),o=se({providerId:e.provider,pluginId:a,dataDir:e.dataDir,memoryDir:t,includeSessions:e.includeSessions});return o.providerSource===`plugin`?{provider:o.provider,providerId:o.providerId,pluginId:o.pluginId,providerOrigin:`plugin`,warnings:r,pluginSystem:n}:((a||e.provider)&&r.push(`requested memory provider was not resolved; falling back to builtin provider`),{provider:o.provider,providerId:`builtin`,providerOrigin:`builtin`,warnings:r,pluginSystem:n})}function Si(e,t,n){let r={...e.custom??{},providerSource:t.providerOrigin,providerId:t.providerId,pluginId:t.pluginId,cliWarnings:t.warnings},i={...e,custom:r};return n&&t.providerOrigin===`plugin`?i.custom={...r,note:`deep probe details are provider-defined for plugin memory providers`}:n&&(i.custom={...r,note:`deep probe is only supported by builtin provider`}),i}function Ci(e){let t=e.command(`memory`).description(`Manage semantic memory indexing and search`),n=e=>e.option(`--plugins-config <path>`,`Plugins config file path`);n(t.command(`status`)).description(`Show memory index status`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--deep`,`Probe embedding/vector availability`).option(`--index`,`Run a refresh before reporting status`).option(`--include-sessions`,`Include session transcripts in indexing`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--verbose`,`Verbose output`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await H(e.dataDir,e,async()=>{let n=await xi({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,includeSessions:e.includeSessions});e.index&&n.provider.sync&&await n.provider.sync(`cli-status`);let r=Si(n.provider.status(),n,e.deep);P(t===`json`?JSON.stringify(r,null,2):_i(r,e.deep))})}catch(e){F(`Error getting memory status: ${e.message}`),process.exit(1)}}),n(t.command(`index`)).description(`Reindex memory files`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--include-sessions`,`Include session transcripts in indexing`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--rebuild`,`Force full rebuild from Markdown source`).option(`--verbose`,`Verbose output`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{try{await H(e.dataDir,e,async()=>{let t=await xi({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,includeSessions:e.includeSessions}),n;if(t.provider.sync&&(await t.provider.sync(e.rebuild?`cli-rebuild`:`cli-index`),n=t.provider.status().custom?.lastRebuildSummary),t.warnings.length>0)for(let e of t.warnings)F(`Warning: ${e}`);e.verbose&&n&&P(JSON.stringify(n,null,2)),P(e.rebuild?`Memory index rebuilt.`:`Memory index refreshed.`)})}catch(e){F(`Error indexing memory: ${e.message}`),process.exit(1)}}),n(t.command(`search [query]`)).description(`Search semantic memory`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--query <text>`,`Search query`).option(`--include-sessions`,`Include session transcripts in search`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t)=>{let n=t.output===`json`?`json`:`text`,r=t.query?.trim()||e?.trim();r||(F(`Query is required: provide [query] or --query <text>`),process.exit(1));try{await H(t.dataDir,t,async()=>{let e=await(await xi({dataDir:t.dataDir,provider:t.provider,providerPlugin:t.providerPlugin,pluginsConfig:t.pluginsConfig,includeSessions:t.includeSessions})).provider.search(r);if(n===`json`){P(JSON.stringify(e,null,2));return}if(e.length===0){P(`No results found for: ${r}`);return}P(e.map(e=>{let t=`${e.path}:${e.startLine}-${e.endLine} (${e.score.toFixed(4)}) ${e.snippet}`;return e.citation?`${t}\n${e.citation}`:t}).join(`
13
- `))})}catch(e){F(`Error searching memory: ${e.message}`),process.exit(1)}}),n(t.command(`dream`)).description(`Trigger Dream Gate host hook for memory plugins`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--provider <id>`,`Memory provider id`).option(`--provider-plugin <id>`,`Memory provider plugin id`).option(`--trigger <mode>`,`Dream Gate trigger mode: cli (default) or cron`,`cli`).option(`--dry-run`,`Return hook results without plugin-side mutation`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await H(e.dataDir,e,async()=>{let n=yi(e.trigger),r=await xi({dataDir:e.dataDir,provider:e.provider,providerPlugin:e.providerPlugin,pluginsConfig:e.pluginsConfig,requirePluginSystem:!0}),i=r.pluginSystem?await r.pluginSystem.registry.hooks.dispatch(`dream_gate`,{dataDir:e.dataDir,memoryDir:S.join(e.dataDir,`.aimax`),providerId:r.providerId,pluginId:r.pluginId,trigger:n,dryRun:!!e.dryRun},{workspaceDir:hi(e.dataDir)}):[],a={ok:!0,trigger:n,providerSource:r.providerOrigin,providerId:r.providerId,pluginId:r.pluginId,resultCount:i.length,results:i,warnings:r.warnings};if(t===`json`){P(JSON.stringify(a,null,2));return}P(`trigger: ${a.trigger}`),P(`provider_source: ${a.providerSource}`),P(`provider_id: ${a.providerId}`),a.pluginId&&P(`plugin_id: ${a.pluginId}`),P(`result_count: ${a.resultCount}`),a.results.length===0?P(`note: no dream_gate hook registered`):P(`results: ${JSON.stringify(a.results)}`);for(let e of a.warnings)P(`warning: ${e}`)})}catch(e){F(`Error running dream gate: ${e.message}`),process.exit(1)}})}function wi(e){return`${e.match.accountId?`${e.match.channel}:${e.match.accountId}`:e.match.channel} -> ${e.agentId}`}function Ti(e){return async t=>{let n=await O(t),r=Le(n),i=Re(n);if(Ue(n),e.json){console.log(JSON.stringify({agents:r,bindings:i},null,2));return}console.log(`Agents:`);for(let e of r){let n=e.default?` (default)`:``,r=e.name&&e.name!==e.id?`${e.id}${n} (${e.name})`:`${e.id}${n}`;if(console.log(` - ${r}`),e.identity?.emoji||e.identity?.name){let t=[e.identity.emoji,e.identity.name].filter(Boolean).join(` `);console.log(` Identity: ${t}`)}let a=He(t,e.id);if(console.log(` Agent dir: ${a}`),e.model){let t=typeof e.model==`string`?e.model:e.model.primary;console.log(` Model: ${t}`)}let o=i.filter(t=>t.agentId===e.id);if(o.length>0){console.log(` Routing rules:`);for(let e of o)console.log(` - ${wi(e)}`)}}}}function Ei(e,t){return async n=>{D(await O(n),ze(e))&&(console.error(`Agent "${e}" already exists.`),process.exit(1)),await Fe(n,{id:e,name:t.name,model:t.model,default:t.default})||(console.error(`Agent "${e}" already exists.`),process.exit(1));let r=He(n,e);console.log(`Agent "${e}" added successfully.`),console.log(` Agent dir: ${r}`)}}function Di(e){return async t=>{let n=D(await O(t),ze(e));n||(console.error(`Agent "${e}" not found.`),process.exit(1)),n.default===!0&&(console.error(`Cannot delete default agent "${e}".`),process.exit(1)),await Be(t,e)||(console.error(`Failed to delete agent "${e}".`),process.exit(1)),console.log(`Agent "${e}" deleted.`)}}function Oi(e){return async t=>{let n=await O(t),r=e.agent??Ue(n);D(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),(!e.bind||e.bind.length===0)&&(console.error(`Please specify --bind <channel>[:<account>]`),process.exit(1));for(let n of e.bind){let[e,...i]=n.split(`:`),a=i.join(`:`),o=[`H5`,`WEB`,`KLPA`,`TASK`,`CRON`,`EIP_ASSISTANT`];o.includes(e)||(console.error(`Invalid channel: ${e}`),console.error(`Valid channels: ${o.join(`, `)}`),process.exit(1)),await Ie(t,{agentId:r,match:{channel:e,accountId:a||void 0}}),console.log(`Binding added: ${n} -> ${r}`)}}}function ki(e){return async t=>{let n=await O(t),r=e.agent??Ue(n);if(D(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),e.all){let e=await Ve(t,r,`*`);console.log(`Removed ${e} binding(s) for agent "${r}".`)}else if(e.bind&&e.bind.length>0){let n=0;for(let i of e.bind){let[e,...a]=i.split(`:`),o=await Ve(t,r,e,a.join(`:`)||void 0);o>0?(console.log(`Binding removed: ${i} -> ${r}`),n+=o):console.log(`No binding found: ${i} -> ${r}`)}}else console.error(`Please specify --bind <channel>[:<account>] or --all`),process.exit(1)}}function Ai(e){return async t=>{let n=Re(await O(t));if(e.agent&&(n=n.filter(t=>t.agentId===e.agent)),e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(`No bindings configured.`);return}console.log(`Routing bindings:`);for(let e of n)console.log(` ${wi(e)}`)}}function ji(e){return async t=>{let n=await O(t),r=e.agent??Ue(n);D(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),await We(t,r,{name:e.name,emoji:e.emoji,avatar:e.avatar})||(console.error(`Failed to update identity for agent "${r}".`),process.exit(1)),console.log(`Identity updated for agent "${r}".`)}}function Mi(e,t){let n=e.command(`agents`).description(`Manage agents`),r=e=>e.option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`);r(n.command(`list`).description(`List all configured agents`).option(`-j, --json`,`Output as JSON`).option(`-b, --bindings`,`Show detailed binding rules`)).action(async e=>{let n=t();await H(n,e,async()=>{await Ti(e)(n)})}),r(n.command(`add <id>`).description(`Add a new agent`).option(`-n, --name <name>`,`Display name`).option(`-m, --model <model>`,`Model identifier`).option(`--default`,`Mark as default agent`)).action(async(e,n)=>{let r=t();await H(r,n,async()=>{await Ei(e,n)(r)})}),r(n.command(`delete <id>`).description(`Delete an agent`)).action(async(e,n)=>{let r=t();await H(r,n,async()=>{await Di(e)(r)})}),r(n.command(`bind`).description(`Bind a channel to an agent`).option(`-a, --agent <id>`,`Target agent ID`).option(`-b, --bind <channel...>`,`Channel binding (e.g., WEB, KLPA:ops)`)).action(async e=>{let n=t();await H(n,e,async()=>{await Oi(e)(n)})}),r(n.command(`unbind`).description(`Unbind a channel from an agent`).option(`-a, --agent <id>`,`Target agent ID`).option(`-b, --bind <channel...>`,`Channel binding to remove`).option(`--all`,`Remove all bindings for the agent`)).action(async e=>{let n=t();await H(n,e,async()=>{await ki(e)(n)})}),r(n.command(`bindings`).description(`List routing bindings`).option(`-a, --agent <id>`,`Filter by agent ID`).option(`-j, --json`,`Output as JSON`)).action(async e=>{let n=t();await H(n,e,async()=>{await Ai(e)(n)})}),r(n.command(`set-identity`).description(`Set agent identity`).option(`-a, --agent <id>`,`Target agent ID`).option(`-n, --name <name>`,`Agent name`).option(`-e, --emoji <emoji>`,`Agent emoji`).option(`--avatar <path>`,`Avatar path`)).action(async e=>{let n=t();await H(n,e,async()=>{await ji(e)(n)})})}function Y(e){return S.join(e,`workspace`)}function X(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function Ni(e){if(e.length===0){P(`No plugins discovered.`);return}for(let t of e){let e=t.status.padEnd(8,` `);P(`${t.id} ${e} ${t.origin} ${t.source}`)}}function Pi(e){P(`id: ${e.id}`),P(`status: ${e.status}`),P(`origin: ${e.origin}`),P(`source: ${e.source}`),P(`enabled: ${e.enabled}`),e.error&&P(`error: ${e.error}`),P(`tools: ${e.toolCount}`),P(`hooks: ${e.hookCount}`),e.skills.length>0&&P(`skills: ${e.skills.join(`, `)}`)}function Fi(e){return Array.from(new Set((e??[]).map(e=>e.trim()).filter(Boolean)))}function Ii(e){if(e.length===0){P(`LLM allowlist is empty.`);return}for(let t of e)P(t)}function Li(e,t){let n=e.command(`plugins`).description(`Manage AIMax plugins`),r=e=>e.option(`--plugins-config <path>`,`Plugins config file path`),i=e=>e.option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`);i(r(n.command(`list`))).description(`List discovered plugins`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await H(n,e,async()=>{Ni(h({config:await U(n,e.pluginsConfig),dataDir:n,workspaceDir:Y(n),bundledDir:X()}).registry.plugins)})}),i(r(n.command(`info`))).description(`Show plugin details`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await H(r,n,async()=>{let t=h({config:await U(r,n.pluginsConfig),dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.find(t=>t.id===e);t||(F(`Plugin not found: ${e}`),process.exit(1)),Pi(t)})}),i(r(n.command(`enable`))).description(`Enable a plugin`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await H(r,n,async()=>{let t=await U(r,n.pluginsConfig)??{},i=ae(t);h({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(F(`Plugin not found: ${e}`),process.exit(1)),await W(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!0}}},n.pluginsConfig),P(`Enabled ${e}`),i.allow.length>0&&!i.allow.includes(e)&&P(`Note: plugins.allow is set; add this plugin id to allowlist if needed.`)})}),i(r(n.command(`disable`))).description(`Disable a plugin`).argument(`<id>`,`Plugin id`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await H(r,n,async()=>{let t=await U(r,n.pluginsConfig)??{};h({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(F(`Plugin not found: ${e}`),process.exit(1)),await W(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!1}}},n.pluginsConfig),P(`Disabled ${e}`)})}),i(r(n.command(`doctor`))).description(`Validate plugin configuration`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await H(n,e,async()=>{let t=h({config:await U(n,e.pluginsConfig),dataDir:n,workspaceDir:Y(n),bundledDir:X()});if(t.diagnostics.length===0){P(`No plugin issues detected.`);return}for(let e of t.diagnostics)P(`${e.level===`error`?`ERROR`:`WARN`}${e.pluginId?` ${e.pluginId}`:``}: ${e.message}`);t.diagnostics.some(e=>e.level===`error`)&&process.exit(1)})});let a=n.command(`llm-allow`).description(`Manage plugin LLM allowlist`);i(r(a.command(`list`))).description(`List LLM allowlist entries`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await H(n,e,async()=>{Ii(Fi((await U(n,e.pluginsConfig))?.llmAllowlist))})}),i(r(a.command(`add`))).description(`Add entries to the LLM allowlist (plugin id or tool name)`).argument(`<entry...>`,`Plugin id or tool name`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await H(r,n,async()=>{let t=await U(r,n.pluginsConfig)??{},i=Fi([...t.llmAllowlist??[],...e]);await W(r,{...t,llmAllowlist:i},n.pluginsConfig),P(`LLM allowlist updated (${i.length} entries).`)})}),i(r(a.command(`remove`))).description(`Remove entries from the LLM allowlist`).argument(`<entry...>`,`Plugin id or tool name`).option(`-d, --data-dir <path>`,`Data directory path`).action(async(e,n)=>{let r=n.dataDir??t();await H(r,n,async()=>{let t=await U(r,n.pluginsConfig)??{},i=new Set(e.map(e=>e.trim()).filter(Boolean)),a=Fi(t.llmAllowlist).filter(e=>!i.has(e));await W(r,{...t,llmAllowlist:a},n.pluginsConfig),P(`LLM allowlist updated (${a.length} entries).`)})}),i(r(a.command(`clear`))).description(`Clear the LLM allowlist`).option(`-d, --data-dir <path>`,`Data directory path`).action(async e=>{let n=e.dataDir??t();await H(n,e,async()=>{await W(n,{...await U(n,e.pluginsConfig)??{},llmAllowlist:[]},e.pluginsConfig),P(`LLM allowlist cleared.`)})})}function Ri(e){e.command(`commands`).description(`List available slash commands for a data directory`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{let t=e.output===`json`?`json`:`text`;try{await H(e.dataDir,e,async()=>{let n=_(await re(e.dataDir,[]));if(t===`json`){P(JSON.stringify(n,null,2));return}P(`Commands`),P(` builtin: ${n.builtin.map(e=>e.name).join(` | `)}`),n.skillCommands.length>0?P(` skills: ${n.skillCommands.map(e=>e.name).join(` | `)}`):P(` skills: (none)`)})}catch(e){F(`Error listing commands: ${e.message}`),process.exit(1)}})}function Z(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function Q(e){if(!e.sessionId)throw Error(`Session ID is required (--session-id or -s)`);return e.sessionId}function $(e){return e?y(e):void 0}async function zi(e){let t={storeName:e.sessionStoreName},n=e.objective.trim(),r=await b(e.dataDir,e.sessionId,t);if(!r||(await oe(e.dataDir,e.sessionId,r,t)).trim()!==n)return he(e.dataDir,e.sessionId,{goalId:Ke(),objective:n,status:`active`,tokenBudget:e.tokenBudget??null,tokensUsed:0,timeUsedSeconds:0},{...t,eventSource:`cli`});if(r.status===`complete`)return r;let i={};return r.status===`paused`&&(i.status=`active`),e.tokenBudget!==void 0&&e.tokenBudget!==r.tokenBudget&&(i.tokenBudget=e.tokenBudget),Object.keys(i).length===0?r:await me(e.dataDir,e.sessionId,i,{...t,eventSource:`cli`})}async function Bi(e,t){let n=Z(t),r=Q(t),i=$(t.sessionStore),a=e.trim();a||(F(`error: objective cannot be empty`),process.exit(1));let o=t.tokenBudget===void 0||t.tokenBudget===`0`||t.tokenBudget===``?null:Number(t.tokenBudget);o!==null&&(Number.isNaN(o)||o<=0)&&(F(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));let s=await zi({dataDir:n,sessionId:r,sessionStoreName:i,objective:a,tokenBudget:o});P(JSON.stringify({goal:s},null,2))}async function Vi(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(!i){P(JSON.stringify({goal:null},null,2));return}let a=await oe(t,n,i,{storeName:r});P(JSON.stringify({goal:{...i,objective:a}},null,2))}async function Hi(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});i||(F(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(F(`error: cannot pause a completed goal`),process.exit(1));let a=await me(t,n,{status:`paused`},{storeName:r,eventSource:`cli`});P(JSON.stringify({goal:a},null,2))}async function Ui(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(i||(F(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(F(`error: cannot resume a completed goal`),process.exit(1)),i.status===`budget_limited`&&(F(`error: cannot resume a budget-limited goal; clear or replace it instead`),process.exit(1)),i.status===`active`){P(JSON.stringify({goal:i},null,2));return}let a=await me(t,n,{status:`active`},{storeName:r,eventSource:`cli`});P(JSON.stringify({goal:a},null,2))}async function Wi(e){let t=await c(Z(e),Q(e),{storeName:$(e.sessionStore),eventSource:`cli`});P(JSON.stringify({cleared:t},null,2))}function Gi(e){let t=e.command(`goal`).description(`Manage thread goals for a session`).addHelpText(`after`,a());t.command(`set <objective>`).description(`Set or replace the thread goal (creates new goalId)`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--token-budget <n>`,`Optional token budget (positive integer, or 0 for unlimited)`).action(async(e,t)=>{try{await Bi(e,t)}catch(e){F(`error: ${e.message}`),process.exit(1)}}),t.command(`get`).description(`Get the current goal as JSON`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Vi(e)}catch(e){F(`error: ${e.message}`),process.exit(1)}}),t.command(`pause`).description(`Pause the current goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Hi(e)}catch(e){F(`error: ${e.message}`),process.exit(1)}}),t.command(`resume`).description(`Resume a paused goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Ui(e)}catch(e){F(`error: ${e.message}`),process.exit(1)}}),t.command(`clear`).description(`Clear the current goal`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).requiredOption(`-s, --session-id <id>`,`Session ID`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).action(async e=>{try{await Wi(e)}catch(e){F(`error: ${e.message}`),process.exit(1)}})}const Ki=[`progress`,`error`,`hitl`];function qi(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir or AIMAX_DATA_DIR`);return t}function Ji(e){if(!e?.trim())return new Set(Ki);let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean),n=new Set([`start`,`text`,`progress`,`done`,`error`,`hitl`,`title_updated`]),r=new Set;for(let e of t){if(!n.has(e))throw Error(`Invalid stream event: ${e}. Must be one of start,text,progress,done,error,hitl`);r.add(e)}return r.size>0?r:new Set(Ki)}function Yi(e){return e?y(e):void 0}function Xi(e){let t=[];return e.callbackUrl&&t.push(new An(e.callbackUrl)),e.streamUrl&&t.push(new zn(e.streamUrl,Ji(e.streamEvents),e.streamAuthToken)),new kn(t)}async function Zi(e){let t=qi(e);await H(t,e,async()=>{M(t,{messageId:e.messageId});let n=new lt(`cancel command`),r=e.channel??`WEB`,i=e.output===`json`?`json`:`text`,a=Xi(e),o=Yi(e.sessionStore);try{let s=await ee(t,e.sessionId,{storeName:o});if(!s)throw Error(`No pending HITL request found for session "${e.sessionId}"`);let c=e.requestId??s.request.requestId;if(s.request.requestId!==c)throw Error(`Request ID mismatch: pending is "${s.request.requestId}", got "${c}"`);if(!(await ce({dataDir:t,sessionStoreName:o,sessionId:e.sessionId,requestId:c,resolution:{requestId:c,sessionId:e.sessionId,action:`cancel`,submittedAt:new Date().toISOString(),submittedBy:{channel:r}}})).state)throw Error(`Failed to cancel HITL request`);let l={type:`hitl_cancelled`,sessionId:e.sessionId,requestId:c,reason:e.reason??`cancelled by operator`};i===`text`&&I(l),await a.send({type:`progress`,sessionId:e.sessionId,channel:r,messageId:e.messageId,event:l}),n.end(),process.exit(0)}catch(t){let i=t;await a.send({type:`error`,sessionId:e.sessionId,channel:r,messageId:e.messageId,message:i.message}),N.error(`cancel command error: ${i.message}`),F(`Fatal: ${i.message}`),n.end(),process.exit(1)}finally{await a.close()}})}function Qi(e){e.command(`cancel`).description(`Cancel a pending HITL request`).requiredOption(`-d, --data-dir <path>`,`Data directory path`).requiredOption(`-s, --session-id <id>`,`Session ID containing the pending HITL request`).option(`--session-store <name>`,`Session store directory under .aimax (default: sessions)`).option(`--request-id <id>`,`HITL request ID to cancel`).option(`--reason <text>`,`Human-readable cancel reason`).option(`-c, --channel <channel>`,`Channel type (default: WEB)`,`WEB`).option(`--callback-url <url>`,`HTTP callback URL for progress events`).option(`--stream-url <url>`,`WebSocket URL for streaming text events`).option(`--stream-auth-token <token>`,`Auth token for WebSocket streaming`).option(`--stream-events <list>`,`Comma-separated stream events`).option(`--message-id <id>`,`Message ID for correlating events`).option(`--output <format>`,`Output format: text (default) or json`,`text`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async e=>{await Zi(e)})}function $i(e){let t=e.dataDir??process.env.AIMAX_DATA_DIR;if(!t)throw Error(`Data directory must be specified via --data-dir option or AIMAX_DATA_DIR environment variable`);return t}function ea(e){return e.query?.trim()||void 0}function ta(e){if(!e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error(`--timeout must be a positive number of milliseconds`);return t}function na(e){if(!e)return;let t=Number(e);if(!Number.isInteger(t)||t<=0)throw Error(`--max-tokens must be a positive integer`);return t}async function ra(e){if(e.filePath){if(!S.isAbsolute(e.filePath))throw Error(`--file-path must be an absolute path`);try{await E.access(e.filePath)}catch(e){throw Error(`Failed to access --file-path: ${e.message}`)}return{source:`file`,filePath:e.filePath}}let t=e.content;if(!t||!t.trim())throw Error(`Either --file-path or --content must be provided`);return{source:`content`,content:t}}async function ia(e){let t=null;try{let n=$i(e);M(n,{messageId:e.messageId}),t=new lt(`summarize command`);let r=ea(e),i=await ra(e),a=ln({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,model:e.model,contextWindow:2e5}),o=ta(e.timeout),s=na(e.maxTokens);N.info(`summarize command started`,{dataDir:n,source:i.source,filePath:i.source===`file`?i.filePath:void 0,queryLength:r?.length,contentLength:i.source===`content`?i.content.length:void 0,timeoutMs:o,maxTokens:s});let c=await de({dataDir:n,channel:`WEB`,messageId:e.messageId,message:aa(i,r),llm:{...a,maxTokens:s},timeoutMs:o});P(c.text.trim()),N.info(`summarize command succeeded`,{source:i.source,summaryLength:c.text.length,durationMs:c.durationMs}),t.end()}catch(e){N.error(`summarize command error: ${e.message}`),F(`Fatal: ${e.message}`),t?.end(),process.exit(1)}}function aa(e,t){return e.source===`file`?[t?`Summarize exactly one file for the query below.`:`Summarize exactly one file.`,`Read only the absolute file path provided here. Do not search, browse, read other files, execute commands, modify files, or perform any other processing.`,`Return only the summary text.`,``,...t?[`Query:\n${t}`,``]:[],`Input source: file`,`File path: ${e.filePath}`].join(`
14
- `):[t?`Summarize the provided content for the query below.`:`Summarize the provided content.`,t?`Use only the provided content and query. Do not search, browse, read files, execute commands, modify files, or perform any other processing.`:`Use only the provided content. Do not search, browse, read files, execute commands, modify files, or perform any other processing.`,`Return only the summary text.`,``,...t?[`Query:\n${t}`,``]:[],`Input source: content`,`Source content:`,`<source>`,e.content,`</source>`].join(`
15
- `)}function oa(e){e.command(`summarize`).description(`Summarize one absolute file path or inline content`).option(`--file-path <path>`,`Absolute file path to summarize`).option(`--content <text>`,`Inline text content to summarize when --file-path is not provided`).option(`--query <text>`,`Optional search target or current description to focus the summary`).option(`-d, --data-dir <path>`,`Data directory path (overrides AIMAX_DATA_DIR)`).option(`--base-url <url>`,`LLM API base URL (overrides AIMAX_BASE_URL)`).option(`--api-format <format>`,`LLM API format: openai-completions or anthropic-messages (overrides AIMAX_API_FORMAT)`).option(`--api-key <key>`,`LLM API key (overrides AIMAX_API_KEY)`).option(`--model <name>`,`LLM model name (overrides AIMAX_MODEL)`).option(`--timeout <ms>`,`Execution timeout in milliseconds`).option(`--max-tokens <number>`,`Maximum number of tokens for model output`).option(`--message-id <id>`,`Message ID for log correlation`).action(async e=>{await ia(e)})}const sa={accent:`#8abeb7`,border:`#5f87ff`,borderAccent:`#00d7ff`,borderMuted:`#505050`,success:`#b5bd68`,error:`#cc6666`,warning:`#ffff00`,muted:`#808080`,dim:`#666666`,text:`#d4d4d4`,thinkingText:`#808080`,selectedBg:`#3a3a4a`,userMessageBg:`#343541`,userMessageText:`#d4d4d4`,customMessageBg:`#2d2838`,customMessageText:`#d4d4d4`,customMessageLabel:`#9575cd`,toolPendingBg:`#282832`,toolSuccessBg:`#283228`,toolErrorBg:`#3c2828`,toolTitle:`#d4d4d4`,toolOutput:`#808080`,mdHeading:`#f0c674`,mdLink:`#81a2be`,mdLinkUrl:`#666666`,mdCode:`#8abeb7`,mdCodeBlock:`#b5bd68`,mdCodeBlockBorder:`#808080`,mdQuote:`#808080`,mdQuoteBorder:`#808080`,mdHr:`#808080`,mdListBullet:`#8abeb7`,toolDiffAdded:`#b5bd68`,toolDiffRemoved:`#cc6666`,toolDiffContext:`#808080`,syntaxComment:`#6A9955`,syntaxKeyword:`#569CD6`,syntaxFunction:`#DCDCAA`,syntaxVariable:`#9CDCFE`,syntaxString:`#CE9178`,syntaxNumber:`#B5CEA8`,syntaxType:`#4EC9B0`,syntaxOperator:`#D4D4D4`,syntaxPunctuation:`#D4D4D4`,thinkingOff:`#505050`,thinkingMinimal:`#6e6e6e`,thinkingLow:`#5f87af`,thinkingMedium:`#81a2be`,thinkingHigh:`#b294bb`,thinkingXhigh:`#d183e8`,bashMode:`#b5bd68`},ca=`#18181e`,la=`#1e1e24`,ua=`#3c3728`;function da(e){if(!e||typeof e!=`object`)return!1;let t=e.role;return t===`user`||t===`assistant`||t===`tool_result`||t===`compaction`}function fa(e){return!e||typeof e!=`object`?!1:typeof e.type==`string`}function pa(e){return{type:`text`,text:e}}function ma(e){return{type:`thinking`,thinking:e}}function ha(e,t){let n=e.timestamp,r=typeof n==`string`&&n?n:e.content;return`${e.role}\0${r}\0${t}`}function ga(e,t,n){let r=ha(e,t);for(let e=0;e<100;e++){let t=Ge(`sha256`).update(`${r}\0${e}`).digest(`hex`).slice(0,8);if(!n.has(t))return n.add(t),t}let i=Ge(`sha256`).update(`${r}\0fallback`).digest(`hex`);return n.add(i),i}function _a(e,t){let n=new Set,r=null,i=[],a={type:`session`,version:3,id:t?.sessionId??Ke(),timestamp:e.find(e=>e.timestamp)?.timestamp??new Date().toISOString(),cwd:t?.cwd??process.cwd()};for(let[t,a]of e.entries()){let e=ga(a,t,n),o={id:e,parentId:r,timestamp:a.timestamp};if(a.role===`user`)i.push({type:`message`,...o,message:{role:`user`,content:[pa(a.content)]}});else if(a.role===`assistant`){let e=[];a.thinking?.trim()&&e.push(ma(a.thinking.trim())),a.content.trim()&&e.push(pa(a.content));for(let t of a.toolCalls??[])e.push({type:`toolCall`,id:t.id,name:t.name,arguments:t.arguments});a.errorMessage&&e.push(pa(a.errorMessage)),i.push({type:`message`,...o,message:{role:`assistant`,content:e,...a.stopReason?{stopReason:a.stopReason}:{}}})}else if(a.role===`tool_result`){let e=a.content;a.toolResultRef?.preview&&!e.includes(a.toolResultRef.preview)&&(e=`${e}\n\nPreview:\n${a.toolResultRef.preview}`),a.toolResultRef?.storagePath&&(e=`${e}\n\n[Full output: ${a.toolResultRef.storagePath}]`),i.push({type:`message`,...o,message:{role:`toolResult`,toolCallId:a.toolCallId,toolName:a.toolName,content:[pa(e)],isError:a.isError}})}else a.role===`compaction`&&i.push({type:`compaction`,...o,summary:a.content,firstKeptEntryId:r??e,tokensBefore:0});r=e}return{header:a,entries:i,leafId:r}}function va(e,t){let n=e.trim().split(`
16
- `).filter(e=>e.trim()),r=[],i=0;for(let e of n)try{r.push(JSON.parse(e))}catch{i+=1}if(r.length===0)return{data:_a([],t),skippedLines:i};let a=r[0];if(fa(a)&&a.type===`session`){let e=a,t=r.slice(1).filter(fa);return{data:{header:e,entries:t,leafId:t.length>0?t[t.length-1].id:null},skippedLines:i}}if(r.every(fa)){let e=r;return{data:{header:{type:`session`,version:3,id:t?.sessionId??Ke(),timestamp:e[0]?.timestamp??new Date().toISOString(),cwd:t?.cwd??process.cwd()},entries:e,leafId:e.length>0?e[e.length-1].id:null},skippedLines:i}}return{data:_a(r.filter(da),t),skippedLines:i}}function ya(e){let t=e;for(;t!==C(t);){if(x(w(t,`package.json`)))return t;t=C(t)}throw Error(`Could not find @gencode/cli package root`)}function ba(){let e=ya(C(Pe(import.meta.url))),t=[w(e,`dist`,`export-html`),w(e,`src`,`export-html`)];for(let e of t)if(x(w(e,`template.html`)))return e;throw Error(`export-html template directory not found under ${e}`)}function xa(e){let t=S.resolve(e),n=`${S.sep}.aimax${S.sep}`,r=t.indexOf(n);if(!(r<0))return t.slice(0,r)}function Sa(e){let t=S.dirname(S.resolve(e));return S.basename(t)}async function Ca(e){let t=e.dataDir??(e.transcriptPath?xa(e.transcriptPath):void 0),n=e.sessionId??(e.transcriptPath?Sa(e.transcriptPath):void 0);return!t||!n?{}:ne(t,n,e.sessionPathOptions)}const wa=new Map;function Ta(e){let t=wa.get(e);if(t!==void 0)return t;let n=Ce(w(ba(),e),`utf-8`);return wa.set(e,n),n}function Ea(){let e=[];for(let[t,n]of Object.entries(sa))e.push(`--${t}: ${n};`);return e.push(`--exportPageBg: ${ca};`),e.push(`--exportCardBg: ${la};`),e.push(`--exportInfoBg: ${ua};`),e.join(`
17
- `)}function Da(e){return e.replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&amp;`;case`<`:return`&lt;`;case`>`:return`&gt;`;case`"`:return`&quot;`;case`'`:return`&#39;`;default:return e}})}function Oa(e){let t=Ta(`template.html`),n=Ta(`template.css`),r=Ta(`template.js`),i=Buffer.from(JSON.stringify(e)).toString(`base64`),a=n.replace(`{{THEME_VARS}}`,Ea()).replace(`{{BODY_BG}}`,ca).replace(`{{CONTAINER_BG}}`,la).replace(`{{INFO_BG}}`,ua);return t.replace(`{{CSS}}`,a).replace(`{{JS}}`,r).replace(`{{SESSION_DATA}}`,i)}function ka(e,t){return t||`aimax-session-${Ee(e,`.jsonl`)}.html`}function Aa(e,t){return`Skipped ${t} malformed JSONL line(s) while exporting ${e}`}function ja(e){for(let t of e)console.warn(t)}async function Ma(e,t){if(t.options?.includeSnapshots===!1)return e;let n=await Ca({dataDir:t.options?.dataDir,sessionId:t.options?.sessionId??e.header.id,transcriptPath:t.inputLabel,sessionPathOptions:t.options?.sessionPathOptions});return!n.systemPrompt&&!n.tools?.length?e:{...e,...n.systemPrompt?{systemPrompt:n.systemPrompt}:{},...n.tools?.length?{tools:n.tools}:{}}}async function Na(e,t,n){let r=va(e,{sessionId:n?.sessionId,cwd:n?.cwd}),i=r.skippedLines>0?[Aa(t,r.skippedLines)]:[],a=r.data;a=await Ma(a,{inputLabel:t,options:n});let o=Oa(a),s=ka(t,n?.outputPath);return Te(s,o,`utf8`),{outputPath:s,warnings:i}}async function Pa(e,t){if(!x(e))throw Error(`File not found: ${e}`);return Na(Ce(e,`utf-8`),e,t)}async function Fa(e,t){let n=await Pa(e,t);return ja(n.warnings),n.outputPath}async function Ia(e,t,n){let r=pe(e,t,n);if(!x(r))throw Error(`Transcript not found: ${r}`);if((await ie(e,t,n)).length===0&&!Ce(r,`utf-8`).trim())throw Error(`Nothing to export yet - transcript is empty`);let i=Ce(r,`utf-8`),{outputPath:a,sessionId:o,cwd:s,dataDir:c,includeSnapshots:l,...u}=n??{};return Na(i,r,{outputPath:n?.outputPath,sessionId:t,cwd:n?.cwd,dataDir:e,sessionPathOptions:u,includeSnapshots:n?.includeSnapshots})}async function La(e,t,n){let r=await Ia(e,t,n);return ja(r.warnings),r.outputPath}function Ra(e,t){let n=t.map(t=>{let n=x(w(e,t.fileName))?we(w(e,t.fileName)):void 0,r=n?`${Math.round(n.size/1024)} KB`:``,i=t.sourcePath?`<span class="muted">${Da(t.sourcePath)}</span>`:``;return`<tr><td><a href="${Da(t.fileName)}">${Da(t.sessionId)}</a></td><td>${r}</td><td>${i}</td></tr>`}).join(`
18
- `),r=`<!DOCTYPE html>
19
- <html lang="zh-CN">
20
- <head>
21
- <meta charset="UTF-8">
22
- <title>AIMax Session Exports</title>
23
- <style>
24
- body { font-family: system-ui, sans-serif; margin: 2rem; background: #18181e; color: #d4d4d4; }
25
- table { border-collapse: collapse; width: 100%; }
26
- th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid #333; }
27
- a { color: #81a2be; }
28
- .muted { color: #808080; font-size: 0.85em; }
29
- </style>
30
- </head>
31
- <body>
32
- <h1>AIMax Session Exports (${t.length})</h1>
33
- <table>
34
- <thead><tr><th>Session</th><th>Size</th><th>Source</th></tr></thead>
35
- <tbody>
36
- ${n}
37
- </tbody>
38
- </table>
39
- </body>
40
- </html>`,i=w(e,`index.html`);return Te(i,r,`utf8`),i}async function za(e,t,n){Se(t,{recursive:!0});let r=fe(e,n),i=[],a=[],o=[],s=[],c;try{c=await ke(r)}catch(e){throw e.code===`ENOENT`?Error(`Sessions directory not found: ${r}`):e}for(let r of c.sort()){let c=pe(e,r,n);if(!x(c)){a.push({sessionId:r,reason:`no transcript.jsonl`});continue}try{let a=w(t,`${r}.html`),l=await Ia(e,r,{...n,outputPath:a});o.push(...l.warnings),i.push({sessionId:r,path:l.outputPath}),s.push({sessionId:r,fileName:`${r}.html`,sourcePath:c})}catch(e){a.push({sessionId:r,reason:e.message})}}let l;return n?.writeIndex!==!1&&s.length>0&&(l=Ra(t,s)),{exported:i,skipped:a,warnings:o,indexPath:l}}async function Ba(e,t,n){Se(t,{recursive:!0});let r=[],i=[],a=[],o=[],s=[];for await(let t of Oe(e,{cwd:process.cwd()}))s.push(t);if(s.sort(),s.length===0)throw Error(`No files matched glob: ${e}`);for(let e of s){let n=T(e),s=Ee(C(n));if(!x(n)){i.push({sessionId:s,reason:`file missing`});continue}try{let e=await Pa(n,{outputPath:w(t,`${s}.html`),sessionId:s,dataDir:xa(n)});a.push(...e.warnings),r.push({sessionId:s,path:e.outputPath}),o.push({sessionId:s,fileName:`${s}.html`,sourcePath:n})}catch(e){i.push({sessionId:s,reason:e.message})}}let c;return n?.writeIndex!==!1&&o.length>0&&(c=Ra(t,o)),{exported:r,skipped:i,warnings:a,indexPath:c}}function Va(e){e.command(`export-html`).description(`Export transcript.jsonl to standalone HTML files for browsing`).argument(`[transcript]`,`Path to transcript.jsonl (or use -d/-s, --all, or --glob)`).option(`-d, --data-dir <path>`,`Data directory containing .aimax/sessions`).option(`-s, --session-id <id>`,`Session ID under the data directory`).option(`--session-store <name>`,`Session store under .aimax (default: sessions)`).option(`-o, --output <path>`,`Output HTML path for a single export`).option(`--output-dir <path>`,`Output directory for batch export`).option(`--all`,`Export all sessions under --data-dir (requires --output-dir)`).option(`--glob <pattern>`,`Export transcripts matching a glob (requires --output-dir)`).option(`--no-index`,`Skip writing index.html in batch mode`).option(`--encrypt-sessions`,`Enable gocryptfs-backed encryption for the .aimax data directory`).action(async(e,t,n)=>{let r=n.opts();try{if(r.glob){r.outputDir||(F(`error: --glob requires --output-dir`),process.exit(1)),Ua(await Ba(r.glob,T(r.outputDir),{writeIndex:!r.noIndex}));return}if(r.all){(!r.dataDir||!r.outputDir)&&(F(`error: --all requires --data-dir and --output-dir`),process.exit(1)),await H(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;Ua(await za(r.dataDir,T(r.outputDir),{storeName:e,writeIndex:!r.noIndex}))});return}if(e){let t=T(e);x(t)||(F(`File not found: ${t}`),process.exit(1)),r.outputDir&&Se(T(r.outputDir),{recursive:!0});let n=await Fa(t,{outputPath:r.outputDir?w(T(r.outputDir),`${Ee(C(t))}.html`):r.output});console.log(n);return}(!r.dataDir||!r.sessionId)&&(F(`error: specify <transcript.jsonl>, --glob, (-d --all --output-dir), or (-d -s)`),process.exit(1)),Ha(r.sessionId),await H(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;r.outputDir&&Se(T(r.outputDir),{recursive:!0});let t=r.outputDir?T(r.outputDir,`${r.sessionId}.html`):r.output,n=await La(r.dataDir,r.sessionId,{outputPath:t,storeName:e});console.log(n)})}catch(e){F(`Error exporting HTML: ${e.message}`),process.exit(1)}})}function Ha(e){if(e.includes(`..`)||e.startsWith(`/`))throw Error(`Invalid session id: ${e}`)}function Ua(e){for(let t of e.exported)console.log(t.path);for(let t of e.warnings??[])F(`warning: ${t}`);for(let t of e.skipped)F(`skipped ${t.sessionId}: ${t.reason}`);e.indexPath&&console.log(e.indexPath),console.log(`exported ${e.exported.length}, skipped ${e.skipped.length}`)}const Wa=e(import.meta.url)(`../package.json`);function Ga(){return process.env.AIMAX_DATA_DIR||process.cwd()}function Ka(){let e=new t;return e.name(`aimax`).description(`AIMax CLI — runs agent tasks in a containerized environment`).version(Wa.version),pi(e),_r(e),Gi(e),Qi(e),mi(e),Va(e),oa(e),Ri(e),rn(e),Ci(e),Mi(e,Ga),Li(e,Ga),e}export{N as a,M as i,Ga as n,ct as o,di as r,Ka as t};