@gencode/cli 0.7.3 → 0.8.1
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 +29 -0
- package/README.md +22 -0
- package/dist/bin.js +1 -1
- package/dist/program-CBzbMheo.js +15 -0
- package/dist/program.js +1 -1
- package/package.json +5 -3
- package/scripts/download-embedding-model.mjs +218 -0
- package/dist/program-CzocoEBh.js +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @gencode/cli
|
|
2
2
|
|
|
3
|
+
## 0.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d311251: Fix `aimax run --encrypt-sessions` so the CLI mounts `<dataDir>/.aimax.enc` onto `<dataDir>/.aimax` before creating run logs or other `.aimax` files. This prevents each serverless run from starting with a freshly initialized plaintext `.aimax` directory, allows existing encrypted session data to be visible at run start, and lets the encrypted mount cleanup run before successful command completion.
|
|
8
|
+
|
|
9
|
+
## 0.8.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- c0def9b: `runAgent` now accepts an optional `env` field on `AgentRunParams` for passing session-scoped environment variables that are isolated to the current run. When supplied, the map is merged into the environment of every child process spawned by the built-in `exec` and `process` tools, and is also exposed to plugin scripts through the read-only `api.runtime.session.env` accessor (carried in the plugin runtime context under `env`). When a single `exec` call also passes its own `env`, the merge order is `process.env` < run-level `env` < per-call `env`, so per-call values override the run-level ones. The map is held in memory only for the duration of the run; it is never written to disk and never crosses a session boundary. The `subagent_spawn` and `batch_subagent_spawn` tools now also forward `env` to child runs through the standard `InheritedRunParams` plumbing, so subagent sessions inherit the same session-scoped env without any extra configuration. Downstream entry points that pass `AgentRunParams` through to the runner (`@gencode/cli`, `@gencode/plugin-sdk`, `@gencode/console`, `@gencode/web`) need to be re-released to expose the new field; no other call-site changes are required.
|
|
14
|
+
|
|
15
|
+
The `aimax run` command now accepts a new `--env <kvlist>` flag for setting session-scoped env vars from the command line. The value is a comma-separated list of `KEY=VALUE` pairs (e.g. `--env TENANT=acme,TOKEN=secret`); backslash-escape `,` and `=` inside values if you need literal ones, and use `KEY=` to pass an empty string. The parsed map is forwarded as `AgentRunParams.env`, so the merge order, plugin visibility, and subagent inheritance described above all apply to CLI runs as well. The start banner shows only the number of keys injected — values are never printed.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 364c7d9: Improves long-session context compaction stability. Session memory, automatic compaction, manual `/compact`, and context-limit recovery now build summarisation requests from bounded context views, so large historical turns are truncated or omitted before the summariser call instead of being sent as an oversized request. Default CLI behavior is unchanged; the fix applies automatically when continuing long sessions with the configured `--context-window` or `AIMAX_CONTEXT_WINDOW`.
|
|
20
|
+
- 03c58de: Agent runs are now resilient to progress delivery failures that happen immediately after an `exec` tool finishes. If stdout rendering, callback delivery, or websocket progress handling fails while reporting a tool result, `aimax run` logs the progress failure and continues the agent run instead of treating the reporting failure as a fatal task error. Tool result progress output is also normalized to text before rendering, so unusual or empty tool result payloads no longer crash the CLI output path.
|
|
21
|
+
- bcbb53f: Smart topic segmentation can now load its local embedding model from the installed CLI package. Set `AIMAX_EMBEDDING_MODEL_URL` during `@gencode/cli` installation to have the CLI `postinstall` download the model archive into `models/Xenova/bge-small-zh-v1.5/`; leave it unset to skip the download with no network access or install failure. Deployments may also set `AIMAX_EMBEDDING_MODEL_SHA256` to verify the archive. At runtime, `aimax run` and `aimax resume` automatically pass the installed `models/` directory to agents, while missing models continue to degrade without remote model downloads.
|
|
22
|
+
- 379f84e: `AgentRunParams.projectDir` is now honored as the effective session workspace directory. When `aimax run` or `aimax resume` is started with `--project-dir <path>` (or the equivalent `projectDir` field passed through the plugin SDK, console, or web entry point), the agent operates directly on that directory instead of the default `<dataDir>/workspace` mount. When `projectDir` is empty or omitted, the previous `<dataDir>/workspace` layout is preserved unchanged. The `subagent_spawn` and `subagents` tools now also forward `projectDir` to child runs, so subagents started inside a `--project-dir` session share the same project workspace without any extra configuration. The new `resolveWorkspaceDir` helper in `@gencode/agents` is the single source of truth for this rule, used by the runner, the session lifecycle, and the tool factory.
|
|
23
|
+
- d0edcb7: LLM provider errors returned inside an HTTP 200 stream now surface the provider's readable message directly, without the internal `LLM upstream returned an error payload in a 200 stream` prefix. Transient failures that only expose the generic `LLMRequestError` marker are also retried by the existing turn retry policy, while structured provider status codes such as `502`, `500`, and `429` keep the same retry behavior and non-retryable errors such as `404` still fail immediately.
|
|
24
|
+
- Updated dependencies [364c7d9]
|
|
25
|
+
- Updated dependencies [03c58de]
|
|
26
|
+
- Updated dependencies [bcbb53f]
|
|
27
|
+
- Updated dependencies [379f84e]
|
|
28
|
+
- Updated dependencies [c0def9b]
|
|
29
|
+
- Updated dependencies [d0edcb7]
|
|
30
|
+
- @gencode/agents@0.10.0
|
|
31
|
+
|
|
3
32
|
## 0.7.3
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -55,12 +55,34 @@
|
|
|
55
55
|
- 优先复用 `@gencode/shared` 中的共享协议结构
|
|
56
56
|
- 保持命令行为小、显式、可测试
|
|
57
57
|
|
|
58
|
+
## 可选 embedding 模型安装
|
|
59
|
+
|
|
60
|
+
智能主题拆分会使用 `transformers.js` 本地 embedding 模型做历史 topic 检索。
|
|
61
|
+
`@gencode/cli` 的 `postinstall` 只在安装环境显式设置 `AIMAX_EMBEDDING_MODEL_URL` 时下载模型;未设置时直接跳过,不访问网络。
|
|
62
|
+
|
|
63
|
+
推荐由部署系统提供企业内网模型包:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
AIMAX_EMBEDDING_MODEL_URL=https://example.internal/aimax/bge-small-zh-v1.5.tar.gz \
|
|
67
|
+
AIMAX_EMBEDDING_MODEL_SHA256=<sha256> \
|
|
68
|
+
npm install -g @gencode/cli
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
下载后模型会放到 CLI 包安装目录的 `models/` 下,并归一化为:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
models/Xenova/bge-small-zh-v1.5/config.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
运行时 `aimax run` / `aimax resume` 会自动把该 `models/` 根目录传给 `@gencode/agents`。如果 postinstall 被跳过或安装时使用了 `--ignore-scripts`,主题拆分仍可运行,但本地 embedding 检索会降级。
|
|
78
|
+
|
|
58
79
|
## 验证
|
|
59
80
|
|
|
60
81
|
在工作区根目录可运行:
|
|
61
82
|
|
|
62
83
|
```bash
|
|
63
84
|
pnpm -C source/packages/cli test
|
|
85
|
+
node --test source/packages/cli/scripts/download-embedding-model.node-test.mjs
|
|
64
86
|
```
|
|
65
87
|
|
|
66
88
|
工作区级验证:
|
package/dist/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as e,i as t,r as n,t as r}from"./program-
|
|
2
|
+
import{a as e,i as t,r as n,t as r}from"./program-CBzbMheo.js";function i(){globalThis.getPkgPath||(globalThis.getPkgPath=()=>`@wizard/aimax`)}i();const a=Date.now(),o=process.env.AIMAX_DATA_DIR,s=process.argv.includes(`run`)&&process.argv.includes(`--encrypt-sessions`);o&&!s&&n(o),t.info(`AIMax CLI starting (pid=${process.pid})`,{dataDir:o,encryptedRun:s,loggerDeferred:!!(o&&s)}),r().parseAsync(process.argv).catch(e=>{t.error(`Unexpected error: ${e.message}`),process.exit(1)}).finally(()=>{let n=Date.now()-a;return t.info(`AIMax CLI exited (total uptime: ${n}ms)`),e()});export{};
|
|
@@ -0,0 +1,15 @@
|
|
|
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,createBuiltinMemoryProvider as c,deleteGoal as l,ensureBootstrapMountLayout as u,exportSession as d,formatApprovalResolution as f,formatClarifyResolution as p,formatReviewResolution as m,hasBootstrapSentinel as h,initializePluginSystem as g,inspectSession as _,listAvailableSlashCommands as v,listSessionSummaries as ee,loadPendingHitl as te,loadPendingUiTool as ne,loadSkillsWithPluginDirs as re,loadTranscript as ie,normalizePluginsConfig as ae,normalizeSessionStoreName as y,readGoal as b,resolveGoalObjective as oe,resolveMemoryProvider as se,resolvePendingHitl as ce,resolvePendingUiTool as le,rewriteTranscript as ue,runAgent as x,updateGoal as de,writeGoal as fe}from"@gencode/agents";import{formatTaskForDisplay as pe,isAgentDiagnosticEvent as me,isHitlTool as he,parseMatchedTextToResolution as ge,parseTextToResolution as _e}from"@gencode/shared";import S from"node:fs/promises";import C from"node:fs";import w from"node:path";import ve from"node:os";import{execFile as ye,execFileSync as be}from"node:child_process";import xe from"log4js";import Se from"gensign-node";import{fileURLToPath as Ce}from"node:url";import{addAgent as we,addBinding as Te,getAgentConfig as T,listAgents as Ee,listBindings as De,loadAgentsConfig as E,normalizeAgentId as Oe,removeAgent as ke,removeBindings as Ae,resolveAgentDir as je,resolveDefaultAgentId as D,updateAgentIdentity as Me}from"@gencode/agents/config";import{randomUUID as Ne}from"node:crypto";function Pe(e){if(typeof e==`string`)return e;let t=JSON.stringify(e);return t===void 0?String(e):t}function Fe(e){process.stdout.write(e)}function O(e){process.stdout.write(e+`
|
|
2
|
+
`)}function k(e){process.stderr.write(e+`
|
|
3
|
+
`)}function A(e){switch(e.type){case`start`:O(`\n[start] ${e.message}`);break;case`text`:Fe(e.text);break;case`stream_text_delta`:Fe(e.text);break;case`bootstrap`:O(`\n[bootstrap:${e.phase}] ${e.dataDir}`);break;case`session_reset`:O(`\n[session:${e.action}] ${e.message}`);break;case`tool_start`:O(`\n[tool:${e.name}] ${JSON.stringify(e.input??{})}`);break;case`tool_end`:{let t=Pe(e.output);O(`[tool:${e.name}] ${e.isError?`ERROR`:`OK`} ${t.slice(0,200)}`);break}case`compaction`:O(`\n[compaction${e.layer?`:${e.layer}`:``}] ${e.reason}${e.strategy?` (${e.strategy})`:``}`);break;case`skill_used`:O(`\n[skill] ${e.skillName} agent=${e.agent} task=${e.taskId}`);break;case`custom`:O(`\n[plugin:${e.pluginId}] ${e.name}${e.label?` ${e.label}`:``}${e.data?` ${JSON.stringify(e.data)}`:``}`);break;case`error`:k(`\n[error] ${e.message}`);break;case`diagnostic`:break;case`subagent_spawn`:O(`\n[subagent:spawn]${e.label?` "${e.label}"`:``} ${pe(e.task)}`);break;case`subagent_complete`:O(`[subagent:${e.status}] ${pe(e.task)}`);break;case`hitl_requested`:if(O(`\n[hitl:${e.request.kind}] ${e.request.title}`),O(` prompt: ${e.request.prompt}`),O(` requestId: ${e.request.requestId}`),e.request.input.mode===`choice`)for(let t of e.request.input.choices)O(` - [${t.id}] ${t.label}`);break;case`hitl_resumed`:O(`\n[hitl:resumed] requestId=${e.requestId} action=${e.resolution.action}`);break;case`hitl_expired`:O(`\n[hitl:expired] requestId=${e.requestId} reason=${e.reason}`);break;case`hitl_cancelled`:O(`\n[hitl:cancelled] requestId=${e.requestId}${e.reason?` reason=${e.reason}`:``}`);break;case`ui_tool_request`:O(`\n[ui-tool:${e.request.toolName}] ${e.request.outputSchema.title}`),O(` requestId: ${e.request.requestId}`),O(` toolCallId: ${e.request.toolCallId}`);break;case`ui_tool_result`:O(`\n[ui-tool:resumed] requestId=${e.requestId} tool=${e.toolName}`);break}}function Ie(e,t){if(t===`json`){e&&O(JSON.stringify(e,null,2));return}O(`
|
|
4
|
+
`),O(`session: ${e.sessionId}`),O(`duration: ${e.durationMs}ms`),O(`tokens: input=${e.usage.input} output=${e.usage.output} total=${e.usage.total}`),e.context&&(O(`context: ${e.context.snapshotPath}`),O(`tool-results: ${e.context.toolResultsDir}`)),e.error&&k(`error: ${e.error}`)}function Le(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}if(e.length===0){O(`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:—]`;O(`${t.id} ${e} [${t.channel}]${n} ${t.title}`)}}function Re(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`session: ${e.id}`),e.metadata&&(O(`title: ${e.metadata.title}`),O(`channel: ${e.metadata.channel}`),O(`created: ${e.metadata.createdAt}`),O(`updated: ${e.metadata.updatedAt}`)),O(`transcript: ${e.transcriptPath}`),O(`entries: ${e.transcriptEntryCount}`),O(`context: ${e.contextSnapshotPath}`),O(`session-memory: ${e.sessionMemoryPath}`),O(`collapse-log: ${e.collapseLogPath}`),O(`read-states: ${e.readStateCount}`),O(`tool-results: ${e.toolResultRefCount}`),O(`tool-results-dir: ${e.toolResultsDir}`)}function ze(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`session: ${e.id}`),O(`transcript: ${e.paths.transcriptPath}`),O(`context: ${e.paths.contextSnapshotPath}`),O(`session-memory: ${e.paths.sessionMemoryPath}`),O(`collapse-log: ${e.paths.collapseLogPath}`),O(`tool-results-dir: ${e.paths.toolResultsDir}`),O(`transcript-entries: ${e.transcript.length}`),O(`read-states: ${e.context.readStates.length}`),O(`tool-results: ${e.context.toolResults.length}`),O(`collapse-spans: ${e.context.compaction.collapseSpans.length}`)}function Be(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`Bootstrap completed.`),O(`dataDir: ${e.dataDir}`),O(`created dirs: ${e.createdDirs.length}`),O(`created files: ${e.createdFiles.length}`),O(`skipped dirs: ${e.skippedDirs.length}`),O(`skipped files: ${e.skippedFiles.length}`)}function Ve(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 He(e=new Date){let t=Ve(e),n=String(e.getMilliseconds()).padStart(3,`0`);return`${t.year}-${t.month}-${t.day} ${t.hour}:${t.minute}:${t.second}.${n}`}let j=function(e){return e.INFO=`INFO`,e.ERROR=`ERROR`,e.WARN=`WARN`,e}({}),M=null;function Ue(){return He()}function We(e){if(!e)return``;let t=Object.entries(e).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${JSON.stringify(t)}`);return t.length>0?` ${t.join(` `)}`:``}function Ge(e){return w.join(e,`.aimax`)}function Ke(e){return{appLogPath:w.join(e,`app.log`),errorLogPath:w.join(e,`errors.log`)}}function qe(e){let{appLogPath:t,errorLogPath:n}=Ke(e);xe.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 Je(e,t,n){return`[${Ue()}] [${e}] ${t}${We(n)}`}function Ye(e,t,n){process.stderr.write(`${Je(e,t,n)}\n`)}function Xe(e,t,n){if(!M){Ye(e,t,n);return}let r=Je(e,t,n),i=xe.getLogger();if(e===j.ERROR){i.error(r);return}if(e===j.WARN){i.warn(r);return}i.info(r)}function N(e){let t=Ge(e);C.mkdirSync(t,{recursive:!0}),qe(t),M={dataDir:e,logDir:t}}function Ze(){return M?{...M}:null}async function Qe(){await xe.shutdown()}const P={info:(e,t)=>Xe(j.INFO,e,t),warn:(e,t)=>Xe(j.WARN,e,t),error:(e,t)=>Xe(j.ERROR,e,t)};var F=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}};const $e=`.aimax`,et=`${$e}.pre-gocryptfs.`,tt=[`fusermount3`,`fusermount`,`umount`],nt=[{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 rt(e){return w.join(e,`.aimax.enc`)}function it(e){return w.join(e,$e)}function at(e){return w.join(e,`${et}${process.pid}.${Date.now()}`)}function ot(e){return e.replace(/\\([0-7]{3})/g,(e,t)=>String.fromCharCode(Number.parseInt(t,8)))}async function I(e){try{let t=await lt.read(),n=w.resolve(e);for(let e of t.split(`
|
|
5
|
+
`)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&w.resolve(ot(t[4]??``))===n)return!0}return!1}catch{return!1}}function st(e){try{let t=C.readFileSync(`/proc/self/mountinfo`,`utf-8`),n=w.resolve(e);for(let e of t.split(`
|
|
6
|
+
`)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&w.resolve(ot(t[4]??``))===n)return!0}return!1}catch{return!1}}async function ct(){return await S.readFile(`/proc/self/mountinfo`,`utf-8`)}const lt={read:ct};async function L(e){try{return await S.stat(e),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function R(e){await S.mkdir(e,{recursive:!0})}async function ut(e){if(await R(e),(await S.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 dt(e){return await L(e)?(await S.readdir(e)).length===0:!0}async function z(e){if(await L(e))return(await S.readdir(e)).length}async function ft(e){if(!await L(w.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 pt(e){return(await S.readdir(e,{withFileTypes:!0})).filter(e=>e.isDirectory()&&e.name.startsWith(et)).map(t=>w.join(e,t.name)).sort()}async function B(e,t){if(!await L(t))return null;let n=at(e);return P.info(`--encrypt-sessions moving plaintext .aimax aside before migration`,{plainDir:t,backupDir:n}),await S.rename(t,n),n}async function V(e,t,n){P.info(`--encrypt-sessions copying plaintext backup into encrypted mount`,{backupDir:e,plainDir:t,force:n}),await S.cp(e,t,{recursive:!0,force:n})}async function mt(e){let t=w.join(ve.tmpdir(),`aimax-gocryptfs-pass.${process.pid}.${Date.now()}`);await S.writeFile(t,`wizard_aimax@2026
|
|
7
|
+
`,{mode:384});try{return await e(t)}finally{await S.rm(t,{force:!0})}}async function ht(e){let t=e.includes(`-init`)?`init`:`mount`;P.info(`--encrypt-sessions starting gocryptfs ${t}`);try{await Ct(`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 Tt(`gocryptfs`,`required for --encrypt-sessions`),P.info(`--encrypt-sessions dependency available`,{command:`gocryptfs`});for(let e of tt)if(await wt(e)){P.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 _t(e,t){P.info(`--encrypt-sessions mounting encrypted .aimax`,{encryptedDir:e,plainDir:t}),await mt(async n=>{await ht([`-q`,`-passfile`,n,e,t])})}async function vt(e){P.info(`--encrypt-sessions initializing encrypted .aimax directory`,{encryptedDir:e}),await mt(async t=>{await ht([`-q`,`-init`,`-passfile`,t,e])})}async function yt(e){let t=[];P.info(`--encrypt-sessions unmounting encrypted .aimax`,{plainDir:e});for(let n of nt)try{if(P.info(`--encrypt-sessions attempting encrypted .aimax unmount`,{command:n.label,plainDir:e}),await Ct(n.command,[...n.args,e]),!await I(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=Et(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 bt(e){for(let t of nt)try{if(be(t.command,[...t.args,e],{stdio:`ignore`}),!st(e))return}catch{}}function xt(e){let t=!1,n=()=>{t||(t=!0,bt(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 St(e){let t=rt(e),n=it(e),r=await L(n),i=await L(t),a=i&&await L(w.join(t,`gocryptfs.conf`)),o=r?await I(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 z(n),encryptedDirEntryCount:await z(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 R(n),s()}if(await I(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 pt(e),l.length>0&&P.warn(`--encrypt-sessions found interrupted pre-gocryptfs migration backups`,{count:l.length}),!await L(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 B(e,n):c=await B(e,n),await R(t),await vt(t),await R(n),await _t(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 V(e,n,!0);u&&=(await V(u,n,!1),await S.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 S.rm(e,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await V(c,n,!0),await S.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 z(n)}),await ft(t),l.length>0?u=await B(e,n):await dt(n)||(c=await B(e,n)),await ut(n),await _t(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 V(e,n,!0);u&&=(await V(u,n,!1),await S.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 S.rm(e,{recursive:!0,force:!0}),P.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});l=[]}else c&&=(await V(c,n,!0),await S.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 I(n),plainDirEntryCount:await z(n),encryptedDirEntryCount:await z(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 yt(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){return d?.release(),f&&await yt(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 L(c)&&await dt(n)&&(await S.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await S.rename(c,n).catch(()=>{}),P.info(`--encrypt-sessions restored plaintext backup after failed migration`,{backupDir:c,plainDir:n})),u&&await L(u)&&await dt(n)&&(await S.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await S.rename(u,n).catch(()=>{}),P.info(`--encrypt-sessions restored residual plaintext backup after failed migration`,{backupDir:u,plainDir:n})),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 R(n),s()}}async function H(e,t,n){if(!t.encryptSessions)return n();P.info(`--encrypt-sessions wrapper starting encrypted .aimax preparation`,{dataDir:e});let r=await St(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 Ct(e,t){await new Promise((n,r)=>{ye(e,t,{encoding:`utf-8`},e=>{if(e){r(e);return}n()})})}async function wt(e){try{return await Ct(`sh`,[`-c`,`command -v "${e}" >/dev/null 2>&1`]),!0}catch{return!1}}async function Tt(e,t){if(!await wt(e))throw Error(`--encrypt-sessions requires ${e}: ${t}.`)}function Et(e,t){return`${e} failed: ${t instanceof Error?t.message:String(t)}`}function Dt(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{Be(await H(e.dataDir,e,async()=>i(e.dataDir)),t)}catch(e){k(`Error bootstrapping data directory: ${e.message}`),process.exit(1)}})}function Ot(e){return Se.sm4_encrypt_ecb(e)}function kt(e){return Ot(e)}function At(e={}){let t=jt(e.apiFormat??process.env.AIMAX_API_FORMAT),n=e.baseUrl??process.env.AIMAX_BASE_URL,r=process.env.AIMAX_AUTH_TOKEN,i=e.authToken?kt(e.authToken):r?kt(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}}function jt(e){if(!e||e===`openai-completions`||e===`anthropic-messages`)return e;throw Error(`Unsupported LLM API format: ${e}`)}function Mt(e,t){return t?w.resolve(t):w.join(e,`.aimax`,`plugins.json`)}async function U(e,t){let n=Mt(e,t);try{let e=await S.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=Mt(e,n);await S.mkdir(w.dirname(r),{recursive:!0}),await S.writeFile(r,JSON.stringify(t,null,2),`utf-8`)}function G(e){return typeof e==`object`&&!!e}function Nt(e){return G(e)&&e.type===`text`&&typeof e.text==`string`&&(e.textSignature===void 0||typeof e.textSignature==`string`)}function Pt(e){return G(e)&&e.type===`image`&&typeof e.data==`string`&&typeof e.mimeType==`string`}function Ft(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 It(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 Lt(e){return typeof e==`string`||Array.isArray(e)&&e.every(e=>Nt(e)||Pt(e))}function Rt(e){return Array.isArray(e)&&e.every(e=>Nt(e)||Ft(e)||It(e))}function zt(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 Bt(e){return!G(e)||typeof e.role!=`string`?!1:e.role===`user`?Lt(e.content):e.role===`assistant`?Rt(e.content)&&typeof e.api==`string`&&typeof e.provider==`string`&&typeof e.model==`string`&&zt(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=>Nt(e)||Pt(e))&&typeof e.isError==`boolean`:!1}async function Vt(e){let t;try{t=await S.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=>Bt(e)))throw Error(`Message file must contain one Message object or an array of Message objects`);return r}async function Ht(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 Vt(e.fromFile)}:{kind:`text`,message:e.message}}var Ut=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()}))}},Wt=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=Gt(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 Gt(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 Kt(e,t){if(t.kind===`none`)return e;let n=new URL(e);return n.searchParams.set(`authToken`,t.token),n.toString()}const K=5e3,qt=5e3;function Jt(){let e=globalThis.WebSocket;if(!e)throw Error(`WebSocket is not available in this runtime`);return e}function Yt(e){return e?{kind:`query_token`,token:e}:{kind:`none`}}function Xt(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 Zt(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 Qt=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 $t(this.ensureConnected(),K,`WebSocket connection timed out after ${K}ms`);let e=Jt();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 $t(this.ensureConnected(),K,`WebSocket connection timed out after ${K}ms`);let e=Jt();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=Jt();if(e.readyState!==t.CLOSED)try{await $t(new Promise(t=>{Xt(e,`close`,()=>t()),e.close()}),qt,`WebSocket close timed out after ${qt}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=Jt();if(this.socket&&this.socket.readyState===e.OPEN)return;if(this.connectPromise){await this.connectPromise;return}let t=new e(Kt(this.url,Yt(this.authToken)));this.connectPromise=new Promise((e,n)=>{Xt(t,`open`,()=>{this.socket=t,Zt(t,`close`,()=>{this.socket===t&&(this.socket=null)}),e()}),Xt(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 $t(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 en(e){let t=e.trim();if(!t)throw Error(`Goal objective cannot be empty`);return t}function tn(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 nn(e){let t=tn(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 rn(e){let t=e?.packageRoot??an(),n=w.join(t,`models`),r=w.join(n,...`Xenova/bge-small-zh-v1.5`.split(`/`));if(C.existsSync(w.join(r,`config.json`)))return n}function an(){let e=w.dirname(Ce(import.meta.url));return w.basename(e)===`src`||w.basename(e)===`dist`?w.resolve(e,`..`):e}const on=[`start`,`text`,`done`,`error`,`hitl`],sn=[`off`,`gate`,`dry_run`,`write`];function cn(e){if(!e?.trim())return new Set(on);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(on)}function ln(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=rn();return t?{embeddingModelDir:t}:void 0}function un(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 dn(e){return e?.trim()||void 0}function fn(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!w.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 pn(e){return e?y(e):void 0}function mn(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(!w.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 hn(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 gn(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 off,gate,dry_run,write.`)}}function _n(e){let t=e.autoSkillsLoadEnabled===void 0?hn(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):hn(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?gn(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):gn(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 vn(e,t){if(e.inputText&&t){let n=_e(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 yn(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 bn(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 xn(e){let t=un(e),n=e.channel??`WEB`,r=At({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});return{dataDir:t,systemAgentsDir:fn(e),channel:n,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:r,skillsLoadPaths:mn(e.skillsLoadPaths),autoSkills:_n(e)}}function Sn(e){let t=[],n=null;return e.callbackUrl&&t.push(new Wt(e.callbackUrl)),e.streamUrl&&(n=new Qt(e.streamUrl,cn(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new Ut(t),websocketSink:n}}async function Cn(e){let{dataDir:t,sessionId:n,sessionStoreName:r,toolCallId:i,toolName:a,resolution:o,encryptSessions:s}=e;if(!i||!a||!he(a))return;let c=(e,t)=>{switch(e){case`request_approval`:return f(t);case`clarify`:return p(t);case`request_review`:return m(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 wn(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})}async function Tn(e){let t=un(e);await H(t,e,async()=>{N(t);let i=new F(`resume command`),a=null;try{let t=await xn(e),o=pn(e.sessionStore),c=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await S.readFile(e.goalFile,`utf-8`):e.goal;let a=en(i),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(k(`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=nn({sessionId:e.sessionId,before:n,result:i})}catch(e){throw e instanceof n&&(k(e.message),k(`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 te(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),u=l?null:await ne(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=vn(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=En(n,s.request.kind);await Cn({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:s.toolContext?.toolCallId,toolName:s.toolContext?.toolName,resolution:n,encryptSessions:e.encryptSessions});let d=Sn(e);a=d.sink;let f=e.sessionId,p=async n=>{if(f=n.sessionId??f,!me(n)){if(n.type===`stream_text_delta`){t.format===`text`&&A(n),await d.websocketSink?.sendTextDelta({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}t.format===`text`&&A(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}),Ie({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 x({dataDir:t.dataDir,projectDir:dn(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:u,encryptSessions:e.encryptSessions??!1,topicSegmentation:ln(e),hitlResume:{request:s.request,resolution:n,checkpoint:s.checkpoint,toolContext:s.toolContext},plugins:h?{config:h,dataDir:t.dataDir,workspaceDir:w.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:{text:g.text,usage:g.usage,durationMs:g.durationMs,error:g.error,paused:g.paused,uiToolPending:g.uiToolPending}}),Ie(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=yn(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 wn({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,result:d,encryptSessions:e.encryptSessions});let f=Sn(e);a=f.sink;let p=e.sessionId,m=async n=>{if(p=n.sessionId??p,!me(n)){if(n.type===`stream_text_delta`){t.format===`text`&&A(n),await f.websocketSink?.sendTextDelta({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}if(t.format===`text`&&A(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 bn({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 x({dataDir:t.dataDir,projectDir:dn(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,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:ln(e),uiToolResume:d,plugins:_?{config:_,dataDir:t.dataDir,workspaceDir:w.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:{text:v.text,usage:v.usage,durationMs:v.durationMs,error:v.error,paused:v.paused,uiToolPending:v.uiToolPending}}),Ie(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}`),k(`Fatal: ${n.message}`),i.end(),process.exit(1)}finally{await a?.close()}})}function En(e,t){return o(e,t)}function Dn(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(`--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 Tn(e)})}const On=[`start`,`text`,`done`,`error`],kn=[`off`,`gate`,`dry_run`,`write`];function An(e){if(!e?.trim())return new Set(On);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(On)}function jn(e){if(e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`)return{enabled:!1};let t=rn();return t?{embeddingModelDir:t}:void 0}function Mn(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 Nn(e){return e?.trim()||void 0}function Pn(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!w.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 Fn(e){return e?.trim()||void 0}function In(e){return e??`WEB`}function Ln(e){return e?y(e):void 0}function Rn(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(!w.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 zn(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 Bn(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 Vn(e){if(!e?.trim())return{};let t=[],n=new Set;for(let r of Bn(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,zn(o)])}return Object.fromEntries(t)}function Hn(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 Un(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(kn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function Wn(e){let t=e.autoSkillsLoadEnabled===void 0?Hn(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):Hn(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?Un(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):Un(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 Gn(e,t){return e.length<=t?e:t<=3?e.slice(0,t):`${e.slice(0,t-3)}...`}function Kn(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 qn(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?` ${Gn(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=>Kn(e,a).map(e=>`│ ${e.padEnd(a,` `)} │`)),l].join(`
|
|
9
|
+
`)}function Jn(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 Yn(e){return e?`set`:`unset`}function Xn(e){return e?`true`:`false`}function Zn(e,t){let n=Ln(e.sessionStore)??`sessions`,r=t.timeoutMs===void 0?`default`:`${t.timeoutMs}`,i=e.callbackUrl?`enabled`:`disabled`,a=e.streamUrl?`enabled`:`disabled`,o=Jn(t.input),s=t.input.kind===`text`?`inline`:e.fromFile??`file`,c=He(),l=jn(e)?.enabled===!1?`disabled`:`enabled`,u=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,d=[...An(e.streamEvents)].join(`,`),f=t.autoSkills?.load?.enabled,p=t.autoSkills?.review?.mode,m=e.tokenBudget===`0`?`unlimited`:q(e.tokenBudget),h=e.env?Object.keys(Vn(e.env)):[],g=h.length===0?`-`:`${h.length} key${h.length===1?``:`s`}`;return{banner:qn(void 0,[`AIMax CLI`,`Stateless Agent Runner`]),contextBox:qn(`Run Context`,[`time : ${c}`,`dataDir : ${t.dataDir}`,`projectDir : ${Nn(e.projectDir)??`-`}`,`systemAgents : ${t.systemAgentsDir??`/aimax/agents`}`,`agent : ${Fn(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 : ${w.join(t.dataDir,`workspace`)}`,`baseUrl : ${t.llm.baseUrl}`,`apiKey : ${Yn(e.apiKey)}`,`authToken : ${Yn(e.authToken)}`,`model : ${t.llm.model}`,`contextWindow: ${q(t.llm.contextWindow)}`,`flashModel : ${q(t.llm.flashModel)}`,`callbackUrl : ${q(e.callbackUrl)}`,`streamUrl : ${q(e.streamUrl)}`,`streamAuth : ${Yn(e.streamAuthToken)}`,`streamEvents : ${d}`,`output : ${t.format}`,`callback : ${i}`,`websocket : ${a}`,`timeoutMs : ${r}`,`pluginsConfig: ${q(u)}`,`env : ${g}`,`goal : ${e.goal===void 0?`-`:`inline (${e.goal.length} chars)`}`,`goalFile : ${q(e.goalFile)}`,`tokenBudget : ${m}`,`force : ${Xn(e.force)}`,`resumeReqId : ${q(e.resumeRequestId)}`,`resumeInput : ${e.resumeInputJson===void 0?`-`:`inline (${e.resumeInputJson.length} chars)`}`,`resumeFile : ${q(e.resumeFromFile)}`,`encryptSess : ${Xn(e.encryptSessions)}`,`topicSegment : ${l}`]),logContext:{time:c,channel:t.channel,user:e.user,dataDir:t.dataDir,projectDir:Nn(e.projectDir),systemAgentsDir:t.systemAgentsDir,agent:Fn(e.agent),workspaceDir:w.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:!!e.apiKey,hasAuthToken:!!e.authToken,model:t.llm.model,contextWindow:t.llm.contextWindow,flashModel:t.llm.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,hasStreamAuthToken:!!e.streamAuthToken,streamEvents:d,output:t.format,hasCallback:!!e.callbackUrl,hasStream:!!e.streamUrl,timeoutMs:t.timeoutMs,pluginsConfig:u,envKeys:h.length>0?h.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 Qn(e,t){let n=Mn(e),r=In(e.channel),i=At({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});return{dataDir:n,systemAgentsDir:Pn(e),channel:r,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:i,input:t,skillsLoadPaths:Rn(e.skillsLoadPaths),autoSkills:Wn(e)}}function $n(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 er(e,t){if(!e.sessionId)return null;let n=$n(t);if(!n)return null;let r=await te(Mn(e),e.sessionId,{storeName:Ln(e.sessionStore),encryptSessions:e.encryptSessions});return!r||r.status!==`pending`||!ge(n,r.request)?null:{requestId:r.request.requestId,inputText:n}}function tr(e){let t=[],n=null;return e.callbackUrl&&t.push(new Wt(e.callbackUrl)),e.streamUrl&&(n=new Qt(e.streamUrl,An(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new Ut(t),websocketSink:n}}async function J(e,t){P.info(`dispatching external event`,xr(t)),await e.sink.send(t)}function nr(e){if(!e)return{};let t={};for(let[n,r]of Object.entries(e)){if(r===null||typeof r==`string`||typeof r==`number`||typeof r==`boolean`){t[n]=r;continue}if(r instanceof Error){t[n]=`${r.name}: ${r.message}`;continue}t[n]=JSON.stringify(r)}return t}function rr(e){let t={sessionId:e.sessionId,messageId:e.messageId,parentSessionId:e.parentSessionId,depth:e.depth,scope:e.scope,phase:e.phase,...nr(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 ir(e,t,n,r,i){return{sink:e,websocketSink:t,channel:n,defaultMessageId:r,user:i}}function ar(){let e=new AbortController,t=()=>e.abort();return process.once(`SIGTERM`,t),process.once(`SIGINT`,t),{controller:e,cleanup:()=>{process.off(`SIGTERM`,t),process.off(`SIGINT`,t)}}}function or(e){return{activeSessionId:e??`pending`,finalResult:null}}function sr(e,t){e.activeSessionId=t.sessionId??e.activeSessionId}function cr(e,t){return e.messageId??t}async function lr(e,t,n){if(!await h(e.dataDir)){if(await ur(t,e.format,n.activeSessionId,e.dataDir,`checking`),(await u(e.dataDir)).performedBootstrap){await ur(t,e.format,n.activeSessionId,e.dataDir,`initializing`),await ur(t,e.format,n.activeSessionId,e.dataDir,`initialized`);return}await ur(t,e.format,n.activeSessionId,e.dataDir,`ready`)}}async function ur(e,t,n,r,i){let a={type:`bootstrap`,phase:i,dataDir:r};t===`text`&&A(a),await J(e,{sessionId:n,channel:e.channel,messageId:e.defaultMessageId,user:e.user,type:`progress`,event:a})}function dr(e,t,n){return async r=>{if(sr(n,r),me(r)){rr(r);return}if(r.type===`stream_text_delta`){e.format===`text`&&A(r),await t.websocketSink?.sendTextDelta({sessionId:n.activeSessionId,channel:e.channel,messageId:cr(r,t.defaultMessageId),user:t.user,text:r.text});return}e.format===`text`&&A(r);let i=cr(r,t.defaultMessageId);if(r.type===`hitl_requested`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`hitl`,request:r.request}),await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`progress`,event:r});return}if(r.type===`start`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`start`,message:r.message});return}if(r.type===`session_reset`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`session_reset`,action:r.action,previousSessionId:r.previousSessionId,message:r.message});return}await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`progress`,event:r})}}function fr(e,t,n,r,i,a){let o={dataDir:t.dataDir,projectDir:Nn(e.projectDir),systemAgentsDir:t.systemAgentsDir,agentPolicy:Fn(e.agent)?{requestedAgentName:Fn(e.agent)}:void 0,sessionStoreName:Ln(e.sessionStore),sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,abortSignal:n.signal,pendingGoal:a,encryptSessions:e.encryptSessions??!1,topicSegmentation:jn(e),env:Vn(e.env),plugins:i?{config:i,dataDir:t.dataDir,workspaceDir:w.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:i.llmAllowlist}:void 0,onProgress:r};return t.input.kind===`messages`?{...o,messages:t.input.messages}:{...o,message:t.input.message}}async function pr(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:{text:r.text,usage:r.usage,durationMs:r.durationMs,error:r.error,paused:r.paused}})}async function mr(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 hr(e,t){let n=Zn(e,t);P.info([`run command started`,n.banner,n.contextBox].join(`
|
|
11
|
+
`),n.logContext),t.format===`text`&&(O(n.banner),O(``),O(n.contextBox),O(``))}function gr(e,t,n){return Ie(t,n),t.error?P.error(`run command failed: ${t.error}`):P.info(`run command succeeded`),e.end(),t.error?1:0}function _r(e){let t=Ze();if(!t)return;let n=`[${He()}] [ERROR] ${e}\n`;try{C.appendFileSync(w.join(t.logDir,`app.log`),n),C.appendFileSync(w.join(t.logDir,`errors.log`),n)}catch{}}async function vr(e,t){let n=`run command error: ${t.message}`;P.error(n),_r(n),k(`Fatal: ${t.message}`),e.end(),await Qe(),process.exit(1)}async function yr(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 S.readFile(e.resumeFromFile,`utf-8`)}catch(e){throw Error(`Failed to read resume input file: ${e.message}`)}}async function br(e){let t=Mn(e);await H(t,e,async i=>{N(t),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 a=new F(`run command`),o=await yr(e);if(e.resumeRequestId||o||e.resumeFromFile){if(!e.sessionId||!e.resumeRequestId||!o)throw Error(`--session-id, --resume-request-id, and exactly one of --resume-input-json or --resume-from-file must be provided together`);await Tn({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:e.resumeRequestId,inputJson:o,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,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 s;try{s=await Ht({message:e.message,fromFile:e.fromFile})}catch(e){await vr(a,e);return}let c=await er(e,s);if(c){await Tn({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:c.requestId,inputText:c.inputText,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,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{controller:l,cleanup:u}=ar(),d=null,f=e.channel??`WEB`,p=or(e.sessionId);try{let t=await Qn(e,s);f=t.channel,hr(e,t);let i=tr(e);d=i.sink,P.info(`external sink configured`,{callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamEvents:e.streamEvents});let o=ir(d,i.websocketSink,t.channel,e.messageId,e.user);await lr(t,o,p);let c,u=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await S.readFile(e.goalFile,`utf-8`):e.goal;let a=en(i),o=Ln(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)&&(k(`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});u=nn({sessionId:e.sessionId,before:n,result:i})}else c={objective:a,tokenBudget:s??null}}catch(e){throw e instanceof n&&(k(e.message),k(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await U(t.dataDir,m),g=dr(t,o,p);u&&await g(u);let _=await x(fr(e,t,l,g,h,c));await pr(o,p,e.messageId,_),process.exitCode=gr(a,_,t.format)}catch(t){let n=t;d&&await mr(ir(d,null,f,e.messageId,e.user),p,e.messageId,n),await vr(a,n)}finally{await d?.close(),u()}})}function xr(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 Sr(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(`--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(`--timeout <ms>`,`Execution timeout in milliseconds (default: 600000)`).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 br(e)})}function Cr(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||(k(`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`&&(k(`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`){Le(await ee(r.dataDir,r.channel,{storeName:e}),a);return}if(r.sessionId||(k(`error: required option '-s, --session-id <id>' not specified`),process.exit(1)),i===`inspect`){Re(await _(r.dataDir,r.sessionId,{storeName:e}),a);return}if(i===`export`){ze(await d(r.dataDir,r.sessionId,{storeName:e}),a);return}k(`Invalid sessions action: ${i}. Must be 'list', 'inspect', or 'export'`),process.exit(1)})}catch(e){k(`${i===`inspect`?`Error inspecting session`:i===`export`?`Error exporting session`:`Error listing sessions`}: ${e.message}`),process.exit(1)}})}function wr(e){return w.join(e,`workspace`)}function Tr(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function Er(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 Dr(e){let t=e.level===`error`?`plugin error`:`plugin warning`;return e.pluginId?`${t} (${e.pluginId}): ${e.message}`:`${t}: ${e.message}`}function Or(e){if(!e||e===`cli`)return`cli`;if(e===`cron`)return`cron`;throw Error(`Unsupported dream trigger: ${e}. Expected "cli" or "cron".`)}async function kr(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=g({config:n,dataDir:e.dataDir,workspaceDir:wr(e.dataDir),bundledDir:Tr()});return t.push(...r.diagnostics.map(Dr)),{pluginSystem:r,warnings:t}}catch(e){return t.push(`failed to initialize plugin system: ${e.message}`),{warnings:t}}}async function Ar(e){let t=w.join(e.dataDir,`.aimax`),{pluginSystem:n,warnings:r}=await kr({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});return o?{provider:o.provider,providerId:o.registration.id,pluginId:o.registration.pluginId,providerOrigin:`plugin`,warnings:r,pluginSystem:n}:((a||e.provider)&&r.push(`requested memory provider was not resolved; falling back to builtin provider`),{provider:c({dataDir:e.dataDir,memoryDir:t},{includeSessions:e.includeSessions}),providerId:`builtin`,providerOrigin:`builtin`,warnings:r,pluginSystem:n})}function jr(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 Mr(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 Ar({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=jr(n.provider.status(),n,e.deep);O(t===`json`?JSON.stringify(r,null,2):Er(r,e.deep))})}catch(e){k(`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 Ar({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)k(`Warning: ${e}`);e.verbose&&n&&O(JSON.stringify(n,null,2)),O(e.rebuild?`Memory index rebuilt.`:`Memory index refreshed.`)})}catch(e){k(`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||(k(`Query is required: provide [query] or --query <text>`),process.exit(1));try{await H(t.dataDir,t,async()=>{let e=await(await Ar({dataDir:t.dataDir,provider:t.provider,providerPlugin:t.providerPlugin,pluginsConfig:t.pluginsConfig,includeSessions:t.includeSessions})).provider.search(r);if(n===`json`){O(JSON.stringify(e,null,2));return}if(e.length===0){O(`No results found for: ${r}`);return}O(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){k(`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=Or(e.trigger),r=await Ar({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:w.join(e.dataDir,`.aimax`),providerId:r.providerId,pluginId:r.pluginId,trigger:n,dryRun:!!e.dryRun},{workspaceDir:wr(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`){O(JSON.stringify(a,null,2));return}O(`trigger: ${a.trigger}`),O(`provider_source: ${a.providerSource}`),O(`provider_id: ${a.providerId}`),a.pluginId&&O(`plugin_id: ${a.pluginId}`),O(`result_count: ${a.resultCount}`),a.results.length===0?O(`note: no dream_gate hook registered`):O(`results: ${JSON.stringify(a.results)}`);for(let e of a.warnings)O(`warning: ${e}`)})}catch(e){k(`Error running dream gate: ${e.message}`),process.exit(1)}})}function Nr(e){return`${e.match.accountId?`${e.match.channel}:${e.match.accountId}`:e.match.channel} -> ${e.agentId}`}function Pr(e){return async t=>{let n=await E(t),r=Ee(n),i=De(n);if(D(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=je(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(` - ${Nr(e)}`)}}}}function Fr(e,t){return async n=>{T(await E(n),Oe(e))&&(console.error(`Agent "${e}" already exists.`),process.exit(1)),await we(n,{id:e,name:t.name,model:t.model,default:t.default})||(console.error(`Agent "${e}" already exists.`),process.exit(1));let r=je(n,e);console.log(`Agent "${e}" added successfully.`),console.log(` Agent dir: ${r}`)}}function Ir(e){return async t=>{let n=T(await E(t),Oe(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 ke(t,e)||(console.error(`Failed to delete agent "${e}".`),process.exit(1)),console.log(`Agent "${e}" deleted.`)}}function Lr(e){return async t=>{let n=await E(t),r=e.agent??D(n);T(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 Te(t,{agentId:r,match:{channel:e,accountId:a||void 0}}),console.log(`Binding added: ${n} -> ${r}`)}}}function Rr(e){return async t=>{let n=await E(t),r=e.agent??D(n);if(T(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),e.all){let e=await Ae(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 Ae(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 zr(e){return async t=>{let n=De(await E(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(` ${Nr(e)}`)}}function Br(e){return async t=>{let n=await E(t),r=e.agent??D(n);T(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),await Me(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 Vr(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 Pr(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 Fr(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 Ir(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 Lr(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 Rr(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 zr(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 Br(e)(n)})})}function Y(e){return w.join(e,`workspace`)}function X(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function Hr(e){if(e.length===0){O(`No plugins discovered.`);return}for(let t of e){let e=t.status.padEnd(8,` `);O(`${t.id} ${e} ${t.origin} ${t.source}`)}}function Ur(e){O(`id: ${e.id}`),O(`status: ${e.status}`),O(`origin: ${e.origin}`),O(`source: ${e.source}`),O(`enabled: ${e.enabled}`),e.error&&O(`error: ${e.error}`),O(`tools: ${e.toolCount}`),O(`hooks: ${e.hookCount}`),e.skills.length>0&&O(`skills: ${e.skills.join(`, `)}`)}function Wr(e){return Array.from(new Set((e??[]).map(e=>e.trim()).filter(Boolean)))}function Gr(e){if(e.length===0){O(`LLM allowlist is empty.`);return}for(let t of e)O(t)}function Kr(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()=>{Hr(g({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=g({config:await U(r,n.pluginsConfig),dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.find(t=>t.id===e);t||(k(`Plugin not found: ${e}`),process.exit(1)),Ur(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);g({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(k(`Plugin not found: ${e}`),process.exit(1)),await W(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!0}}},n.pluginsConfig),O(`Enabled ${e}`),i.allow.length>0&&!i.allow.includes(e)&&O(`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)??{};g({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(k(`Plugin not found: ${e}`),process.exit(1)),await W(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!1}}},n.pluginsConfig),O(`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=g({config:await U(n,e.pluginsConfig),dataDir:n,workspaceDir:Y(n),bundledDir:X()});if(t.diagnostics.length===0){O(`No plugin issues detected.`);return}for(let e of t.diagnostics)O(`${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()=>{Gr(Wr((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=Wr([...t.llmAllowlist??[],...e]);await W(r,{...t,llmAllowlist:i},n.pluginsConfig),O(`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=Wr(t.llmAllowlist).filter(e=>!i.has(e));await W(r,{...t,llmAllowlist:a},n.pluginsConfig),O(`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),O(`LLM allowlist cleared.`)})})}function qr(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=v(await re(e.dataDir,[]));if(t===`json`){O(JSON.stringify(n,null,2));return}O(`Commands`),O(` builtin: ${n.builtin.map(e=>e.name).join(` | `)}`),n.skillCommands.length>0?O(` skills: ${n.skillCommands.map(e=>e.name).join(` | `)}`):O(` skills: (none)`)})}catch(e){k(`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 Jr(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 fe(e.dataDir,e.sessionId,{goalId:Ne(),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 de(e.dataDir,e.sessionId,i,{...t,eventSource:`cli`})}async function Yr(e,t){let n=Z(t),r=Q(t),i=$(t.sessionStore),a=e.trim();a||(k(`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)&&(k(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));let s=await Jr({dataDir:n,sessionId:r,sessionStoreName:i,objective:a,tokenBudget:o});O(JSON.stringify({goal:s},null,2))}async function Xr(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(!i){O(JSON.stringify({goal:null},null,2));return}let a=await oe(t,n,i,{storeName:r});O(JSON.stringify({goal:{...i,objective:a}},null,2))}async function Zr(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});i||(k(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(k(`error: cannot pause a completed goal`),process.exit(1));let a=await de(t,n,{status:`paused`},{storeName:r,eventSource:`cli`});O(JSON.stringify({goal:a},null,2))}async function Qr(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(i||(k(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(k(`error: cannot resume a completed goal`),process.exit(1)),i.status===`budget_limited`&&(k(`error: cannot resume a budget-limited goal; clear or replace it instead`),process.exit(1)),i.status===`active`){O(JSON.stringify({goal:i},null,2));return}let a=await de(t,n,{status:`active`},{storeName:r,eventSource:`cli`});O(JSON.stringify({goal:a},null,2))}async function $r(e){let t=await l(Z(e),Q(e),{storeName:$(e.sessionStore),eventSource:`cli`});O(JSON.stringify({cleared:t},null,2))}function ei(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 Yr(e,t)}catch(e){k(`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 Xr(e)}catch(e){k(`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 Zr(e)}catch(e){k(`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 Qr(e)}catch(e){k(`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 $r(e)}catch(e){k(`error: ${e.message}`),process.exit(1)}})}const ti=[`progress`,`error`,`hitl`];function ni(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 ri(e){if(!e?.trim())return new Set(ti);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(ti)}function ii(e){return e?y(e):void 0}function ai(e){let t=[];return e.callbackUrl&&t.push(new Wt(e.callbackUrl)),e.streamUrl&&t.push(new Qt(e.streamUrl,ri(e.streamEvents),e.streamAuthToken)),new Ut(t)}async function oi(e){let t=ni(e);await H(t,e,async()=>{N(t);let n=new F(`cancel command`),r=e.channel??`WEB`,i=e.output===`json`?`json`:`text`,a=ai(e),o=ii(e.sessionStore);try{let s=await te(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`&&A(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}`),k(`Fatal: ${i.message}`),n.end(),process.exit(1)}finally{await a.close()}})}function si(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 oi(e)})}function ci(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 li(e){return e.query?.trim()||void 0}function ui(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 di(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 fi(e){if(e.filePath){if(!w.isAbsolute(e.filePath))throw Error(`--file-path must be an absolute path`);try{await S.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 pi(e){let t=null;try{let n=ci(e);N(n),t=new F(`summarize command`);let r=li(e),i=await fi(e),a=At({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,model:e.model,contextWindow:2e5}),o=ui(e.timeout),s=di(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 x({dataDir:n,channel:`WEB`,message:mi(i,r),llm:{...a,maxTokens:s},timeoutMs:o});O(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}`),k(`Fatal: ${e.message}`),t?.end(),process.exit(1)}}function mi(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 hi(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`).action(async e=>{await pi(e)})}const gi=e(import.meta.url)(`../package.json`);function _i(){return process.env.AIMAX_DATA_DIR||process.cwd()}function vi(){let e=new t;return e.name(`aimax`).description(`AIMax CLI — runs agent tasks in a containerized environment`).version(gi.version),Sr(e),Dn(e),ei(e),si(e),Cr(e),hi(e),qr(e),Dt(e),Mr(e),Vr(e,_i),Kr(e,_i),e}export{Qe as a,P as i,_i as n,N as r,vi as t};
|
package/dist/program.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./program-
|
|
1
|
+
import{n as e,t}from"./program-CBzbMheo.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.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aimax": "./dist/bin.js"
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
|
+
"scripts/download-embedding-model.mjs",
|
|
16
17
|
"CHANGELOG.md"
|
|
17
18
|
],
|
|
18
19
|
"publishConfig": {
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"commander": "^14.0.3",
|
|
23
24
|
"gensign-node": "latest",
|
|
24
25
|
"log4js": "^6.9.1",
|
|
25
|
-
"@gencode/agents": "0.
|
|
26
|
+
"@gencode/agents": "0.10.0",
|
|
26
27
|
"@gencode/shared": "0.2.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"build": "tsdown",
|
|
36
37
|
"test": "vitest run",
|
|
37
38
|
"test:coverage": "vitest run --coverage",
|
|
38
|
-
"typecheck": "tsc --noEmit"
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"postinstall": "node ./scripts/download-embedding-model.mjs"
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import fsSync from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { Readable, Transform } from "node:stream";
|
|
9
|
+
import { pipeline } from "node:stream/promises";
|
|
10
|
+
|
|
11
|
+
const MODEL_ID = "Xenova/bge-small-zh-v1.5";
|
|
12
|
+
const MODEL_ID_PARTS = MODEL_ID.split("/");
|
|
13
|
+
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const DEFAULT_PACKAGE_ROOT = path.resolve(SCRIPT_DIR, "..");
|
|
15
|
+
|
|
16
|
+
export async function installEmbeddingModel(options = {}) {
|
|
17
|
+
const env = options.env ?? process.env;
|
|
18
|
+
const modelUrl = env.AIMAX_EMBEDDING_MODEL_URL?.trim();
|
|
19
|
+
const log = options.log ?? console.log;
|
|
20
|
+
const errorLog = options.errorLog ?? console.error;
|
|
21
|
+
if (!modelUrl) {
|
|
22
|
+
log("[aimax postinstall] AIMAX_EMBEDDING_MODEL_URL is not set; skipping embedding model download.");
|
|
23
|
+
return { status: "skipped" };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const packageRoot = path.resolve(options.packageRoot ?? DEFAULT_PACKAGE_ROOT);
|
|
27
|
+
const modelRoot = path.join(packageRoot, "models");
|
|
28
|
+
const tempRoot = await fs.mkdtemp(path.join(packageRoot, ".embedding-model-download-"));
|
|
29
|
+
try {
|
|
30
|
+
const archivePath = path.join(tempRoot, "model-archive");
|
|
31
|
+
const extractDir = path.join(tempRoot, "extract");
|
|
32
|
+
log(`[aimax postinstall] Downloading embedding model from ${modelUrl}`);
|
|
33
|
+
const sha256 = await downloadArchive(modelUrl, archivePath);
|
|
34
|
+
const expectedSha256 = env.AIMAX_EMBEDDING_MODEL_SHA256?.trim().toLowerCase();
|
|
35
|
+
if (expectedSha256 && sha256.toLowerCase() !== expectedSha256) {
|
|
36
|
+
throw new Error(`AIMAX_EMBEDDING_MODEL_SHA256 mismatch: expected ${expectedSha256}, got ${sha256}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await fs.mkdir(extractDir, { recursive: true });
|
|
40
|
+
await extractArchive(archivePath, extractDir);
|
|
41
|
+
const sourceModelDir = await locateExtractedModelDir(extractDir);
|
|
42
|
+
const targetModelDir = await installModelDirectory({
|
|
43
|
+
sourceModelDir,
|
|
44
|
+
modelRoot,
|
|
45
|
+
});
|
|
46
|
+
log(`[aimax postinstall] Embedding model installed at ${targetModelDir}`);
|
|
47
|
+
return { status: "installed", modelRoot, targetModelDir, sha256 };
|
|
48
|
+
} catch (error) {
|
|
49
|
+
errorLog(`[aimax postinstall] Failed to install embedding model: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
throw error;
|
|
51
|
+
} finally {
|
|
52
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function downloadArchive(url, destination) {
|
|
57
|
+
const response = await fetch(url);
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(`download failed with HTTP ${response.status} ${response.statusText}`);
|
|
60
|
+
}
|
|
61
|
+
if (!response.body) {
|
|
62
|
+
throw new Error("download response did not include a body");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const hash = crypto.createHash("sha256");
|
|
66
|
+
const hashStream = new Transform({
|
|
67
|
+
transform(chunk, _encoding, callback) {
|
|
68
|
+
hash.update(chunk);
|
|
69
|
+
callback(null, chunk);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
await pipeline(
|
|
73
|
+
Readable.fromWeb(response.body),
|
|
74
|
+
hashStream,
|
|
75
|
+
fsSync.createWriteStream(destination),
|
|
76
|
+
);
|
|
77
|
+
return hash.digest("hex");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function extractArchive(archivePath, extractDir) {
|
|
81
|
+
try {
|
|
82
|
+
await runTar(["-xzf", archivePath, "-C", extractDir]);
|
|
83
|
+
return;
|
|
84
|
+
} catch (gzipError) {
|
|
85
|
+
try {
|
|
86
|
+
await runTar(["-xf", archivePath, "-C", extractDir]);
|
|
87
|
+
return;
|
|
88
|
+
} catch (tarError) {
|
|
89
|
+
throw new Error(`unable to extract model archive as tar/tar.gz: ${formatError(gzipError)}; ${formatError(tarError)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function runTar(args) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const child = spawn("tar", args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
97
|
+
let stderr = "";
|
|
98
|
+
child.stderr.on("data", (chunk) => {
|
|
99
|
+
stderr += String(chunk);
|
|
100
|
+
});
|
|
101
|
+
child.on("error", reject);
|
|
102
|
+
child.on("close", (code) => {
|
|
103
|
+
if (code === 0) {
|
|
104
|
+
resolve();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
reject(new Error(`tar ${args.join(" ")} exited with ${code}${stderr.trim() ? `: ${stderr.trim()}` : ""}`));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function locateExtractedModelDir(extractDir) {
|
|
113
|
+
const directCandidates = [
|
|
114
|
+
path.join(extractDir, ...MODEL_ID_PARTS),
|
|
115
|
+
path.join(extractDir, MODEL_ID_PARTS[1]),
|
|
116
|
+
extractDir,
|
|
117
|
+
];
|
|
118
|
+
for (const candidate of directCandidates) {
|
|
119
|
+
if (await hasModelConfig(candidate)) {
|
|
120
|
+
return candidate;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const configDirs = await findDirsContainingConfig(extractDir, 6);
|
|
125
|
+
const exact = configDirs.find((candidate) => candidate.endsWith(path.join(...MODEL_ID_PARTS)));
|
|
126
|
+
if (exact) {
|
|
127
|
+
return exact;
|
|
128
|
+
}
|
|
129
|
+
const byName = configDirs.find((candidate) => path.basename(candidate) === MODEL_ID_PARTS[1]);
|
|
130
|
+
if (byName) {
|
|
131
|
+
return byName;
|
|
132
|
+
}
|
|
133
|
+
if (configDirs.length === 1) {
|
|
134
|
+
return configDirs[0];
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`model archive must contain ${MODEL_ID}/config.json or a single model directory with config.json`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function installModelDirectory(params) {
|
|
140
|
+
const targetModelDir = path.join(params.modelRoot, ...MODEL_ID_PARTS);
|
|
141
|
+
const stageRoot = path.join(params.modelRoot, `.staging-${process.pid}-${Date.now()}`);
|
|
142
|
+
const stagedModelDir = path.join(stageRoot, ...MODEL_ID_PARTS);
|
|
143
|
+
const backupModelDir = `${targetModelDir}.previous-${process.pid}-${Date.now()}`;
|
|
144
|
+
await fs.rm(stageRoot, { recursive: true, force: true });
|
|
145
|
+
await fs.mkdir(path.dirname(stagedModelDir), { recursive: true });
|
|
146
|
+
await fs.cp(params.sourceModelDir, stagedModelDir, { recursive: true, force: true });
|
|
147
|
+
if (!await hasModelConfig(stagedModelDir)) {
|
|
148
|
+
throw new Error(`extracted model is missing config.json: ${stagedModelDir}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await fs.mkdir(path.dirname(targetModelDir), { recursive: true });
|
|
152
|
+
let movedExisting = false;
|
|
153
|
+
try {
|
|
154
|
+
if (await exists(targetModelDir)) {
|
|
155
|
+
await fs.rm(backupModelDir, { recursive: true, force: true });
|
|
156
|
+
await fs.rename(targetModelDir, backupModelDir);
|
|
157
|
+
movedExisting = true;
|
|
158
|
+
}
|
|
159
|
+
await fs.rename(stagedModelDir, targetModelDir);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (movedExisting && !await exists(targetModelDir) && await exists(backupModelDir)) {
|
|
162
|
+
await fs.rename(backupModelDir, targetModelDir);
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
} finally {
|
|
166
|
+
await fs.rm(stageRoot, { recursive: true, force: true });
|
|
167
|
+
await fs.rm(backupModelDir, { recursive: true, force: true });
|
|
168
|
+
}
|
|
169
|
+
return targetModelDir;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function findDirsContainingConfig(root, maxDepth) {
|
|
173
|
+
const out = [];
|
|
174
|
+
async function visit(dir, depth) {
|
|
175
|
+
if (await hasModelConfig(dir)) {
|
|
176
|
+
out.push(dir);
|
|
177
|
+
}
|
|
178
|
+
if (depth >= maxDepth) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
if (entry.isDirectory()) {
|
|
184
|
+
await visit(path.join(dir, entry.name), depth + 1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
await visit(root, 0);
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function hasModelConfig(dir) {
|
|
193
|
+
try {
|
|
194
|
+
const stat = await fs.stat(path.join(dir, "config.json"));
|
|
195
|
+
return stat.isFile();
|
|
196
|
+
} catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function exists(target) {
|
|
202
|
+
try {
|
|
203
|
+
await fs.access(target);
|
|
204
|
+
return true;
|
|
205
|
+
} catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function formatError(error) {
|
|
211
|
+
return error instanceof Error ? error.message : String(error);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
215
|
+
installEmbeddingModel().catch(() => {
|
|
216
|
+
process.exitCode = 1;
|
|
217
|
+
});
|
|
218
|
+
}
|
package/dist/program-CzocoEBh.js
DELETED
|
@@ -1,15 +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,createBuiltinMemoryProvider as c,deleteGoal as l,ensureBootstrapMountLayout as u,exportSession as d,formatApprovalResolution as f,formatClarifyResolution as p,formatReviewResolution as m,hasBootstrapSentinel as h,initializePluginSystem as g,inspectSession as _,listAvailableSlashCommands as v,listSessionSummaries as ee,loadPendingHitl as te,loadPendingUiTool as ne,loadSkillsWithPluginDirs as re,loadTranscript as ie,normalizePluginsConfig as ae,normalizeSessionStoreName as y,readGoal as b,resolveGoalObjective as oe,resolveMemoryProvider as se,resolvePendingHitl as ce,resolvePendingUiTool as le,rewriteTranscript as ue,runAgent as x,updateGoal as de,writeGoal as fe}from"@gencode/agents";import{formatTaskForDisplay as pe,isAgentDiagnosticEvent as me,isHitlTool as he,parseMatchedTextToResolution as ge,parseTextToResolution as _e}from"@gencode/shared";import S from"node:fs/promises";import C from"node:fs";import w from"node:path";import ve from"node:os";import{execFile as ye,execFileSync as be}from"node:child_process";import xe from"log4js";import Se from"gensign-node";import{addAgent as Ce,addBinding as we,getAgentConfig as T,listAgents as Te,listBindings as Ee,loadAgentsConfig as E,normalizeAgentId as De,removeAgent as Oe,removeBindings as ke,resolveAgentDir as Ae,resolveDefaultAgentId as D,updateAgentIdentity as je}from"@gencode/agents/config";import{randomUUID as Me}from"node:crypto";function Ne(e){process.stdout.write(e)}function O(e){process.stdout.write(e+`
|
|
2
|
-
`)}function k(e){process.stderr.write(e+`
|
|
3
|
-
`)}function A(e){switch(e.type){case`start`:O(`\n[start] ${e.message}`);break;case`text`:Ne(e.text);break;case`stream_text_delta`:Ne(e.text);break;case`bootstrap`:O(`\n[bootstrap:${e.phase}] ${e.dataDir}`);break;case`session_reset`:O(`\n[session:${e.action}] ${e.message}`);break;case`tool_start`:O(`\n[tool:${e.name}] ${JSON.stringify(e.input??{})}`);break;case`tool_end`:O(`[tool:${e.name}] ${e.isError?`ERROR`:`OK`} ${e.output.slice(0,200)}`);break;case`compaction`:O(`\n[compaction${e.layer?`:${e.layer}`:``}] ${e.reason}${e.strategy?` (${e.strategy})`:``}`);break;case`skill_used`:O(`\n[skill] ${e.skillName} agent=${e.agent} task=${e.taskId}`);break;case`custom`:O(`\n[plugin:${e.pluginId}] ${e.name}${e.label?` ${e.label}`:``}${e.data?` ${JSON.stringify(e.data)}`:``}`);break;case`error`:k(`\n[error] ${e.message}`);break;case`diagnostic`:break;case`subagent_spawn`:O(`\n[subagent:spawn]${e.label?` "${e.label}"`:``} ${pe(e.task)}`);break;case`subagent_complete`:O(`[subagent:${e.status}] ${pe(e.task)}`);break;case`hitl_requested`:if(O(`\n[hitl:${e.request.kind}] ${e.request.title}`),O(` prompt: ${e.request.prompt}`),O(` requestId: ${e.request.requestId}`),e.request.input.mode===`choice`)for(let t of e.request.input.choices)O(` - [${t.id}] ${t.label}`);break;case`hitl_resumed`:O(`\n[hitl:resumed] requestId=${e.requestId} action=${e.resolution.action}`);break;case`hitl_expired`:O(`\n[hitl:expired] requestId=${e.requestId} reason=${e.reason}`);break;case`hitl_cancelled`:O(`\n[hitl:cancelled] requestId=${e.requestId}${e.reason?` reason=${e.reason}`:``}`);break;case`ui_tool_request`:O(`\n[ui-tool:${e.request.toolName}] ${e.request.outputSchema.title}`),O(` requestId: ${e.request.requestId}`),O(` toolCallId: ${e.request.toolCallId}`);break;case`ui_tool_result`:O(`\n[ui-tool:resumed] requestId=${e.requestId} tool=${e.toolName}`);break}}function j(e,t){if(t===`json`){e&&O(JSON.stringify(e,null,2));return}O(`
|
|
4
|
-
`),O(`session: ${e.sessionId}`),O(`duration: ${e.durationMs}ms`),O(`tokens: input=${e.usage.input} output=${e.usage.output} total=${e.usage.total}`),e.context&&(O(`context: ${e.context.snapshotPath}`),O(`tool-results: ${e.context.toolResultsDir}`)),e.error&&k(`error: ${e.error}`)}function Pe(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}if(e.length===0){O(`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:—]`;O(`${t.id} ${e} [${t.channel}]${n} ${t.title}`)}}function Fe(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`session: ${e.id}`),e.metadata&&(O(`title: ${e.metadata.title}`),O(`channel: ${e.metadata.channel}`),O(`created: ${e.metadata.createdAt}`),O(`updated: ${e.metadata.updatedAt}`)),O(`transcript: ${e.transcriptPath}`),O(`entries: ${e.transcriptEntryCount}`),O(`context: ${e.contextSnapshotPath}`),O(`session-memory: ${e.sessionMemoryPath}`),O(`collapse-log: ${e.collapseLogPath}`),O(`read-states: ${e.readStateCount}`),O(`tool-results: ${e.toolResultRefCount}`),O(`tool-results-dir: ${e.toolResultsDir}`)}function Ie(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`session: ${e.id}`),O(`transcript: ${e.paths.transcriptPath}`),O(`context: ${e.paths.contextSnapshotPath}`),O(`session-memory: ${e.paths.sessionMemoryPath}`),O(`collapse-log: ${e.paths.collapseLogPath}`),O(`tool-results-dir: ${e.paths.toolResultsDir}`),O(`transcript-entries: ${e.transcript.length}`),O(`read-states: ${e.context.readStates.length}`),O(`tool-results: ${e.context.toolResults.length}`),O(`collapse-spans: ${e.context.compaction.collapseSpans.length}`)}function Le(e,t){if(t===`json`){O(JSON.stringify(e,null,2));return}O(`Bootstrap completed.`),O(`dataDir: ${e.dataDir}`),O(`created dirs: ${e.createdDirs.length}`),O(`created files: ${e.createdFiles.length}`),O(`skipped dirs: ${e.skippedDirs.length}`),O(`skipped files: ${e.skippedFiles.length}`)}function Re(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 ze(e=new Date){let t=Re(e),n=String(e.getMilliseconds()).padStart(3,`0`);return`${t.year}-${t.month}-${t.day} ${t.hour}:${t.minute}:${t.second}.${n}`}let M=function(e){return e.INFO=`INFO`,e.ERROR=`ERROR`,e.WARN=`WARN`,e}({}),N=null;function Be(){return ze()}function Ve(e){if(!e)return``;let t=Object.entries(e).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${JSON.stringify(t)}`);return t.length>0?` ${t.join(` `)}`:``}function He(e){return w.join(e,`.aimax`)}function Ue(e){return{appLogPath:w.join(e,`app.log`),errorLogPath:w.join(e,`errors.log`)}}function We(e){let{appLogPath:t,errorLogPath:n}=Ue(e);xe.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 Ge(e,t,n){return`[${Be()}] [${e}] ${t}${Ve(n)}`}function Ke(e,t,n){process.stderr.write(`${Ge(e,t,n)}\n`)}function qe(e,t,n){if(!N){Ke(e,t,n);return}let r=Ge(e,t,n),i=xe.getLogger();if(e===M.ERROR){i.error(r);return}if(e===M.WARN){i.warn(r);return}i.info(r)}function P(e){let t=He(e);C.mkdirSync(t,{recursive:!0}),We(t),N={dataDir:e,logDir:t}}function Je(){return N?{...N}:null}async function Ye(){await xe.shutdown()}const F={info:(e,t)=>qe(M.INFO,e,t),warn:(e,t)=>qe(M.WARN,e,t),error:(e,t)=>qe(M.ERROR,e,t)};var I=class{startTime;name;constructor(e){this.name=e,this.startTime=Date.now()}end(){let e=Date.now()-this.startTime;return F.info(`${this.name} completed in ${e}ms`),e}};const Xe=`.aimax`,Ze=`${Xe}.pre-gocryptfs.`,Qe=[`fusermount3`,`fusermount`,`umount`],$e=[{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 w.join(e,`.aimax.enc`)}function tt(e){return w.join(e,Xe)}function nt(e){return w.join(e,`${Ze}${process.pid}.${Date.now()}`)}function rt(e){return e.replace(/\\([0-7]{3})/g,(e,t)=>String.fromCharCode(Number.parseInt(t,8)))}async function it(e){try{let t=await st.read(),n=w.resolve(e);for(let e of t.split(`
|
|
5
|
-
`)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&w.resolve(rt(t[4]??``))===n)return!0}return!1}catch{return!1}}function at(e){try{let t=C.readFileSync(`/proc/self/mountinfo`,`utf-8`),n=w.resolve(e);for(let e of t.split(`
|
|
6
|
-
`)){if(!e.trim())continue;let t=e.split(` `);if(t.length>=5&&w.resolve(rt(t[4]??``))===n)return!0}return!1}catch{return!1}}async function ot(){return await S.readFile(`/proc/self/mountinfo`,`utf-8`)}const st={read:ot};async function L(e){try{return await S.stat(e),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function R(e){await S.mkdir(e,{recursive:!0})}async function ct(e){if(await R(e),(await S.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 lt(e){return await L(e)?(await S.readdir(e)).length===0:!0}async function ut(e){if(!await L(w.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 dt(e){return(await S.readdir(e,{withFileTypes:!0})).filter(e=>e.isDirectory()&&e.name.startsWith(Ze)).map(t=>w.join(e,t.name)).sort()}async function z(e,t){if(!await L(t))return null;let n=nt(e);return F.info(`--encrypt-sessions moving plaintext .aimax aside before migration`,{plainDir:t,backupDir:n}),await S.rename(t,n),n}async function B(e,t,n){F.info(`--encrypt-sessions copying plaintext backup into encrypted mount`,{backupDir:e,plainDir:t,force:n}),await S.cp(e,t,{recursive:!0,force:n})}async function ft(e){let t=w.join(ve.tmpdir(),`aimax-gocryptfs-pass.${process.pid}.${Date.now()}`);await S.writeFile(t,`wizard_aimax@2026
|
|
7
|
-
`,{mode:384});try{return await e(t)}finally{await S.rm(t,{force:!0})}}async function pt(e){let t=e.includes(`-init`)?`init`:`mount`;F.info(`--encrypt-sessions starting gocryptfs ${t}`);try{await xt(`gocryptfs`,e),F.info(`--encrypt-sessions completed gocryptfs ${t}`)}catch(n){let r=n instanceof Error?n.message:String(n);throw F.warn(`--encrypt-sessions failed gocryptfs ${t}`,{error:r}),Error(`gocryptfs ${e.join(` `)} failed: ${r}`)}}async function mt(){F.info(`--encrypt-sessions checking encryption dependencies`),await Ct(`gocryptfs`,`required for --encrypt-sessions`),F.info(`--encrypt-sessions dependency available`,{command:`gocryptfs`});for(let e of Qe)if(await St(e)){F.info(`--encrypt-sessions unmount dependency available`,{command:e});return}throw Error(`--encrypt-sessions requires one of ${Qe.join(`, `)} to be installed for secure unmount cleanup.`)}async function ht(e,t){F.info(`--encrypt-sessions mounting encrypted .aimax`,{encryptedDir:e,plainDir:t}),await ft(async n=>{await pt([`-q`,`-passfile`,n,e,t])})}async function gt(e){F.info(`--encrypt-sessions initializing encrypted .aimax directory`,{encryptedDir:e}),await ft(async t=>{await pt([`-q`,`-init`,`-passfile`,t,e])})}async function _t(e){let t=[];F.info(`--encrypt-sessions unmounting encrypted .aimax`,{plainDir:e});for(let n of $e)try{if(F.info(`--encrypt-sessions attempting encrypted .aimax unmount`,{command:n.label,plainDir:e}),await xt(n.command,[...n.args,e]),!await it(e)){F.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),F.warn(`--encrypt-sessions unmount command returned success but mountpoint remains`,{command:n.label,plainDir:e})}catch(r){let i=wt(n.label,r);t.push(i),F.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 vt(e){for(let t of $e)try{if(be(t.command,[...t.args,e],{stdio:`ignore`}),!at(e))return}catch{}}function yt(e){let t=!1,n=()=>{t||(t=!0,vt(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 bt(e){let t=et(e),n=tt(e);F.info(`--encrypt-sessions preparing encrypted .aimax mount`,{dataDir:e,encryptedDir:t,plainDir:n});let r=()=>({mounted:!1,plainDir:n,encryptedDir:t,async cleanup(){}});try{await mt()}catch(e){return F.warn(`--encrypt-sessions is unavailable; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e)}),await R(n),r()}if(await it(n))return F.warn(`--encrypt-sessions found existing .aimax mount; continuing without taking ownership`,{plainDir:n}),r();let i=null,a=[],o=null,s=null,c=!1;try{if(a=await dt(e),a.length>0&&F.warn(`--encrypt-sessions found interrupted pre-gocryptfs migration backups`,{count:a.length}),!await L(t))if(F.info(`--encrypt-sessions encrypted .aimax directory does not exist; starting first-time migration`,{encryptedDir:t}),a.length>0?o=await z(e,n):i=await z(e,n),await R(t),await gt(t),await R(n),await ht(t,n),c=!0,s=yt(n),F.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),a.length>0){for(let e of a)await B(e,n,!0);o&&=(await B(o,n,!1),await S.rm(o,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:o}),null);for(let e of a)await S.rm(e,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});a=[]}else i&&=(await B(i,n,!0),await S.rm(i,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:i}),null);else if(F.info(`--encrypt-sessions encrypted .aimax directory exists; mounting existing encrypted data`,{encryptedDir:t}),await ut(t),a.length>0?o=await z(e,n):await lt(n)||(i=await z(e,n)),await ct(n),await ht(t,n),c=!0,s=yt(n),F.info(`--encrypt-sessions mounted encrypted .aimax`,{plainDir:n,encryptedDir:t}),a.length>0){for(let e of a)await B(e,n,!0);o&&=(await B(o,n,!1),await S.rm(o,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed residual plaintext backup after migration`,{backupDir:o}),null);for(let e of a)await S.rm(e,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed resumed plaintext migration backup`,{backupDir:e});a=[]}else i&&=(await B(i,n,!0),await S.rm(i,{recursive:!0,force:!0}),F.info(`--encrypt-sessions removed plaintext migration backup`,{backupDir:i}),null);return{mounted:c,plainDir:n,encryptedDir:t,async cleanup(){if(s?.release(),c){c=!1,F.info(`--encrypt-sessions cleanup started`,{plainDir:n,encryptedDir:t});try{await _t(n),F.info(`--encrypt-sessions cleanup completed`,{plainDir:n,encryptedDir:t})}catch(e){F.warn(`--encrypt-sessions failed to unmount encrypted .aimax; continuing shutdown`,{error:e instanceof Error?e.message:String(e)})}}}}}catch(e){return s?.release(),c&&await _t(n).catch(e=>{F.warn(`--encrypt-sessions failed to unmount during mount rollback`,{error:e instanceof Error?e.message:String(e)})}),i&&await L(i)&&await lt(n)&&(await S.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await S.rename(i,n).catch(()=>{}),F.info(`--encrypt-sessions restored plaintext backup after failed migration`,{backupDir:i,plainDir:n})),o&&await L(o)&&await lt(n)&&(await S.rm(n,{recursive:!0,force:!0}).catch(()=>{}),await S.rename(o,n).catch(()=>{}),F.info(`--encrypt-sessions restored residual plaintext backup after failed migration`,{backupDir:o,plainDir:n})),F.warn(`--encrypt-sessions failed; continuing with plaintext .aimax`,{error:e instanceof Error?e.message:String(e)}),await R(n),r()}}async function V(e,t,n){if(!t.encryptSessions)return n();let r=await bt(e);try{return await n()}finally{await r.cleanup()}}async function xt(e,t){await new Promise((n,r)=>{ye(e,t,{encoding:`utf-8`},e=>{if(e){r(e);return}n()})})}async function St(e){try{return await xt(`sh`,[`-c`,`command -v "${e}" >/dev/null 2>&1`]),!0}catch{return!1}}async function Ct(e,t){if(!await St(e))throw Error(`--encrypt-sessions requires ${e}: ${t}.`)}function wt(e,t){return`${e} failed: ${t instanceof Error?t.message:String(t)}`}function Tt(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{Le(await V(e.dataDir,e,async()=>i(e.dataDir)),t)}catch(e){k(`Error bootstrapping data directory: ${e.message}`),process.exit(1)}})}function Et(e){return Se.sm4_encrypt_ecb(e)}function Dt(e){return Et(e)}function Ot(e={}){let t=kt(e.apiFormat??process.env.AIMAX_API_FORMAT),n=e.baseUrl??process.env.AIMAX_BASE_URL,r=process.env.AIMAX_AUTH_TOKEN,i=e.authToken?Dt(e.authToken):r?Dt(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}}function kt(e){if(!e||e===`openai-completions`||e===`anthropic-messages`)return e;throw Error(`Unsupported LLM API format: ${e}`)}function At(e,t){return t?w.resolve(t):w.join(e,`.aimax`,`plugins.json`)}async function H(e,t){let n=At(e,t);try{let e=await S.readFile(n,`utf-8`);return JSON.parse(e)}catch(e){if(e.code===`ENOENT`)return;throw e}}async function U(e,t,n){let r=At(e,n);await S.mkdir(w.dirname(r),{recursive:!0}),await S.writeFile(r,JSON.stringify(t,null,2),`utf-8`)}function W(e){return typeof e==`object`&&!!e}function jt(e){return W(e)&&e.type===`text`&&typeof e.text==`string`&&(e.textSignature===void 0||typeof e.textSignature==`string`)}function Mt(e){return W(e)&&e.type===`image`&&typeof e.data==`string`&&typeof e.mimeType==`string`}function Nt(e){return W(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 Pt(e){return W(e)&&e.type===`toolCall`&&typeof e.id==`string`&&typeof e.name==`string`&&W(e.arguments)&&(e.thoughtSignature===void 0||typeof e.thoughtSignature==`string`)}function Ft(e){return typeof e==`string`||Array.isArray(e)&&e.every(e=>jt(e)||Mt(e))}function It(e){return Array.isArray(e)&&e.every(e=>jt(e)||Nt(e)||Pt(e))}function Lt(e){return W(e)&&typeof e.input==`number`&&typeof e.output==`number`&&typeof e.cacheRead==`number`&&typeof e.cacheWrite==`number`&&typeof e.totalTokens==`number`&&W(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 Rt(e){return!W(e)||typeof e.role!=`string`?!1:e.role===`user`?Ft(e.content):e.role===`assistant`?It(e.content)&&typeof e.api==`string`&&typeof e.provider==`string`&&typeof e.model==`string`&&Lt(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=>jt(e)||Mt(e))&&typeof e.isError==`boolean`:!1}async function zt(e){let t;try{t=await S.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=>Rt(e)))throw Error(`Message file must contain one Message object or an array of Message objects`);return r}async function Bt(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 zt(e.fromFile)}:{kind:`text`,message:e.message}}var Vt=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()}))}},Ht=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=Ut(e);F.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){F.error(`callback event failed`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,timedOut:i,...n});return}F.info(`callback event delivered`,{callbackUrl:this.url,httpStatus:a.status,durationMs:o,...n})}catch(e){let r=Date.now()-t;F.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 Ut(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 Wt(e,t){if(t.kind===`none`)return e;let n=new URL(e);return n.searchParams.set(`authToken`,t.token),n.toString()}const G=5e3,Gt=5e3;function K(){let e=globalThis.WebSocket;if(!e)throw Error(`WebSocket is not available in this runtime`);return e}function Kt(e){return e?{kind:`query_token`,token:e}:{kind:`none`}}function qt(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 Jt(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 Yt=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 Xt(this.ensureConnected(),G,`WebSocket connection timed out after ${G}ms`);let e=K();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){F.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 Xt(this.ensureConnected(),G,`WebSocket connection timed out after ${G}ms`);let e=K();if(!this.socket||this.socket.readyState!==e.OPEN)return;this.socket.send(JSON.stringify(t))}catch(e){F.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=K();if(e.readyState!==t.CLOSED)try{await Xt(new Promise(t=>{qt(e,`close`,()=>t()),e.close()}),Gt,`WebSocket close timed out after ${Gt}ms`)}catch(e){F.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=K();if(this.socket&&this.socket.readyState===e.OPEN)return;if(this.connectPromise){await this.connectPromise;return}let t=new e(Wt(this.url,Kt(this.authToken)));this.connectPromise=new Promise((e,n)=>{qt(t,`open`,()=>{this.socket=t,Jt(t,`close`,()=>{this.socket===t&&(this.socket=null)}),e()}),qt(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 Xt(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 Zt(e){let t=e.trim();if(!t)throw Error(`Goal objective cannot be empty`);return t}function Qt(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 $t(e){let t=Qt(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}const en=[`start`,`text`,`done`,`error`,`hitl`],tn=[`off`,`gate`,`dry_run`,`write`];function nn(e){if(!e?.trim())return new Set(en);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(en)}function rn(e){return e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`?{enabled:!1}:void 0}function an(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 on(e){return e?.trim()||void 0}function sn(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!w.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 cn(e){return e?y(e):void 0}function ln(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(!w.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 un(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 dn(e,t){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(tn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function fn(e){let t=e.autoSkillsLoadEnabled===void 0?un(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):un(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?dn(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):dn(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 pn(e,t){if(e.inputText&&t){let n=_e(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 mn(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 hn(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 gn(e){let t=an(e),n=e.channel??`WEB`,r=Ot({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});return{dataDir:t,systemAgentsDir:sn(e),channel:n,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:r,skillsLoadPaths:ln(e.skillsLoadPaths),autoSkills:fn(e)}}function _n(e){let t=[],n=null;return e.callbackUrl&&t.push(new Ht(e.callbackUrl)),e.streamUrl&&(n=new Yt(e.streamUrl,nn(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new Vt(t),websocketSink:n}}async function vn(e){let{dataDir:t,sessionId:n,sessionStoreName:r,toolCallId:i,toolName:a,resolution:o,encryptSessions:s}=e;if(!i||!a||!he(a))return;let c=(e,t)=>{switch(e){case`request_approval`:return f(t);case`clarify`:return p(t);case`request_review`:return m(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 yn(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})}async function bn(e){let t=an(e);await V(t,e,async()=>{P(t);let i=new I(`resume command`),a=null;try{let t=await gn(e),o=cn(e.sessionStore),c=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await S.readFile(e.goalFile,`utf-8`):e.goal;let a=Zt(i),s=e.tokenBudget===void 0?void 0:e.tokenBudget===`0`||e.tokenBudget===``?null:Number(e.tokenBudget);s!=null&&(Number.isNaN(s)||s<=0)&&(k(`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=$t({sessionId:e.sessionId,before:n,result:i})}catch(e){throw e instanceof n&&(k(e.message),k(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}F.info(`resume command started`,{sessionId:e.sessionId,requestId:e.requestId,channel:t.channel,dataDir:t.dataDir});let l=await te(t.dataDir,e.sessionId,{storeName:o,encryptSessions:e.encryptSessions}),u=l?null:await ne(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=pn(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=xn(n,s.request.kind);await vn({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,toolCallId:s.toolContext?.toolCallId,toolName:s.toolContext?.toolName,resolution:n,encryptSessions:e.encryptSessions});let d=_n(e);a=d.sink;let f=e.sessionId,p=async n=>{if(f=n.sessionId??f,!me(n)){if(n.type===`stream_text_delta`){t.format===`text`&&A(n),await d.websocketSink?.sendTextDelta({sessionId:f,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}t.format===`text`&&A(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&&(F.info(`resume command treated as idempotent replay`,{sessionId:e.sessionId,requestId:e.requestId,idempotencyKey:n.idempotencyKey}),j({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 H(t.dataDir,m),g;try{g=await x({dataDir:t.dataDir,projectDir:on(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,message:u,encryptSessions:e.encryptSessions??!1,topicSegmentation:rn(e),hitlResume:{request:s.request,resolution:n,checkpoint:s.checkpoint,toolContext:s.toolContext},plugins:h?{config:h,dataDir:t.dataDir,workspaceDir:w.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:{text:g.text,usage:g.usage,durationMs:g.durationMs,error:g.error,paused:g.paused,uiToolPending:g.uiToolPending}}),j(g,t.format),g.error?F.error(`resume command failed: ${g.error}`):F.info(`resume command succeeded`),i.end(),process.exit(g.error?1:0);return}let d=mn(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 yn({dataDir:t.dataDir,sessionId:e.sessionId,sessionStoreName:o,result:d,encryptSessions:e.encryptSessions});let f=_n(e);a=f.sink;let p=e.sessionId,m=async n=>{if(p=n.sessionId??p,!me(n)){if(n.type===`stream_text_delta`){t.format===`text`&&A(n),await f.websocketSink?.sendTextDelta({sessionId:p,channel:t.channel,messageId:e.messageId,user:e.user,text:n.text});return}if(t.format===`text`&&A(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 hn({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 H(t.dataDir,g),v=await x({dataDir:t.dataDir,projectDir:on(e.projectDir),systemAgentsDir:t.systemAgentsDir,sessionStoreName:o,sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,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:rn(e),uiToolResume:d,plugins:_?{config:_,dataDir:t.dataDir,workspaceDir:w.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:{text:v.text,usage:v.usage,durationMs:v.durationMs,error:v.error,paused:v.paused,uiToolPending:v.uiToolPending}}),j(v,t.format),v.error?F.error(`resume command failed: ${v.error}`):F.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}`})),F.error(`resume command error: ${n.message}`),k(`Fatal: ${n.message}`),i.end(),process.exit(1)}finally{await a?.close()}})}function xn(e,t){return o(e,t)}function Sn(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(`--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 bn(e)})}const Cn=[`start`,`text`,`done`,`error`],wn=[`off`,`gate`,`dry_run`,`write`];function Tn(e){if(!e?.trim())return new Set(Cn);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(Cn)}function En(e){return e.disableTopicSegmentation===!0||process.env.AIMAX_DISABLE_TOPIC_SEGMENTATION===`true`?{enabled:!1}:void 0}function Dn(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 On(e){return e?.trim()||void 0}function kn(e){let t=(e.systemAgentsDir??process.env.AIMAX_SYSTEM_AGENTS_DIR)?.trim();if(t){if(!w.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 An(e){return e?.trim()||void 0}function jn(e){return e??`WEB`}function Mn(e){return e?y(e):void 0}function Nn(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(!w.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 Pn(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().toLowerCase();if(n){if(wn.includes(n))return n;throw Error(`Invalid ${t}: ${e}. Must be one of off,gate,dry_run,write.`)}}function In(e){let t=e.autoSkillsLoadEnabled===void 0?Pn(process.env.AIMAX_AUTO_SKILLS_LOAD_ENABLED,`AIMAX_AUTO_SKILLS_LOAD_ENABLED`):Pn(e.autoSkillsLoadEnabled,`--auto-skills-load-enabled`),n=e.autoSkillsReviewMode===void 0?Fn(process.env.AIMAX_AUTO_SKILLS_REVIEW_MODE,`AIMAX_AUTO_SKILLS_REVIEW_MODE`):Fn(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 Ln(e,t){return e.length<=t?e:t<=3?e.slice(0,t):`${e.slice(0,t-3)}...`}function Rn(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 zn(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?` ${Ln(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=>Rn(e,a).map(e=>`│ ${e.padEnd(a,` `)} │`)),l].join(`
|
|
9
|
-
`)}function Bn(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 Vn(e){return e?`set`:`unset`}function Hn(e){return e?`true`:`false`}function Un(e,t){let n=Mn(e.sessionStore)??`sessions`,r=t.timeoutMs===void 0?`default`:`${t.timeoutMs}`,i=e.callbackUrl?`enabled`:`disabled`,a=e.streamUrl?`enabled`:`disabled`,o=Bn(t.input),s=t.input.kind===`text`?`inline`:e.fromFile??`file`,c=ze(),l=En(e)?.enabled===!1?`disabled`:`enabled`,u=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,d=[...Tn(e.streamEvents)].join(`,`),f=t.autoSkills?.load?.enabled,p=t.autoSkills?.review?.mode,m=e.tokenBudget===`0`?`unlimited`:q(e.tokenBudget);return{banner:zn(void 0,[`AIMax CLI`,`Stateless Agent Runner`]),contextBox:zn(`Run Context`,[`time : ${c}`,`dataDir : ${t.dataDir}`,`projectDir : ${On(e.projectDir)??`-`}`,`systemAgents : ${t.systemAgentsDir??`/aimax/agents`}`,`agent : ${An(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 : ${w.join(t.dataDir,`workspace`)}`,`baseUrl : ${t.llm.baseUrl}`,`apiKey : ${Vn(e.apiKey)}`,`authToken : ${Vn(e.authToken)}`,`model : ${t.llm.model}`,`contextWindow: ${q(t.llm.contextWindow)}`,`flashModel : ${q(t.llm.flashModel)}`,`callbackUrl : ${q(e.callbackUrl)}`,`streamUrl : ${q(e.streamUrl)}`,`streamAuth : ${Vn(e.streamAuthToken)}`,`streamEvents : ${d}`,`output : ${t.format}`,`callback : ${i}`,`websocket : ${a}`,`timeoutMs : ${r}`,`pluginsConfig: ${q(u)}`,`goal : ${e.goal===void 0?`-`:`inline (${e.goal.length} chars)`}`,`goalFile : ${q(e.goalFile)}`,`tokenBudget : ${m}`,`force : ${Hn(e.force)}`,`resumeReqId : ${q(e.resumeRequestId)}`,`resumeInput : ${e.resumeInputJson===void 0?`-`:`inline (${e.resumeInputJson.length} chars)`}`,`resumeFile : ${q(e.resumeFromFile)}`,`encryptSess : ${Hn(e.encryptSessions)}`,`topicSegment : ${l}`]),logContext:{time:c,channel:t.channel,user:e.user,dataDir:t.dataDir,projectDir:On(e.projectDir),systemAgentsDir:t.systemAgentsDir,agent:An(e.agent),workspaceDir:w.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:!!e.apiKey,hasAuthToken:!!e.authToken,model:t.llm.model,contextWindow:t.llm.contextWindow,flashModel:t.llm.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,hasStreamAuthToken:!!e.streamAuthToken,streamEvents:d,output:t.format,hasCallback:!!e.callbackUrl,hasStream:!!e.streamUrl,timeoutMs:t.timeoutMs,pluginsConfig:u,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 Wn(e,t){let n=Dn(e),r=jn(e.channel),i=Ot({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});return{dataDir:n,systemAgentsDir:kn(e),channel:r,format:e.output===`json`?`json`:`text`,timeoutMs:e.timeout?Number(e.timeout):void 0,llm:i,input:t,skillsLoadPaths:Nn(e.skillsLoadPaths),autoSkills:In(e)}}function Gn(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 Kn(e,t){if(!e.sessionId)return null;let n=Gn(t);if(!n)return null;let r=await te(Dn(e),e.sessionId,{storeName:Mn(e.sessionStore),encryptSessions:e.encryptSessions});return!r||r.status!==`pending`||!ge(n,r.request)?null:{requestId:r.request.requestId,inputText:n}}function qn(e){let t=[],n=null;return e.callbackUrl&&t.push(new Ht(e.callbackUrl)),e.streamUrl&&(n=new Yt(e.streamUrl,Tn(e.streamEvents),e.streamAuthToken),t.push(n)),{sink:new Vt(t),websocketSink:n}}async function J(e,t){F.info(`dispatching external event`,pr(t)),await e.sink.send(t)}function Jn(e){if(!e)return{};let t={};for(let[n,r]of Object.entries(e)){if(r===null||typeof r==`string`||typeof r==`number`||typeof r==`boolean`){t[n]=r;continue}if(r instanceof Error){t[n]=`${r.name}: ${r.message}`;continue}t[n]=JSON.stringify(r)}return t}function Yn(e){let t={sessionId:e.sessionId,messageId:e.messageId,parentSessionId:e.parentSessionId,depth:e.depth,scope:e.scope,phase:e.phase,...Jn(e.details)};if(e.level===`error`){F.error(e.message,t);return}if(e.level===`warn`){F.warn(e.message,t);return}F.info(e.message,t)}function Xn(e,t,n,r,i){return{sink:e,websocketSink:t,channel:n,defaultMessageId:r,user:i}}function Zn(){let e=new AbortController,t=()=>e.abort();return process.once(`SIGTERM`,t),process.once(`SIGINT`,t),{controller:e,cleanup:()=>{process.off(`SIGTERM`,t),process.off(`SIGINT`,t)}}}function Qn(e){return{activeSessionId:e??`pending`,finalResult:null}}function $n(e,t){e.activeSessionId=t.sessionId??e.activeSessionId}function er(e,t){return e.messageId??t}async function tr(e,t,n){if(!await h(e.dataDir)){if(await nr(t,e.format,n.activeSessionId,e.dataDir,`checking`),(await u(e.dataDir)).performedBootstrap){await nr(t,e.format,n.activeSessionId,e.dataDir,`initializing`),await nr(t,e.format,n.activeSessionId,e.dataDir,`initialized`);return}await nr(t,e.format,n.activeSessionId,e.dataDir,`ready`)}}async function nr(e,t,n,r,i){let a={type:`bootstrap`,phase:i,dataDir:r};t===`text`&&A(a),await J(e,{sessionId:n,channel:e.channel,messageId:e.defaultMessageId,user:e.user,type:`progress`,event:a})}function rr(e,t,n){return async r=>{if($n(n,r),me(r)){Yn(r);return}if(r.type===`stream_text_delta`){e.format===`text`&&A(r),await t.websocketSink?.sendTextDelta({sessionId:n.activeSessionId,channel:e.channel,messageId:er(r,t.defaultMessageId),user:t.user,text:r.text});return}e.format===`text`&&A(r);let i=er(r,t.defaultMessageId);if(r.type===`hitl_requested`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`hitl`,request:r.request}),await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`progress`,event:r});return}if(r.type===`start`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`start`,message:r.message});return}if(r.type===`session_reset`){await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`session_reset`,action:r.action,previousSessionId:r.previousSessionId,message:r.message});return}await J(t,{sessionId:n.activeSessionId,channel:e.channel,messageId:i,user:t.user,type:`progress`,event:r})}}function ir(e,t,n,r,i,a){let o={dataDir:t.dataDir,projectDir:On(e.projectDir),systemAgentsDir:t.systemAgentsDir,agentPolicy:An(e.agent)?{requestedAgentName:An(e.agent)}:void 0,sessionStoreName:Mn(e.sessionStore),sessionId:e.sessionId,messageId:e.messageId,channel:t.channel,llm:t.llm,skillsLoadPaths:t.skillsLoadPaths,autoSkills:t.autoSkills,timeoutMs:t.timeoutMs,abortSignal:n.signal,pendingGoal:a,encryptSessions:e.encryptSessions??!1,topicSegmentation:En(e),plugins:i?{config:i,dataDir:t.dataDir,workspaceDir:w.join(t.dataDir,`workspace`),bundledDir:process.env.AIMAX_PLUGINS_BUNDLED_DIR,llmAllowlist:i.llmAllowlist}:void 0,onProgress:r};return t.input.kind===`messages`?{...o,messages:t.input.messages}:{...o,message:t.input.message}}async function ar(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:{text:r.text,usage:r.usage,durationMs:r.durationMs,error:r.error,paused:r.paused}})}async function or(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 sr(e,t){let n=Un(e,t);F.info([`run command started`,n.banner,n.contextBox].join(`
|
|
11
|
-
`),n.logContext),t.format===`text`&&(O(n.banner),O(``),O(n.contextBox),O(``))}function cr(e,t,n){j(t,n),t.error?F.error(`run command failed: ${t.error}`):F.info(`run command succeeded`),e.end(),process.exit(t.error?1:0)}function lr(e){let t=Je();if(!t)return;let n=`[${ze()}] [ERROR] ${e}\n`;try{C.appendFileSync(w.join(t.logDir,`app.log`),n),C.appendFileSync(w.join(t.logDir,`errors.log`),n)}catch{}}async function ur(e,t){let n=`run command error: ${t.message}`;F.error(n),lr(n),k(`Fatal: ${t.message}`),e.end(),await Ye(),process.exit(1)}async function dr(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 S.readFile(e.resumeFromFile,`utf-8`)}catch(e){throw Error(`Failed to read resume input file: ${e.message}`)}}async function fr(e){let t=Dn(e);P(t);let i=new I(`run command`),a=null;try{a=e.encryptSessions?await bt(t):null,a&&P(t)}catch(e){await ur(i,e);return}try{let t=await dr(e);if(e.resumeRequestId||t||e.resumeFromFile){if(!e.sessionId||!e.resumeRequestId||!t)throw Error(`--session-id, --resume-request-id, and exactly one of --resume-input-json or --resume-from-file must be provided together`);await bn({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:e.resumeRequestId,inputJson:t,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,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 a;try{a=await Bt({message:e.message,fromFile:e.fromFile})}catch(e){await ur(i,e);return}let o=await Kn(e,a);if(o){await bn({dataDir:e.dataDir,projectDir:e.projectDir,systemAgentsDir:e.systemAgentsDir,sessionId:e.sessionId,sessionStore:e.sessionStore,requestId:o.requestId,inputText:o.inputText,channel:e.channel,baseUrl:e.baseUrl,apiKey:e.apiKey,authToken:e.authToken,model:e.model,contextWindow:e.contextWindow,flashModel:e.flashModel,callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamAuthToken:e.streamAuthToken,streamEvents:e.streamEvents,timeout:e.timeout,output:e.output,pluginsConfig:e.pluginsConfig,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{controller:s,cleanup:c}=Zn(),l=null,u=e.channel??`WEB`,d=Qn(e.sessionId);try{let t=await Wn(e,a);u=t.channel,sr(e,t);let o=qn(e);l=o.sink,F.info(`external sink configured`,{callbackUrl:e.callbackUrl,streamUrl:e.streamUrl,streamEvents:e.streamEvents});let c=Xn(l,o.websocketSink,t.channel,e.messageId,e.user);await tr(t,c,d);let f,p=null;if(e.goal||e.goalFile){let i;i=e.goalFile?await S.readFile(e.goalFile,`utf-8`):e.goal;let a=Zt(i),o=Mn(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)&&(k(`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});p=$t({sessionId:e.sessionId,before:n,result:i})}else f={objective:a,tokenBudget:s??null}}catch(e){throw e instanceof n&&(k(e.message),k(`Existing: ${e.existingObjectivePreview}`),process.exit(2)),e}}let m=e.pluginsConfig??process.env.AIMAX_PLUGINS_CONFIG,h=await H(t.dataDir,m),g=rr(t,c,d);p&&await g(p);let _=await x(ir(e,t,s,g,h,f));await ar(c,d,e.messageId,_),cr(i,_,t.format)}catch(t){let n=t;l&&await or(Xn(l,null,u,e.messageId,e.user),d,e.messageId,n),await ur(i,n)}finally{await l?.close(),c()}}finally{await a?.cleanup()}}function pr(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 mr(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(`--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(`--timeout <ms>`,`Execution timeout in milliseconds (default: 600000)`).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 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 fr(e)})}function hr(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||(k(`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`&&(k(`Invalid channel: ${r.channel}. Must be 'H5', 'WEB', 'KLPA', 'TASK', 'CRON', or 'EIP_ASSISTANT'`),process.exit(1));try{await V(r.dataDir,r,async()=>{let e=r.sessionStore?y(r.sessionStore):void 0;if(i===`list`){Pe(await ee(r.dataDir,r.channel,{storeName:e}),a);return}if(r.sessionId||(k(`error: required option '-s, --session-id <id>' not specified`),process.exit(1)),i===`inspect`){Fe(await _(r.dataDir,r.sessionId,{storeName:e}),a);return}if(i===`export`){Ie(await d(r.dataDir,r.sessionId,{storeName:e}),a);return}k(`Invalid sessions action: ${i}. Must be 'list', 'inspect', or 'export'`),process.exit(1)})}catch(e){k(`${i===`inspect`?`Error inspecting session`:i===`export`?`Error exporting session`:`Error listing sessions`}: ${e.message}`),process.exit(1)}})}function gr(e){return w.join(e,`workspace`)}function _r(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function vr(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 yr(e){let t=e.level===`error`?`plugin error`:`plugin warning`;return e.pluginId?`${t} (${e.pluginId}): ${e.message}`:`${t}: ${e.message}`}function br(e){if(!e||e===`cli`)return`cli`;if(e===`cron`)return`cron`;throw Error(`Unsupported dream trigger: ${e}. Expected "cli" or "cron".`)}async function xr(e){let t=[],n;try{n=await H(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=g({config:n,dataDir:e.dataDir,workspaceDir:gr(e.dataDir),bundledDir:_r()});return t.push(...r.diagnostics.map(yr)),{pluginSystem:r,warnings:t}}catch(e){return t.push(`failed to initialize plugin system: ${e.message}`),{warnings:t}}}async function Sr(e){let t=w.join(e.dataDir,`.aimax`),{pluginSystem:n,warnings:r}=await xr({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});return o?{provider:o.provider,providerId:o.registration.id,pluginId:o.registration.pluginId,providerOrigin:`plugin`,warnings:r,pluginSystem:n}:((a||e.provider)&&r.push(`requested memory provider was not resolved; falling back to builtin provider`),{provider:c({dataDir:e.dataDir,memoryDir:t},{includeSessions:e.includeSessions}),providerId:`builtin`,providerOrigin:`builtin`,warnings:r,pluginSystem:n})}function Cr(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 wr(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 V(e.dataDir,e,async()=>{let n=await Sr({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=Cr(n.provider.status(),n,e.deep);O(t===`json`?JSON.stringify(r,null,2):vr(r,e.deep))})}catch(e){k(`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 V(e.dataDir,e,async()=>{let t=await Sr({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)k(`Warning: ${e}`);e.verbose&&n&&O(JSON.stringify(n,null,2)),O(e.rebuild?`Memory index rebuilt.`:`Memory index refreshed.`)})}catch(e){k(`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||(k(`Query is required: provide [query] or --query <text>`),process.exit(1));try{await V(t.dataDir,t,async()=>{let e=await(await Sr({dataDir:t.dataDir,provider:t.provider,providerPlugin:t.providerPlugin,pluginsConfig:t.pluginsConfig,includeSessions:t.includeSessions})).provider.search(r);if(n===`json`){O(JSON.stringify(e,null,2));return}if(e.length===0){O(`No results found for: ${r}`);return}O(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){k(`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 V(e.dataDir,e,async()=>{let n=br(e.trigger),r=await Sr({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:w.join(e.dataDir,`.aimax`),providerId:r.providerId,pluginId:r.pluginId,trigger:n,dryRun:!!e.dryRun},{workspaceDir:gr(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`){O(JSON.stringify(a,null,2));return}O(`trigger: ${a.trigger}`),O(`provider_source: ${a.providerSource}`),O(`provider_id: ${a.providerId}`),a.pluginId&&O(`plugin_id: ${a.pluginId}`),O(`result_count: ${a.resultCount}`),a.results.length===0?O(`note: no dream_gate hook registered`):O(`results: ${JSON.stringify(a.results)}`);for(let e of a.warnings)O(`warning: ${e}`)})}catch(e){k(`Error running dream gate: ${e.message}`),process.exit(1)}})}function Tr(e){return`${e.match.accountId?`${e.match.channel}:${e.match.accountId}`:e.match.channel} -> ${e.agentId}`}function Er(e){return async t=>{let n=await E(t),r=Te(n),i=Ee(n);if(D(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=Ae(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(` - ${Tr(e)}`)}}}}function Dr(e,t){return async n=>{T(await E(n),De(e))&&(console.error(`Agent "${e}" already exists.`),process.exit(1)),await Ce(n,{id:e,name:t.name,model:t.model,default:t.default})||(console.error(`Agent "${e}" already exists.`),process.exit(1));let r=Ae(n,e);console.log(`Agent "${e}" added successfully.`),console.log(` Agent dir: ${r}`)}}function Or(e){return async t=>{let n=T(await E(t),De(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 Oe(t,e)||(console.error(`Failed to delete agent "${e}".`),process.exit(1)),console.log(`Agent "${e}" deleted.`)}}function kr(e){return async t=>{let n=await E(t),r=e.agent??D(n);T(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 we(t,{agentId:r,match:{channel:e,accountId:a||void 0}}),console.log(`Binding added: ${n} -> ${r}`)}}}function Ar(e){return async t=>{let n=await E(t),r=e.agent??D(n);if(T(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),e.all){let e=await ke(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 ke(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 jr(e){return async t=>{let n=Ee(await E(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(` ${Tr(e)}`)}}function Mr(e){return async t=>{let n=await E(t),r=e.agent??D(n);T(n,r)||(console.error(`Agent "${r}" not found.`),process.exit(1)),await je(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 Nr(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 V(n,e,async()=>{await Er(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 V(r,n,async()=>{await Dr(e,n)(r)})}),r(n.command(`delete <id>`).description(`Delete an agent`)).action(async(e,n)=>{let r=t();await V(r,n,async()=>{await Or(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 V(n,e,async()=>{await kr(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 V(n,e,async()=>{await Ar(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 V(n,e,async()=>{await jr(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 V(n,e,async()=>{await Mr(e)(n)})})}function Y(e){return w.join(e,`workspace`)}function X(){let e=process.env.AIMAX_PLUGINS_BUNDLED_DIR;return e&&e.trim()||void 0}function Pr(e){if(e.length===0){O(`No plugins discovered.`);return}for(let t of e){let e=t.status.padEnd(8,` `);O(`${t.id} ${e} ${t.origin} ${t.source}`)}}function Fr(e){O(`id: ${e.id}`),O(`status: ${e.status}`),O(`origin: ${e.origin}`),O(`source: ${e.source}`),O(`enabled: ${e.enabled}`),e.error&&O(`error: ${e.error}`),O(`tools: ${e.toolCount}`),O(`hooks: ${e.hookCount}`),e.skills.length>0&&O(`skills: ${e.skills.join(`, `)}`)}function Ir(e){return Array.from(new Set((e??[]).map(e=>e.trim()).filter(Boolean)))}function Lr(e){if(e.length===0){O(`LLM allowlist is empty.`);return}for(let t of e)O(t)}function Rr(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 V(n,e,async()=>{Pr(g({config:await H(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 V(r,n,async()=>{let t=g({config:await H(r,n.pluginsConfig),dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.find(t=>t.id===e);t||(k(`Plugin not found: ${e}`),process.exit(1)),Fr(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 V(r,n,async()=>{let t=await H(r,n.pluginsConfig)??{},i=ae(t);g({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(k(`Plugin not found: ${e}`),process.exit(1)),await U(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!0}}},n.pluginsConfig),O(`Enabled ${e}`),i.allow.length>0&&!i.allow.includes(e)&&O(`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 V(r,n,async()=>{let t=await H(r,n.pluginsConfig)??{};g({config:t,dataDir:r,workspaceDir:Y(r),bundledDir:X()}).registry.plugins.some(t=>t.id===e)||(k(`Plugin not found: ${e}`),process.exit(1)),await U(r,{...t,entries:{...t.entries,[e]:{...t.entries?.[e]??{},enabled:!1}}},n.pluginsConfig),O(`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 V(n,e,async()=>{let t=g({config:await H(n,e.pluginsConfig),dataDir:n,workspaceDir:Y(n),bundledDir:X()});if(t.diagnostics.length===0){O(`No plugin issues detected.`);return}for(let e of t.diagnostics)O(`${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 V(n,e,async()=>{Lr(Ir((await H(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 V(r,n,async()=>{let t=await H(r,n.pluginsConfig)??{},i=Ir([...t.llmAllowlist??[],...e]);await U(r,{...t,llmAllowlist:i},n.pluginsConfig),O(`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 V(r,n,async()=>{let t=await H(r,n.pluginsConfig)??{},i=new Set(e.map(e=>e.trim()).filter(Boolean)),a=Ir(t.llmAllowlist).filter(e=>!i.has(e));await U(r,{...t,llmAllowlist:a},n.pluginsConfig),O(`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 V(n,e,async()=>{await U(n,{...await H(n,e.pluginsConfig)??{},llmAllowlist:[]},e.pluginsConfig),O(`LLM allowlist cleared.`)})})}function zr(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 V(e.dataDir,e,async()=>{let n=v(await re(e.dataDir,[]));if(t===`json`){O(JSON.stringify(n,null,2));return}O(`Commands`),O(` builtin: ${n.builtin.map(e=>e.name).join(` | `)}`),n.skillCommands.length>0?O(` skills: ${n.skillCommands.map(e=>e.name).join(` | `)}`):O(` skills: (none)`)})}catch(e){k(`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 Br(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 fe(e.dataDir,e.sessionId,{goalId:Me(),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 de(e.dataDir,e.sessionId,i,{...t,eventSource:`cli`})}async function Vr(e,t){let n=Z(t),r=Q(t),i=$(t.sessionStore),a=e.trim();a||(k(`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)&&(k(`error: --token-budget must be a positive integer, or 0 for unlimited`),process.exit(1));let s=await Br({dataDir:n,sessionId:r,sessionStoreName:i,objective:a,tokenBudget:o});O(JSON.stringify({goal:s},null,2))}async function Hr(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(!i){O(JSON.stringify({goal:null},null,2));return}let a=await oe(t,n,i,{storeName:r});O(JSON.stringify({goal:{...i,objective:a}},null,2))}async function Ur(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});i||(k(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(k(`error: cannot pause a completed goal`),process.exit(1));let a=await de(t,n,{status:`paused`},{storeName:r,eventSource:`cli`});O(JSON.stringify({goal:a},null,2))}async function Wr(e){let t=Z(e),n=Q(e),r=$(e.sessionStore),i=await b(t,n,{storeName:r});if(i||(k(`error: no goal exists for this session`),process.exit(1)),i.status===`complete`&&(k(`error: cannot resume a completed goal`),process.exit(1)),i.status===`budget_limited`&&(k(`error: cannot resume a budget-limited goal; clear or replace it instead`),process.exit(1)),i.status===`active`){O(JSON.stringify({goal:i},null,2));return}let a=await de(t,n,{status:`active`},{storeName:r,eventSource:`cli`});O(JSON.stringify({goal:a},null,2))}async function Gr(e){let t=await l(Z(e),Q(e),{storeName:$(e.sessionStore),eventSource:`cli`});O(JSON.stringify({cleared:t},null,2))}function Kr(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 Vr(e,t)}catch(e){k(`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 Hr(e)}catch(e){k(`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 Ur(e)}catch(e){k(`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 Wr(e)}catch(e){k(`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 Gr(e)}catch(e){k(`error: ${e.message}`),process.exit(1)}})}const qr=[`progress`,`error`,`hitl`];function Jr(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 Yr(e){if(!e?.trim())return new Set(qr);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(qr)}function Xr(e){return e?y(e):void 0}function Zr(e){let t=[];return e.callbackUrl&&t.push(new Ht(e.callbackUrl)),e.streamUrl&&t.push(new Yt(e.streamUrl,Yr(e.streamEvents),e.streamAuthToken)),new Vt(t)}async function Qr(e){let t=Jr(e);await V(t,e,async()=>{P(t);let n=new I(`cancel command`),r=e.channel??`WEB`,i=e.output===`json`?`json`:`text`,a=Zr(e),o=Xr(e.sessionStore);try{let s=await te(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`&&A(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}),F.error(`cancel command error: ${i.message}`),k(`Fatal: ${i.message}`),n.end(),process.exit(1)}finally{await a.close()}})}function $r(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 Qr(e)})}function ei(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 ti(e){return e.query?.trim()||void 0}function ni(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 ri(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 ii(e){if(e.filePath){if(!w.isAbsolute(e.filePath))throw Error(`--file-path must be an absolute path`);try{await S.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 ai(e){let t=null;try{let n=ei(e);P(n),t=new I(`summarize command`);let r=ti(e),i=await ii(e),a=Ot({apiFormat:e.apiFormat,baseUrl:e.baseUrl,apiKey:e.apiKey,model:e.model,contextWindow:2e5}),o=ni(e.timeout),s=ri(e.maxTokens);F.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 x({dataDir:n,channel:`WEB`,message:oi(i,r),llm:{...a,maxTokens:s},timeoutMs:o});O(c.text.trim()),F.info(`summarize command succeeded`,{source:i.source,summaryLength:c.text.length,durationMs:c.durationMs}),t.end()}catch(e){F.error(`summarize command error: ${e.message}`),k(`Fatal: ${e.message}`),t?.end(),process.exit(1)}}function oi(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 si(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`).action(async e=>{await ai(e)})}const ci=e(import.meta.url)(`../package.json`);function li(){return process.env.AIMAX_DATA_DIR||process.cwd()}function ui(){let e=new t;return e.name(`aimax`).description(`AIMax CLI — runs agent tasks in a containerized environment`).version(ci.version),mr(e),Sn(e),Kr(e),$r(e),hr(e),si(e),zr(e),Tt(e),wr(e),Nr(e,li),Rr(e,li),e}export{Ye as a,F as i,li as n,P as r,ui as t};
|