@yuandc/aica 0.1.95 → 0.1.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- 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};
1
+ import{schemaFields as O}from"./form-schema.js";import{randomUUID as x}from"node:crypto";import{INTERACTION_TIMEOUT_MS as E,validateInteractionAnswers as b,validateInteractionUrl as U}from"./types.js";const h="item/tool/requestUserInput",w="mcpServer/elicitation/request";function A(t){return t===h||t===w}function p(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function _(t,c,r,n){const u=p(r),e=Object.keys(p(u.request)).length?p(u.request):u,o=typeof e.method=="string"?e.method:c;if(!(o==="elicitation/create"||(t==="native-codex"||t==="codex-acp")&&A(o)))throw new Error(`Unsupported user input method: ${o}`);if(o==="elicitation/create"&&!["form","url"].includes(String(e.mode)))throw new Error("Unsupported elicitation mode: explicit form or url required");const s=String(n??e.requestId??e.id??x()),f=String(e.prompt??e.message??e.question??""),q=typeof e.sessionId=="string"?{sessionId:e.sessionId,...typeof e.toolCallId=="string"?{toolCallId:e.toolCallId}:{}}:typeof e.requestId=="string"||typeof e.requestId=="number"?{requestId:e.requestId}:void 0;if(e.mode==="url"){if(!U(e.url)||typeof e.elicitationId!="string"||!e.elicitationId||e.elicitationId.length>256)throw new Error("Unsupported elicitation URL or ID");return{requestId:s,prompt:f,params:r,interaction:{version:2,kind:"url",provider:t,method:o,requestId:s,runtimeId:"",expiresAtMs:Date.now()+E,prompt:f,scope:q,url:e.url,elicitationId:e.elicitationId}}}let l,I="questions";if(o!==h&&e.requestedSchema){if(e.mode&&!["form","openai/form","openaiForm"].includes(String(e.mode)))throw new Error("Unsupported elicitation mode");I="form",l=O(e.requestedSchema)}else if(o===h&&Array.isArray(e.questions))l=e.questions.map(a=>{const i=p(a),g=Array.isArray(i.options)?i.options.map(S=>{const m=p(S),y=String(m.label??m.value??"");return{value:String(m.value??m.label??""),label:y,description:typeof m.description=="string"?m.description:void 0,recommended:m.recommended===!0||/\(Recommended\)|(推荐)|\(推荐\)/i.test(y)}}):void 0;if(i.multiple===!0||i.multiSelect===!0)throw new Error("Unsupported multi-select question protocol");return{id:String(i.id??""),label:String(i.question??i.title??""),description:typeof i.header=="string"?i.header:void 0,type:"string",required:!0,secret:i.isSecret===!0,allowOther:i.isOther===!0||!g?.length,options:g?.length?g:void 0}});else throw new Error("Unsupported user input payload: missing questions or form schema");if(l.length>100||l.some(a=>!a.id||!a.label||["__proto__","constructor","prototype"].includes(a.id))||new Set(l.map(a=>a.id)).size!==l.length)throw new Error("Unsupported user input fields: missing/duplicate IDs or too many fields");return{requestId:s,prompt:f,params:r,interaction:{version:I==="questions"?1:2,kind:I,provider:t,method:o,requestId:s,runtimeId:"",expiresAtMs:Date.now()+E,prompt:f,fields:l,scope:q}}}async function C(t,c,r,n,u){const e=p(r);if(t==="codex-acp"&&e.acaInteractionBridge===1){const s=p(e.request);return n?n(s):{outcome:{outcome:"cancelled"}}}let o;try{o=_(t,c,r,u)}catch(s){throw Object.assign(s instanceof Error?s:new Error(String(s)),{rpcCode:-32602})}const d=n?await n(o):{outcome:{outcome:"cancelled"}};return v(o,d)}function v(t,c){const r=t.interaction;if(!r)throw new Error("Missing structured interaction contract");const n=c.outcome.outcome==="submitted",u=c.outcome.outcome==="submitted"?c.outcome.answers:void 0;if(n&&r.kind!=="url"&&Object.keys(b(r,u)).length)throw new Error("Invalid structured answers");const e=n?"accept":c.outcome.outcome==="declined"?"decline":"cancel";if(r.kind==="url")return{action:e,...r.method===w?{content:null,_meta:null}:{}};if(r.kind==="form")return{action:e,content:n?Object.fromEntries(Object.entries(u).map(([o,d])=>[o,d.value])):null,...r.method===w?{_meta:null}:{}};if(r.method===h)return{answers:n?Object.fromEntries(Object.entries(u).map(([o,d])=>[o,{answers:Array.isArray(d.value)?d.value:[String(d.value)]}])):{}};throw new Error(`Unsupported interaction response method: ${r.method}`)}export{w as CODEX_FORM_METHOD,h as CODEX_QUESTIONS_METHOD,C as handleProviderInput,A as isCodexInputMethod,_ as normalizeProviderInput,p as object,v as providerInputResponse};
@@ -1 +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};
1
+ const u=6e5;function y(s,r){const i=Object.create(null);if(!r||typeof r!="object"||Array.isArray(r))return{_form:"请填写回答后提交。"};const f=r,d=s.fields??[];for(const e of Object.keys(f))d.some(n=>n.id===e)||(i[e]="回答包含未知字段。");for(const e of d){const n=Object.hasOwn(f,e.id)?f[e.id]:void 0;if(n===void 0){e.required&&(i[e.id]="此项为必填。");continue}if(!n||typeof n!="object"||Array.isArray(n)||Object.keys(n).some(o=>o!=="type"&&o!=="value")){i[e.id]="回答格式不正确。";continue}const t=n.value,a=e.type==="string[]"?Array.isArray(t)&&t.every(o=>typeof o=="string"):e.type==="integer"?typeof t=="number"&&Number.isSafeInteger(t):typeof t===e.type&&(typeof t!="number"||Number.isFinite(t));if(n.type!==e.type||!a){i[e.id]="回答类型不正确。";continue}if(typeof t=="string"){if(e.required&&s.kind!=="form"&&!t.trim()&&(i[e.id]="此项为必填。"),[...t].length<(e.minLength??0)&&(i[e.id]=`至少填写 ${e.minLength} 个字符。`),[...t].length>Math.min(e.maxLength??16e3,16e3)&&(i[e.id]="填写内容过长。"),e.pattern)try{new RegExp(e.pattern,"u").test(t)||(i[e.id]="填写内容不符合要求的格式。")}catch{i[e.id]="此字段的格式规则无效,请取消后联系 Agent。"}if(e.format==="date-time"&&(!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/i.test(t)||!Number.isFinite(Date.parse(t))||new Date(t.slice(0,10)).toISOString().slice(0,10)!==t.slice(0,10))&&(i[e.id]="请输入包含时区的有效日期时间。"),e.format==="email"&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)&&(i[e.id]="请输入有效的邮箱地址。"),e.format==="uri")try{new URL(t)}catch{i[e.id]="请输入完整的网址。"}e.format==="date"&&(!/^\d{4}-\d{2}-\d{2}$/.test(t)||!Number.isFinite(Date.parse(t))||new Date(t).toISOString().slice(0,10)!==t)&&(i[e.id]="请输入有效的日期。")}typeof t=="number"&&(t<(e.minimum??-1/0)||t>(e.maximum??1/0))&&(i[e.id]="数值超出允许范围。"),Array.isArray(t)&&(([...t].length<(e.minItems??(e.required&&s.kind!=="form"?1:0))||t.length>(e.maxItems??100))&&(i[e.id]="选择数量不符合要求。"),new Set(t).size!==t.length&&(i[e.id]="不能重复选择同一项。")),e.options&&!e.allowOther&&(Array.isArray(t)?t:[t]).some(c=>!e.options.some(m=>m.value===c))&&(i[e.id]="请选择提供的选项。")}return i}function p(s){if(typeof s!="string"||s.length>8192||/[\u0000-\u0020\u007f\\]/u.test(s))return!1;try{const r=new URL(s);return["https:","http:"].includes(r.protocol)&&!!r.hostname&&!r.username&&!r.password}catch{return!1}}export{u as INTERACTION_TIMEOUT_MS,y as validateInteractionAnswers,p as validateInteractionUrl};
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.95";export{o as AICA_VERSION};
1
+ const o="0.1.97";export{o as AICA_VERSION};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{Command as m}from"commander";import a from"node:path";import{createStartCommand as n}from"./commands/start.js";import{createDaemonCommand as t}from"./commands/daemon.js";import{createWorkerAuthCommand as c}from"./commands/worker-auth.js";import{createWorkerCodexCommand as i}from"./commands/worker-codex.js";import{createWorkerProjectCommand as s}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as d}from"./core/aca-config.js";import{AICA_VERSION as p}from"./version.js";import{applyToolEnvironment as C}from"./core/tool-environment.js";import{checkDesktopWorker as f}from"./core/desktop-check.js";process.env.ACA_DEFAULT_SERVER_URL||=d;async function A(r=process.argv){C();const o=new m;o.name("aica").description("AICA remote Agent worker").version(p).enablePositionalOptions(),o.addCommand(n()),o.addCommand(t()),o.addCommand(c()),o.addCommand(s()),o.addCommand(i()),o.addCommand(new m("desktop-check").description("检查桌面运行环境,不连接 Server").action(f)),await o.parseAsync(r)}const k=process.argv[1]||"",e=a.basename(k).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&A().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{A as runWorkerCli};
2
+ import{Command as m}from"commander";import a from"node:path";import{createStartCommand as n}from"./commands/start.js";import{createDaemonCommand as t}from"./commands/daemon.js";import{createWorkerAuthCommand as i}from"./commands/worker-auth.js";import{createWorkerCodexCommand as c}from"./commands/worker-codex.js";import{createWorkerProjectCommand as s}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as d}from"./core/aca-config.js";import{AICA_VERSION as p}from"./version.js";import{applyToolEnvironment as C}from"./core/tool-environment.js";import{checkDesktopWorker as f}from"./core/desktop-check.js";import{handleLogCollector as A}from"./core/logging/rotating-log.js";process.env.ACA_DEFAULT_SERVER_URL||=d;async function k(r=process.argv){if(await A(r))return;C();const o=new m;o.name("aica").description("AICA remote Agent worker").version(p).enablePositionalOptions(),o.addCommand(n()),o.addCommand(t()),o.addCommand(i()),o.addCommand(s()),o.addCommand(c()),o.addCommand(new m("desktop-check").description("检查桌面运行环境,不连接 Server").action(f)),await o.parseAsync(r)}const l=process.argv[1]||"",e=a.basename(l).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&k().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{k as runWorkerCli};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.95",
3
+ "version": "0.1.97",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",