@yuandc/aica 0.1.87 → 0.1.88

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.
Files changed (35) hide show
  1. package/dist/acp/client/acp-runtime-pool.js +1 -1
  2. package/dist/acp/providers/codex/codex-path.js +1 -1
  3. package/dist/acp/providers/codex/permissions.js +1 -1
  4. package/dist/acp/providers/codex/provider.js +1 -1
  5. package/dist/acp/providers/codex-acp/adapter.js +4 -4
  6. package/dist/acp/providers/codex-acp/provider.js +1 -1
  7. package/dist/acp/providers/mimo/provider.js +5 -5
  8. package/dist/acp/providers/opencode/provider.js +4 -4
  9. package/dist/acp/providers/registry.js +1 -1
  10. package/dist/acp/providers/workbuddy/auth-environment.js +1 -0
  11. package/dist/acp/providers/workbuddy/auth-gate.js +1 -0
  12. package/dist/acp/providers/workbuddy/auth-manager.js +1 -0
  13. package/dist/acp/providers/workbuddy/auth-transport.js +3 -0
  14. package/dist/acp/providers/workbuddy/config.js +1 -0
  15. package/dist/acp/providers/workbuddy/discovery.js +1 -0
  16. package/dist/acp/providers/workbuddy/events.js +1 -0
  17. package/dist/acp/providers/workbuddy/interactions.js +1 -0
  18. package/dist/acp/providers/workbuddy/launch.js +1 -0
  19. package/dist/acp/providers/workbuddy/provider.js +1 -0
  20. package/dist/acp/providers/workbuddy/supplements.js +1 -0
  21. package/dist/commands/start.js +1 -1
  22. package/dist/core/desktop-control.js +1 -1
  23. package/dist/core/heartbeat.js +3 -3
  24. package/dist/core/job-worker.js +1 -1
  25. package/dist/core/machine-filesystem-worker.js +4 -4
  26. package/dist/core/provider-health.js +1 -1
  27. package/dist/core/provider-install-mimo.js +1 -0
  28. package/dist/core/provider-install-paths.js +1 -0
  29. package/dist/core/provider-installer.js +1 -0
  30. package/dist/core/workbuddy-auth-worker.js +1 -0
  31. package/dist/interactions/job-interactions.js +2 -0
  32. package/dist/interactions/provider-input.js +1 -0
  33. package/dist/interactions/types.js +1 -0
  34. package/dist/version.js +1 -1
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- import{execFileSync as m}from"node:child_process";import i from"node:fs";import l from"node:os";import u from"node:path";import{resolveCodexPath as f}from"../acp/providers/codex/codex-process.js";const d=360*60*1e3,p="aica-provider-probe-",E=3600*1e3;let c=null;function A(){const t=Date.now();if(c&&c.expiresAtMs>t)return c.items;const e={codex:s(f()),mimo:s(process.env.ACA_MIMO_COMMAND||"mimo"),opencode:s(process.env.ACA_OPENCODE_COMMAND||"opencode")};return c={expiresAtMs:t+d,items:e},e}function s(t){const e=Date.now();let r=null;try{_(e),r=i.mkdtempSync(u.join(l.tmpdir(),p));const o=m(t,["--version"],{windowsHide:!0,encoding:"utf8",timeout:8e3,maxBuffer:256*1024,stdio:["ignore","pipe","pipe"],env:{...process.env,TMPDIR:r,TEMP:r,TMP:r}});return{available:!0,status:"ready",version:v(o),checkedAtMs:e,errorCode:null}}catch(o){const n=y(o);return{available:!1,status:n==="ENOENT"?"unavailable":"error",version:null,checkedAtMs:e,errorCode:n==="ENOENT"?"not_installed":"probe_failed"}}finally{r&&i.rmSync(r,{recursive:!0,force:!0})}}function _(t){const e=l.tmpdir();let r;try{r=i.readdirSync(e).filter(o=>o.startsWith(p))}catch{return}for(const o of r){const n=u.join(e,o);try{const a=i.lstatSync(n);if(!a.isDirectory()||t-a.mtimeMs<E)continue;i.rmSync(n,{recursive:!0,force:!0})}catch{}}}function v(t){const e=t.split(/\r?\n/).map(r=>r.trim()).find(Boolean);return e?e.slice(0,120):null}function y(t){if(!t||typeof t!="object")return null;const e=t.code;return typeof e=="string"?e:null}export{s as probeProvider,A as providerHealthSnapshot};
1
+ import{resolveInstalledLaunch as m}from"./provider-install-paths.js";import{execFileSync as f}from"node:child_process";import c from"node:fs";import l from"node:os";import u from"node:path";import{resolveCodexPath as v}from"../acp/providers/codex/codex-process.js";import{resolveWorkBuddyExecutable as y}from"../acp/providers/workbuddy/launch.js";const D=360*60*1e3,d="aica-provider-probe-",_=3600*1e3;let s=null;function T(){s=null}function B(){const e=Date.now();if(s&&s.expiresAtMs>e)return s.items;const r={codex:a(v()),mimo:p("mimo"),opencode:p("opencode"),workbuddy:b()};return s={expiresAtMs:e+D,items:r},r}function p(e){const r=m(e);return a(r.command,[...r.args,"--version"])}function b(){try{const e=y(process.env.ACA_WORKBUDDY_COMMAND||process.env.ACA_CODEBUDDY_COMMAND||"codebuddy");return a(e.command,[...e.args,"--version"])}catch{return{available:!1,status:"error",version:null,checkedAtMs:Date.now(),errorCode:"probe_failed"}}}function a(e,r=["--version"]){const o=Date.now();let t=null;try{E(o),t=c.mkdtempSync(u.join(l.tmpdir(),d));const n=f(e,r,{windowsHide:!0,encoding:"utf8",timeout:8e3,maxBuffer:256*1024,stdio:["ignore","pipe","pipe"],env:{...process.env,TMPDIR:t,TEMP:t,TMP:t}});return{available:!0,status:"ready",version:h(n),checkedAtMs:o,errorCode:null}}catch(n){const i=M(n);return{available:!1,status:i==="ENOENT"?"unavailable":"error",version:null,checkedAtMs:o,errorCode:i==="ENOENT"?"not_installed":"probe_failed"}}finally{t&&c.rmSync(t,{recursive:!0,force:!0})}}function E(e){const r=l.tmpdir();let o;try{o=c.readdirSync(r).filter(t=>t.startsWith(d))}catch{return}for(const t of o){const n=u.join(r,t);try{const i=c.lstatSync(n);if(!i.isDirectory()||e-i.mtimeMs<_)continue;c.rmSync(n,{recursive:!0,force:!0})}catch{}}}function h(e){const r=e.split(/\r?\n/).map(o=>o.trim()).find(Boolean);return r?r.slice(0,120):null}function M(e){if(!e||typeof e!="object")return null;const r=e.code;return typeof r=="string"?r:null}export{a as probeProvider,B as providerHealthSnapshot,T as resetProviderHealth};
@@ -0,0 +1 @@
1
+ import e from"node:fs";import a from"node:path";import{Readable as $}from"node:stream";import{pipeline as l}from"node:stream/promises";import{createHash as y}from"node:crypto";import{providerPackages as h}from"./provider-install-paths.js";async function z(c,r,w){const o=process.platform==="win32"?"windows":process.platform;if(!["linux","darwin","windows"].includes(o)||!["x64","arm64"].includes(process.arch))throw new Error("unsupported-platform");const u=o==="linux"&&(e.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime),x=`mimocode-${o}-${process.arch}${process.arch==="x64"?"-baseline":""}${u?"-musl":""}`,n=o==="linux"?".tar.gz":".zip",m=`https://mimocode.cnbj1.mi-fds.com/mimocode/mimocode/releases/v${h.mimo.version}/${x}${n}`,t=a.join(c,`mimo${n}`),i=await fetch(m,{signal:r});if(!i.ok||!i.body)throw new Error("download-failed");await l($.fromWeb(i.body),e.createWriteStream(t),{signal:r});const p=await fetch(`${m}.sha256`,{signal:AbortSignal.any([r,AbortSignal.timeout(3e4)])}).catch(()=>null);if(p?.ok){const d=(await p.text()).trim().split(/\s+/)[0];if(/^[a-f0-9]{64}$/i.test(d)){const f=y("sha256");if(await l(e.createReadStream(t),f,{signal:r}),f.digest("hex")!==d.toLowerCase())throw new Error("checksum-mismatch")}}const s=a.join(c,"node_modules",h.mimo.package,"vendor");e.mkdirSync(s,{recursive:!0}),await w("tar",[o==="linux"?"-xzf":"-xf",t,"-C",s]);const b=a.join(s,o==="windows"?"mimo.exe":"mimo");e.chmodSync(b,493),e.rmSync(t,{force:!0})}export{z as prepareMimoBinary};
@@ -0,0 +1 @@
1
+ import r from"node:fs";import t from"node:path";import{isSea as x}from"node:sea";import{getAcaHome as y}from"./paths.js";const l={codex:{package:"@openai/codex",version:"0.163.0",command:"codex",env:"CODEX_PATH"},mimo:{package:"@mimo-ai/cli",version:"0.1.16",command:"mimo",env:"ACA_MIMO_COMMAND"},opencode:{package:"opencode-ai",version:"1.19.5",command:"opencode",env:"ACA_OPENCODE_COMMAND"},workbuddy:{package:"@tencent-ai/codebuddy-code",version:"2.179.3",command:"codebuddy",env:"ACA_WORKBUDDY_COMMAND"}};function E(e){return Object.hasOwn(l,e)}function g(e){return t.resolve(y(),"providers",e)}function b(e){try{const o=g(e),n=JSON.parse(r.readFileSync(t.join(o,"current.json"),"utf8"));return/^[a-f0-9-]{36}$/.test(n.release)?O(e,t.join(o,n.release)):null}catch{return null}}function A(){return x()||process.env.ACA_SINGLE_FILE_WORKER==="1"?process.env.ACA_PROVIDER_NODE||"node":process.execPath}function k(e){const o=l[e],n=process.env[o.env];if(n)return{command:n,args:[]};const s=b(e);return s?S(s):{command:o.command,args:[]}}function O(e,o){const n=l[e],s=t.join(o,"node_modules",n.package);try{if(e==="mimo"){const i=t.join(s,"vendor",process.platform==="win32"?"mimo.exe":"mimo");return r.existsSync(i)?i:null}if(e==="opencode"){const p=`opencode-${process.platform==="win32"?"windows":process.platform}-${process.arch}`,m=process.platform==="linux"&&(r.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime)?"-musl":"",f=process.arch==="x64"?[`${p}-baseline${m}`,`${p}${m}`]:[`${p}${m}`];for(const v of f){const u=t.join(o,"node_modules",v,"bin",`${n.command}${process.platform==="win32"?".exe":""}`);if(r.existsSync(u))return u}return null}const c=JSON.parse(r.readFileSync(t.join(s,"package.json"),"utf8")),d=typeof c.bin=="string"?c.bin:c.bin?.[n.command];if(typeof d!="string")return null;const a=t.resolve(s,d);return!a.startsWith(s+t.sep)||!r.existsSync(a)?null:a}catch{return null}}function S(e){const o=r.openSync(e,"r");try{const n=Buffer.alloc(128);return r.readSync(o,n,0,n.length,0),/\.[cm]?js$/i.test(e)||/^#![^\r\n]*\bnode\b/.test(n.toString("utf8"))?{command:A(),args:[e]}:{command:e,args:[]}}finally{r.closeSync(o)}}export{S as entryLaunch,b as installedProviderEntry,E as isInstallProvider,O as packageEntry,g as providerInstallRoot,A as providerNode,l as providerPackages,k as resolveInstalledLaunch};
@@ -0,0 +1 @@
1
+ import{prepareMimoBinary as P}from"./provider-install-mimo.js";import{resetWorkBuddyDiscovery as O}from"../acp/providers/workbuddy/discovery.js";import{resolveCodexPath as h}from"../acp/providers/codex/codex-path.js";import u from"node:fs";import o from"node:path";import{spawn as C,execFileSync as D}from"node:child_process";import{randomUUID as L}from"node:crypto";import{isInstallProvider as _,providerPackages as E,providerInstallRoot as $,providerNode as x,packageEntry as G,entryLaunch as M}from"./provider-install-paths.js";import{managementActivity as H}from"./management/activity.js";import{resetProviderHealth as b}from"./provider-health.js";import{sendHeartbeat as U}from"./heartbeat.js";const a=new Map;let c=null,y=!1;function V(e){const r=String(e.provider||"");if(!_(r)||!["status","install"].includes(String(e.action)))throw new Error("无效的 Provider 安装操作");if(e.action==="status")return a.get(r)||{state:"idle",message:""};if(a.get(r)?.state==="installing")return a.get(r);if(c||y)return{state:"error",message:"Worker 正在安装其他 CLI 或退出,请稍后重试。"};if(process.env[E[r].env]||r==="workbuddy"&&process.env.ACA_CODEBUDDY_COMMAND)return{state:"error",message:"此 Provider 已指定自定义命令,请先在 Worker 配置中移除该覆盖项。"};a.set(r,{state:"installing",message:"正在下载并安装 CLI,关闭页面后仍会继续。"});const s={done:Promise.resolve(),controller:new AbortController};return c=s,s.done=F(r,s).finally(()=>{c===s&&(c=null)}),a.get(r)}async function F(e,r){const s=H.track("provider-install"),m=$(e),f=L(),n=o.join(m,f);let p=!1,i="准备 Node/npm";const g=setTimeout(()=>{r.controller.abort(),r.child&&N(r.child)},15*6e4);try{u.mkdirSync(n,{recursive:!0});const t=x(),d=D(t,["-p","process.execPath"],{encoding:"utf8",timeout:8e3,windowsHide:!0}).trim(),l=[o.join(o.dirname(d),"node_modules/npm/bin/npm-cli.js"),o.resolve(o.dirname(d),"../lib/node_modules/npm/bin/npm-cli.js")].find(w=>u.existsSync(w));if(!l)throw new Error("missing-npm");i="下载 npm 包",await I(d,[l,"install","--prefix",n,"--no-audit","--no-fund","--no-package-lock","--ignore-scripts","--include=optional","--registry=https://registry.npmjs.org",`${E[e].package}@${E[e].version}`],n,r,10*6e4),e==="mimo"&&(i="下载 MiMoCode 原生程序",a.set(e,{state:"installing",message:"正在从小米官方下载 MiMoCode 程序…"}),await P(n,r.controller.signal,(w,T)=>I(w,T,n,r,6e4))),i="验证 CLI",a.set(e,{state:"installing",message:"正在验证 CLI 能否启动…"});const v=G(e,n);if(!v)throw new Error("missing-entry");const S=M(e==="codex"?h({env:{...process.env,CODEX_PATH:v}}):v);await I(S.command,[...S.args,"--version"],n,r,6e4);const A=JSON.parse(u.readFileSync(o.join(n,"node_modules",E[e].package,"package.json"),"utf8")).version,k=o.join(m,`${f}.json`);u.writeFileSync(k,JSON.stringify({release:f})),u.renameSync(k,o.join(m,"current.json")),p=!0,b(),e==="workbuddy"&&O(),a.set(e,{state:"installed",message:"安装完成,正在同步设备状态。",version:String(A).slice(0,120)}),U().catch(()=>{})}catch(t){a.set(e,{state:"error",message:t instanceof Error&&(t.message==="npm-ENOSPC"||t.code==="ENOSPC")?"Worker 磁盘空间不足,请清理空间后重试安装。":t instanceof Error&&t.message==="missing-npm"?"Worker 的 Node 环境缺少 npm,请安装含 npm 的 Node.js 后重试。":`${i}失败,请检查 Node.js 版本、网络及磁盘权限后重试。${t instanceof Error&&/^npm-(ETARGET|EAI_AGAIN|ENOTFOUND|EACCES|ENOSPC|ECONNRESET|ETIMEDOUT|EBADENGINE)$/.test(t.message)?`(${t.message})`:""}`})}finally{clearTimeout(g);try{p||u.rmSync(n,{recursive:!0,force:!0})}catch{}s()}}function I(e,r,s,m,f){return new Promise((n,p)=>{if(y||m.controller.signal.aborted)return p(new Error("stopping"));const i=C(e,r,{cwd:s,windowsHide:!0,detached:process.platform!=="win32",stdio:["ignore","ignore","pipe"],env:{...process.env,PATH:o.isAbsolute(e)?`${o.dirname(e)}${o.delimiter}${process.env.PATH||""}`:process.env.PATH}});m.child=i;let g="";i.stderr?.on("data",l=>{g=(g+String(l)).slice(-16384)});let t=!1;const d=setTimeout(()=>{t=!0,N(i)},f);i.once("error",l=>{clearTimeout(d),p(l)}),i.once("close",l=>{clearTimeout(d),m.child=void 0,l===0&&!t?n():p(new Error(`npm-${/\b(ENOSPC|EACCES|ETARGET|EAI_AGAIN|ENOTFOUND|ECONNRESET|ETIMEDOUT|EBADENGINE)\b/.exec(g)?.[1]||"failed"}`))})})}async function Z(){y=!0,c?.controller.abort(),c?.child&&N(c.child),await c?.done}function N(e){if(!(!e.pid||e.exitCode!==null||e.signalCode!==null))if(process.platform==="win32"){const r=C("taskkill",["/pid",String(e.pid),"/T","/F"],{windowsHide:!0,stdio:"ignore"});r.once("error",()=>{e.kill("SIGKILL")}),r.once("close",s=>{s!==0&&e.kill("SIGKILL")})}else try{process.kill(-e.pid,"SIGKILL")}catch{e.kill("SIGKILL")}}export{V as providerInstallOperation,Z as stopProviderInstaller};
@@ -0,0 +1 @@
1
+ import{WorkBuddyAuthManager as r}from"../acp/providers/workbuddy/auth-manager.js";import{sendHeartbeat as a}from"./heartbeat.js";const n=new r(void 0,async()=>{await a()});export{n as workBuddyAuthManager};
@@ -0,0 +1,2 @@
1
+ import{randomUUID as S}from"node:crypto";import{setTimeout as T}from"node:timers/promises";import{acaServerRequest as l,AcaServerHttpError as A}from"../core/aca-server-client.js";import{INTERACTION_TIMEOUT_MS as v}from"./types.js";function U(a,n,d,s){const o=S(),w=new AbortController,r=AbortSignal.any([s,w.signal]),f=`/api/client/jobs/${encodeURIComponent(a)}`;let c=!1,g;const b=()=>g??=(async()=>{try{c=(await l("GET","/api/interactions/capabilities",void 0,{signal:r})).interactionVersion===1}catch(t){if(!(t instanceof A)||t.status!==404)throw t}c&&await l("POST",`${f}/interactions/runtime`,{machineId:n,runtimeId:o},{signal:r})})();async function M(t,m){if(await b(),m&&!c)throw new Error("ACA Server 不支持结构化回答,请先更新 Server;本次请求未提交给旧接口。");const h=m?t.interaction:void 0,u=h?{...h,runtimeId:o}:{version:1,kind:"approval",provider:d,method:t.method??"session/request_permission",requestId:t.requestId,runtimeId:o,expiresAtMs:t.expiresAtMs??Date.now()+v,prompt:x(t.params),options:t.options},y={machineId:n,request:{...t,...m?{kind:"elicitation"}:{},...c?{interaction:u}:{}}};let e;for(;!r.aborted&&Date.now()<u.expiresAtMs;){try{const i={signal:r,timeoutMs:Math.max(1,Math.min(15e3,u.expiresAtMs-Date.now()))};if(e?e=(await l("GET",`/api/client/permissions/${encodeURIComponent(e.permission_id)}`,void 0,i)).item:e=(await l("POST",`${f}/permissions`,y,i)).item,e.status!=="pending"){const p=e.response?.outcome;return e.status==="resolved"&&p?.outcome==="selected"&&!m&&t.options.some(I=>I.optionId===p.optionId)?{outcome:p}:e.status==="resolved"&&p?.outcome==="submitted"&&m?{outcome:p}:{outcome:{outcome:"cancelled"}}}}catch(i){if(r.aborted)break;if(i instanceof A&&i.status<500){if([404,409,410].includes(i.status))break;throw i}}await T(Math.min(1e3,Math.max(1,u.expiresAtMs-Date.now())),void 0,{signal:r}).catch(()=>{})}return{outcome:{outcome:"cancelled"}}}return{initialize:b,permission:t=>M(t,!1),input:t=>M(t,!0),close:async()=>{w.abort(),c&&await l("POST",`${f}/interactions/runtime`,{machineId:n,runtimeId:o,closed:!0},{timeoutMs:3e3}).catch(()=>{})}}}function x(a){const n=a&&typeof a=="object"?a:{},d=n.request??n,s=d.params??d;return[s.reason,s.description,s.command,s.title].filter(o=>typeof o=="string"&&o.trim()).join(`
2
+ `)||"Agent 请求继续执行。"}export{U as createJobInteractions};
@@ -0,0 +1 @@
1
+ import{randomUUID as E}from"node:crypto";import{INTERACTION_TIMEOUT_MS as q,validateInteractionAnswers as x}from"./types.js";const w="item/tool/requestUserInput",O="mcpServer/elicitation/request";function I(s){return s===w||s===O}function d(s){return s&&typeof s=="object"&&!Array.isArray(s)?s:{}}function S(s,i,p,c){const r=d(p),o=Object.keys(d(r.request)).length?d(r.request):r,e=typeof o.method=="string"?o.method:i;if(!(e==="elicitation/create"||(s==="native-codex"||s==="codex-acp")&&I(e)))throw new Error(`Unsupported user input method: ${e}`);const y=String(c??o.requestId??o.id??E()),u=String(o.prompt??o.message??o.question??"");let m,h="questions";if(e!==w&&o.requestedSchema){if(o.mode&&!["form","openai/form","openaiForm"].includes(String(o.mode)))throw new Error("Unsupported elicitation mode");h="form",m=U(o.requestedSchema)}else if(e===w&&Array.isArray(o.questions))m=o.questions.map(t=>{const n=d(t),f=Array.isArray(n.options)?n.options.map(g=>{const l=d(g),b=String(l.label??l.value??"");return{value:String(l.value??l.label??""),label:b,description:typeof l.description=="string"?l.description:void 0,recommended:l.recommended===!0||/\(Recommended\)|(推荐)|\(推荐\)/i.test(b)}}):void 0;if(n.multiple===!0||n.multiSelect===!0)throw new Error("Unsupported multi-select question protocol");return{id:String(n.id??""),label:String(n.question??n.title??""),description:typeof n.header=="string"?n.header:void 0,type:"string",required:!0,secret:n.isSecret===!0,allowOther:n.isOther===!0||!f?.length,options:f?.length?f:void 0}});else throw new Error("Unsupported user input payload: missing questions or form schema");if(!m.length||m.length>100||m.some(t=>!t.id||!t.label||["__proto__","constructor","prototype"].includes(t.id))||new Set(m.map(t=>t.id)).size!==m.length)throw new Error("Unsupported user input fields: missing/duplicate IDs or too many fields");return{requestId:y,prompt:u,params:p,interaction:{version:1,kind:h,provider:s,method:e,requestId:y,runtimeId:"",expiresAtMs:Date.now()+q,prompt:u,fields:m}}}function U(s){const i=d(s);if(i.type!=="object"||!i.properties)throw new Error("Unsupported elicitation schema: expected an object");const p=new Set(["type","properties","required","title","description","$schema","additionalProperties"]);if(Object.keys(i).some(r=>!p.has(r))||i.additionalProperties!==void 0&&i.additionalProperties!==!1||i.required!==void 0&&!Array.isArray(i.required))throw new Error("Unsupported form root validation");const c=Array.isArray(i.required)?i.required:[];if(c.some(r=>typeof r!="string"||!Object.hasOwn(d(i.properties),r)))throw new Error("Unsupported required field");return Object.entries(d(i.properties)).map(([r,o])=>{if(["__proto__","constructor","prototype"].includes(r))throw new Error("Unsupported field ID");const e=d(o),a=e.type==="array"?"string[]":e.type;if(!["string","number","integer","boolean","string[]"].includes(String(a)))throw new Error(`Unsupported form field type: ${r}`);const y=new Set(["type","title","description","enum","enumNames","oneOf","anyOf","items","default","minLength","maxLength","minimum","maximum","minItems","maxItems","uniqueItems","format"]);for(const t of Object.keys(e))if(!y.has(t))throw new Error(`Unsupported form validation: ${r}.${t}`);const u=a==="string[]"?d(e.items):e;if(a==="string[]"&&(u.type!=="string"||Object.keys(u).some(t=>!["type","enum","oneOf","anyOf","enumNames"].includes(t))))throw new Error(`Unsupported array item schema: ${r}`);if(["enum","oneOf","anyOf"].filter(t=>u[t]!==void 0).length>1)throw new Error(`Unsupported combined enum: ${r}`);for(const t of["enum","oneOf","anyOf"])if(u[t]!==void 0&&!Array.isArray(u[t]))throw new Error(`Unsupported enum schema: ${r}`);let m;if(Array.isArray(u.enum)){if(!u.enum.every(t=>typeof t=="string"))throw new Error(`Unsupported non-string enum: ${r}`);m=u.enum.map((t,n)=>({value:String(t),label:String(Array.isArray(u.enumNames)?u.enumNames[n]??t:t)}))}else(Array.isArray(u.oneOf)||Array.isArray(u.anyOf))&&(m=(Array.isArray(u.oneOf)?u.oneOf:u.anyOf).map(t=>{const n=d(t);if(typeof n.const!="string"||Object.keys(n).some(f=>!["const","title","description"].includes(f)))throw new Error(`Unsupported enum option: ${r}`);return{value:n.const,label:String(n.title??n.const),...typeof n.description=="string"?{description:n.description}:{}}}));if(a==="string[]"&&!m)throw new Error(`Unsupported free-form array: ${r}`);if(m&&(!m.length||new Set(m.map(t=>t.value)).size!==m.length||!["string","string[]"].includes(String(a))))throw new Error(`Unsupported enum field: ${r}`);if(e.format&&!["email","uri","date","password"].includes(String(e.format)))throw new Error(`Unsupported form format: ${r}`);for(const t of["minLength","maxLength","minimum","maximum","minItems","maxItems"]){const n=e[t],f=["minimum","maximum"].includes(t)?["number","integer"].includes(String(a)):t.endsWith("Length")?a==="string":a==="string[]";if(n!==void 0&&(!f||typeof n!="number"||!Number.isFinite(n)||!["minimum","maximum"].includes(t)&&(!Number.isSafeInteger(n)||n<0)))throw new Error(`Unsupported form bound: ${r}.${t}`)}if(e.format!==void 0&&a!=="string"||e.items!==void 0&&a!=="string[]"||e.uniqueItems!==void 0&&(a!=="string[]"||typeof e.uniqueItems!="boolean"))throw new Error(`Unsupported form constraints: ${r}`);for(const[t,n]of[["minimum","maximum"],["minLength","maxLength"],["minItems","maxItems"]]){const f=e[t],g=e[n];if(typeof f=="number"&&typeof g=="number"&&f>g)throw new Error(`Unsupported inverted bounds: ${r}`)}const h=Object.fromEntries(["minLength","maxLength","minimum","maximum","minItems","maxItems"].filter(t=>typeof e[t]=="number").map(t=>[t,e[t]]));return{id:r,label:String(e.title??r),description:typeof e.description=="string"?e.description:void 0,type:a,required:c.includes(r),secret:e.format==="password",options:m,...h,...typeof e.format=="string"?{format:e.format}:{},...e.default!==void 0&&e.format!=="password"?{defaultValue:e.default}:{}}})}async function _(s,i,p,c,r){const o=d(p);if(s==="codex-acp"&&o.acaInteractionBridge===1){const y=d(o.request);return c?c(y):{outcome:{outcome:"cancelled"}}}const e=S(s,i,p,r),a=c?await c(e):{outcome:{outcome:"cancelled"}};return A(e,a)}function A(s,i){const p=s.interaction;if(!p)throw new Error("Missing structured interaction contract");const c=i.outcome.outcome==="submitted",r=i.outcome.outcome==="submitted"?i.outcome.answers:void 0;if(c&&Object.keys(x(p,r)).length)throw new Error("Invalid structured answers");if(p.kind==="form")return{action:c?"accept":"cancel",content:c?Object.fromEntries(Object.entries(r).map(([o,e])=>[o,e.value])):null,...p.method===O?{_meta:null}:{}};if(p.method===w)return{answers:c?Object.fromEntries(Object.entries(r).map(([o,e])=>[o,{answers:Array.isArray(e.value)?e.value:[String(e.value)]}])):{}};throw new Error(`Unsupported interaction response method: ${p.method}`)}export{O as CODEX_FORM_METHOD,w as CODEX_QUESTIONS_METHOD,_ as handleProviderInput,I as isCodexInputMethod,S as normalizeProviderInput,d as object,A as providerInputResponse};
@@ -0,0 +1 @@
1
+ const c=6e5;function u(a,s){const t=Object.create(null);if(!s||typeof s!="object"||Array.isArray(s))return{_form:"请填写回答后提交。"};const o=s,f=a.fields??[];for(const e of Object.keys(o))f.some(r=>r.id===e)||(t[e]="回答包含未知字段。");for(const e of f){const r=Object.hasOwn(o,e.id)?o[e.id]:void 0;if(r===void 0){e.required&&(t[e.id]="此项为必填。");continue}if(!r||typeof r!="object"||Array.isArray(r)||Object.keys(r).some(n=>n!=="type"&&n!=="value")){t[e.id]="回答格式不正确。";continue}const i=r.value,d=e.type==="string[]"?Array.isArray(i)&&i.every(n=>typeof n=="string"):e.type==="integer"?typeof i=="number"&&Number.isSafeInteger(i):typeof i===e.type&&(typeof i!="number"||Number.isFinite(i));if(r.type!==e.type||!d){t[e.id]="回答类型不正确。";continue}if(typeof i=="string"){if(e.required&&!i.trim()&&(t[e.id]="此项为必填。"),i.length<(e.minLength??0)&&(t[e.id]=`至少填写 ${e.minLength} 个字符。`),i.length>Math.min(e.maxLength??16e3,16e3)&&(t[e.id]="填写内容过长。"),e.format==="email"&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i)&&(t[e.id]="请输入有效的邮箱地址。"),e.format==="uri")try{new URL(i)}catch{t[e.id]="请输入完整的网址。"}e.format==="date"&&(!/^\d{4}-\d{2}-\d{2}$/.test(i)||!Number.isFinite(Date.parse(i))||new Date(i).toISOString().slice(0,10)!==i)&&(t[e.id]="请输入有效的日期。")}typeof i=="number"&&(i<(e.minimum??-1/0)||i>(e.maximum??1/0))&&(t[e.id]="数值超出允许范围。"),Array.isArray(i)&&((i.length<(e.minItems??(e.required?1:0))||i.length>(e.maxItems??100))&&(t[e.id]="选择数量不符合要求。"),new Set(i).size!==i.length&&(t[e.id]="不能重复选择同一项。")),e.options&&!e.allowOther&&(Array.isArray(i)?i:[i]).some(m=>!e.options.some(y=>y.value===m))&&(t[e.id]="请选择提供的选项。")}return t}export{c as INTERACTION_TIMEOUT_MS,u as validateInteractionAnswers};
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.87";export{o as AICA_VERSION};
1
+ const o="0.1.88";export{o as AICA_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.87",
3
+ "version": "0.1.88",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",