@yuandc/aica 0.1.92 → 0.1.94
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/dist/acp/agent.js +1 -1
- package/dist/acp/client/commands.js +1 -0
- package/dist/acp/providers/codex/codex-path.js +1 -1
- package/dist/acp/providers/mimo/commands.js +1 -0
- package/dist/acp/providers/mimo/errors.js +1 -0
- package/dist/acp/providers/mimo/provider.js +2 -5
- package/dist/acp/providers/mimo/usage.js +1 -0
- package/dist/acp/providers/opencode/config.js +1 -0
- package/dist/acp/providers/opencode/errors.js +1 -0
- package/dist/acp/providers/opencode/provider.js +4 -4
- package/dist/acp/providers/opencode/retry.js +1 -0
- package/dist/acp/providers/opencode/runtime.js +1 -0
- package/dist/acp/providers/opencode/usage.js +1 -0
- package/dist/acp/providers/workbuddy/auth-gate.js +1 -1
- package/dist/acp/providers/workbuddy/discovery.js +1 -1
- package/dist/acp/providers/workbuddy/launch.js +1 -1
- package/dist/commands/start.js +1 -1
- package/dist/core/codex-capabilities.js +1 -1
- package/dist/core/heartbeat.js +1 -3
- package/dist/core/machine-filesystem-worker.js +4 -4
- package/dist/core/mimo-auth/credentials.js +1 -0
- package/dist/core/mimo-auth/crypto.js +1 -0
- package/dist/core/mimo-auth/gate.js +1 -0
- package/dist/core/mimo-auth/manager.js +1 -0
- package/dist/core/mimo-auth-worker.js +1 -0
- package/dist/core/mimo-models/catalog.js +1 -0
- package/dist/core/mimo-models/service.js +1 -0
- package/dist/core/opencode/auth.js +1 -0
- package/dist/core/opencode/catalog.js +1 -0
- package/dist/core/opencode/gate.js +1 -0
- package/dist/core/opencode/local-server.js +1 -0
- package/dist/core/opencode/models.js +1 -0
- package/dist/core/opencode/worker.js +1 -0
- package/dist/core/provider-install-mimo.js +1 -1
- package/dist/core/provider-install-paths.js +1 -1
- package/dist/core/provider-installer.js +1 -1
- package/dist/core/provider-updates/capabilities.js +1 -0
- package/dist/core/provider-updates/checker.js +1 -0
- package/dist/core/provider-updates/gate.js +1 -0
- package/dist/core/provider-updates/releases.js +1 -0
- package/dist/core/provider-updates/service.js +1 -0
- package/dist/core/provider-updates/verify.js +1 -0
- package/dist/core/provider-updates/versions.js +1 -0
- package/dist/core/workbuddy-credits/checkin.js +1 -0
- package/dist/core/workbuddy-credits/query.js +1 -1
- package/dist/core/workbuddy-credits/scheduler.js +1 -1
- package/dist/core/workbuddy-credits/worker.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/acp/agent.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import i from"node:fs";import{acquireProviderUse as c,providerForRuntime as n}from"../core/provider-updates/gate.js";import{createAgentProvider as a}from"./providers/registry.js";async function w(e){if(!i.existsSync(e.cwd)||!i.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(e.requireSessionResume&&!e.acpSessionId)throw new Error("导入的历史 Session 缺少 Provider Session ID,禁止创建新的会话。");const o=a({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}),s=await c(n(o.id),e.signal);try{const r=await o.createSession({cwd:e.cwd,providerSessionId:e.acpSessionId??null,timeoutMs:e.timeoutMs});try{const t=await r.sendPrompt({...e,providerSessionId:e.acpSessionId??null});return{...t,acpSessionId:t.providerSessionId}}finally{await r.close().catch(()=>{})}}finally{s()}}async function S(e){const o=a({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}),s=await c(n(o.id),e.signal);try{const r=await o.createSession({cwd:e.cwd,providerSessionId:e.acpSessionId,timeoutMs:e.timeoutMs});if(!r.compactContext)throw await r.close().catch(()=>{}),new Error(`Provider does not support context compaction: ${e.agentType||"codex"}`);try{const t=await r.compactContext(e);return{...t,acpSessionId:t.providerSessionId}}finally{await r.close().catch(()=>{})}}finally{s()}}async function f(e){if(!i.existsSync(e.cwd)||!i.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(!e.sourceProviderSessionId.trim())throw new Error("Source ACP session ID is required for fork");const o=a({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"});if(!o.forkSession)throw new Error(`Provider does not support native session fork: ${e.agentType||"codex"}`);const s=await c(n(o.id),e.signal);try{return{acpSessionId:(await o.forkSession(e)).providerSessionId}}finally{s()}}export{S as compactAgentContext,f as forkAgentSession,w as sendAgentPrompt};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function o(r){if(!Array.isArray(r))return null;const i=new Set;return r.slice(0,500).flatMap(n=>{if(!n||typeof n!="object")return[];const t=n,e=String(t.name||"").replace(/^\/+/,"");if(!/^[\p{L}\p{N}_][\p{L}\p{N}_.:/-]{0,127}$/u.test(e)||i.has(e.toLowerCase()))return[];i.add(e.toLowerCase());const s=t.input?.hint;return[{name:e,description:typeof t.description=="string"?t.description.slice(0,500):"",...typeof s=="string"?{input:{hint:s.slice(0,200)}}:{}}]})}export{o as parseAcpCommands};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{installedProviderEntry as T}from"../../../core/provider-install-paths.js";import d from"node:fs";import{createRequire as F}from"node:module";import{isSea as g}from"node:sea";import
|
|
1
|
+
import{installedProviderEntry as T}from"../../../core/provider-install-paths.js";import d from"node:fs";import{createRequire as F}from"node:module";import{isSea as g}from"node:sea";import k from"node:os";import L from"node:path";const O=F(g()?process.execPath:import.meta.url);function h(n={}){const e=n.env??process.env,r=n.platform??process.platform,c=n.arch??process.arch,o=n.homeDir??k.homedir(),i=n.execPath??process.execPath,t=r==="win32"?L.win32:L.posix,u=l(e.CODEX_PATH);if(u){const s=C(u,e,r,t);return s?B(s,r,c,t)??s:u}const f=n.bundledCodexLauncher===void 0?S():l(n.bundledCodexLauncher??void 0),a=x([n.skipInstalled?null:T("codex"),f,C("codex",e,r,t),...M(e,r,o,i,t)]);let y=null;for(const s of a){if(!s||!w(s,r))continue;const m=$(s,r,c,t);if(m)return m;if(!D(s))return s;y??=s}for(const s of E(e,r,o,i,t)){const m=P(s,r,c,t);if(m)return m}return y??"codex"}function S(){try{return O.resolve("@openai/codex/bin/codex.js")}catch{return null}}function M(n,e,r,c,o){const i=e==="win32"?"codex.exe":"codex",t=e==="win32"?"codex.cmd":"codex",u=l(n.npm_config_prefix),f=l(n.APPDATA),a=l(n.LOCALAPPDATA);return x([o.join(r,".codex","packages","standalone","current","bin",i),n.NVM_BIN?o.join(n.NVM_BIN,i):null,n.VOLTA_HOME?o.join(n.VOLTA_HOME,"bin",i):null,u?o.join(u,e==="win32"?"":"bin",t):null,o.join(o.dirname(c),t),e==="win32"&&f?o.join(f,"npm",t):null,e==="win32"&&a?o.join(a,"npm",t):null,e!=="win32"?o.join(r,".local","bin",i):null,e==="darwin"?"/opt/homebrew/bin/codex":null,e!=="win32"?"/usr/local/bin/codex":null,e!=="win32"?"/usr/bin/codex":null])}function E(n,e,r,c,o){const i=x([l(n.npm_config_prefix),l(n.NVM_BIN)?o.dirname(l(n.NVM_BIN)):null,o.dirname(o.dirname(c)),e==="win32"?l(n.APPDATA):null,e==="win32"?l(n.LOCALAPPDATA):null,e!=="win32"?o.join(r,".local"):null,e!=="win32"?"/usr/local":null,e!=="win32"?"/usr":null]);return x(i.flatMap(t=>_(t,e,o)))}function $(n,e,r,c){const o=I(n,e,c);for(const i of o){const t=P(i,e,r,c);if(t)return t}return null}function B(n,e,r,c){for(const o of R(n,c)){const i=P(o,e,r,c);if(i)return i}return null}function I(n,e,r){const c=[];let o=j(n)??n;o=r.dirname(o);for(let i=0;i<8;i+=1){r.basename(o)==="codex"&&r.basename(r.dirname(o))==="@openai"&&c.push(o),c.push(..._(o,e,r));const t=r.dirname(o);if(t===o)break;o=t}return x(c)}function R(n,e){const r=[];let c=e.dirname(j(n)??n);for(let o=0;o<8;o+=1){e.basename(c)==="codex"&&e.basename(e.dirname(c))==="@openai"&&r.push(c);const i=e.dirname(c);if(i===c)break;c=i}return x(r)}function _(n,e,r){return e==="win32"?[r.join(n,"node_modules","@openai","codex")]:[r.join(n,"lib","node_modules","@openai","codex"),r.join(n,"node_modules","@openai","codex")]}function P(n,e,r,c){if(!N(n))return null;const o=`codex-${e}-${r==="x64"?"x64":r}`,i=c.join(n,"node_modules","@openai",o),t=c.dirname(n),u=c.basename(n)==="codex"&&c.basename(t)==="@openai"?c.join(t,o):null;return b(i,e,c)??(u?b(u,e,c):null)??b(n,e,c)}function b(n,e,r,c=0){if(c>8||!N(n))return null;let o;try{o=d.readdirSync(n,{withFileTypes:!0})}catch{return null}const i=e==="win32"?"codex.exe":"codex";for(const t of o){const u=r.join(n,t.name);if(t.isFile()&&t.name.toLowerCase()===i&&w(u,e)&&!D(u))return u}for(const t of o){if(!t.isDirectory())continue;const u=b(r.join(n,t.name),e,r,c+1);if(u)return u}return null}function C(n,e,r,c){if(c.isAbsolute(n)||n.includes("/")||n.includes("\\"))return w(n,r)?n:null;const o=r==="win32"?n.includes(".")?[""]:(e.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";").map(t=>t.toLowerCase()):[""],i=r==="win32"?";":":";for(const t of(e.PATH||"").split(i)){const u=l(t);if(u)for(const f of o){const a=c.join(u,`${n}${f}`);if(w(a,r))return a}}return null}function w(n,e){try{return d.accessSync(n,e==="win32"?d.constants.F_OK:d.constants.X_OK),d.statSync(n).isFile()}catch{return!1}}function N(n){try{return d.statSync(n).isDirectory()}catch{return!1}}function D(n){const e=j(n)??n;if(/\.(?:js|mjs|cjs|cmd|bat)$/i.test(e))return!0;try{const r=d.readFileSync(e,{encoding:"utf8",flag:"r"}).slice(0,256);return/^#!.*\bnode\b/m.test(r)}catch{return!1}}function j(n){try{return d.realpathSync(n)}catch{return null}}function l(n){return n?.trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2")||null}function x(n){return[...new Set(n.filter(e=>e!=null))]}export{h as resolveCodexPath};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parseAcpCommands as a}from"../../client/commands.js";export{a as mimoCommands};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFile as l}from"node:child_process";import{resolveInstalledLaunch as f}from"../../../core/provider-install-paths.js";class c extends Error{failure;constructor(e,i,o){super(i),this.name="MimoRunError",this.failure={provider:"mimocode",category:e,...o!==void 0?{code:o}:{}}}}function u(r){return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}function d(r){if(r instanceof c)return r;const e=u(r),i=u(e.rpcData??e.data),o=[e.name,e.message,e.code,i.message,i.code].filter(a=>typeof a=="string").join(" "),n=Number(i.statusCode??e.statusCode??e.rpcCode),s=Number.isFinite(n)?n:void 0,t=(a,m)=>new c(a,m,s);return[401,403].includes(n)||/invalid.?api.?key|unauthori[sz]ed|authentication|ProviderAuthError|未认证/i.test(o)?t("auth",`小米 MiMo 认证失败${[401,403].includes(n)?`(HTTP ${n})`:""}:API Key 无效、缺失或无访问权限。请到设置 → 我的设备 → 小米 MiMo Code 完成登录;使用自定义接口或环境密钥时,请检查对应认证配置。`):/ProviderModelNotFoundError|model not found|unknown model|模型不存在/i.test(o)?t("model","小米 MiMo 所选模型不存在或已下线。请刷新模型列表并重新选择;旧版 mimo/mimo-auto 不能继续使用。"):/insufficient|balance|quota|credit|余额不足|额度|配额/i.test(o)||n===402?t("quota","小米 MiMo 余额或可用额度不足,请检查小米平台的账号、套餐与用量后重试。"):n===429||/rate.?limit|too many requests/i.test(o)?t("rate_limit","小米 MiMo 请求过于频繁,请稍后重试。"):/context.{0,24}(length|window)|maximum context|上下文.*上限/i.test(o)?t("context","小米 MiMo 上下文超过模型限制,请压缩上下文或新建会话后重试。"):/cancelled|aborted|已取消/i.test(o)?t("cancelled","小米 MiMo 任务已取消。"):[408,502,503,504].includes(n)||/network|connection|econn|enet|etimedout|fetch failed|timed? ?out|socket|disconnected/i.test(o)?t("network","小米 MiMo 网络连接异常或响应超时,请检查 Worker 网络后重试;已有执行结果可能仍然有效。"):e.code==="ENOENT"?t("internal","未找到 MiMo CLI,请在设备设置中检查安装状态。"):/^(MiMo|MimoCode|当前 MiMo)/.test(String(e.message||""))&&e.rpcResponse!==!0?t("internal",String(e.message)):t("internal",`小米 MiMo 执行失败${s&&s>=400&&s<=599?`(HTTP ${s})`:""},请检查已有结果、Worker 状态及模型配置后重试。`)}function g(r){const e=u(r);if(e.error)throw d(e.error);if(e.stopReason!=="end_turn")throw e.stopReason==="cancelled"?new c("cancelled","小米 MiMo 任务已取消。"):e.stopReason==="refusal"?new c("refusal","小米 MiMo 模型拒绝了本次请求,请调整请求内容后重试。"):new c("incomplete",["max_tokens","max_turn_requests"].includes(String(e.stopReason))?"小米 MiMo 已达到本轮输出或请求次数上限,任务尚未完成;请检查已有结果后继续。":"小米 MiMo 未返回有效的完成状态,请检查已有结果后重试。")}function M(r,e){const i=u(r).messages;if(!Array.isArray(i))return null;let o=!1,n=null;for(const s of i){const t=u(u(s).info),a=u(t.time).created;t.role==="user"?(o=typeof a=="number"&&a>=e,n=null):o&&t.role==="assistant"&&t.error&&(n=d(t.error))}return n}async function x(r){const{command:e,args:i}=f("mimo");try{const o=await new Promise((n,s)=>{l(e,[...i,"export",r.sessionId],{cwd:r.cwd,windowsHide:!0,encoding:"utf8",timeout:15e3,maxBuffer:16777216,signal:r.signal},(t,a)=>t?s(t):n(a))});return M(JSON.parse(o),r.startedAt)}catch{return null}}export{c as MimoRunError,g as assertMimoPromptCompleted,x as diagnoseMimoEmptyResponse,d as mimoError,M as mimoExportFailure};
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import{resolveInstalledLaunch as
|
|
2
|
-
`),this.providerSessionId=null}}this.emitStatus("acp","MimoCode 会话创建中","session/new");const
|
|
3
|
-
`)});const c=O(t.mode);c&&await e.setSessionMode({sessionId:s,modeId:c},6e4).catch(async()=>{await e.setSessionConfigOption({sessionId:s,configId:n,value:c},6e4).catch(a=>{this.appendStderr(`MimoCode mode config failed: ${m(a)}
|
|
4
|
-
`)})});for(const[a,d]of Object.entries(t.configOptionValues??{}))["variant","reasoning_effort","effort","model","mode"].includes(a)||await e.setSessionConfigOption({sessionId:s,configId:a,value:d},6e4).catch(C=>{this.appendStderr(`MimoCode config ${a} failed: ${m(C)}
|
|
5
|
-
`)})}handleSessionUpdate(e){this.updates.push({method:"session/update",params:e}),this.latestContextUsage=M(e,this.contextWindow)??this.latestContextUsage;const s=x("mimo",e);s&&(s.type==="agent_message_chunk"&&(this.content+=s.text??""),this.updateCallback?.(s));const t=_("mimo",e);t&&this.emitStatus(t.phase,t.label,t.detail,t.updateType)}async handleClientRequest(e,s,t){if(!this.canExecuteTools&&(e==="fs/read_text_file"||e==="fs/write_text_file"))throw new Error(`Chat Room role policy disabled tool execution: ${e}`);switch(e){case"fs/read_text_file":return this.readTextFile(s);case"fs/write_text_file":return this.writeTextFile(s);case"session/request_permission":return this.requestPermission(s,t);case"elicitation/create":case"session/request_user_input":return this.requestUserInput(e,s,t);default:throw new Error(`Unsupported ACP client request: ${e}`)}}readTextFile(e){const s=y(this.cwd,l(e,"path")||l(e,"filePath"));return{content:u.readFileSync(s,"utf8")}}writeTextFile(e){const s=y(this.cwd,l(e,"path")||l(e,"filePath")),t=l(e,"content")??l(e,"text")??"";return u.mkdirSync(p.dirname(s),{recursive:!0}),u.writeFileSync(s,t,"utf8"),{}}async requestPermission(e,s){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},n=(Array.isArray(t.options)?t.options:[]).map((r,c)=>{const a=r&&typeof r=="object"&&!Array.isArray(r)?r:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??a.outcome??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.permissionCallback({requestId:String(t.requestId??s??t.id??`mimo-permission-${Date.now()}`),params:e,expiresAtMs:typeof t.expiresAtMs=="number"?t.expiresAtMs:void 0,options:n})}async requestUserInput(e,s,t){return this.emitStatus("requestPermission","等待回答",void 0,e),I("mimo",e,s,this.userInputCallback,t)}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("MimoCode prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}emitStatus(e,s,t,o){const n={phase:e,label:s,...t?{detail:t}:{},...o?{updateType:o}:{},atMs:Date.now()},r=this.statusTimeline[this.statusTimeline.length-1];r&&r.phase===n.phase&&r.label===n.label&&r.detail===n.detail&&r.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}requireClient(){if(!this.lease)throw new Error("MimoCode ACP client is not started");return this.lease.client}appendStderr(e){const s=this.lease?.client;s&&(s.rpc.stderr+=e)}releaseLease(){this.lease?.release(),this.lease=null}}function f(i){if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function h(i){return i&&typeof i=="object"&&!Array.isArray(i)?i:null}function P(i){return typeof i=="number"&&Number.isFinite(i)&&i>0?i:0}function S(i,e){const s=i?.configOptions;if(!Array.isArray(s))return null;for(const t of s){if(!t||typeof t!="object"||Array.isArray(t))continue;const o=t;if(o.category===e&&typeof o.id=="string"&&o.id.trim())return o.id.trim()}return null}function E(i,e,s){const t=U(e?.variant,e?.reasoning_effort,e?.effort);if(!t||i.endsWith(`/${t}`))return i;const o=`${i}/${t}`;return k(s,o)?o:i}function k(i,e){const s=i?.configOptions;if(!Array.isArray(s))return!1;for(const t of s){if(!t||typeof t!="object"||Array.isArray(t))continue;const o=t;if(!(o.category!=="model"||!Array.isArray(o.options))&&o.options.some(n=>q(n)===e))return!0}return!1}function q(i){if(typeof i=="string"&&i.trim())return i.trim();if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i;for(const s of["value","id","modelId","model_id"]){const t=e[s];if(typeof t=="string"&&t.trim())return t.trim()}return null}function l(i,e){if(!i||typeof i!="object"||Array.isArray(i))return null;const s=i[e];return typeof s=="string"&&s.trim()?s:null}function y(i,e){if(!e)throw new Error("ACP file request did not include a path");const s=p.resolve(i,e),t=p.resolve(i);if(s!==t&&!s.startsWith(`${t}${p.sep}`))throw new Error(`ACP file request is outside project root: ${e}`);return s}function O(i){const e=String(i||"").trim();return e?["agent","agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"build":e==="read-only"?"plan":e:null}function U(...i){for(const e of i)if(typeof e=="string"&&e.trim())return e.trim();return null}function m(i){return i instanceof Error?i.message:String(i)}function g(){return process.env.ACA_MIMO_DEFAULT_MODEL||"mimo/mimo-auto"}function $(i,e){return(e?.length?e:[{type:"text",text:i}]).map(t=>t.type==="image"?{type:"image",data:t.data,mimeType:t.mimeType}:{type:"text",text:t.text})}function j(){const i=Number.parseInt(process.env.ACA_MIMO_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(i)&&i>=3e4?i:720*60*1e3}export{G as MimoCodeProvider,T as mimoCodeCapabilities};
|
|
1
|
+
import{mimoCommands as y}from"./commands.js";import{assertMimoPromptCompleted as C,diagnoseMimoEmptyResponse as M,mimoError as b,MimoRunError as g}from"./errors.js";import{enterMimoTask as A}from"../../../core/mimo-auth/gate.js";import{resolveInstalledLaunch as R}from"../../../core/provider-install-paths.js";import{handleProviderInput as x}from"../../../interactions/provider-input.js";import m from"node:fs";import h from"node:path";import{runAbortableRequest as _}from"../../client/abortable-request.js";import{BoundedItemBuffer as P}from"../../client/bounded-buffer.js";import{mimoContextUsage as E}from"./usage.js";import{defaultAcpRuntimePool as T}from"../../client/acp-runtime-pool.js";import{providerEventFromAcpSessionUpdate as U,providerStatusFromAcpSessionUpdate as O}from"../standard-acp-events.js";const k={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!1};class oe{id="mimocode";name="MimoCode";capabilities=k;async createSession(e){return new q(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class q{cwd;providerSessionId;defaultTimeoutMs;busy=!1;commands=null;effectiveModel=null;lease=null;acpSessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;canExecuteTools=!0;abortHandler=null;statusTimeline=[];updates=new P(16);content="";latestContextUsage=null;contextWindow=0;constructor(e,t,s=W()){this.cwd=e,this.providerSessionId=t,this.defaultTimeoutMs=s}async compactContext(e){if(!this.providerSessionId)throw new Error("MiMo 当前没有可压缩的会话。");const t=await this.sendPrompt({...e,prompt:"/compact",requireSessionResume:!0});if(!t.providerSessionId)throw new Error("MiMo 未返回压缩后的会话标识。");return{providerSessionId:t.providerSessionId,contextUsage:t.contextUsage?{...t.contextUsage,state:"compacted",maintenanceAction:"compact"}:null,maintenance:{action:"compact",provider:"mimocode",protocol:"session/prompt"},durationMs:t.durationMs}}async sendPrompt(e){if(this.busy)throw new Error("MiMo 会话正在执行另一项操作。");this.busy=!0;try{return await this.runPrompt(e)}finally{this.busy=!1}}async runPrompt(e){if(!m.existsSync(e.cwd)||!m.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.canExecuteTools=e.canExecuteTools!==!1,this.content="",this.updates.clear(),this.statusTimeline.length=0,this.latestContextUsage=null,this.contextWindow=j(e.contextWindow);let s=null,o=null,n=this.providerSessionId,r;const d=A();try{this.attachAbortSignal(e.signal),this.emitStatus("initializing","MimoCode ACP 启动中","mimo acp");const a=await this.acquireRuntime(e.cwd);this.lease=a,s=a.client,o=a.started,await this.initialize(a),n=await this.establishSession(a,e.cwd,e.requireSessionResume===!0),await this.applyConfig(s,n,e),this.emitStatus("thinking","思考中");const c=s,u=n;if(!c||!u)throw new Error("MimoCode ACP session is unavailable");if(r=await _({signal:e.signal,cancelledMessage:"MimoCode prompt cancelled",startRequest:()=>c.prompt({sessionId:u,prompt:B(e.prompt,e.promptBlocks)},e.timeoutMs??this.defaultTimeoutMs),onAbort:async()=>{c.cancel(u),await this.lease?.dispose()}}),C(r),!this.content.trim()){const f=await M({cwd:e.cwd,sessionId:u,startedAt:t,signal:e.signal});if(e.signal?.aborted)throw new g("cancelled","小米 MiMo 任务已取消。");if(f)throw f;if(!/^\s*\//.test(e.prompt))throw new g("incomplete","小米 MiMo 未返回回复正文,本轮未正常完成。请检查登录状态、所选模型和 Worker 网络后重试。")}}catch(a){await this.lease?.dispose();const c=b(a);throw this.emitStatus("failed","执行失败",c.message),Object.assign(c,{statusTimeline:[...this.statusTimeline],providerDiagnostics:{mimo:{availableCommands:this.commands}}})}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease(),d()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"mimo",effectiveConfig:{model:this.effectiveModel||e.model||v(),mode:e.mode||null,configOptionValues:e.configOptionValues??null,command:o.command,processPid:o.child.pid??null,provider:"mimocode",protocol:"acp"},command:o.command,args:o.args,cwd:e.cwd,exitCode:o.child.exitCode,signal:o.child.signalCode,durationMs:Date.now()-t,stdout:s.rpc.stdout,stderr:s.rpc.stderr,content:this.content.trim(),updateCount:this.updates.count(),updates:this.updates.snapshot(),statusTimeline:[...this.statusTimeline],contextUsage:this.latestContextUsage,providerDiagnostics:{mimo:{...this.commands!==null?{availableCommands:this.commands}:{}}},promptResponse:r}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.canExecuteTools=!0,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const{command:t,args:s}=R("mimo"),o=[...s,"acp","--cwd",e];return T.acquire({providerId:"mimocode",cwd:e,providerSessionId:this.providerSessionId,command:t,args:o,onSessionUpdate:n=>this.handleSessionUpdate(n),onClientRequest:(n,r,d)=>this.handleClientRequest(n,r,d.id)})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,t,s=!1){const o=e.client;if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.acpSessionResponse=e.sessionResponse,this.commands=y(e.sessionResponse?.availableCommands),this.commands!==null&&this.handleSessionUpdate({sessionId:e.providerSessionId,update:{sessionUpdate:"available_commands_update",availableCommands:this.commands}}),e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","MimoCode 会话恢复中","session/resume");const d=await o.resumeSession({sessionId:this.providerSessionId,cwd:t},6e4);this.acpSessionResponse=l(d);const a=S(d)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.acpSessionResponse}),a}catch(d){try{this.emitStatus("resuming","MimoCode 会话加载中","session/load");const a=await o.loadSession({sessionId:this.providerSessionId,cwd:t},6e4);this.acpSessionResponse=l(a);const c=S(a)||this.providerSessionId;return this.providerSessionId=c,e.setProviderSession({providerSessionId:c,sessionResponse:this.acpSessionResponse}),c}catch{if(s)throw new Error("MiMo 历史会话恢复失败,未执行压缩。请先确认原会话可继续对话。");this.appendStderr(`MimoCode resume failed, creating new session: ${z(d)}
|
|
2
|
+
`),this.providerSessionId=null}}if(s)throw new Error("MiMo 历史会话缺少 Session ID,未执行压缩。");this.emitStatus("acp","MimoCode 会话创建中","session/new");const n=await o.newSession({cwd:t},12e4);this.acpSessionResponse=l(n);const r=S(n);if(!r)throw new Error("MimoCode ACP session/new did not return sessionId");return this.providerSessionId=r,e.setProviderSession({providerSessionId:r,sessionResponse:this.acpSessionResponse}),r}async applyConfig(e,t,s){const o=w(this.acpSessionResponse,"model")||"model",n=w(this.acpSessionResponse,"mode")||"mode",r=s.model||v(),d=r==="default"?null:D(r,s.configOptionValues,this.acpSessionResponse);if(this.effectiveModel=d||F(this.acpSessionResponse),d){const c=await e.setSessionConfigOption({sessionId:t,configId:o,value:d},6e4).catch(u=>{throw new Error("MiMo 拒绝了模型或思考档位设置,请刷新模型列表并重新选择后重试。",{cause:u})});this.acpSessionResponse={...this.acpSessionResponse,...l(c)},this.lease?.setProviderSession({providerSessionId:t,sessionResponse:this.acpSessionResponse})}const a=H(s.mode);a&&await e.setSessionMode({sessionId:t,modeId:a},6e4).catch(async()=>{await e.setSessionConfigOption({sessionId:t,configId:n,value:a},6e4).catch(c=>{throw new Error("MiMo 拒绝了运行模式设置,请重新选择后重试。",{cause:c})})});for(const[c,u]of Object.entries(s.configOptionValues??{}))["variant","reasoning_effort","effort","model","mode"].includes(c)||await e.setSessionConfigOption({sessionId:t,configId:c,value:u},6e4).catch(f=>{throw new Error("MiMo 拒绝了配置选项,请更新模型配置后重试。",{cause:f})})}handleSessionUpdate(e){const t=l(e)?.sessionId;if(this.providerSessionId&&t&&t!==this.providerSessionId)return;this.updates.push({method:"session/update",params:e});const s=l(l(e)?.update);if(s?.sessionUpdate==="available_commands_update"){const r=y(s.availableCommands);r!==null&&(this.commands=r,this.acpSessionResponse={...this.acpSessionResponse,availableCommands:r},this.providerSessionId&&this.lease?.setProviderSession({providerSessionId:this.providerSessionId,sessionResponse:this.acpSessionResponse}))}s?.sessionUpdate==="config_option_update"&&Array.isArray(s.configOptions)&&(this.acpSessionResponse={...this.acpSessionResponse,configOptions:s.configOptions},this.providerSessionId&&this.lease?.setProviderSession({providerSessionId:this.providerSessionId,sessionResponse:this.acpSessionResponse})),this.latestContextUsage=E(e,this.contextWindow)??this.latestContextUsage;const o=U("mimo",e);o&&(o.type==="agent_message_chunk"&&(this.content+=o.text??""),this.updateCallback?.(o));const n=O("mimo",e);n&&this.emitStatus(n.phase,n.label,n.detail,n.updateType)}async handleClientRequest(e,t,s){if(!this.canExecuteTools&&(e==="fs/read_text_file"||e==="fs/write_text_file"))throw new Error(`Chat Room role policy disabled tool execution: ${e}`);switch(e){case"fs/read_text_file":return this.readTextFile(t);case"fs/write_text_file":return this.writeTextFile(t);case"session/request_permission":return this.requestPermission(t,s);case"elicitation/create":case"session/request_user_input":return this.requestUserInput(e,t,s);default:throw new Error(`Unsupported ACP client request: ${e}`)}}readTextFile(e){const t=I(this.cwd,p(e,"path")||p(e,"filePath"));return{content:m.readFileSync(t,"utf8")}}writeTextFile(e){const t=I(this.cwd,p(e,"path")||p(e,"filePath")),s=p(e,"content")??p(e,"text")??"";return m.mkdirSync(h.dirname(t),{recursive:!0}),m.writeFileSync(t,s,"utf8"),{}}async requestPermission(e,t){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},n=(Array.isArray(s.options)?s.options:[]).map((r,d)=>{const a=r&&typeof r=="object"&&!Array.isArray(r)?r:{};return{optionId:String(a.optionId??a.id??d),kind:String(a.kind??a.outcome??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.permissionCallback({requestId:String(s.requestId??t??s.id??`mimo-permission-${Date.now()}`),params:e,expiresAtMs:typeof s.expiresAtMs=="number"?s.expiresAtMs:void 0,options:n})}async requestUserInput(e,t,s){return this.emitStatus("requestPermission","等待回答",void 0,e),x("mimo",e,t,this.userInputCallback,s)}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("MimoCode prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}emitStatus(e,t,s,o){const n={phase:e,label:t,...s?{detail:s}:{},...o?{updateType:o}:{},atMs:Date.now()},r=this.statusTimeline[this.statusTimeline.length-1];r&&r.phase===n.phase&&r.label===n.label&&r.detail===n.detail&&r.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}requireClient(){if(!this.lease)throw new Error("MimoCode ACP client is not started");return this.lease.client}appendStderr(e){const t=this.lease?.client;t&&(t.rpc.stderr+=e)}releaseLease(){this.lease?.release(),this.lease=null}}function S(i){if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function l(i){return i&&typeof i=="object"&&!Array.isArray(i)?i:null}function j(i){return typeof i=="number"&&Number.isFinite(i)&&i>0?i:0}function w(i,e){const t=i?.configOptions;if(!Array.isArray(t))return null;for(const s of t){if(!s||typeof s!="object"||Array.isArray(s))continue;const o=s;if(o.category===e&&typeof o.id=="string"&&o.id.trim())return o.id.trim()}return null}function D(i,e,t){const s=L(e?.variant,e?.reasoning_effort,e?.effort);if(!s||i.endsWith(`/${s}`))return i;const o=`${i}/${s}`;if(V(t,o))return o;throw new Error("当前 MiMo 模型不支持所选思考档位,请重新选择。")}function F(i){const e=i?.configOptions;if(Array.isArray(e))for(const s of e){const o=l(s);if(o?.category==="model"&&typeof o.currentValue=="string")return o.currentValue}const t=l(i?.models)?.currentModelId;return typeof t=="string"?t:null}function V(i,e){const t=i?.configOptions;if(!Array.isArray(t))return!1;for(const s of t){if(!s||typeof s!="object"||Array.isArray(s))continue;const o=s;if(!(o.category!=="model"||!Array.isArray(o.options))&&o.options.some(n=>$(n)===e))return!0}return!1}function $(i){if(typeof i=="string"&&i.trim())return i.trim();if(!i||typeof i!="object"||Array.isArray(i))return null;const e=i;for(const t of["value","id","modelId","model_id"]){const s=e[t];if(typeof s=="string"&&s.trim())return s.trim()}return null}function p(i,e){if(!i||typeof i!="object"||Array.isArray(i))return null;const t=i[e];return typeof t=="string"&&t.trim()?t:null}function I(i,e){if(!e)throw new Error("ACP file request did not include a path");const t=h.resolve(i,e),s=h.resolve(i);if(t!==s&&!t.startsWith(`${s}${h.sep}`))throw new Error(`ACP file request is outside project root: ${e}`);return t}function H(i){const e=String(i||"").trim();return e?["agent","agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"build":e==="read-only"?"plan":e:null}function L(...i){for(const e of i)if(typeof e=="string"&&e.trim())return e.trim();return null}function z(i){return i instanceof Error?i.message:String(i)}function v(){return process.env.ACA_MIMO_DEFAULT_MODEL||"default"}function B(i,e){return(e?.length?e:[{type:"text",text:i}]).map(s=>s.type==="image"?{type:"image",data:s.data,mimeType:s.mimeType}:{type:"text",text:s.text})}function W(){const i=Number.parseInt(process.env.ACA_MIMO_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(i)&&i>=3e4?i:720*60*1e3}export{oe as MimoCodeProvider,k as mimoCodeCapabilities};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{acpSessionUpdateFromParams as m}from"../../client/acp-events.js";function p(a,r=0){const u=m(a);if(u?.update.sessionUpdate!=="usage_update")return null;const{used:e,size:n,cost:o}=u.update,s=typeof n=="number"&&Number.isFinite(n)&&n>0?n:r;if(typeof e!="number"||!Number.isFinite(e)||e<0||s<=0)return null;const t=o&&typeof o=="object"?o:{},i=typeof t.amount=="number"&&Number.isFinite(t.amount)&&t.amount>=0&&t.currency==="USD"?{amount:t.amount,currency:"USD",source:"mimo-acp"}:void 0;return{usedTokens:e,inputTokens:e,contextWindow:s,ratio:Math.min(1,e/s),observedAtMs:Date.now(),state:"active",...i?{estimatedCost:i}:{}}}export{p as mimoContextUsage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{record as n}from"../../../core/opencode/catalog.js";function _(i){const s=i?.configOptions,c=(Array.isArray(s)?s.map(n).find(a=>a.id==="model"||a.category==="model"):void 0)?.currentValue??n(i?.models).currentModelId;return typeof c=="string"&&c.trim()?c.trim():null}function h(i){return n(i).rpcCode===-32601}async function v(i,s,u,c,a,g){let o=u;const p=async(t,e)=>{const r=n(await i.setSessionConfigOption({sessionId:s,configId:t,value:e},6e4));Array.isArray(r.configOptions)&&(o={...o,configOptions:r.configOptions})},y=async t=>{try{await p("model",t)}catch(e){if(!h(e))throw e;await i.rpc.request("session/set_model",{sessionId:s,modelId:t},6e4),o={...o,models:{...n(o?.models),currentModelId:t}}}};a&&await y(a);const d=c.configOptionValues??{},m=String(d.effort??d.variant??d.reasoning_effort??"").trim();if(m){const t=Array.isArray(o?.configOptions)?o.configOptions.map(n):[],e=t.find(r=>r.category==="thought_level"||["effort","variant","reasoning_effort"].includes(String(r.id)));if(e)await p(String(e.id),m);else{const l=`${a||_(o)}/${m}`,O=t.find(f=>f.id==="model")?.options,w=n(o?.models).availableModels;if(![...Array.isArray(O)?O:[],...Array.isArray(w)?w:[]].some(f=>f===l||n(f).value===l||n(f).modelId===l))throw new Error("OpenCode 当前模型不支持所选思考档位,请刷新模型列表后重新选择。");await y(l)}}g&&await i.setSessionMode({sessionId:s,modeId:g},6e4);const A=Array.isArray(o?.configOptions)?o.configOptions.map(n):[];for(const[t,e]of Object.entries(d))["model","mode","effort","variant","reasoning_effort"].includes(t)||A.some(r=>r.id===t)&&await p(t,e);return o}export{v as configureOpenCode,_ as currentOpenCodeModel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFile as w}from"node:child_process";import{resolveInstalledLaunch as g}from"../../../core/provider-install-paths.js";import{record as o}from"../../../core/opencode/catalog.js";class f extends Error{failure;constructor(e,i,a){super(i),this.name="OpenCodeRunError",this.failure={provider:"opencode",category:e,...a===void 0?{}:{code:a}}}}function C(s){if(s instanceof f)return s;const e=o(s),i=o(e.rpcData??e.data),a=o(i.error),m=o(a.data),n=[e.name,e.message,i.name,i.message,a.name,a.message,m.message].filter(u=>typeof u=="string").join(" "),d=Number(i.statusCode??m.statusCode??e.statusCode??e.rpcCode),p=Number.isFinite(d)?d:void 0,t=(u,r)=>new f(u,r,p),c=()=>t("quota","OpenCode 模型服务商额度不足或用量已达上限,请检查对应服务商的账户与用量。");return d===402||/FreeUsageLimitError|GoUsageLimitError|(?:free\s+)?usage\s+(?:limit\s+(?:reached|exceeded)|exceeded)/i.test(n)?c():[401,403,-32e3].includes(d)||/invalid.?api.?key|unauthori[sz]ed|ProviderAuth|authentication/i.test(n)?t("auth","OpenCode 服务商认证失败,请到设置 → 我的设备 → OpenCode 检查认证;环境变量或项目配置中的密钥也可能覆盖本机凭据。"):/model.*not.*found|unknown model|ProviderModelNotFound/i.test(n)?t("model","OpenCode 所选模型不存在或不可用,请刷新模型列表后重新选择。"):/insufficient|quota|balance|credit/i.test(n)?c():d===429||/rate.?limit|too many requests/i.test(n)?t("rate_limit","OpenCode 模型服务商请求过于频繁,请稍后重试。"):/context.{0,30}(length|window)|maximum context/i.test(n)?t("context","OpenCode 上下文超过模型限制,请整理上下文或新建会话后重试。"):/cancelled|aborted|已取消/i.test(n)?t("cancelled","OpenCode 任务已取消。"):[408,502,503,504].includes(d)||/network|econn|enet|fetch failed|timeout|timed out|disconnected/i.test(n)?t("network","OpenCode 网络连接异常或响应超时,请检查 Worker 网络及已有执行结果后重试。"):/^OpenCode 当前模型不支持所选思考档位/.test(n.replace(/^Error /,""))?t("model","OpenCode 当前模型不支持所选思考档位,请刷新模型列表后重新选择。"):t("internal","OpenCode 执行失败,请检查 CLI 安装、模型配置及已有执行结果后重试。")}function E(s){const e=o(s);if(e.error)throw C(e.error);if(e.stopReason!=="end_turn")throw e.stopReason==="cancelled"?new f("cancelled","OpenCode 任务已取消。"):e.stopReason==="refusal"?new f("refusal","OpenCode 模型拒绝了本次请求,请调整请求内容。"):new f("incomplete","OpenCode 未完成本轮请求,可能达到输出或调用次数上限,请检查已有结果后继续。")}async function k(s,e,i,a){try{const{command:m,args:n}=g("opencode"),d=await new Promise((u,r)=>w(m,[...n,"export",e],{cwd:s,windowsHide:!0,encoding:"utf8",timeout:15e3,maxBuffer:16*1024*1024,signal:a},(l,O)=>l?r(l):u(O))),p=o(JSON.parse(d)).messages;if(!Array.isArray(p))return null;let t=!1,c=null;for(const u of p){const r=o(o(u).info),l=o(r.time).created;r.role==="user"?(t=typeof l=="number"&&l>=i,c=null):t&&r.role==="assistant"&&r.error&&(c=C(r.error))}return c}catch{return null}}export{f as OpenCodeRunError,E as assertOpenCodeCompleted,k as diagnoseOpenCodeEmpty,C as openCodeError};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{resolveInstalledLaunch as
|
|
2
|
-
`),await this.lease?.dispose().catch(()=>{}),this.lease=null,this.providerSessionId=null,this.sessionResponse=null,this.resumedExistingSession=!1,this.emitStatus("resuming","OpenCode 会话已失效,正在新建","session/prompt invalid params");const
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import{parseAcpCommands as w}from"../../client/commands.js";import{openCodeContextUsage as x}from"./usage.js";import{configureOpenCode as R,currentOpenCodeModel as O}from"./config.js";import{assertOpenCodeCompleted as A,diagnoseOpenCodeEmpty as _,openCodeError as P,OpenCodeRunError as h}from"./errors.js";import{enterOpenCodeTask as E}from"../../../core/opencode/gate.js";import{resolveInstalledLaunch as T}from"../../../core/provider-install-paths.js";import{handleProviderInput as q}from"../../../interactions/provider-input.js";import f from"node:fs";import g from"node:path";import{runAbortableRequest as U}from"../../client/abortable-request.js";import{BoundedItemBuffer as k}from"../../client/bounded-buffer.js";import{acquireOpenCodeRuntime as M}from"./runtime.js";import{monitorOpenCodeRetry as D}from"./retry.js";import{providerEventFromAcpSessionUpdate as S,providerStatusFromAcpSessionUpdate as F}from"../standard-acp-events.js";const N={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class le{id="opencode";name="OpenCode";capabilities=N;async createSession(e){return new $(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class ${cwd;providerSessionId;defaultTimeoutMs;busy=!1;promptActive=!1;promptProgress=!1;commands=null;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;canExecuteTools=!0;abortHandler=null;statusTimeline=[];updates=new k(16);content="";latestContextUsage=null;contextWindow=0;resumedExistingSession=!1;constructor(e,s,t=J()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t}async compactContext(e){if(!this.providerSessionId)throw new h("incomplete","OpenCode 当前没有可压缩的会话。");const s=await this.sendPrompt({...e,prompt:"/compact",requireSessionResume:!0});if(!s.providerSessionId)throw new h("incomplete","OpenCode 未返回压缩后的会话标识。");return{providerSessionId:s.providerSessionId,durationMs:s.durationMs,contextUsage:s.contextUsage?{...s.contextUsage,state:"compacted",maintenanceAction:"compact"}:null,maintenance:{action:"compact",provider:"opencode",protocol:"session/prompt"}}}async sendPrompt(e){if(this.busy)throw new Error("OpenCode 会话正在执行另一项操作。");this.busy=!0;try{return await this.runPrompt(e)}finally{this.busy=!1}}async runPrompt(e){if(!f.existsSync(e.cwd)||!f.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.canExecuteTools=e.canExecuteTools!==!1,this.content="",this.updates.clear(),this.statusTimeline.length=0,this.latestContextUsage=null,this.contextWindow=z(e.contextWindow),this.promptProgress=!1;let t=null,o=null,n=this.providerSessionId,r;const c=E();try{this.attachAbortSignal(e.signal),this.emitStatus("initializing","OpenCode ACP 启动中","opencode acp");const a=await this.acquireRuntime(e.cwd);this.lease=a,t=a.client,o=a.started,await this.initialize(a),n=await this.establishSession(a,e),await this.applyConfig(t,n,e),this.emitStatus("thinking","思考中");const d=V(e.prompt,e.promptBlocks);try{r=await this.promptWithAbort(t,{sessionId:n,prompt:d,timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal})}catch(u){if(e.requireSessionResume||!this.resumedExistingSession||!B(u)||this.promptProgress)throw u;this.appendStderr(`OpenCode resumed session rejected session/prompt with Invalid params; creating a fresh session and retrying once.
|
|
2
|
+
`),await this.lease?.dispose().catch(()=>{}),this.lease=null,this.providerSessionId=null,this.sessionResponse=null,this.resumedExistingSession=!1,this.emitStatus("resuming","OpenCode 会话已失效,正在新建","session/prompt invalid params");const m=await this.acquireRuntime(e.cwd);this.lease=m,t=m.client,o=m.started,await this.initialize(m),n=await this.establishSession(m,e),await this.applyConfig(t,n,e),this.emitStatus("thinking","思考中"),r=await this.promptWithAbort(t,{sessionId:n,prompt:d,timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal})}if(A(r),!this.content.trim()){const u=await _(e.cwd,n,s,e.signal);if(u)throw u;if(!e.prompt.trim().startsWith("/"))throw new h("incomplete","OpenCode 未返回回复正文,请检查模型认证及已有执行结果。")}}catch(a){const d=P(e.signal?.aborted?new Error("cancelled"):a);throw this.emitStatus("failed",d.message),d}finally{c(),this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"opencode",providerDiagnostics:this.commands===null?{}:{opencode:{availableCommands:this.commands}},effectiveConfig:{model:O(this.sessionResponse)||C(e.model)||null,mode:e.mode||null,configOptionValues:e.configOptionValues??null,command:o.command,processPid:o.child.pid??null,provider:"opencode",protocol:"acp"},command:o.command,args:o.args,cwd:e.cwd,exitCode:o.child.exitCode,signal:o.child.signalCode,durationMs:Date.now()-s,stdout:t.rpc.stdout,stderr:t.rpc.stderr,content:this.content.trim(),updateCount:this.updates.count(),updates:this.updates.snapshot(),statusTimeline:[...this.statusTimeline],contextUsage:this.latestContextUsage,promptResponse:r}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.canExecuteTools=!0,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const{command:s,args:t}=T("opencode");return M({providerId:"opencode",cwd:e,providerSessionId:this.providerSessionId,command:s,args:[...t,"acp","--cwd",e],onSessionUpdate:o=>this.handleSessionUpdate(o),onClientRequest:(o,n,r)=>this.handleClientRequest(o,n,r.id)})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,s){const t=e.client,o=L(s);if(this.resumedExistingSession=!1,e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,this.commands=w(this.sessionResponse?.acaOpenCodeCommands),this.commands!==null&&this.handleSessionUpdate({sessionId:e.providerSessionId,update:{sessionUpdate:"available_commands_update",availableCommands:this.commands}}),this.resumedExistingSession=!0,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","OpenCode 会话恢复中","session/load");const c=await t.loadSession({sessionId:this.providerSessionId,cwd:s.cwd},6e4);this.sessionResponse=l(c);const a=v(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),this.resumedExistingSession=!0,a}catch{if(s.requireSessionResume)throw new h("incomplete","OpenCode 原会话恢复失败,已取消压缩,请检查会话状态。");this.providerSessionId=null}if(s.requireSessionResume)throw new h("incomplete","OpenCode 原会话不可用,已取消压缩。");this.emitStatus("acp","OpenCode 会话创建中","session/new");const n=await t.newSession({cwd:s.cwd,config:o},12e4);this.sessionResponse=l(n);const r=v(n);if(!r)throw new Error("OpenCode ACP session/new did not return sessionId");return this.providerSessionId=r,e.setProviderSession({providerSessionId:r,sessionResponse:this.sessionResponse}),r}async applyConfig(e,s,t){this.sessionResponse=await R(e,s,this.sessionResponse,t,C(t.model),y(t.mode)),this.sessionResponse={...this.sessionResponse,acaOpenCodeCommands:this.commands},this.lease?.setSessionResponse(this.sessionResponse)}handleSessionUpdate(e){const s=l(e);if(this.providerSessionId&&s?.sessionId&&s.sessionId!==this.providerSessionId)return;const t=l(s?.update),o=t?.sessionUpdate==="available_commands_update"||t?.sessionUpdate==="config_options_update";if(!this.promptActive&&!o)return;t?.sessionUpdate==="available_commands_update"&&(this.commands=w(t.availableCommands),this.sessionResponse={...this.sessionResponse,acaOpenCodeCommands:this.commands},this.lease?.setSessionResponse(this.sessionResponse)),t?.sessionUpdate==="config_options_update"&&Array.isArray(t.configOptions)&&(this.sessionResponse={...this.sessionResponse,configOptions:t.configOptions}),this.promptActive&&!o&&t?.sessionUpdate!=="usage_update"&&(this.promptProgress=!0),this.updates.push({method:"session/update",params:e}),this.latestContextUsage=x(e,this.contextWindow)??this.latestContextUsage;const n=S("opencode",e);n&&(n.type==="agent_message_chunk"&&(this.content+=n.text??""),this.updateCallback?.(n));const r=F("opencode",e);r&&this.emitStatus(r.phase,r.label,r.detail,r.updateType)}async handleClientRequest(e,s,t){if(!this.canExecuteTools&&(e==="fs/read_text_file"||e==="fs/write_text_file"))throw new Error(`Chat Room role policy disabled tool execution: ${e}`);switch(e){case"fs/read_text_file":return this.readTextFile(s);case"fs/write_text_file":return this.writeTextFile(s);case"session/request_permission":return this.requestPermission(s,t);case"elicitation/create":case"session/request_user_input":return this.requestUserInput(e,s,t);default:throw new Error(`Unsupported OpenCode ACP client request: ${e}`)}}readTextFile(e){const s=I(this.cwd,p(e,"path")||p(e,"filePath"));return{content:f.readFileSync(s,"utf8")}}writeTextFile(e){const s=I(this.cwd,p(e,"path")||p(e,"filePath")),t=p(e,"content")??p(e,"text")??"";return f.mkdirSync(g.dirname(s),{recursive:!0}),f.writeFileSync(s,t,"utf8"),{}}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("OpenCode prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,s){this.promptActive=!0,this.promptProgress=!1;const t=D({lease:this.lease,sessionId:s.sessionId,onNotice:o=>this.emitRuntimeNotice(o.label,o.detail),onRecovered:()=>this.emitRuntimeNotice("OpenCode 已恢复,继续执行")});try{return await Promise.race([t.failure,U({signal:s.signal,cancelledMessage:"OpenCode prompt cancelled",startRequest:()=>e.prompt({sessionId:s.sessionId,prompt:s.prompt},s.timeoutMs),onAbort:async()=>{e.cancel(s.sessionId),await this.lease?.dispose()}})])}catch(o){throw e.cancel(s.sessionId),await this.lease?.dispose().catch(()=>{}),o}finally{this.promptActive=!1,await t.stop()}}emitRuntimeNotice(e,s){const t=`${e}${s?`:${s}`:""}
|
|
3
|
+
|
|
4
|
+
`,o={sessionId:this.providerSessionId,update:{sessionUpdate:"agent_progress_chunk",content:{type:"text",text:t}}},n=S("opencode",o);this.updates.push({method:"session/update",params:o}),n&&this.updateCallback?.(n),e!=="OpenCode 状态监测暂不可用"&&(this.promptProgress=!0),this.emitStatus("thinking",e,s,"session.status")}async requestPermission(e,s){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const t=l(e)??{},o=l(t.request)??t,r=(Array.isArray(o.options)?o.options:[]).map((c,a)=>{const d=l(c)??{};return{optionId:String(d.optionId??d.id??a),kind:String(d.kind??d.outcome??"choice"),...typeof d.label=="string"?{label:d.label}:{}}});return this.emitStatus("requestPermission","等待授权",H(o),"session/request_permission"),this.permissionCallback({requestId:String(o.requestId??s??o.id??`opencode-permission-${Date.now()}`),params:e,expiresAtMs:typeof o.expiresAtMs=="number"?o.expiresAtMs:void 0,options:r})}async requestUserInput(e,s,t){return this.emitStatus("requestPermission","等待回答",void 0,e),q("opencode",e,s,this.userInputCallback,t)}emitStatus(e,s,t,o){const n={phase:e,label:s,...t?{detail:t}:{},...o?{updateType:o}:{},atMs:Date.now()},r=this.statusTimeline[this.statusTimeline.length-1];r&&r.phase===n.phase&&r.label===n.label&&r.detail===n.detail&&r.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}appendStderr(e){const s=this.lease?.client;s&&(s.rpc.stderr+=e)}releaseLease(){this.lease?.release(),this.lease=null}}function v(i){const s=l(i)?.sessionId;return typeof s=="string"&&s.trim()?s.trim():null}function l(i){return i&&typeof i=="object"&&!Array.isArray(i)?i:null}function z(i){return typeof i=="number"&&Number.isFinite(i)&&i>0?i:0}function L(i){const e=C(i.model),s=y(i.mode);return{...W(i.configOptionValues),...e?{model:e}:{},...s?{mode:s}:{}}}function W(i){const e={};for(const[s,t]of Object.entries(i??{}))["model","mode","reasoning_effort","effort","variant"].includes(s)||(e[s]=t);return e}function y(i){const e=String(i||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"build":e==="read-only"?"plan":e:null}function p(i,e){const t=l(i)?.[e];return typeof t=="string"&&t.trim()?t:null}function I(i,e){if(!e)throw new Error("ACP file request did not include a path");const s=g.resolve(i,e),t=g.resolve(i);if(s!==t&&!s.startsWith(`${t}${g.sep}`))throw new Error(`ACP file request is outside project root: ${e}`);return s}function H(i){const e=l(i.params)??i;for(const s of["command","cwd","reason","grantRoot","method"]){const t=e[s];if(typeof t=="string"&&t.trim())return b(t)}}function ce(i){for(const e of["prompt","message","question","title"]){const s=i[e];if(typeof s=="string"&&s.trim())return b(s)}}function b(i){const e=i.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function j(i){return i instanceof Error?i.message:String(i)}function B(i){return/\binvalid params\b/i.test(j(i))}function V(i,e){return(e?.length?e:[{type:"text",text:i}]).map(t=>t.type==="image"?{type:"image",data:t.data,mimeType:t.mimeType}:{type:"text",text:t.text})}function G(){return process.env.ACA_OPENCODE_DEFAULT_MODEL||""}function C(i){const e=String(i||G()).trim();return e==="default"||e==="opencode-default"?"":e}function J(){const i=Number.parseInt(process.env.ACA_OPENCODE_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(i)&&i>=3e4?i:720*60*1e3}export{le as OpenCodeProvider,N as openCodeCapabilities};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setTimeout as p}from"node:timers/promises";import{record as c}from"../../../core/opencode/catalog.js";import{openCodeError as y,OpenCodeRunError as m}from"./errors.js";import{readOpenCodeSessionStatus as b}from"./runtime.js";const d=5*6e4;function g(o,a,s){const e=c(o);if(e.type!=="retry")return null;const i=c(e.action).reason,t=y({message:i==="free_tier_limit"?"Free usage exceeded":e.message}),n=typeof e.next=="number"&&Number.isFinite(e.next)&&e.next>0&&e.next<=864e13?e.next:null,u=typeof e.attempt=="number"&&Number.isSafeInteger(e.attempt)&&e.attempt>0?e.attempt:null,r=[t.failure.category==="internal"?"模型服务商暂时不可用":t.message,u?`第 ${u} 次重试`:"正在重试",n?`下次重试:${new Date(n).toISOString()}(UTC)`:"服务商未提供重试时间"].join(";");return["quota","auth","model","context"].includes(t.failure.category)?{label:"OpenCode 请求无法继续",detail:r,failure:new m(t.failure.category,`${t.message} 已停止本轮重试,请检查账户或切换可用模型后手动重试。${n?` CLI 原定下次重试:${new Date(n).toISOString()}(UTC)。`:""}`)}:n!==null&&n-a>d||a-s>=d?{label:"OpenCode 重试等待过长",detail:r,failure:new m(t.failure.category==="rate_limit"?"rate_limit":"network",`${r}。重试等待超过 5 分钟限制,已停止本轮,请检查已有结果后手动重试。`)}:{label:"OpenCode 等待重试",detail:r}}function O(o){const a=new AbortController;let s;const e=new Promise((l,r)=>{s=r});let i=null,t="",n=0;const u=(async()=>{for(;!a.signal.aborted;){try{const l=await b(o.lease,o.sessionId,a.signal);if(a.signal.aborted)break;if(n=0,c(l).type==="retry"){i??=Date.now();const r=g(l,Date.now(),i),f=JSON.stringify(r);if(f!==t&&(t=f,o.onNotice(r)),r.failure){s(r.failure);break}}else c(l).type==="busy"&&((i!==null||t==="unavailable")&&o.onRecovered(),i=null,t="")}catch{if(a.signal.aborted)break;++n===3&&t!=="unavailable"&&(t="unavailable",o.onNotice({label:"OpenCode 状态监测暂不可用",detail:"仍在等待 ACP 响应,可手动停止本轮。"}))}try{await p(1e3,void 0,{signal:a.signal})}catch{break}}})();return{failure:e,async stop(){a.abort(),await u}}}export{d as OPEN_CODE_RETRY_BUDGET_MS,O as monitorOpenCodeRetry,g as openCodeRetryNotice};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{randomBytes as f}from"node:crypto";import{createServer as p}from"node:net";import{defaultAcpRuntimePool as h}from"../../client/acp-runtime-pool.js";const c=new WeakMap;async function S(e){const o=await l(),r=f(32).toString("hex"),t=await h.acquire({...e,args:[...e.args,"--hostname","127.0.0.1","--port",String(o),"--mdns=false"],env:{...e.env,OPENCODE_SERVER_USERNAME:"aca",OPENCODE_SERVER_PASSWORD:r}});return c.has(t.started.child)||c.set(t.started.child,{base:`http://127.0.0.1:${o}`,authorization:`Basic ${Buffer.from(`aca:${r}`).toString("base64")}`}),t}async function y(e,o,r){const t=c.get(e.started.child);if(!t)throw new Error("OpenCode 状态接口不可用。");const n=await fetch(`${t.base}/session/status?directory=${encodeURIComponent(e.cwd)}`,{redirect:"error",signal:AbortSignal.any([r,AbortSignal.timeout(3e3)]),headers:{authorization:t.authorization}});if(!n.ok)throw await n.body?.cancel(),new Error("OpenCode 状态读取失败。");const a=n.body?.getReader();if(!a)return;const d=[];let u=0;try{for(;;){const i=await a.read();if(i.done)break;if(u+=i.value.length,u>1024*1024)throw new Error("OpenCode 状态响应过大。");d.push(i.value)}}finally{await a.cancel().catch(()=>{})}const s=JSON.parse(Buffer.concat(d).toString("utf8"));return s&&typeof s=="object"&&!Array.isArray(s)?s[o]:void 0}async function l(){const e=p();return new Promise((o,r)=>{e.once("error",()=>r(new Error("无法分配 OpenCode 本机状态端口。"))),e.listen(0,"127.0.0.1",()=>{const t=e.address(),n=t&&typeof t=="object"?t.port:0;e.close(a=>a||!n?r(new Error("无法分配 OpenCode 本机状态端口。")):o(n))})})}export{S as acquireOpenCodeRuntime,y as readOpenCodeSessionStatus};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{record as o}from"../../../core/opencode/catalog.js";function r(s,u=0){const e=o(o(s).update),t=o(e.cost);if(e.sessionUpdate!=="usage_update")return null;const n=typeof e.size=="number"&&Number.isFinite(e.size)&&e.size>0?e.size:u;return typeof e.used!="number"||!Number.isFinite(e.used)||e.used<0||n<=0?null:{usedTokens:e.used,inputTokens:e.used,contextWindow:n,ratio:Math.min(1,e.used/n),state:"active",observedAtMs:Date.now(),...typeof t.amount=="number"&&Number.isFinite(t.amount)&&t.amount>=0&&t.currency==="USD"?{estimatedCost:{amount:t.amount,currency:"USD",source:"opencode-acp"}}:{}}}export{r as openCodeContextUsage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
let
|
|
1
|
+
let n=0,e=!1;function d(){if(e)throw new Error("腾讯账号正在登录或退出,请完成后重试任务。");const r=t("workbuddy");n++;let o=!1;return()=>{o||(o=!0,n--,r())}}function u(){if(e||n)throw new Error("腾讯 Code Buddy 正在执行任务或检测状态,请稍后重试登录操作。");const r=t("workbuddy");return e=!0,()=>{e=!1,r()}}function i(){return e}import{enterProviderUse as t}from"../../../core/provider-updates/gate.js";export{u as beginWorkBuddyAuthChange,d as enterWorkBuddyTask,i as workBuddyAuthChanging};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import l from"node:fs";import p from"node:os";import y from"node:path";import{AcpClient as w}from"../../client/acp-client.js";import{closeAcpProcess as b,startAcpProcess as h}from"../../client/acp-process.js";import{record as k,rememberWorkBuddyCapabilities as B,workBuddyHeartbeatCapabilities as d}from"./config.js";import{resolveWorkBuddyLaunch as u}from"./launch.js";import{enterWorkBuddyTask as g,workBuddyAuthChanging as v}from"./auth-gate.js";let n=null,o=null,i=0,f=0;function j(){i++,n=null}async function A(){const e=d();if(v()||e.source==="codebuddy-acp")return e;const r=u(!1);if(n?.identity===r.runtimeIdentity&&n.retryAtMs>Date.now())return e;if(o){const s=f,t=await o;return s===i?t:A()}return f=i,o=C(i).finally(()=>{o=null}),o}async function C(e){const r=u(!1),s=g();let t,a;try{t=l.mkdtempSync(y.join(p.tmpdir(),"aca-workbuddy-capabilities-")),a=h(r.command,[...r.args,"--no-session-persistence"],t,r.env);const c=new w(a.child,()=>{});await c.initialize(8e3);const m=k(await c.newSession({cwd:t},8e3));e===i&&(B(m),n=null)}catch{e===i&&(n={identity:r.runtimeIdentity,retryAtMs:Date.now()+300*1e3})}finally{try{a&&await b(a.child),t&&l.rmSync(t,{recursive:!0,force:!0})}finally{s()}}return d()}export{A as readWorkBuddyCapabilities,j as resetWorkBuddyDiscovery};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{installedProviderEntry as d,entryLaunch as m}from"../../../core/provider-install-paths.js";import o from"node:fs";import
|
|
1
|
+
import{installedProviderEntry as d,entryLaunch as m}from"../../../core/provider-install-paths.js";import o from"node:fs";import n from"node:path";import{createHash as D}from"node:crypto";import{workBuddyRegionEnv as p}from"./auth-environment.js";function E(e=!0){const r=process.env.ACA_WORKBUDDY_COMMAND||process.env.ACA_CODEBUDDY_COMMAND||"codebuddy",t=_(r),s=[...t.args,"--acp"];e?s.push("--settings",JSON.stringify({enableAllProjectMcpServers:!0})):s.push("--tools","","--strict-mcp-config","--mcp-config",'{"mcpServers":{}}');const c={CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS:"1",...p()},i=D("sha256").update(JSON.stringify({command:t.command,args:s,env:c,configDir:process.env.CODEBUDDY_CONFIG_DIR,region:process.env.CODEBUDDY_INTERNET_ENVIRONMENT,apiKey:process.env.CODEBUDDY_API_KEY,authToken:process.env.CODEBUDDY_AUTH_TOKEN})).digest("hex");return{command:t.command,args:s,env:c,runtimeIdentity:i}}function _(e,r=!1){if(!r&&e==="codebuddy"&&!process.env.ACA_WORKBUDDY_COMMAND&&!process.env.ACA_CODEBUDDY_COMMAND){const s=d("workbuddy");if(s)return m(s)}if(/\.[cm]?js$/i.test(e)||/[/\\]/.test(e)&&u(e))return{command:a(n.dirname(n.resolve(e))),args:[n.resolve(e)]};if(process.platform!=="win32")return{command:e,args:[]};const t=n.isAbsolute(e)||/[/\\]/.test(e)?[n.dirname(n.resolve(e))]:(process.env.PATH||"").split(n.delimiter);for(const s of t){const c=n.join(s,"node_modules","@tencent-ai","codebuddy-code","bin","codebuddy");if(o.existsSync(c)&&/^(codebuddy(?:-code)?|cbc)(?:\.cmd)?$/i.test(n.basename(e)))return{command:a(s),args:[c]};const i=n.join(s,/\.exe$/i.test(e)?n.basename(e):`${n.basename(e)}.exe`);if(o.existsSync(i))return{command:i,args:[]}}if(/\.cmd$/i.test(e))throw new Error("WorkBuddy 无法解析 CodeBuddy npm 启动入口,请将 ACA_WORKBUDDY_COMMAND 指向官方 bin/codebuddy 的 JS 包装文件或原生 exe。");return{command:e,args:[]}}function a(e){if(process.env.ACA_WORKBUDDY_NODE)return process.env.ACA_WORKBUDDY_NODE;const r=n.join(e,"node.exe");return process.platform==="win32"&&o.existsSync(r)?r:process.isSea||process.env.ACA_SINGLE_FILE_WORKER==="1"?"node":process.execPath}function u(e){let r;try{r=o.openSync(e,"r");const t=Buffer.alloc(128),s=o.readSync(r,t,0,t.length,0);return/^#![^\r\n]*\bnode\b/.test(t.subarray(0,s).toString("utf8"))}catch{return!1}finally{r!==void 0&&o.closeSync(r)}}function f(){const e=Number(process.env.ACA_WORKBUDDY_PROMPT_TIMEOUT_MS||process.env.ACA_ACP_PROMPT_TIMEOUT_MS);return Number.isSafeInteger(e)&&e>=3e4?e:720*60*1e3}export{_ as resolveWorkBuddyExecutable,E as resolveWorkBuddyLaunch,f as workBuddyTimeout};
|
package/dist/commands/start.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stopProviderInstaller as
|
|
1
|
+
import{openCodeAuthManager as N}from"../core/opencode/worker.js";import{mimoAuthManager as L}from"../core/mimo-auth-worker.js";import{stopProviderInstaller as U}from"../core/provider-installer.js";import{startProviderUpdates as F,stopProviderUpdates as H}from"../core/provider-updates/service.js";import{activateWorkBuddyCredits as B,stopWorkBuddyCredits as K}from"../core/workbuddy-credits/worker.js";import{stopManagedClaims as V}from"../core/management/claims.js";import{workBuddyAuthManager as G}from"../core/workbuddy-auth-worker.js";import{assertManualStartAllowed as J}from"../core/management/manual.js";import{startManagementControl as q}from"../core/management/control-server.js";import{managementActivity as u}from"../core/management/activity.js";import{acquireWorkerLease as z,assertNoWorkerInstances as Q}from"../core/worker-instances.js";import{getAcaHome as X}from"../core/paths.js";import{Command as Y}from"commander";import I from"node:fs";import D from"node:os";import c from"node:path";import t from"node:process";import{randomUUID as Z}from"node:crypto";import{Logger as ee}from"../core/logger.js";import{loadCredentials as te,saveApiKeyCredential as re}from"../core/auth.js";import{getRuntimeStatePath as oe}from"../core/paths.js";import{writeJsonFile as ae}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as ie,startHeartbeatLoop as ne}from"../core/heartbeat.js";import{startJobWorkerLoop as se}from"../core/job-worker.js";import{startFileTransferWorkerLoop as me}from"../core/file-transfer-worker.js";import{startTerminalWorker as ce}from"../core/terminal/worker.js";import{startMachineFilesystemWorkerLoop as de}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as fe}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as _}from"../acp/client/acp-runtime-pool.js";import{isProcessAlive as h,readPidFile as d,writePidFile as pe,removePidFile as W}from"../core/process.js";import{applyRuntimePathOptions as x}from"../core/runtime-options.js";import{loadAcaConfig as $,updateAcaConfig as R}from"../core/aca-config.js";import{acaServerRequest as le}from"../core/aca-server-client.js";import{restoreProjectsAfterLogin as ue}from"../core/project-recovery.js";import{syncCodexProviderRuntimeConfig as he}from"../core/codex-provider-runtime-config.js";import{ACA_WORKER_INSTANCE_ENV as O,ACA_WORKER_PID_ENV as ge,ACA_WORKER_START_TICKS_ENV as we,readProcessStartTicks as ve}from"../core/process-identity.js";import{printStartTips as Ae,spawnDaemon as Ie}from"./daemon.js";import{startDesktopControl as Se}from"../core/desktop-control.js";function lt(){return new Y("start").description("Start agent service in native mode").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica or AICA_HOME)").option("--aica-config <path>","Config file path (defaults to <aica-home>/config.json)").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--server <url>","ACA Server URL override").option("--machine-id <id>","Machine ID override for this runtime").option("--machine-name <name>","Machine name to register (defaults to hostname)").option("--cli-types <types...>","Specify CLI types to register, `claude` or `codex`").option("--managed-start <operationId>","受管理启动:保持业务入口关闭,等待 Proxy 激活").option("--debug","enable debug output").option("--heartbeat-log","output current timestamp every 5 seconds").option("--auth <api-key>","Use a CLI API key for non-interactive authentication").option("--token <enrollment-token>","Use a one-time Web-generated token to register this machine").option("-b, --background","在后台启动 Worker").action(async e=>{if(e.background){await ke(e);return}await Pe(e)})}async function ke(e){x(e),Q();const a=d();if(t.platform!=="linux"&&a&&h(a))throw new Error(`Worker 已在后台运行,PID ${a}。`);a&&W(a);const n=Ie(ye());if(n.unref(),!n.pid)throw new Error("后台 Worker 启动失败:未获得进程 PID。");if(!await Ce(n.pid,3e3)&&!h(n.pid))throw new Error(`后台 Worker 启动失败,请检查 ${c.join(t.env.AICA_HOME||t.env.ACA_HOME||c.join(D.homedir(),".aica"),"logs")}。`);console.log(`Worker 已在后台启动,PID ${n.pid}。`),Ae()}function ye(){const e=t.argv.findIndex((a,n)=>n>=2&&a==="start");return e<0?[]:t.argv.slice(e+1).filter(a=>a!=="--background"&&a!=="-b")}async function Ce(e,a){const n=Date.now();for(;Date.now()-n<a;){if(d()===e)return!0;if(!h(e))return!1;await new Promise(o=>setTimeout(o,50))}return d()===e}async function Pe(e){x(e);const a=await z();try{await Ee(e)}finally{a()}}async function Ee(e){if(e.managedStart||J(),e.managedStart){if(t.platform!=="linux")throw new Error("当前平台尚未支持受管理启动");if(!t.env.AICA_MANAGER_ID)throw new Error("受管理启动缺少管理实例");t.env.AICA_UPDATE_OPERATION=e.managedStart}const a=t.env[O]||Z(),n=ve(t.pid)||"";t.env[O]=a,t.env[ge]=String(t.pid),t.env[we]=n;const o=new ee("start",e.debug?"debug":"info"),g=$(),S={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let m=Object.keys(S).length>0?R(S):g;const f=e.machineName?.trim()||m.machineName||D.hostname();if(e.token?.trim()){const r=await le("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:m.machineId,machineName:f},{serverUrl:m.serverUrl});m=R({machineId:r.machineId,machineName:f,token:r.token,username:r.username}),o.info(`Machine enrollment completed for user ${r.username}`);try{const i=await ue();i.restored>0&&o.info(`restored ${i.restored} local project(s) after machine enrollment`),i.unavailable>0&&o.warn(`skipped ${i.unavailable} unavailable project path(s) during machine enrollment recovery`),m=$()}catch(i){o.warn(`project recovery after machine enrollment failed: ${i instanceof Error?i.message:String(i)}`)}}const M=e.auth?re(e.auth,f):te(),l=d();if(t.platform!=="linux"&&l&&l!==t.pid&&h(l))throw new Error(`Worker 已在运行,PID ${l}`);pe(t.pid),j({pid:t.pid,workerInstanceId:a,workerStartTicks:n,phase:"running",startupStage:"local-compatible",machineId:m.machineId||M?.machine?.machineId||"local-machine",machineName:f,cliTypes:e.cliTypes??be(),startedAt:new Date().toISOString(),heartbeatIntervalMs:ie,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),o.info(`Starting aca local-compatible service on machine ${f}`),o.info(`PID ${t.pid}`);const w=await fe();w.terminated>0&&o.warn(`terminated ${w.terminated} orphaned ACP process(es): ${w.pids.join(",")}`),he().then(r=>o.info(r?`Codex Provider runtime config loaded revision=${r.revision}`:"Codex Provider runtime config is not configured")).catch(r=>o.warn(`Codex Provider runtime config sync failed: ${r instanceof Error?r.message:String(r)}`));let k=!1,v,y,C,P,E;const p=async r=>{if(k)return;k=!0,V(),o.info("Shutting down"),v&&clearInterval(v),C?.stop(),E?.stop(),P?.stop(),await H(),await U(),await K(),await G.stop(),await N.stop(),await L.stop(),await y?.stop().catch(s=>o.warn(`job worker shutdown failed: ${s instanceof Error?s.message:String(s)}`));const i=_.stats();await _.disposeAll().catch(s=>o.warn(`ACP runtime shutdown failed: ${s instanceof Error?s.message:String(s)}`)),o.info(`ACP runtimes stopped total=${i.total} inUse=${i.inUse} idle=${i.idle}`),d()===t.pid&&(j({pid:t.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),W(t.pid)),t.exit(r)},b=r=>{if(!u.stopping&&d()===t.pid){const i=c.join(X(),"management");I.mkdirSync(i,{recursive:!0,mode:448}),I.writeFileSync(c.join(i,"manual-stop.json"),JSON.stringify({workerInstanceId:a,at:Date.now()}),{mode:384})}p(r)};t.once("SIGINT",()=>b(130)),t.once("SIGTERM",()=>b(0)),t.once("uncaughtException",r=>{o.error(`uncaught exception: ${r.stack||r.message}`),p(1)}),t.once("unhandledRejection",r=>{const i=r instanceof Error?r.stack||r.message:String(r);o.error(`unhandled rejection: ${i}`),p(1)}),e.heartbeatLog&&setInterval(()=>o.info(`heartbeat: ${new Date().toISOString()}`),5e3);let T=!1;const A=()=>{T||(T=!0,F(),B(),y=se(o),C=me(o),E=de(o),P=ce(o))};try{await q(a,()=>p(0),A)}catch(r){if(e.managedStart||r instanceof Error&&r.message.includes("已有 Worker 管理实例"))throw r;u.paused=!1,o.warn(`可选管理通道不可用: ${r instanceof Error?r.message:String(r)}`)}v=ne(o),t.env.ACA_DESKTOP_CHILD==="1"&&t.env.ACA_DESKTOP_STAGED==="1"&&(u.paused=!0),u.paused||A(),Se(()=>p(0),A),await new Promise(()=>{})}function be(){return["codex","claude"].filter(e=>Te(e))}function Te(e){const a=t.env.PATH||"";for(const n of a.split(c.delimiter))try{const o=t.platform==="win32"?["",".exe",".cmd",".bat"]:[""];if(n&&o.some(g=>I.existsSync(c.join(n,e+g))))return!0}catch{}return!1}function j(e){ae(oe(),e)}export{lt as createStartCommand};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{closeAcpProcess as
|
|
1
|
+
import{closeAcpProcess as y}from"../acp/client/acp-process.js";import{JsonLineRpcClient as E}from"../acp/client/json-rpc.js";import{startCodexAppServer as A}from"../acp/providers/codex/codex-process.js";import{acquireProviderUse as x}from"./provider-updates/gate.js";const R=360*60*1e3,g=2e4,C=8;let c=null,s=null,d=0,p=0;function D(){p++,c=null,d=0,s=null}async function T(){const e=Date.now();if(c&&c.expiresAtMs>e)return c;if(d>e)return null;if(s)return s;const t=p,r=(async()=>{const i=await x("codex");try{return await w()}finally{i()}})();s=r;const o=await r.finally(()=>{s===r&&(s=null)});return t!==p?null:(o?(c=o,d=0):d=e+300*1e3,o)}function h(e,t=Date.now()){const r=u(e),i=(Array.isArray(r.data)?r.data:[]).map(n=>v(u(n))).filter(n=>!!n);if(!i.length)return null;const a=i.find(n=>n.isDefault)?.modelId||i[0].modelId,f=M(i),m=[{id:"read-only",name:"Read-only",description:"Requires approval to edit files and run commands."},{id:"agent",name:"Agent",description:"Read and edit files, and run commands."},{id:"agent-full-access",name:"Agent (full access)",description:"Edit files and run commands with full access."}];return{expiresAtMs:t+R,defaultModel:a,capabilities:{source:"codex-app-server",fetchedAt:t,modelCatalogAuthoritative:!0,contextUsage:!0,contextCompaction:!0,modes:m,models:i.map(n=>({modelId:n.modelId,name:n.name,description:n.description,metadata:{defaultReasoningEffort:n.defaultReasoningEffort,supportedReasoningEfforts:n.supportedReasoningEfforts}})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:m.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:a,options:i.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"reasoning_effort",name:"Reasoning effort",category:"thought_level",type:"select",currentValue:i.find(n=>n.modelId===a)?.defaultReasoningEffort||f[0]?.value,options:f}]}}}async function w(){const e=A(process.cwd()),t=new E(e.child,{peerName:"Codex app-server"});try{await t.request("initialize",{clientInfo:{name:"aica-worker",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},g);const r=[];let o=null;for(let i=0;i<C;i+=1){const a=u(await t.request("model/list",{limit:100,...o?{cursor:o}:{}},g));if(Array.isArray(a.data)&&r.push(...a.data),o=typeof a.nextCursor=="string"&&a.nextCursor?a.nextCursor:null,!o)break}return h({data:r})}catch{return null}finally{await y(e.child).catch(()=>{})}}function v(e){if(e.hidden===!0)return null;const t=l(e.model,e.id);if(!t)return null;const r=(Array.isArray(e.supportedReasoningEfforts)?e.supportedReasoningEfforts:[]).map(i=>{const a=u(i),f=l(a.reasoningEffort,a.reasoning_effort,a.value);return f?{reasoningEffort:f,description:l(a.description)||""}:null}).filter(i=>!!i),o=l(e.defaultReasoningEffort,e.default_reasoning_effort)||r[0]?.reasoningEffort||"";return{modelId:t,name:l(e.displayName,e.name,t)||t,description:l(e.description)||"",isDefault:e.isDefault===!0,defaultReasoningEffort:o,supportedReasoningEfforts:r}}function M(e){const t=new Map;for(const r of e)for(const o of r.supportedReasoningEfforts)t.has(o.reasoningEffort)||t.set(o.reasoningEffort,{value:o.reasoningEffort,name:_(o.reasoningEffort),description:o.description});return[...t.values()]}function _(e){return e.toLowerCase()==="xhigh"?"X High":e.replace(/[-_]+/g," ").replace(/\b\w/g,t=>t.toUpperCase())}function u(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function l(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return null}export{h as codexCapabilitiesFromModelList,T as readCodexCapabilities,D as resetCodexCapabilities};
|
package/dist/core/heartbeat.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`));if(!r)continue;const l=M(r.name,r.id,a)??a;o.push({modelId:a,displayName:J(l,r),description:K(r),metadata:r})}return o}function z(e){const t=process.env.ACA_OPENCODE_DEFAULT_MODEL?.trim();return t&&e.some(o=>o.modelId===t)?t:e.find(o=>o.modelId==="opencode/big-pickle")?.modelId||e.find(o=>/free$/i.test(o.modelId))?.modelId||e[0]?.modelId||""}function J(e,t){return q(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function q(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function K(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0),n=Number(t.output??0);return o>0&&n>0?`Context ${o}, output ${n}`:o>0?`Context ${o}`:"OpenCode model"}function X(){try{const{command:e,args:t}=g("mimo"),o=y(e,[...t,"models","--verbose"],{windowsHide:!0,encoding:"utf8",timeout:15e3,maxBuffer:2*1024*1024,stdio:["ignore","pipe","pipe"]}),n=Y(o);if(!n.length)return null;const a=[{id:"agent",name:"Agent",description:"Run MimoCode with normal workspace permissions."},{id:"agent-full-access",name:"Agent (full access)",description:"Run MimoCode and auto-approve supported local permissions."}],s=G(n);return{source:"mimo-cli",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:a,models:n.map(i=>({modelId:i.modelId,name:i.displayName,description:i.description,metadata:i.metadata})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:a.map(i=>({value:i.id,name:i.name,description:i.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:n.some(i=>i.modelId==="mimo/mimo-auto")?"mimo/mimo-auto":n[0]?.modelId,options:n.map(i=>({value:i.modelId,name:i.displayName,description:i.description}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",currentValue:s.some(i=>i.value==="high")?"high":s[0]?.value,options:s}]}}catch{return null}}function Y(e){const t=e.split(/\r?\n/),o=[];let n=0;for(;n<t.length;){const a=t[n]?.trim()??"";if(n+=1,!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(a))continue;const s=[];let i=0,c=!1;for(;n<t.length;){const d=t[n]??"";if(n+=1,!(!c&&!d.trim().startsWith("{"))&&(c=!0,s.push(d),i+=f(d,"{")-f(d,"}"),c&&i<=0))break}const r=w(s.join(`
|
|
3
|
-
`));if(!r)continue;const l=M(r.name,r.id,a)??a;o.push({modelId:a,displayName:Q(l,r),description:ee(r),metadata:r})}return o}function G(e){const t=new Set;for(const a of e){const s=a.metadata.variants;if(!(!s||typeof s!="object"||Array.isArray(s)))for(const i of Object.keys(s))t.add(i)}const o=["minimal","low","medium","high","max"].filter(a=>t.has(a));return(o.length?o:["minimal","high","max"]).map(a=>({value:a,name:te(a),description:a==="high"?"More reasoning for difficult tasks":a==="max"?"Maximum reasoning when supported":"Fastest responses"}))}function Q(e,t){return Z(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function Z(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function ee(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0);return o>0?`Context ${o}`:"MimoCode model"}function w(e){try{const t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function M(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim()}function te(e){return e.slice(0,1).toUpperCase()+e.slice(1)}function f(e,t){let o=0;for(const n of e)n===t&&(o+=1);return o}function ge(e){let t=!1;const o=async(s,i="heartbeat")=>{const c=new Date().toISOString();try{const r=await R(C(),{includeProviderDetails:s});if(r.skipped){h({lastHeartbeatAt:c,lastHeartbeatStatus:"skipped",lastHeartbeatReason:r.reason??"unknown"}),e.debug(`${i} skipped: ${r.reason??"unknown"}`);return}h({lastHeartbeatAt:c,lastHeartbeatStatus:"ok",lastHeartbeatProjectCount:r.projectCount??null,presenceExpiresAtMs:r.presenceExpiresAtMs??null}),e.debug(`${i} ok projects=${r.projectCount??0}`)}catch(r){const l=r instanceof Error?r.message:String(r);h({lastHeartbeatAt:c,lastHeartbeatStatus:"error",lastHeartbeatError:l}),e.warn(`${i} failed: ${l}`)}},n=async()=>{if(!t){t=!0;try{await o(!0)}finally{t=!1}}};return(async()=>{if(!t){t=!0;try{await o(!1,"initial presence heartbeat"),await o(!0)}finally{t=!1}}})(),setInterval(()=>{n()},A)}function h(e){const t=v(b())??{};x(b(),{...t,heartbeatIntervalMs:A,...e})}export{A as HEARTBEAT_INTERVAL_MS,T as reportedAicaVersion,R as sendHeartbeat,ge as startHeartbeatLoop};
|
|
1
|
+
import{readMimoCapabilities as k,resetMimoModelCatalog as u}from"./mimo-models/service.js";import{readOpenCodeCapabilities as C,openCodeModelCatalog as g}from"./opencode/models.js";import{providerPackages as v}from"./provider-install-paths.js";import{invalidateProviderCapabilities as A}from"./provider-updates/capabilities.js";import i from"node:os";import{readJsonFile as x,writeJsonFile as H}from"./fs.js";import{getRuntimeStatePath as f}from"./paths.js";import{acaServerRequest as M}from"./aca-server-client.js";import{loadAcaConfig as b}from"./aca-config.js";import{providerHealthSnapshot as n}from"./provider-health.js";import{readCodexCapabilities as S}from"./codex-capabilities.js";import{AICA_VERSION as E}from"../version.js";import{applyProjectSync as _}from"./project-sync.js";import{workBuddyHeartbeatCapabilities as h}from"../acp/providers/workbuddy/config.js";import{readWorkBuddyCapabilities as O}from"../acp/providers/workbuddy/discovery.js";import{workBuddyCreditsConnected as T}from"./workbuddy-credits/worker.js";const I=3e4;function te(){u(),g.reset()}async function R(e=b(),t={}){if(!e.token)return{ok:!1,skipped:!0,reason:"not_logged_in"};const o=await M("POST","/api/heartbeat",{machineId:e.machineId,machineName:e.machineName,machineInfo:{platform:i.platform(),architecture:i.arch(),osRelease:i.release(),acaVersion:$(),hostname:i.hostname()},workspaceId:e.defaultWorkspaceId,agentConfigs:t.includeProviderDetails===!1?[]:t.onlyMimo?[await w(e)]:t.onlyOpenCode?[await y(e)]:await D(e,t.onlyProvider),projects:e.projects.map(a=>({projectId:a.projectId,workspaceId:a.workspaceId,name:a.name,rootPath:a.rootPath}))});return _(e,o),T(),o}async function D(e,t){const o=t?[t]:["codex","mimo","opencode","workbuddy"],a=[];for(const l of o)switch(l){case"codex":a.push(await P(e));break;case"mimo":a.push(await w(e));break;case"opencode":a.push(await y(e));break;case"workbuddy":a.push(await L(e));break}return a}async function P(e){const t=await S();return{agentId:`${e.machineId}:builtin:codex`,workspaceId:e.defaultWorkspaceId,name:"Codex",agentType:"codex",cliType:"builtin",machineId:e.machineId,model:t?.defaultModel||"gpt-5.5",mode:"agent-full-access",raw:{providerStatus:n().codex,capabilities:t?.capabilities??B()}}}async function L(e){const t=n().workbuddy,o=t.available?await O().catch(()=>h()):h();return{agentId:`${e.machineId}:builtin:workbuddy`,workspaceId:e.defaultWorkspaceId,name:"腾讯 Code Buddy",agentType:"workbuddy",cliType:"builtin",machineId:e.machineId,model:process.env.ACA_WORKBUDDY_DEFAULT_MODEL||null,mode:"default",raw:{providerStatus:t,capabilities:o}}}function $(e=process.env){return e.ACA_VERSION?.trim()||E}async function w(e){return{agentId:`${e.machineId}:builtin:mimo`,workspaceId:e.defaultWorkspaceId,name:"MimoCode",agentType:"mimo",cliType:"builtin",machineId:e.machineId,model:process.env.ACA_MIMO_DEFAULT_MODEL||null,mode:"agent-full-access",raw:{providerStatus:n().mimo,capabilities:await k()}}}function B(){const e=[{id:"read-only",name:"Read-only",description:"Requires approval to edit files and run commands."},{id:"agent",name:"Agent",description:"Read and edit files, and run commands."},{id:"agent-full-access",name:"Agent (full access)",description:"Edit files and run commands with full access."}],t=[{modelId:"gpt-5.5",name:"gpt-5.5",description:"Latest frontier Codex model"},{modelId:"gpt-5.4",name:"gpt-5.4",description:"Frontier Codex model"},{modelId:"gpt-5.4-mini",name:"gpt-5.4-mini",description:"Smaller, faster Codex model"}],o=[{value:"low",name:"Low",description:"Fastest responses"},{value:"medium",name:"Medium",description:"Balanced reasoning"},{value:"high",name:"High",description:"More reasoning for difficult tasks"},{value:"xhigh",name:"X High",description:"Extra reasoning for complex tasks"}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!0,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(a=>({value:a.id,name:a.name,description:a.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:"gpt-5.5",options:t.map(a=>({value:a.modelId,name:a.name,description:a.description}))},{id:"reasoning_effort",name:"Reasoning effort",category:"thought_level",type:"select",currentValue:"medium",options:o}]}}function ae(){u()}async function y(e){return{agentId:`${e.machineId}:builtin:opencode`,workspaceId:e.defaultWorkspaceId,name:"OpenCode",agentType:"opencode",cliType:"builtin",machineId:e.machineId,model:process.env.ACA_OPENCODE_DEFAULT_MODEL||null,mode:"agent-full-access",raw:{providerStatus:n().opencode,capabilities:await C()}}}function oe(e){for(const s of Object.keys(v))A(s);let t=!1;const o=async(s,d="heartbeat")=>{const c=new Date().toISOString();try{const r=await R(b(),{includeProviderDetails:s});if(r.skipped){p({lastHeartbeatAt:c,lastHeartbeatStatus:"skipped",lastHeartbeatReason:r.reason??"unknown"}),e.debug(`${d} skipped: ${r.reason??"unknown"}`);return}p({lastHeartbeatAt:c,lastHeartbeatStatus:"ok",lastHeartbeatProjectCount:r.projectCount??null,presenceExpiresAtMs:r.presenceExpiresAtMs??null}),e.debug(`${d} ok projects=${r.projectCount??0}`)}catch(r){const m=r instanceof Error?r.message:String(r);p({lastHeartbeatAt:c,lastHeartbeatStatus:"error",lastHeartbeatError:m}),e.warn(`${d} failed: ${m}`)}},a=async()=>{if(!t){t=!0;try{await o(!0)}finally{t=!1}}};return(async()=>{if(!t){t=!0;try{await o(!1,"initial presence heartbeat"),await o(!0)}finally{t=!1}}})(),setInterval(()=>{a()},I)}function p(e){const t=x(f())??{};H(f(),{...t,heartbeatIntervalMs:I,...e})}export{I as HEARTBEAT_INTERVAL_MS,$ as reportedAicaVersion,te as resetHeartbeatProviderCapabilities,ae as resetMimoCapabilities,R as sendHeartbeat,oe as startHeartbeatLoop};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{providerInstallOperation as q}from"./provider-installer.js";import{executeExternalCodexOperation as tt}from"./external-codex-worker.js";import{workBuddyAuthManager as et}from"./workbuddy-auth-worker.js";import{workBuddyCredits as rt}from"./workbuddy-credits/worker.js";import{managementActivity as T}from"./management/activity.js";import{managedClaim as ot}from"./management/claims.js";import{activeTerminalService as it}from"./terminal/service.js";import{execFileSync as _}from"node:child_process";import{randomUUID as F}from"node:crypto";import l from"node:fs";import M from"node:os";import u from"node:path";import{acaServerDownloadToFile as nt,acaServerRequest as E}from"./aca-server-client.js";import{loadAcaConfig as k,upsertLocalProject as st}from"./aca-config.js";import{startLongPollWorker as at}from"./long-poll-worker.js";import{expandWorkerRuntimePath as ct}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as lt}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as ut}from"../acp/client/acp-runtime-pool.js";import{execPowerShell as L}from"./machine-filesystem/powershell.js";const O=25e3,dt=O+1e4,x=300,ft=3e4;let b=null;function pe(t){return at({run:async()=>{const e=k();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await ot("machine",()=>E("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${O}`,void 0,{timeoutMs:dt}));if(!r.item)return;const o=T.track("machine");try{const i=await mt(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:i})}catch(i){const s=i instanceof Error?i.message:String(i);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${s}`),await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:s}).catch(()=>{T.uncertain.add("machine-finalize")})}finally{o()}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function mt(t){if(t.operation==="provider_install")return q(t.payload);if(t.operation==="workbuddy_auth")return et.execute(String(t.payload.action||""),t.payload);if(t.operation==="workbuddy_credits")return{machineId:k().machineId,instanceId:process.env.ACA_WORKER_INSTANCE_ID||String(process.pid),snapshot:await rt.refresh(!0)};if(t.operation.startsWith("external_codex_"))return tt(t.operation,t.payload);if(t.operation==="sync_codex_provider_config"){const e=await lt(),r=await ut.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return Ft();if(t.operation==="list_directory")return Mt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return Bt(t.payload);if(t.operation==="list_project_directory")return wt(t.payload);if(t.operation==="upload_project_file")return gt(t.payload);if(t.operation==="mutate_project_files")return St(t.payload);if(t.operation==="get_project_git_status")return B(t.payload);if(t.operation==="get_project_git_diff")return jt(t.payload);if(t.operation==="get_project_git_log")return vt(t.payload);if(t.operation==="get_project_git_commit")return At(t.payload);if(t.operation==="get_worktree_status")return D(t.payload);if(t.operation==="commit_worktree")return pt(t.payload);if(t.operation==="cleanup_worktree")return ht(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function D(t){const e=$(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=p(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:Rt(r),changedFiles:null,ahead:0};const o=B({rootPath:r}),i=String(t.baseCommit||"").trim(),s=i&&/^[0-9a-f]{7,64}$/i.test(i)?Ct(r,i):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function pt(t){const e=p(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");_("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return _("git",["-C",e,"diff","--cached","--quiet"],{windowsHide:!0,stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...D(t)}}catch(o){if(Number(o.status)!==1)throw o}return _("git",["-C",e,"commit","-m",r],{windowsHide:!0,stdio:"pipe",timeout:6e4}),{committed:!0,commit:m(e,["rev-parse","HEAD"],8*1024).trim(),...D(t)}}function ht(t){const e=$(String(t.worktreePath||"")),r=p(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=p(e);if(it?.hasRunningInDirectory(o,String(t.sessionId||"")))throw new Error("请先结束此目录中的会话终端,再清理 Worktree。");const i=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(_("git",["-C",r,"worktree","remove","--force",o],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&i)try{_("git",["-C",r,"branch","-D",i],{windowsHide:!0,stdio:"pipe",timeout:3e4})}catch(n){const c=String(n.stderr||n);if(!/not found|not exist/i.test(c))throw n}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&i)}}function wt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||"")),o=v(e,r,!0),i=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),n=t.sort==="modified-desc"||t.sort==="modified-asc"?t.sort:"name",c=l.readdirSync(o,{withFileTypes:!0}).filter(a=>!a.isSymbolicLink()).map(a=>({name:a.name,path:J(e,u.join(o,a.name)),type:a.isDirectory()?"directory":a.isFile()?"file":"other",hidden:a.name.startsWith("."),extension:a.isFile()?u.extname(a.name).slice(1).toLowerCase():"",modifiedAt:n==="name"?void 0:yt(u.join(o,a.name))})).filter(a=>a.type!=="other").sort((a,f)=>{if(a.type!==f.type)return a.type==="directory"?-1:1;if(n!=="name"){if(a.modifiedAt==null&&f.modifiedAt!=null)return 1;if(f.modifiedAt==null&&a.modifiedAt!=null)return-1;const P=(a.modifiedAt??0)-(f.modifiedAt??0);if(P)return n==="modified-desc"?-P:P}return a.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),d=c.slice(i,i+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:d,total:c.length,nextOffset:i+d.length<c.length?i+d.length:null}}function yt(t){try{const e=l.lstatSync(t);return e.isSymbolicLink()?null:e.mtimeMs}catch{return null}}async function gt(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=p(String(t.rootPath||"")),o=g(String(t.relativeDirectory||"")),i=v(r,o,!0),s=H(String(t.fileName||"")),n=Number(t.sizeBytes),c=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(n)||n<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(c))throw new Error("项目上传文件摘要无效。");const d=u.join(i,`.aca-upload-${F()}.tmp`);try{const a=await nt(`/api/client/project-uploads/${encodeURIComponent(e)}`,d,{maxBytes:n,timeoutMs:3e5});if(a.sizeBytes!==n)throw new Error("项目上传文件大小校验失败。");if(a.sha256.toLowerCase()!==c)throw new Error("项目上传文件完整性校验失败。");const f=Et(r,o,s,d);return{name:u.basename(f),path:J(r,f),directory:o,size:a.sizeBytes,sha256:a.sha256,renamed:u.basename(f)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(d,{force:!0})}}function St(t){const e=p(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return _t(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function _t(t,e,r,o){const i=g(e);if(!i)throw new Error("project_file_root_protected");Pt(i);const s=i.split("/"),n=s.slice(0,-1).join("/"),c=v(t,n,!0),d=u.join(c,s.at(-1)||"");let a;try{a=l.lstatSync(d)}catch(f){throw f.code==="ENOENT"?new Error("project_file_not_found"):f}if(a.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!a.isFile()&&!a.isDirectory())throw new Error("project_file_type_unsupported");if(a.isDirectory()&&!r&&l.readdirSync(d).length>0)throw new Error("project_directory_not_empty");return a.isDirectory()&&r?l.rmSync(d,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):a.isDirectory()?l.rmdirSync(d):l.unlinkSync(d),{operation:"delete",path:i,entryType:a.isDirectory()?"directory":"file",parentPath:n,affectedDirectories:[n],rootKind:o==="worktree"?"worktree":"project"}}function Pt(t){const e=t.split("/")[0].toLocaleLowerCase("en-US");if([".git",".aca",".aica"].includes(e))throw new Error("project_file_protected")}function Et(t,e,r,o){const i=p(t),s=g(e),n=v(i,s,!0),c=H(r);if(l.realpathSync.native(u.dirname(o))!==n)throw new Error("项目上传临时文件不在目标目录中。");const a=l.lstatSync(o);if(!a.isFile()||a.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let f=1;f<=1e4;f+=1){const P=f===1?c:xt(c,f),S=u.join(n,P);try{return l.linkSync(o,S),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(A){if(G(A))continue;if(!bt(A))throw A;try{return l.copyFileSync(o,S,l.constants.COPYFILE_EXCL),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(N){if(G(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function H(t){const e=t.trim();if(!e||e==="."||e===".."||/[\\/\x00-\x1F]/.test(e))throw new Error("项目上传文件名无效。");if(process.platform==="win32"&&(/[<>:"|?*]/.test(e)||/[. ]$/.test(e)))throw new Error("项目上传文件名在 Windows 上无效。");return e.slice(0,180)}function xt(t,e){const r=u.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function G(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function bt(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const W=500,j=2*1024*1024,y=2*1024*1024;function B(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=m(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],j).split("\0").filter(Boolean).slice(0,W),i=o.map(c=>Dt(c)).filter(c=>!!c),s=C(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],j));for(const c of i){const d=s.get(c.path);if(d)c.additions=d.additions,c.deletions=d.deletions;else if(c.status==="untracked"){const a=U(e,c.path);c.additions=a.additions,c.deletions=a.deletions}}const n=Tt(e);return{isRepository:!0,branch:Nt(e),files:i,ahead:n.ahead,behind:n.behind,truncated:o.length>=W}}function jt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=K(e,r),i=It(e,r),s=i?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],y):X(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],y),n=i?C(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):U(e,r);return{isRepository:!0,path:r,diff:V(s),additions:n?.additions??0,deletions:n?.deletions??0,truncated:s.length>y}}function vt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!$t(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:m(e,["log",`--max-count=${r}`,"--date=iso-strict","--pretty=format:%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%D%x1f%s%x1f%b%x1e"],j).split("").map(n=>kt(n)).filter(n=>!!n),limit:r}}function At(t){const e=p(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!w(e))return{isRepository:!1,commit:r,diff:"",additions:0,deletions:0};m(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=m(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],y),i=[...C(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:V(o),additions:i.reduce((s,n)=>s+(n.additions||0),0),deletions:i.reduce((s,n)=>s+(n.deletions||0),0),changedFiles:i.length,truncated:o.length>y}}function kt(t){const e=t.replace(/^\s+|\s+$/g,"");if(!e)return null;const r=e.split(""),o=String(r[0]||"").trim();return o?{hash:o,shortHash:String(r[1]||o.slice(0,8)).trim(),authorName:String(r[2]||"").trim(),authorEmail:String(r[3]||"").trim(),authoredAt:String(r[4]||"").trim(),refs:String(r[5]||"").trim(),subject:String(r[6]||"").trim(),body:r.slice(7).join("").trim()}:null}function Dt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=g(t.slice(3));return o?{path:o,status:e==="?"&&r==="?"?"untracked":e==="U"||r==="U"?"conflicted":e==="D"||r==="D"?"deleted":e==="A"||r==="A"?"added":e==="R"||r==="R"?"renamed":"modified",indexStatus:e,worktreeStatus:r,staged:e!==" "&&e!=="?",additions:null,deletions:null}:null}function C(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=z(r);if(!o||!o.path)continue;const i=g(o.path);i&&e.set(i,{additions:o.additions,deletions:o.deletions})}return e}function U(t,e){const r=K(t,e),i=X(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=z(i);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function z(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),i=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(i)?Number(i):null,path:t.slice(r+1)}}function w(t){try{return m(t,["rev-parse","--is-inside-work-tree"],8*1024).trim()==="true"}catch(e){if(String(e.code||"")==="ENOENT")throw new Error("设备未安装 Git。");return!1}}function Ct(t,e){try{const r=m(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function Rt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function It(t,e){try{return m(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function $t(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Nt(t){try{return m(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${m(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function Tt(t){try{const e=m(t,["rev-list","--left-right","--count","HEAD...@{upstream}"],8192).trim().split(/\s+/).map(Number);return{ahead:Number.isFinite(e[0])?e[0]:0,behind:Number.isFinite(e[1])?e[1]:0}}catch{return{ahead:0,behind:0}}}function K(t,e){const r=u.resolve(t,...e.split("/")),o=u.relative(t,r);if(o.startsWith("..")||u.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function m(t,e,r){return _("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function X(t,e,r){try{return m(t,e,r)}catch(o){const i=String(o.stdout||"");if(i)return i;if(Number(o.status)===1)return"";throw o}}function V(t){return t.length<=y?t:`${t.slice(0,y)}
|
|
1
|
+
import{openCodeAuthManager as q,refreshOpenCodeModels as tt}from"./opencode/worker.js";import{mimoModelCatalog as et}from"./mimo-models/service.js";import{sendHeartbeat as rt}from"./heartbeat.js";import{mimoAuthManager as ot}from"./mimo-auth-worker.js";import{providerInstallOperation as it}from"./provider-installer.js";import{executeExternalCodexOperation as nt}from"./external-codex-worker.js";import{workBuddyAuthManager as st}from"./workbuddy-auth-worker.js";import{workBuddyCredits as at}from"./workbuddy-credits/worker.js";import{managementActivity as T}from"./management/activity.js";import{managedClaim as ct}from"./management/claims.js";import{activeTerminalService as lt}from"./terminal/service.js";import{execFileSync as _}from"node:child_process";import{randomUUID as F}from"node:crypto";import l from"node:fs";import M from"node:os";import d from"node:path";import{acaServerDownloadToFile as dt,acaServerRequest as E}from"./aca-server-client.js";import{loadAcaConfig as k,upsertLocalProject as ut}from"./aca-config.js";import{startLongPollWorker as ft}from"./long-poll-worker.js";import{expandWorkerRuntimePath as mt}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as pt}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as ht}from"../acp/client/acp-runtime-pool.js";import{execPowerShell as L}from"./machine-filesystem/powershell.js";const O=25e3,wt=O+1e4,x=300,yt=3e4;let b=null;function xe(t){return ft({run:async()=>{const e=k();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await ct("machine",()=>E("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${O}`,void 0,{timeoutMs:wt}));if(!r.item)return;const o=T.track("machine");try{const i=await gt(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:i})}catch(i){const s=i instanceof Error?i.message:String(i);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${s}`),await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:s}).catch(()=>{T.uncertain.add("machine-finalize")})}finally{o()}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function gt(t){if(t.operation==="provider_install")return it(t.payload);if(t.operation==="mimo_models"){const e=await et.read(!0);return await rt(void 0,{onlyMimo:!0}),{count:e.models.length,fetchedAt:e.fetchedAt,stale:e.stale}}if(t.operation==="opencode_models")return tt();if(t.operation==="opencode_auth")return q.execute(String(t.payload.action||""),t.payload);if(t.operation==="mimo_auth")return ot.execute(String(t.payload.action||""),t.payload);if(t.operation==="workbuddy_auth")return st.execute(String(t.payload.action||""),t.payload);if(t.operation==="workbuddy_credits")return{machineId:k().machineId,instanceId:process.env.ACA_WORKER_INSTANCE_ID||String(process.pid),snapshot:await at.refresh(!0)};if(t.operation.startsWith("external_codex_"))return nt(t.operation,t.payload);if(t.operation==="sync_codex_provider_config"){const e=await pt(),r=await ht.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return Gt();if(t.operation==="list_directory")return Wt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return Vt(t.payload);if(t.operation==="list_project_directory")return Pt(t.payload);if(t.operation==="upload_project_file")return xt(t.payload);if(t.operation==="mutate_project_files")return bt(t.payload);if(t.operation==="get_project_git_status")return B(t.payload);if(t.operation==="get_project_git_diff")return Dt(t.payload);if(t.operation==="get_project_git_log")return Rt(t.payload);if(t.operation==="get_project_git_commit")return It(t.payload);if(t.operation==="get_worktree_status")return C(t.payload);if(t.operation==="commit_worktree")return St(t.payload);if(t.operation==="cleanup_worktree")return _t(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function C(t){const e=$(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=p(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:Ft(r),changedFiles:null,ahead:0};const o=B({rootPath:r}),i=String(t.baseCommit||"").trim(),s=i&&/^[0-9a-f]{7,64}$/i.test(i)?Tt(r,i):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function St(t){const e=p(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");_("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return _("git",["-C",e,"diff","--cached","--quiet"],{windowsHide:!0,stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...C(t)}}catch(o){if(Number(o.status)!==1)throw o}return _("git",["-C",e,"commit","-m",r],{windowsHide:!0,stdio:"pipe",timeout:6e4}),{committed:!0,commit:m(e,["rev-parse","HEAD"],8*1024).trim(),...C(t)}}function _t(t){const e=$(String(t.worktreePath||"")),r=p(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=p(e);if(lt?.hasRunningInDirectory(o,String(t.sessionId||"")))throw new Error("请先结束此目录中的会话终端,再清理 Worktree。");const i=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(_("git",["-C",r,"worktree","remove","--force",o],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&i)try{_("git",["-C",r,"branch","-D",i],{windowsHide:!0,stdio:"pipe",timeout:3e4})}catch(n){const c=String(n.stderr||n);if(!/not found|not exist/i.test(c))throw n}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&i)}}function Pt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||"")),o=v(e,r,!0),i=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),n=t.sort==="modified-desc"||t.sort==="modified-asc"?t.sort:"name",c=l.readdirSync(o,{withFileTypes:!0}).filter(a=>!a.isSymbolicLink()).map(a=>({name:a.name,path:J(e,d.join(o,a.name)),type:a.isDirectory()?"directory":a.isFile()?"file":"other",hidden:a.name.startsWith("."),extension:a.isFile()?d.extname(a.name).slice(1).toLowerCase():"",modifiedAt:n==="name"?void 0:Et(d.join(o,a.name))})).filter(a=>a.type!=="other").sort((a,f)=>{if(a.type!==f.type)return a.type==="directory"?-1:1;if(n!=="name"){if(a.modifiedAt==null&&f.modifiedAt!=null)return 1;if(f.modifiedAt==null&&a.modifiedAt!=null)return-1;const P=(a.modifiedAt??0)-(f.modifiedAt??0);if(P)return n==="modified-desc"?-P:P}return a.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),u=c.slice(i,i+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:u,total:c.length,nextOffset:i+u.length<c.length?i+u.length:null}}function Et(t){try{const e=l.lstatSync(t);return e.isSymbolicLink()?null:e.mtimeMs}catch{return null}}async function xt(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=p(String(t.rootPath||"")),o=g(String(t.relativeDirectory||"")),i=v(r,o,!0),s=H(String(t.fileName||"")),n=Number(t.sizeBytes),c=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(n)||n<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(c))throw new Error("项目上传文件摘要无效。");const u=d.join(i,`.aca-upload-${F()}.tmp`);try{const a=await dt(`/api/client/project-uploads/${encodeURIComponent(e)}`,u,{maxBytes:n,timeoutMs:3e5});if(a.sizeBytes!==n)throw new Error("项目上传文件大小校验失败。");if(a.sha256.toLowerCase()!==c)throw new Error("项目上传文件完整性校验失败。");const f=At(r,o,s,u);return{name:d.basename(f),path:J(r,f),directory:o,size:a.sizeBytes,sha256:a.sha256,renamed:d.basename(f)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(u,{force:!0})}}function bt(t){const e=p(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return jt(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function jt(t,e,r,o){const i=g(e);if(!i)throw new Error("project_file_root_protected");vt(i);const s=i.split("/"),n=s.slice(0,-1).join("/"),c=v(t,n,!0),u=d.join(c,s.at(-1)||"");let a;try{a=l.lstatSync(u)}catch(f){throw f.code==="ENOENT"?new Error("project_file_not_found"):f}if(a.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!a.isFile()&&!a.isDirectory())throw new Error("project_file_type_unsupported");if(a.isDirectory()&&!r&&l.readdirSync(u).length>0)throw new Error("project_directory_not_empty");return a.isDirectory()&&r?l.rmSync(u,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):a.isDirectory()?l.rmdirSync(u):l.unlinkSync(u),{operation:"delete",path:i,entryType:a.isDirectory()?"directory":"file",parentPath:n,affectedDirectories:[n],rootKind:o==="worktree"?"worktree":"project"}}function vt(t){const e=t.split("/")[0].toLocaleLowerCase("en-US");if([".git",".aca",".aica"].includes(e))throw new Error("project_file_protected")}function At(t,e,r,o){const i=p(t),s=g(e),n=v(i,s,!0),c=H(r);if(l.realpathSync.native(d.dirname(o))!==n)throw new Error("项目上传临时文件不在目标目录中。");const a=l.lstatSync(o);if(!a.isFile()||a.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let f=1;f<=1e4;f+=1){const P=f===1?c:kt(c,f),S=d.join(n,P);try{return l.linkSync(o,S),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(A){if(G(A))continue;if(!Ct(A))throw A;try{return l.copyFileSync(o,S,l.constants.COPYFILE_EXCL),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(N){if(G(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function H(t){const e=t.trim();if(!e||e==="."||e===".."||/[\\/\x00-\x1F]/.test(e))throw new Error("项目上传文件名无效。");if(process.platform==="win32"&&(/[<>:"|?*]/.test(e)||/[. ]$/.test(e)))throw new Error("项目上传文件名在 Windows 上无效。");return e.slice(0,180)}function kt(t,e){const r=d.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function G(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function Ct(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const W=500,j=2*1024*1024,y=2*1024*1024;function B(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=m(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],j).split("\0").filter(Boolean).slice(0,W),i=o.map(c=>Nt(c)).filter(c=>!!c),s=D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],j));for(const c of i){const u=s.get(c.path);if(u)c.additions=u.additions,c.deletions=u.deletions;else if(c.status==="untracked"){const a=U(e,c.path);c.additions=a.additions,c.deletions=a.deletions}}const n=Ht(e);return{isRepository:!0,branch:Ot(e),files:i,ahead:n.ahead,behind:n.behind,truncated:o.length>=W}}function Dt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=K(e,r),i=Mt(e,r),s=i?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],y):X(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],y),n=i?D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):U(e,r);return{isRepository:!0,path:r,diff:V(s),additions:n?.additions??0,deletions:n?.deletions??0,truncated:s.length>y}}function Rt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!Lt(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:m(e,["log",`--max-count=${r}`,"--date=iso-strict","--pretty=format:%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%D%x1f%s%x1f%b%x1e"],j).split("").map(n=>$t(n)).filter(n=>!!n),limit:r}}function It(t){const e=p(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!w(e))return{isRepository:!1,commit:r,diff:"",additions:0,deletions:0};m(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=m(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],y),i=[...D(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:V(o),additions:i.reduce((s,n)=>s+(n.additions||0),0),deletions:i.reduce((s,n)=>s+(n.deletions||0),0),changedFiles:i.length,truncated:o.length>y}}function $t(t){const e=t.replace(/^\s+|\s+$/g,"");if(!e)return null;const r=e.split(""),o=String(r[0]||"").trim();return o?{hash:o,shortHash:String(r[1]||o.slice(0,8)).trim(),authorName:String(r[2]||"").trim(),authorEmail:String(r[3]||"").trim(),authoredAt:String(r[4]||"").trim(),refs:String(r[5]||"").trim(),subject:String(r[6]||"").trim(),body:r.slice(7).join("").trim()}:null}function Nt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=g(t.slice(3));return o?{path:o,status:e==="?"&&r==="?"?"untracked":e==="U"||r==="U"?"conflicted":e==="D"||r==="D"?"deleted":e==="A"||r==="A"?"added":e==="R"||r==="R"?"renamed":"modified",indexStatus:e,worktreeStatus:r,staged:e!==" "&&e!=="?",additions:null,deletions:null}:null}function D(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=z(r);if(!o||!o.path)continue;const i=g(o.path);i&&e.set(i,{additions:o.additions,deletions:o.deletions})}return e}function U(t,e){const r=K(t,e),i=X(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=z(i);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function z(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),i=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(i)?Number(i):null,path:t.slice(r+1)}}function w(t){try{return m(t,["rev-parse","--is-inside-work-tree"],8*1024).trim()==="true"}catch(e){if(String(e.code||"")==="ENOENT")throw new Error("设备未安装 Git。");return!1}}function Tt(t,e){try{const r=m(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function Ft(t){try{return l.readdirSync(t).length>0}catch{return!1}}function Mt(t,e){try{return m(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function Lt(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Ot(t){try{return m(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${m(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function Ht(t){try{const e=m(t,["rev-list","--left-right","--count","HEAD...@{upstream}"],8192).trim().split(/\s+/).map(Number);return{ahead:Number.isFinite(e[0])?e[0]:0,behind:Number.isFinite(e[1])?e[1]:0}}catch{return{ahead:0,behind:0}}}function K(t,e){const r=d.resolve(t,...e.split("/")),o=d.relative(t,r);if(o.startsWith("..")||d.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function m(t,e,r){return _("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function X(t,e,r){try{return m(t,e,r)}catch(o){const i=String(o.stdout||"");if(i)return i;if(Number(o.status)===1)return"";throw o}}function V(t){return t.length<=y?t:`${t.slice(0,y)}
|
|
2
2
|
|
|
3
|
-
[Diff 内容过大,已截断]`}function
|
|
4
|
-
`),o=Z(L(r));for(const i of o){const s=String(i.Root||"");if(!s)continue;const n=Number(i.DriveType||0),c=String(i.Name||s.replace(/[\\/]+$/,"")),
|
|
5
|
-
`),i=Z(L(o,{ACA_MACHINE_FS_PATH:r})),s=i.map(n=>{const c=String(n.Attributes||"");return{name:String(n.Name||""),path:String(n.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(n=>n.name&&n.path&&!n.reparsePoint&&(e||!n.hidden)).slice(0,x).sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return Y(r,s,i.length>x,"win32")}function Y(t,e,r,o){const i=o==="win32"?
|
|
3
|
+
[Diff 内容过大,已截断]`}function Gt(){const t=process.platform,e=R(t);return{platform:t,roots:e}}function Wt(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?Kt(t.directoryPath,!!t.includeHidden):zt(t.directoryPath,!!t.includeHidden)}function h(t,e=process.platform){const r=e==="win32"?d.win32:d.posix,o=r.normalize(t),i=r.parse(o).root,s=o.length>i.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function Bt(){const t=l.realpathSync(M.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==d.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function R(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?Ut():Bt();return b={platform:t,roots:e,expiresAtMs:Date.now()+yt},e}function Ut(){const t=l.realpathSync.native(M.homedir()),e=new Map;e.set(h(t,"win32"),{id:"home",label:"用户目录",path:t,kind:"home",available:!0});try{const r=["$items = Get-CimInstance Win32_LogicalDisk | ForEach-Object {"," [PSCustomObject]@{ Name = $_.DeviceID; Root = ($_.DeviceID + '\\\\'); DriveType = $_.DriveType; VolumeName = $_.VolumeName }","}","@($items) | ConvertTo-Json -Compress"].join(`
|
|
4
|
+
`),o=Z(L(r));for(const i of o){const s=String(i.Root||"");if(!s)continue;const n=Number(i.DriveType||0),c=String(i.Name||s.replace(/[\\/]+$/,"")),u=String(i.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${c.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:u?`${u} (${c})`:qt(c,n),path:s,kind:Zt(n),available:!0})}}catch{const r=d.win32.parse(t).root;e.set(h(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function zt(t,e){const r=I(t),i=l.readdirSync(r,{withFileTypes:!0}).filter(n=>n.isDirectory()&&!n.isSymbolicLink()&&(e||!n.name.startsWith("."))),s=i.slice(0,x).map(n=>({name:n.name,path:d.join(r,n.name),kind:"directory",hidden:n.name.startsWith("."),hasChildren:!0}));return s.sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"})),Y(r,s,i.length>x,"linux")}function Kt(t,e){const r=I(t),o=["$items = Get-ChildItem -LiteralPath $env:ACA_MACHINE_FS_PATH -Directory -Force -ErrorAction Stop | ForEach-Object {"," [PSCustomObject]@{ Name = $_.Name; FullName = $_.FullName; Attributes = $_.Attributes.ToString() }","}","@($items) | ConvertTo-Json -Compress"].join(`
|
|
5
|
+
`),i=Z(L(o,{ACA_MACHINE_FS_PATH:r})),s=i.map(n=>{const c=String(n.Attributes||"");return{name:String(n.Name||""),path:String(n.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(n=>n.name&&n.path&&!n.reparsePoint&&(e||!n.hidden)).slice(0,x).sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return Y(r,s,i.length>x,"win32")}function Y(t,e,r,o){const i=o==="win32"?d.win32:d.posix,s=i.parse(t).root,n=h(t,o)===h(s,o)?null:i.dirname(t);return{platform:o,path:t,parentPath:n,breadcrumbs:Xt(t,o),readable:Q(t,l.constants.R_OK),writable:Q(t,l.constants.W_OK),items:e,truncated:r}}function Xt(t,e){const r=e==="win32"?d.win32:d.posix,o=r.parse(t),i=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let n=o.root;for(const c of i)n=r.join(n,c),s.push({label:c,path:n});return s}async function Vt(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const i=I(String(t.path||""));l.accessSync(i,l.constants.R_OK|l.constants.W_OK);const s=k().machineId,c=(await E("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(a=>(!a.machine_id||a.machine_id===s)&&h(a.root_path)===h(i)),u=c||(await E("POST","/api/projects",{projectId:F(),workspaceId:e,name:r,rootPath:i,source:"aica",projectType:o})).item;return ut(Yt(u)),{project:u,duplicate:!!c}}function Yt(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function I(t){if(!t.trim()||!d.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(Jt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return Qt(r),r}function p(t){const e=$(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function $(t){const e=mt(t);if(!e||!d.isAbsolute(e))throw new Error("项目根目录无效。");return d.resolve(e)}function g(t){const e=t.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if(!e)return"";if(e.includes("\0")||e.split("/").some(r=>!r||r==="."||r===".."))throw new Error("项目相对路径无效。");return e}function v(t,e,r){const o=e?d.join(t,...e.split("/")):t,i=l.realpathSync.native(o),s=d.relative(t,i);if(s.startsWith("..")||d.isAbsolute(s))throw new Error("目录超出项目范围。");const n=l.statSync(i);if(r&&!n.isDirectory())throw new Error("请求路径不是目录。");return i}function J(t,e){return d.relative(t,e).split(d.sep).join("/")}function Jt(t){const e=process.platform==="win32"?d.win32:d.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Qt(t){const e=process.platform==="win32"?d.win32:d.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Q(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function Z(t){if(!t)return[];const e=JSON.parse(t);return Array.isArray(e)?e.filter(r=>!!(r&&typeof r=="object")):e&&typeof e=="object"?[e]:[]}function Zt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function qt(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{_t as cleanupWorktree,At as commitProjectUploadTempFile,St as commitWorktree,h as comparableMachinePath,It as getProjectGitCommit,Dt as getProjectGitDiff,Rt as getProjectGitLog,B as getProjectGitStatus,C as getWorktreeStatus,Wt as listMachineDirectory,Gt as listMachineFilesystemRoots,Pt as listProjectDirectory,bt as mutateProjectFiles,xe as startMachineFilesystemWorkerLoop,xt as uploadProjectFile};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import r from"node:fs";import d from"node:os";import i from"node:path";import{randomUUID as f}from"node:crypto";const s={"api.xiaomimimo.com":"xiaomi","token-plan-cn.xiaomimimo.com":"xiaomi-token-plan-cn","token-plan-ams.xiaomimimo.com":"xiaomi-token-plan-ams","token-plan-sgp.xiaomimimo.com":"xiaomi-token-plan-sgp"};function m(){if(process.env.MIMOCODE_HOME){if(!i.isAbsolute(process.env.MIMOCODE_HOME))throw new Error("MIMOCODE_HOME 必须为绝对路径。");return i.join(process.env.MIMOCODE_HOME,"data","auth.json")}return i.join(process.env.XDG_DATA_HOME||i.join(d.homedir(),".local","share"),"mimocode","auth.json")}function v(){return!!(process.env.MIMOCODE_AUTH_CONTENT||process.env.XIAOMI_API_KEY)}function M(o){const t=o;if(!t||typeof t.sk!="string"||!t.sk.trim()||t.sk.length>8192||typeof t.uid!="string"||!t.uid||t.uid.length>200||typeof t.url!="string")throw new Error("invalid_credential");const e=new URL(t.url);if(e.protocol!=="https:"||e.username||e.password||e.port||!Object.hasOwn(s,e.hostname)||!/^\/v1\/?$/.test(e.pathname)||e.search||e.hash)throw new Error("invalid_endpoint");return{type:"api",key:t.sk,metadata:{uid:t.uid,base_url:e.href.replace(/\/$/,"")}}}function p(o){try{const t=JSON.parse(r.readFileSync(o,"utf8"));if(!t||typeof t!="object"||Array.isArray(t))throw new Error("invalid_store");return t}catch(t){if(t.code==="ENOENT")return{};throw new Error("无法读取 MiMo 凭据文件,请先检查文件格式和权限。")}}function x(o=m()){return Object.entries(p(o)).flatMap(([t,e])=>{if(t!=="xiaomi"&&!Object.values(s).includes(t))return[];const n=e;if(!n||n.type!=="api"||!n.key)return[];const c=n.metadata?.base_url,l=Object.keys(s).map(a=>`https://${a}/v1`).find(a=>c===a||c===`${a}/`)??(c?"":"https://api.xiaomimimo.com/v1");return[{id:typeof n.metadata?.uid=="string"?n.metadata.uid.slice(0,200):"",provider:t,endpoint:l}]})}function u(o,t){r.mkdirSync(i.dirname(o),{recursive:!0});const e=`${o}.${f()}.tmp`;try{r.writeFileSync(e,JSON.stringify(t,null,2),{mode:384,flag:"wx"}),r.renameSync(e,o)}finally{r.rmSync(e,{force:!0})}}function w(o,t=m()){const e=p(t);e.xiaomi=o,u(t,e)}function k(o=m()){const t=p(o);for(const e of Object.values(s))delete t[e];u(o,t)}export{x as accounts,m as credentialFile,v as environmentAuth,k as removeCredentials,w as saveCredential,M as validateCredential};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createDecipheriv as l,createHash as o,createPrivateKey as p,createPublicKey as f,diffieHellman as y,generateKeyPairSync as u}from"node:crypto";import{validateCredential as h}from"./credentials.js";function b(){const t=u("x25519",{publicKeyEncoding:{type:"spki",format:"der"},privateKeyEncoding:{type:"pkcs8",format:"der"}});return{publicKey:t.publicKey.toString("base64url"),privateKey:t.privateKey}}function g(t,r){if(r=r.trim(),/^https?:\/\//i.test(r)){const e=new URL(r);if(e.protocol!=="http:"||!["localhost","127.0.0.1","[::1]"].includes(e.hostname)||!e.port||e.pathname!=="/auth"||e.username||e.password||e.hash||e.searchParams.size!==1||e.searchParams.getAll("u").length!==1)throw new Error("invalid_callback");r=e.searchParams.get("u")||""}if(!/^[A-Za-z0-9_-]{81,16384}$/.test(r))throw new Error("invalid_code");const a=Buffer.from(r,"base64url"),c=f({key:Buffer.concat([Buffer.from("302a300506032b656e032100","hex"),a.subarray(0,32)]),format:"der",type:"spki"}),i=y({privateKey:p({key:t,format:"der",type:"pkcs8"}),publicKey:c}),s=o("sha256").update(i).digest();try{const e=l("aes-256-gcm",s,a.subarray(32,44));e.setAuthTag(a.subarray(-16));const n=Buffer.concat([e.update(a.subarray(44,-16)),e.final()]);try{return h(JSON.parse(n.toString("utf8")))}finally{n.fill(0)}}finally{i.fill(0),s.fill(0)}}export{b as createLoginKeys,g as decryptCredential};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let o=0,e=!1;function i(){if(e)throw new Error("MiMo 账号正在登录或退出,请完成后重试。");const r=n("mimo");o++;let t=!1;return()=>{t||(t=!0,o--,r())}}function s(){if(e||o)throw new Error("MiMo 正在执行任务,请稍后再登录或退出。");const r=n("mimo");return e=!0,()=>{e=!1,r()}}import{enterProviderUse as n}from"../provider-updates/gate.js";export{s as beginMimoAuthChange,i as enterMimoTask};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as y,randomUUID as v}from"node:crypto";import M from"node:os";import{createServer as k}from"node:http";import{defaultAcpRuntimePool as d}from"../../acp/client/acp-runtime-pool.js";import{managementActivity as A}from"../management/activity.js";import{accounts as x,credentialFile as C,environmentAuth as h,removeCredentials as E,saveCredential as b}from"./credentials.js";import{createLoginKeys as H,decryptCredential as q}from"./crypto.js";import{beginMimoAuthChange as p}from"./gate.js";class _{options;flow;queue=Promise.resolve();terminal;stopping=!1;constructor(e={}){this.options=e}execute(e,r={}){const s=this.queue.then(async()=>{if(this.stopping)throw new Error("Worker 正在停止。");if(e==="status")return this.status();if(e==="start")return this.start(r.callbackPort);if(e==="complete")return this.complete(String(r.flowId||""),String(r.code||"").trim());if(e==="cancel")return this.requireFlow(String(r.flowId||"")),this.finish("cancelled"),this.status();if(e==="logout")return this.logout();throw new Error("不支持的 MiMo 账号操作。")});return this.queue=s.catch(()=>{}),s}async stop(){this.stopping=!0,await this.queue,this.finish("cancelled")}file(){return this.options.file??C()}status(){if(this.flow)return{...this.flow.snapshot};if(h())return{state:"environment",message:"使用 Worker 环境变量凭据,网页不能更改或退出。"};const e=x(this.file());return e.length?{state:"configured",accounts:e,message:"已保存本机凭据;有效性以实际模型请求为准。请刷新模型列表,选择账号可用的 Xiaomi 或对应 Token Plan 模型。"}:this.terminal??{state:"signed_out"}}async start(e){if(this.flow||h())return this.status();if(e!==void 0&&(!Number.isInteger(e)||Number(e)<1024||Number(e)>65535))throw new Error("回调端口无效。");const r=p(),s=A.track("mimo-login"),t={id:v(),keys:H(),release:()=>{r(),s()},snapshot:{state:"waiting"}};try{await d.retireProviderRuntimes("mimocode");let l=Number(e);if(!l){const i=k((n,o)=>{o.setHeader("Cache-Control","no-store"),o.setHeader("Referrer-Policy","no-referrer");const m=new URL(n.url||"/","http://localhost"),u=t.server?.address(),w=u&&typeof u!="string"?`localhost:${u.port}`:"",f=n.headers.origin;if(n.method!=="GET"||m.pathname!=="/auth"||n.headers.host!==w||f&&f!=="https://platform.xiaomimimo.com"){o.writeHead(404).end();return}const g=m.searchParams.get("u")||"";this.execute("complete",{flowId:t.id,code:g}).then(()=>{o.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"}).end("MiMo 登录完成,请返回 ACA。")},()=>{o.writeHead(400).end("Authorization failed. Return to ACA and retry.")})});t.server=i,i.maxHeadersCount=30,i.headersTimeout=5e3,i.requestTimeout=5e3,await new Promise((n,o)=>{i.once("error",o),i.listen(0,"127.0.0.1",()=>n())});const a=i.address();if(!a||typeof a=="string")throw new Error("回调监听启动失败。");l=a.port}const c=i=>`https://platform.xiaomimimo.com/authorize?${new URLSearchParams({pk:t.keys.publicKey,redirect_uri:i,kn:"mimocode",key_name:`aca-mimocode-${y("sha256").update(`${M.hostname()}:${this.file()}`).digest("hex").slice(0,12)}`,app:"ACA"})}`;return t.snapshot={state:"waiting",flowId:t.id,authUrl:c(`http://localhost:${l}/`),manualUrl:c("https://platform.xiaomimimo.com/authorize/code/callback"),expiresAtMs:Date.now()+(this.options.timeoutMs??3e5)},this.flow=t,this.terminal=void 0,t.timer=setTimeout(()=>{const i=this.queue.then(()=>{this.flow===t&&this.finish("expired")});this.queue=i.catch(()=>{})},this.options.timeoutMs??3e5),t.timer.unref(),this.status()}catch{throw t.server?.close(),t.keys.privateKey.fill(0),t.release(),new Error("无法准备 MiMo 登录,请检查 Worker 的本机网络与文件权限。")}}requireFlow(e){if(!this.flow||this.flow.id!==e||Date.now()>=this.flow.snapshot.expiresAtMs)throw new Error("MiMo 登录已结束或过期,请重新发起。");return this.flow}async complete(e,r){const s=this.requireFlow(e);let t;try{t=q(s.keys.privateKey,r)}catch{throw new Error("授权码或回调地址无效、与当前登录不匹配或服务地址不受支持,请重新授权。")}if(h())throw new Error("Worker 已切换为环境变量凭据,请取消本次登录。");try{b(t,this.file())}catch{throw new Error("无法保存 MiMo 凭据,请检查 Worker 文件权限后重试。")}return this.finish("configured"),this.options.changed?.().catch(()=>{}),this.status()}finish(e){const r=this.flow;r&&(this.flow=void 0,clearTimeout(r.timer),r.server?.close(),r.server?.closeIdleConnections(),r.keys.privateKey.fill(0),r.release(),this.terminal=e==="configured"?void 0:{state:e})}async logout(){if(h())return this.status();if(this.flow)throw new Error("请先取消正在进行的 MiMo 登录。");const e=p();try{return await d.retireProviderRuntimes("mimocode"),E(this.file()),this.terminal=void 0,this.options.changed?.().catch(()=>{}),this.status()}finally{e()}}}export{_ as MimoAuthManager};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{MimoAuthManager as e}from"./mimo-auth/manager.js";import{resetMimoCapabilities as a,sendHeartbeat as t}from"./heartbeat.js";const n=new e({changed:async()=>{a(),await t(void 0,{onlyMimo:!0})}});export{n as mimoAuthManager};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stripVTControlCharacters as C}from"node:util";function c(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function r(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0?t:void 0}function S(t){t=C(t);const l=[],m=new Set,o=[...t.matchAll(/^([\w.-]+\/[\w.-]+)(?:[ \t]+[—–][ \t]+[^\r\n]*)?[ \t]*\r?\n/gm)];for(let n=0;n<o.length;n++){const i=o[n][1];if(m.has(i))continue;const e=t.slice(o[n].index+o[n][0].length,o[n+1]?.index).trim();let a;try{a=c(JSON.parse(e))}catch{continue}if(!Object.keys(a).length)continue;const p=c(a.cost),y=c(p.cache),g=c(a.limit),u={input:r(p.input),output:r(p.output),cache:{read:r(y.read),write:r(y.write)}},f={context:r(g.context),input:r(g.input),output:r(g.output)},d=c(a.capabilities),h=Object.keys(c(a.variants)).filter(s=>/^[\w-]{1,64}$/.test(s)),w=[u.input,u.output,u.cache.read,u.cache.write].every(s=>s===0),b=typeof a.name=="string"?a.name.slice(0,200):i,x={cost:u,limit:f,capabilities:{reasoning:d.reasoning===!0,toolcall:d.toolcall===!0,attachment:d.attachment===!0,input:Object.fromEntries(["text","image","audio","video","pdf"].map(s=>[s,c(d.input)[s]===!0]))},supportedReasoningEfforts:h,defaultReasoningEffort:h.includes("high")?"high":h[0]||"",catalogSource:"mimo-cli"};l.push({modelId:i,name:w&&!/\bfree\b/i.test(b)?`${b} (free)`:b,description:f.context?`上下文 ${f.context.toLocaleString("en-US")} tokens`:"上下文大小未知",metadata:x}),m.add(i)}return l}function O(t,l,m=!1,o=""){t=t.map(e=>({...e,metadata:{...e.metadata,catalogFetchedAt:l,catalogStale:m}}));const n=t,i=[{id:"agent",name:"Agent"},{id:"agent-full-access",name:"Agent (full access)"}];return{source:"mimo-cli",fetchedAt:l,stale:m,modelCatalogAuthoritative:!0,contextUsage:!0,contextCompaction:!0,models:n,modes:i,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:i.map(e=>({value:e.id,name:e.name}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:o.trim().toLowerCase()==="default"?"":o,options:n.map(e=>({value:e.modelId,name:e.name,description:e.description,metadata:e.metadata}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",options:[]}]}}export{O as mimoCapabilities,S as parseMimoModels,c as record};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFile as f}from"node:child_process";import d from"node:os";import{resolveInstalledLaunch as m}from"../provider-install-paths.js";import{enterMimoTask as c}from"../mimo-auth/gate.js";import{acquireProviderUse as u}from"../provider-updates/gate.js";import{mimoCapabilities as p,parseMimoModels as g}from"./catalog.js";const w=30*6e4,A=6e4;class y{run;now;snapshot={models:[],fetchedAt:0,stale:!0};flight=null;generation=0;retryAt=0;forcedAt=0;forceFlight=!1;flightGeneration=0;refreshRequired=!1;constructor(t,e=Date.now){this.run=t,this.now=e}peek(){return this.snapshot}reset(t=!1){this.generation++,this.retryAt=0,this.forcedAt=0,this.refreshRequired||=t,this.snapshot=t?{models:[],fetchedAt:0,stale:!0}:{...this.snapshot,stale:!0}}async read(t=!1){if(this.flight){const i=this.forceFlight,n=this.flightGeneration,a=await this.flight;return n!==this.generation?this.read(t):t&&!i?this.read(!0):a}const e=this.now();if(t?e-this.forcedAt<3e4:e<this.retryAt||!this.snapshot.stale&&e-this.snapshot.fetchedAt<w)return this.snapshot;t&&(this.forcedAt=e);const r=this.generation;this.flightGeneration=r,this.forceFlight=t,this.flight=(async()=>{try{const i=g(await this.run(t||this.refreshRequired));if(!i.length)throw new Error("empty-model-catalog");r===this.generation&&(this.snapshot={models:i,fetchedAt:this.now(),stale:!1},this.refreshRequired=!1)}catch{r===this.generation&&(this.snapshot={...this.snapshot,stale:!0},this.retryAt=this.now()+A)}return this.snapshot})();try{return await this.flight}finally{this.flight=null}}}async function M(s){const t=await u("mimo");let e;try{e=c();const{command:r,args:i}=m("mimo");return await new Promise((n,a)=>{f(r,[...i,"models","--verbose",...s?["--refresh"]:[]],{cwd:d.homedir(),windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:4*1024*1024},(h,l)=>h?a(h):n(l))})}finally{e?.(),t()}}const o=new y(M);function F(){o.reset()}async function T(){let s=o.peek();return s.models.length?o.read():s=await o.read(),p(s.models,s.fetchedAt,s.stale,process.env.ACA_MIMO_DEFAULT_MODEL||"")}export{y as MimoModelCatalog,o as mimoModelCatalog,T as readMimoCapabilities,F as resetMimoModelCatalog};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import w from"node:fs";import y from"node:path";import C from"node:os";import{randomUUID as E}from"node:crypto";import{record as d}from"./catalog.js";import{startOpenCodeLocalApi as v}from"./local-server.js";import{beginOpenCodeAuthChange as g}from"./gate.js";import{enterProviderUse as A}from"../provider-updates/gate.js";import{defaultAcpRuntimePool as O}from"../../acp/client/acp-runtime-pool.js";import{managementActivity as T}from"../management/activity.js";class M{options;flow;queue=Promise.resolve();terminal;stopping=!1;constructor(e={}){this.options=e}execute(e,t={}){const s=this.queue.then(async()=>{if(this.stopping)throw new Error("Worker 正在停止。");if(e==="status")return this.flow?.snapshot??this.status();if(e==="start")return this.start(t);if(e==="complete"){const r=this.requireFlow(t.flowId);if(r.snapshot.method!=="code"||r.completing)throw new Error("OpenCode 当前授权不能提交授权码。");const i=String(t.code||"").trim();if(!i||i.length>16384)throw new Error("OpenCode 授权码无效。");return r.completing=!0,this.complete(r,i),r.snapshot}if(e==="cancel"){const r=this.requireFlow(t.flowId);return await this.finish(r,"cancelled"),this.terminal}if(e==="save_key"||e==="logout")return this.change(e,t);throw new Error("不支持的 OpenCode 认证操作。")});return this.queue=s.catch(()=>{}),s}async stop(){this.stopping=!0,await this.queue,this.flow&&await this.finish(this.flow,"cancelled")}open(){return(this.options.api??v)()}credentials(){try{if(process.env.OPENCODE_AUTH_CONTENT)return d(JSON.parse(process.env.OPENCODE_AUTH_CONTENT));const e=this.options.file??y.join(process.env.XDG_DATA_HOME||y.join(C.homedir(),".local","share"),"opencode","auth.json");if(!w.existsSync(e))return{};if(w.statSync(e).size>1024*1024)throw new Error("oversize");return d(JSON.parse(w.readFileSync(e,"utf8")))}catch{throw new Error("无法读取 OpenCode 凭据,请检查本机文件格式及权限。")}}async accounts(e){const[t,s]=await Promise.all([e.request("/provider"),e.request("/provider/auth")]),r=d(t),i=d(s),p=this.credentials(),a=new Set(Array.isArray(r.connected)?r.connected:[]);if(!Array.isArray(r.all))throw new Error("OpenCode 认证响应不兼容,请升级 CLI 后重试。");return r.all.slice(0,1e3).flatMap(c=>{const u=d(c),o=String(u.id||"");if(!/^[\w.-]{1,128}$/.test(o))return[];const h=d(p[o]);return[{id:o,name:typeof u.name=="string"?u.name.slice(0,200):o,connected:a.has(o),credential:process.env.OPENCODE_AUTH_CONTENT&&h.type?"environment":typeof h.type=="string"&&["api","oauth","wellknown"].includes(h.type)?h.type:"none",methods:Array.isArray(i[o])?i[o].slice(0,30).flatMap((m,f)=>{const n=d(m);return n.type!=="oauth"&&n.type!=="api"?[]:[{index:f,label:typeof n.label=="string"?n.label.slice(0,200):String(n.type),type:n.type,supported:!Array.isArray(n.prompts)||n.prompts.length===0}]}):[]}]})}async status(){const e=A("opencode");let t;try{t=await this.open();const s=await this.accounts(t);return{...this.terminal,state:this.terminal?.state??(s.some(r=>r.credential!=="none")?"configured":"ready"),accounts:s,message:this.terminal?.message??"已连接表示 OpenCode 已加载此服务商,可能使用环境变量、配置文件或免费模型;不代表已验证密钥。"}}finally{await t?.close(),e()}}async change(e,t){if(this.flow)throw new Error("请先完成或取消 OpenCode 授权。");if(process.env.OPENCODE_AUTH_CONTENT)throw new Error("OpenCode 使用环境变量认证,网页不能修改,请调整 Worker 环境。");const s=g();let r,i;try{r=await this.open();const p=await this.accounts(r),a=String(t.providerId||"");if(!p.some(o=>o.id===a))throw new Error("OpenCode 服务商无效,请刷新状态。");const c=String(t.apiKey||"").trim();if(e==="save_key"&&(!c||c.length>16384))throw new Error("OpenCode API Key 无效。");if(e==="logout"&&t.confirmed!==!0)throw new Error("请确认移除此服务商的本机凭据。");if(await O.retireProviderRuntimes("opencode"),(e==="save_key"?await r.request(`/auth/${encodeURIComponent(a)}`,"PUT",{type:"api",key:c}):await r.request(`/auth/${encodeURIComponent(a)}`,"DELETE"))!==!0)throw new Error("OpenCode 未能完成认证操作,请检查 CLI 版本、服务商配置及网络。");this.terminal=void 0,i={state:e==="save_key"?"configured":"ready",accounts:p.map(o=>o.id===a?{...o,credential:e==="save_key"?"api":"none"}:o),message:e==="save_key"?"OpenCode API Key 已保存,有效性以实际模型请求为准。":"已移除此服务商的本机凭据,环境变量和项目配置仍可能生效。"}}finally{await r?.close(),s()}try{await this.options.changed?.()}catch{i.message+="模型目录同步未完成,请稍后刷新。"}return i}async start(e){if(this.flow)throw new Error("请先完成或取消 OpenCode 授权。");if(process.env.OPENCODE_AUTH_CONTENT)throw new Error("OpenCode 使用环境变量认证,网页不能修改,请调整 Worker 环境。");const t=g(),s=T.track("opencode-login"),r=()=>{t(),s()};let i;try{i=await this.open();const p=await this.accounts(i),a=String(e.providerId||""),c=Number(e.method);if(!p.find(l=>l.id===a)?.methods.find(l=>l.index===c&&l.type==="oauth"&&l.supported))throw new Error("此 OpenCode 登录方式需要在设备终端执行 opencode auth login。");await O.retireProviderRuntimes("opencode");const o=d(await i.request(`/provider/${encodeURIComponent(a)}/oauth/authorize`,"POST",{method:c})),h=new URL(String(o.url||""));if(h.protocol!=="https:"||h.username||h.password||o.method!=="auto"&&o.method!=="code")throw new Error("OpenCode 返回了不受支持的授权地址。");const m=E(),f=Date.now()+(this.options.timeoutMs??5*6e4),n={id:m,providerId:a,method:c,api:i,release:r,completing:o.method==="auto",timer:setTimeout(()=>{this.finish(n,"expired")},this.options.timeoutMs??5*6e4),snapshot:{state:"waiting",flowId:m,providerId:a,authUrl:h.href,method:o.method,instructions:typeof o.instructions=="string"?o.instructions.slice(0,2e3):"",expiresAtMs:f}};return n.timer.unref(),this.flow=n,this.terminal=void 0,o.method==="auto"&&this.complete(n),n.snapshot}catch(p){throw await i?.close(),r(),p}}requireFlow(e){if(!this.flow||this.flow.id!==e)throw new Error("OpenCode 授权已结束或过期,请重新发起。");return this.flow}async complete(e,t){try{if(await e.api.request(`/provider/${encodeURIComponent(e.providerId)}/oauth/callback`,"POST",{method:e.method,...t?{code:t}:{}},this.options.timeoutMs??3e5)!==!0)throw new Error("oauth-failed");await this.finish(e,"configured")}catch{await this.finish(e,"failed")}}async finish(e,t){this.flow===e&&(this.flow=void 0,clearTimeout(e.timer),await e.api.close(),e.release(),this.terminal={state:t,message:t==="configured"?"OpenCode 服务商授权已保存,有效性以实际请求为准。":t==="failed"?"OpenCode 授权失败,请检查服务商与网络;需要 localhost 回调的登录请在 Worker 所在设备完成。":t==="expired"?"OpenCode 授权已过期。":"OpenCode 授权已取消,请刷新状态确认本机凭据。"},await this.options.changed?.().catch(()=>{}))}}export{M as OpenCodeAuthManager};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stripVTControlCharacters as x}from"node:util";function c(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}const i=t=>typeof t=="number"&&Number.isFinite(t)&&t>=0?t:void 0;function O(t){t=x(t);const n=[...t.matchAll(/^([\w.-]+\/[^\s{}]+)[ \t]*\r?\n/gm)],r=new Map;for(let o=0;o<n.length;o++){const a=n[o][1];let e;try{e=c(JSON.parse(t.slice(n[o].index+n[o][0].length,n[o+1]?.index).trim()))}catch{continue}if(!Object.keys(e).length||r.has(a))continue;const d=c(e.cost),g=c(d.cache),p=c(e.limit),u=c(e.capabilities),l={input:i(d.input),output:i(d.output),cache:{read:i(g.read),write:i(g.write)}},m={context:i(p.context),input:i(p.input),output:i(p.output)},h=Object.keys(c(e.variants)).filter(s=>/^[\w-]{1,64}$/.test(s)),y=h.length?[...new Set([...h,"default"])]:[],b=[l.input,l.output,l.cache.read,l.cache.write].every(s=>s===0),f=typeof e.name=="string"?e.name.slice(0,200):a;r.set(a,{modelId:a,name:b&&!/\bfree\b/i.test(f)?`${f} (free)`:f,description:m.context?`上下文 ${m.context.toLocaleString("en-US")} tokens`:"上下文大小未知",metadata:{catalogSource:"opencode-cli",cost:l,limit:m,supportedReasoningEfforts:y,defaultReasoningEffort:y.length?"default":"",capabilities:{reasoning:u.reasoning===!0,toolcall:u.toolcall===!0,input:Object.fromEntries(["text","image","audio","video","pdf"].map(s=>[s,c(u.input)[s]===!0]))}}})}return[...r.values()]}function w(t,n,r){const o=t.map(e=>({...e,metadata:{...e.metadata,catalogFetchedAt:n,catalogStale:r}})),a=[{id:"plan",name:"Plan"},{id:"build",name:"Build"},{id:"agent-full-access",name:"Agent (full access)"}];return{source:"opencode-cli",fetchedAt:n,stale:r,modelCatalogAuthoritative:!0,contextUsage:!0,contextCompaction:!0,models:o,modes:a,configOptions:[{id:"model",name:"Model",category:"model",type:"select",currentValue:process.env.ACA_OPENCODE_DEFAULT_MODEL?.trim()||"",options:o.map(e=>({value:e.modelId,name:e.name,description:e.description,metadata:e.metadata}))},{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:a.map(e=>({value:e.id,name:e.name}))},{id:"effort",name:"Effort",category:"thought_level",type:"select",options:[]}]}}export{w as openCodeCapabilities,O as parseOpenCodeModels,c as record};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{enterProviderUse as t}from"../provider-updates/gate.js";let o=0,r=!1;function f(){if(r)throw new Error("OpenCode 认证正在变更,请完成或取消授权后重试。");const n=t("opencode");o++;let e=!1;return()=>{e||(e=!0,o--,n())}}function a(){if(r||o)throw new Error("OpenCode 正在执行任务或授权,请稍后重试。");const n=t("opencode");r=!0;let e=!1;return()=>{e||(e=!0,r=!1,n())}}export{a as beginOpenCodeAuthChange,f as enterOpenCodeTask};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawn as E}from"node:child_process";import{randomBytes as y}from"node:crypto";import g from"node:os";import{resolveInstalledLaunch as O}from"../provider-install-paths.js";import{acpChildEnvironment as S}from"../process-identity.js";async function v(){const{command:f,args:w}=O("opencode"),l=y(32).toString("hex"),m=[...w,"serve","--hostname","127.0.0.1","--port","0"],e=E(f,m,{cwd:g.homedir(),windowsHide:!0,stdio:"pipe",env:S(f,m,{OPENCODE_SERVER_USERNAME:"aca",OPENCODE_SERVER_PASSWORD:l})});let d=!1;const p=async()=>{d||(d=!0,!(e.exitCode!==null||e.signalCode!==null)&&(e.kill(),await new Promise(r=>{const c=setTimeout(()=>{e.kill("SIGKILL"),r()},2e3);e.once("exit",()=>{clearTimeout(c),r()})}),e.stdout.destroy(),e.stderr.destroy(),e.stdin.destroy()))};let h;try{h=await new Promise((r,c)=>{let i="";const u=setTimeout(()=>a(new Error("OpenCode 本机认证服务启动超时。")),25e3),s=n=>{i=(i+n.toString()).slice(-32768);const t=/opencode server listening on http:\/\/127\.0\.0\.1:(\d+)/.exec(i);t&&Number(t[1])>0&&Number(t[1])<=65535&&a(void 0,`http://127.0.0.1:${t[1]}`)},o=()=>a(new Error("无法启动 OpenCode,请检查安装状态。")),a=(n,t)=>{clearTimeout(u),e.stdout.off("data",s),e.off("error",o),e.off("exit",o),n?c(n):r(t)};e.stdout.on("data",s),e.once("error",o),e.once("exit",o),e.stderr.resume()}),e.stdout.resume(),e.on("error",()=>{})}catch(r){throw await p(),r}return{close:p,async request(r,c="GET",i,u=25e3){if(d)throw new Error("OpenCode 本机认证服务已停止。");const s=await fetch(h+r,{method:c,redirect:"error",signal:AbortSignal.timeout(u),headers:{authorization:`Basic ${Buffer.from(`aca:${l}`).toString("base64")}`,"content-type":"application/json"},...i===void 0?{}:{body:JSON.stringify(i)}});if(!s.ok)throw await s.body?.cancel(),new Error("OpenCode 未能完成认证操作,请检查 CLI 版本、服务商配置及网络。");const o=s.body?.getReader();if(!o)return null;const a=[];let n=0;try{for(;;){const t=await o.read();if(t.done)break;if(n+=t.value.length,n>16*1024*1024)throw new Error("OpenCode 认证响应过大。");a.push(t.value)}}finally{await o.cancel().catch(()=>{})}return JSON.parse(Buffer.concat(a).toString("utf8"))}}}export{v as startOpenCodeLocalApi};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFile as l}from"node:child_process";import f from"node:os";import{resolveInstalledLaunch as d}from"../provider-install-paths.js";import{acquireProviderUse as c}from"../provider-updates/gate.js";import{openCodeCapabilities as p,parseOpenCodeModels as u}from"./catalog.js";class g{run;now;snapshot={models:[],fetchedAt:0,stale:!0};flight=null;generation=0;retryAt=0;forcedAt=-1/0;forcing=!1;flightGeneration=0;refreshRequired=!1;constructor(t=m,s=Date.now){this.run=t,this.now=s}peek(){return this.snapshot}reset(t=!1){this.generation++,this.retryAt=0,this.forcedAt=-1/0,this.refreshRequired||=t,this.snapshot={models:[],fetchedAt:0,stale:!0}}async read(t=!1){if(this.flight){const i=this.forcing,o=this.flightGeneration,r=await this.flight;return o!==this.generation?this.read(t):t&&!i?this.read(!0):r}const s=this.now();if(t?s-this.forcedAt<3e4:s<this.retryAt||!this.snapshot.stale&&s-this.snapshot.fetchedAt<30*6e4)return this.snapshot;t&&(this.forcedAt=s);const n=this.generation;this.flightGeneration=n,this.forcing=t,this.flight=(async()=>{try{const i=u(await this.run(t||this.refreshRequired));if(!i.length)throw new Error("empty-models");n===this.generation&&(this.snapshot={models:i,fetchedAt:this.now(),stale:!1},this.refreshRequired=!1)}catch{n===this.generation&&(this.snapshot={...this.snapshot,stale:!0},this.retryAt=this.now()+6e4)}return this.snapshot})();try{return await this.flight}finally{this.flight=null}}}async function m(e){const t=await c("opencode");try{const{command:s,args:n}=d("opencode");return await new Promise((i,o)=>l(s,[...n,"models","--verbose",...e?["--refresh"]:[]],{cwd:f.homedir(),windowsHide:!0,encoding:"utf8",timeout:25e3,maxBuffer:8*1024*1024},(r,h)=>r?o(r):i(h)))}finally{t()}}const a=new g;async function v(){let e=a.peek();return e.models.length?a.read():e=await a.read(),p(e.models,e.fetchedAt,e.stale)}export{g as OpenCodeModelCatalog,a as openCodeModelCatalog,v as readOpenCodeCapabilities};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{OpenCodeAuthManager as o}from"./auth.js";import{openCodeModelCatalog as t}from"./models.js";import{sendHeartbeat as n}from"../heartbeat.js";const s=new o({changed:async()=>{t.reset(),await n(void 0,{onlyOpenCode:!0})}});async function p(){const e=await t.read(!0);return await n(void 0,{onlyOpenCode:!0}),{count:e.models.length,fetchedAt:e.fetchedAt,stale:e.stale}}export{s as openCodeAuthManager,p as refreshOpenCodeModels};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:fs";import a from"node:path";import{Readable as
|
|
1
|
+
import e from"node:fs";import a from"node:path";import{Readable as y}from"node:stream";import{pipeline as l}from"node:stream/promises";import{createHash as S}from"node:crypto";import{providerPackages as h}from"./provider-install-paths.js";async function E(c,r,w,u=h.mimo.version){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 x=o==="linux"&&(e.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime),b=`mimocode-${o}-${process.arch}${process.arch==="x64"?"-baseline":""}${x?"-musl":""}`,n=o==="linux"?".tar.gz":".zip",m=`https://mimocode.cnbj1.mi-fds.com/mimocode/mimocode/releases/v${u}/${b}${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(y.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=S("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 $=a.join(s,o==="windows"?"mimo.exe":"mimo");e.chmodSync($,493),e.rmSync(t,{force:!0})}export{E as prepareMimoBinary};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import t from"node:fs";import s from"node:path";import{isSea as v}from"node:sea";import{getAcaHome as y}from"./paths.js";const a={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(a,e)}function g(e){return s.resolve(y(),"providers",e)}function b(e){return e===a.codex.version}function O(e){try{const o=g(e),n=JSON.parse(t.readFileSync(s.join(o,"current.json"),"utf8"));if(!/^[a-f0-9-]{36}$/.test(n.release))return null;if(e==="codex"){const r=JSON.parse(t.readFileSync(s.join(o,n.release,"node_modules",a.codex.package,"package.json"),"utf8"));if(!b(r.version))return null}return A(e,s.join(o,n.release))}catch{return null}}function S(){return v()||process.env.ACA_SINGLE_FILE_WORKER==="1"?process.env.ACA_PROVIDER_NODE||"node":process.execPath}function N(e,o=!1){const n=a[e],r=process.env[n.env];if(r)return{command:r,args:[]};const c=o?null:O(e);return c?_(c):{command:n.command,args:[]}}function A(e,o){const n=a[e],r=s.join(o,"node_modules",n.package);try{if(e==="mimo"){const p=s.join(r,"vendor",process.platform==="win32"?"mimo.exe":"mimo");return t.existsSync(p)?p:null}if(e==="opencode"){const l=`opencode-${process.platform==="win32"?"windows":process.platform}-${process.arch}`,m=process.platform==="linux"&&(t.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime)?"-musl":"",f=process.arch==="x64"?[`${l}-baseline${m}`,`${l}${m}`]:[`${l}${m}`];for(const x of f){const u=s.join(o,"node_modules",x,"bin",`${n.command}${process.platform==="win32"?".exe":""}`);if(t.existsSync(u))return u}return null}const c=JSON.parse(t.readFileSync(s.join(r,"package.json"),"utf8")),d=typeof c.bin=="string"?c.bin:c.bin?.[n.command];if(typeof d!="string")return null;const i=s.resolve(r,d);return!i.startsWith(r+s.sep)||!t.existsSync(i)?null:i}catch{return null}}function _(e){const o=t.openSync(e,"r");try{const n=Buffer.alloc(128);return t.readSync(o,n,0,n.length,0),/\.[cm]?js$/i.test(e)||/^#![^\r\n]*\bnode\b/.test(n.toString("utf8"))?{command:S(),args:[e]}:{command:e,args:[]}}finally{t.closeSync(o)}}export{b as compatibleCodexVersion,_ as entryLaunch,O as installedProviderEntry,E as isInstallProvider,A as packageEntry,g as providerInstallRoot,S as providerNode,a as providerPackages,N as resolveInstalledLaunch};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{providerUpdates as R}from"./provider-updates/service.js";import{versionFromOutput as U}from"./provider-updates/versions.js";import{acquireProviderSwitch as B}from"./provider-updates/gate.js";import{currentRelease as H,rollbackRelease as y,publishRelease as F}from"./provider-updates/releases.js";import{verifyProviderProtocol as W}from"./provider-updates/verify.js";import{defaultAcpRuntimePool as K}from"../acp/client/acp-runtime-pool.js";import{invalidateProviderCapabilities as V,refreshProviderCapabilities as q}from"./provider-updates/capabilities.js";import{resolveWorkBuddyExecutable as J}from"../acp/providers/workbuddy/launch.js";import{prepareMimoBinary as X}from"./provider-install-mimo.js";import{resolveCodexPath as C}from"../acp/providers/codex/codex-path.js";import E from"node:fs";import p from"node:path";import{spawn as S,execFileSync as Y}from"node:child_process";import{randomUUID as z}from"node:crypto";import{isInstallProvider as Q,providerPackages as w,providerInstallRoot as Z,providerNode as j,packageEntry as T,entryLaunch as x,resolveInstalledLaunch as ee,compatibleCodexVersion as te}from"./provider-install-paths.js";import{managementActivity as I}from"./management/activity.js";import{sendHeartbeat as re}from"./heartbeat.js";class se{statuses=new Map;active=null;stopping=!1;dependencies;constructor(e={}){this.dependencies={updates:R,nodeNpm:oe,run:ae,verify:W,changed:ie,...e}}operation(e){const t=String(e.provider||""),s=String(e.action||"");if(!Q(t)||!["status","check","install","upgrade","rollback"].includes(s))throw new Error("无效的 Provider 安装操作");if(s==="status")return this.snapshot(t);if(s==="check")return this.dependencies.updates.check(t,!0),this.snapshot(t);if(["installing","waiting"].includes(this.statuses.get(t)?.state||""))return this.snapshot(t);if(this.active||this.stopping||I.paused||I.stopping)return this.error(t,"Worker 正在安装其他 CLI 或维护,请稍后重试。");if(process.env[w[t].env]||t==="workbuddy"&&process.env.ACA_CODEBUDDY_COMMAND)return this.error(t,"此 Provider 已指定自定义命令,请按原安装方式升级。");const o=this.dependencies.updates.snapshot(t),u=s==="rollback"?y(t):null;if(s==="rollback"&&!u)return this.error(t,"没有可回退的兼容版本。");if(s==="upgrade"&&!o.canUpgrade)return this.error(t,o.reason||"没有可升级的版本,请先检查更新。");const l=u?.version||(s==="upgrade"?o.targetVersion:w[t].version);this.statuses.set(t,{state:"installing",message:s==="rollback"?"正在验证上一版本…":`正在下载安装 ${l},关闭页面后仍会继续。`});const i={done:Promise.resolve(),controller:new AbortController};return this.active=i,i.done=this.install(t,l,i,u).finally(()=>{this.active===i&&(this.active=null)}),this.snapshot(t)}snapshot(e){return{...this.statuses.get(e)||{state:"idle",message:""},update:this.dependencies.updates.snapshot(e),rollbackAvailable:!!y(e)}}error(e,t){return{state:"error",message:t,update:this.dependencies.updates.snapshot(e),rollbackAvailable:!!y(e)}}async install(e,t,s,o){const u=I.track("provider-install"),l=Z(e),i=z(),a=p.join(l,i);let f=!1,m,c="准备 Node/npm";const d=setTimeout(()=>{s.controller.abort(),s.child&&N(s.child)},15*6e4);try{let n,v;if(o){v=o.release?p.join(l,o.release):l;const h=o.release?T(e,v):null;if(o.release&&!h)throw new Error("missing-entry");n=h?$(e,h):ne(e)}else{E.mkdirSync(a,{recursive:!0});const{nodePath:h,npm:D}=this.dependencies.nodeNpm();c="下载 npm 包",await this.dependencies.run(h,[D,"install","--prefix",a,"--no-audit","--no-fund","--no-package-lock","--ignore-scripts","--include=optional","--engine-strict","--registry=https://registry.npmjs.org",`${w[e].package}@${t}`],a,s,10*6e4),e==="mimo"&&(c="下载 MiMoCode 原生程序",this.statuses.set(e,{state:"installing",message:"正在从小米官方下载 MiMoCode 程序…"}),await X(a,s.controller.signal,(G,M)=>this.dependencies.run(G,M,a,s,6e4),t));const A=T(e,a);if(!A)throw new Error("missing-entry");if(n=$(e,A),v=a,JSON.parse(E.readFileSync(p.join(a,"node_modules",w[e].package,"package.json"),"utf8")).version!==t)throw new Error("version-mismatch")}c="验证 CLI 版本",this.statuses.set(e,{state:"installing",message:`正在验证 ${t}…`});const b=await this.dependencies.run(n.command,[...n.args,"--version"],v,s,6e4);if(U(b.trim().split(/\r?\n/)[0])!==t)throw new Error("version-mismatch");c="验证协议兼容性",await this.dependencies.verify(e,n,v,s.controller.signal,h=>{s.child=h}),c="等待版本切换",this.statuses.set(e,{state:"waiting",message:"验证完成,等待当前任务或登录结束后切换版本…"}),m=await B(e,s.controller.signal);const L=e==="codex"?"codex-acp":e==="mimo"?"mimocode":e;await K.retireProviderRuntimes(L),s.controller.signal.throwIfAborted();const g=H(e),P=this.dependencies.updates.snapshot(e),_=g&&(e!=="codex"||te(g.version))?{release:g.release,version:g.version}:P.currentVersion?{release:null,version:P.currentVersion}:void 0;F(e,o||{release:i,version:t},_),f=!0,V(e);const k=`${o?"已回退":"已安装"}至 ${t}`;this.statuses.set(e,{state:"installing",message:`${k},正在重新获取模型与能力并同步设备状态…`,version:t}),m(),m=void 0;try{await this.dependencies.changed(e),this.statuses.set(e,{state:"installed",message:`${k},模型与能力已重新获取并同步。`,version:t})}catch{this.statuses.set(e,{state:"installed",message:`${k};模型与能力刷新或同步未完成,将在后续心跳重试。`,version:t})}}catch(n){this.statuses.set(e,{state:"error",message:n instanceof Error&&(n.message==="npm-ENOSPC"||n.code==="ENOSPC")?"Worker 磁盘空间不足,请清理空间后重试。原版本继续可用。":n instanceof Error&&n.message==="missing-npm"?"Worker 的 Node 环境缺少 npm,请安装含 npm 的 Node.js 后重试。":n instanceof Error&&n.message==="npm-EBADENGINE"?"当前 Node.js 不满足目标版本要求,请先升级 Node.js。原版本保持不变。":c==="验证协议兼容性"?"目标版本的协议握手失败或超时,原版本保持不变。请确认 Worker 已更新后重试;持续失败时检查目标程序是否能在设备上正常启动。":`${c}失败,原版本保持不变。请检查 Node.js 版本、网络和磁盘权限后重试。${n instanceof Error&&/^npm-(ETARGET|EAI_AGAIN|ENOTFOUND|EACCES|ENOSPC|ECONNRESET|ETIMEDOUT|EBADENGINE)$/.test(n.message)?`(${n.message})`:""}`})}finally{m?.(),clearTimeout(d);try{!f&&!o&&E.rmSync(a,{recursive:!0,force:!0})}catch{}u()}}async stop(){this.stopping=!0,this.active?.controller.abort(),this.active?.child&&N(this.active.child),await this.active?.done}}const O=new se;function Ce(r){return O.operation(r)}function Se(){return O.stop()}function $(r,e){return x(r==="codex"?C({env:{...process.env,CODEX_PATH:e}}):e)}function ne(r){return r==="codex"?x(C({skipInstalled:!0})):r==="workbuddy"?J("codebuddy",!0):ee(r,!0)}function oe(){const r=Y(j(),["-p","process.execPath"],{encoding:"utf8",timeout:8e3,windowsHide:!0}).trim(),e=[p.join(p.dirname(r),"node_modules/npm/bin/npm-cli.js"),p.resolve(p.dirname(r),"../lib/node_modules/npm/bin/npm-cli.js")].find(t=>E.existsSync(t));if(!e)throw new Error("missing-npm");return{nodePath:r,npm:e}}async function ie(r){const e=await q(r).catch(()=>!1);if(!(await re(void 0,{onlyProvider:r})).ok||!e)throw new Error("provider-refresh-incomplete")}function ae(r,e,t,s,o){return new Promise((u,l)=>{if(s.controller.signal.aborted)return l(new Error("stopping"));const i=S(r,e,{cwd:t,windowsHide:!0,detached:process.platform!=="win32",stdio:["ignore","pipe","pipe"],env:{...process.env,PATH:p.isAbsolute(r)?`${p.dirname(r)}${p.delimiter}${process.env.PATH||""}`:process.env.PATH}});s.child=i;let a="",f="";i.stdout?.on("data",d=>{f=(f+String(d)).slice(-16384)}),i.stderr?.on("data",d=>{a=(a+String(d)).slice(-16384)});let m=!1;const c=setTimeout(()=>{m=!0,N(i)},o);i.once("error",d=>{clearTimeout(c),l(d)}),i.once("close",d=>{clearTimeout(c),s.child=void 0,d===0&&!m&&!s.controller.signal.aborted?u(f):l(new Error(`npm-${/\b(ENOSPC|EACCES|ETARGET|EAI_AGAIN|ENOTFOUND|ECONNRESET|ETIMEDOUT|EBADENGINE)\b/.exec(a)?.[1]||"failed"}`))})})}function N(r){if(!(!r.pid||r.exitCode!==null||r.signalCode!==null))if(process.platform==="win32"){const e=S("taskkill",["/pid",String(r.pid),"/T","/F"],{windowsHide:!0,stdio:"ignore"});e.once("error",()=>{r.kill("SIGKILL")}),e.once("close",t=>{t!==0&&r.kill("SIGKILL")})}else try{process.kill(-r.pid,"SIGKILL")}catch{r.kill("SIGKILL")}}export{se as ProviderInstaller,Ce as providerInstallOperation,ae as runProviderInstallCommand,Se as stopProviderInstaller};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{resetProviderHealth as o}from"../provider-health.js";import{readCodexCapabilities as i,resetCodexCapabilities as t}from"../codex-capabilities.js";import{mimoModelCatalog as r}from"../mimo-models/service.js";import{openCodeModelCatalog as a}from"../opencode/models.js";import{clearWorkBuddyCapabilities as d}from"../../acp/providers/workbuddy/config.js";import{readWorkBuddyCapabilities as s,resetWorkBuddyDiscovery as c}from"../../acp/providers/workbuddy/discovery.js";function C(e){switch(o(),e){case"codex":t();break;case"mimo":r.reset(!0);break;case"opencode":a.reset(!0);break;case"workbuddy":d(),c();break}}async function f(e){switch(e){case"codex":return!!await i();case"mimo":return!(await r.read()).stale;case"opencode":return!(await a.read()).stale;case"workbuddy":return(await s()).source==="codebuddy-acp"}}export{C as invalidateProviderCapabilities,f as refreshProviderCapabilities};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{providerPackages as h}from"../provider-install-paths.js";import{newerVersion as i,stableVersion as u}from"./versions.js";const d=360*6e4;class w{read;latest;now;records=new Map;pending=new Map;controllers=new Set;stopped=!1;constructor(e,t=p,r=Date.now){this.read=e,this.latest=t,this.now=r}snapshot(e){const t=this.read(e),r=this.records.get(e),s=e==="codex"?h.codex.version:r?.latestVersion||null,o=r?.latestVersion||null,n=t.source!=="custom"&&i(s,t.currentVersion),c=t.source==="custom"?"使用自定义路径,请按原安装方式升级。":e==="codex"&&i(o,s)?"官方有新版,尚未纳入当前 Worker 的兼容版本;后续可能需要升级 Worker。":!t.currentVersion&&t.source!=="missing"?"无法识别当前版本,请检查 CLI。":"";return{...t,latestVersion:o,targetVersion:s,available:i(o,t.currentVersion)||i(s,t.currentVersion),canUpgrade:n,reason:c,checking:this.pending.has(e),checkedAtMs:r?.checkedAtMs||null,lastSuccessAtMs:r?.lastSuccessAtMs||null,checkError:r?.checkError||null}}check(e,t=!1){if(this.stopped)return Promise.resolve();const r=this.pending.get(e);if(r)return r;const s=this.records.get(e);if(s&&this.now()-s.checkedAtMs<(t?3e4:s.checkError?5*6e4:d))return Promise.resolve();const o=new AbortController;this.controllers.add(o);const n=setTimeout(()=>o.abort(),12e3),c=(async()=>{try{const l=u(await this.latest(e,o.signal));if(!l)throw new Error("invalid-version");this.stopped||this.records.set(e,{latestVersion:l,checkedAtMs:this.now(),lastSuccessAtMs:this.now(),checkError:null})}catch{this.stopped||this.records.set(e,{latestVersion:s?.latestVersion||null,checkedAtMs:this.now(),lastSuccessAtMs:s?.lastSuccessAtMs||null,checkError:"检查更新失败,请检查 Worker 网络后重试。"})}finally{clearTimeout(n),this.controllers.delete(o),this.pending.delete(e)}})();return this.pending.set(e,c),c}async stop(){this.stopped=!0;for(const e of this.controllers)e.abort();await Promise.allSettled(this.pending.values())}}async function p(a,e){const t=await fetch(`https://registry.npmjs.org/${encodeURIComponent(h[a].package)}/latest`,{signal:e,redirect:"error",headers:{Accept:"application/json"}});if(!t.ok)throw new Error("registry-failed");const r=t.body?.getReader();if(!r)throw new Error("missing-body");const s=[];let o=0;try{for(;;){const n=await r.read();if(n.done)break;if(o+=n.value.length,o>2*1024*1024)throw new Error("large-response");s.push(n.value)}}finally{await r.cancel()}return JSON.parse(Buffer.concat(s).toString("utf8")).version}export{w as ProviderUpdateChecker,d as UPDATE_INTERVAL_MS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setTimeout as n}from"node:timers/promises";const t=new Map,o=new Set;function c(e){if(e==="mimocode")return"mimo";if(e.includes("codex"))return"codex";if(e==="opencode"||e==="workbuddy")return e;throw new Error("未知 Provider")}function u(e){if(o.has(e))throw new Error("Provider 正在切换版本,请稍后重试。");t.set(e,(t.get(e)||0)+1);let r=!1;return()=>{r||(r=!0,t.set(e,(t.get(e)||1)-1))}}async function a(e,r){for(;o.has(e);)await n(50,void 0,{signal:r});return r?.throwIfAborted(),u(e)}async function s(e,r){for(;o.has(e)||t.get(e);)await n(100,void 0,{signal:r});return r.throwIfAborted(),o.add(e),()=>{o.delete(e)}}export{s as acquireProviderSwitch,a as acquireProviderUse,u as enterProviderUse,c as providerForRuntime};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import s from"node:fs";import o from"node:path";import{randomUUID as f}from"node:crypto";import{compatibleCodexVersion as m,packageEntry as i,providerInstallRoot as l,providerPackages as c}from"../provider-install-paths.js";import{stableVersion as u}from"./versions.js";const p=r=>typeof r=="string"&&/^[a-f0-9-]{36}$/.test(r);function y(r){try{const e=l(r),n=JSON.parse(s.readFileSync(o.join(e,"current.json"),"utf8"));if(!p(n.release)||!i(r,o.join(e,n.release)))return null;const t=JSON.parse(s.readFileSync(o.join(e,n.release,"node_modules",c[r].package,"package.json"),"utf8")).version;return u(t)?{release:n.release,version:t,previous:n.previous}:null}catch{return null}}function k(r){const e=y(r)?.previous;if(!e||!u(e.version)||r==="codex"&&!m(e.version))return null;if(e.release===null)return e;if(!p(e.release))return null;const n=o.join(l(r),e.release);try{return JSON.parse(s.readFileSync(o.join(n,"node_modules",c[r].package,"package.json"),"utf8")).version===e.version&&i(r,n)?e:null}catch{return null}}function R(r,e,n){const t=l(r);if(e.release===null){s.rmSync(o.join(t,"current.json"),{force:!0});return}const a=o.join(t,`${f()}.json`);try{s.writeFileSync(a,JSON.stringify({...e,...n?{previous:n}:{}})),s.renameSync(a,o.join(t,"current.json"))}finally{s.rmSync(a,{force:!0})}}export{y as currentRelease,R as publishRelease,k as rollbackRelease};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import a from"node:fs";import n from"node:path";import{createRequire as l}from"node:module";import{isSea as v}from"node:sea";import{providerHealthSnapshot as h}from"../provider-health.js";import{installedProviderEntry as y,providerInstallRoot as x,providerPackages as c}from"../provider-install-paths.js";import{resolveCodexPath as P}from"../../acp/providers/codex/codex-path.js";import{ProviderUpdateChecker as g}from"./checker.js";import{versionFromOutput as k}from"./versions.js";import{managementActivity as m}from"../management/activity.js";const b=l(v()?process.execPath:import.meta.url),p=new g(C);let o,i;function C(e){const r=h()[e],t=k(r.version);if(process.env[c[e].env]||e==="workbuddy"&&process.env.ACA_CODEBUDDY_COMMAND)return{currentVersion:t,source:"custom"};if(!r.available)return{currentVersion:t,source:"missing"};if(e!=="codex")return{currentVersion:t,source:y(e)?"managed":"system"};const s=P();if(u(s,x(e)))return{currentVersion:t,source:"managed"};try{const d=b.resolve("@openai/codex/bin/codex.js"),f=n.dirname(n.dirname(n.dirname(d)));if(u(s,f))return{currentVersion:t,source:"bundled"}}catch{}return{currentVersion:t,source:"system"}}function u(e,r){try{return a.realpathSync(e).startsWith(a.realpathSync(r)+n.sep)}catch{return!1}}function E(){if(o)return;const e=()=>{if(!(m.paused||m.stopping))for(const r of Object.keys(c))p.check(r)};i=setTimeout(e,5e3),i.unref(),o=setInterval(e,6e4),o.unref()}async function M(){clearTimeout(i),clearInterval(o),o=void 0,await p.stop()}export{p as providerUpdates,C as readProviderInstallation,E as startProviderUpdates,M as stopProviderUpdates};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{startAcpProcess as f,closeAcpProcess as m}from"../../acp/client/acp-process.js";import{AcpClient as l}from"../../acp/client/acp-client.js";import{JsonLineRpcClient as d}from"../../acp/client/json-rpc.js";async function b(e,t,n,r,i){r.throwIfAborted();const c=e==="codex"?["app-server","--stdio"]:e==="mimo"?["acp","--cwd",n]:e==="opencode"?["acp"]:["--acp"];e==="workbuddy"&&c.push("--tools","","--strict-mcp-config","--mcp-config",'{"mcpServers":{}}');const{child:o}=f(t.command,[...t.args,...c],n);i(o);const s=()=>{o.kill("SIGKILL")};r.addEventListener("abort",s,{once:!0});try{if(e==="codex"){const a=await new d(o).request("initialize",{clientInfo:{name:"aca-version-check",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},2e4);if(!a||typeof a!="object")throw new Error("invalid-handshake")}else if((await new l(o,()=>{}).initialize(2e4))?.protocolVersion!==1)throw new Error("invalid-handshake");r.throwIfAborted()}finally{r.removeEventListener("abort",s),await m(o),i()}}export{b as verifyProviderProtocol};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function n(e){return typeof e=="string"&&/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(e)&&e.split(".").every(r=>Number.isSafeInteger(Number(r)))?e:null}function i(e){const r=/(?:^|\s)v?(\d+\.\d+\.\d+)(?=$|\s)/.exec(e||"");return n(r?.[1])}function u(e,r){if(!n(e)||!n(r))return!1;const s=e.split(".").map(Number),o=r.split(".").map(Number);for(let t=0;t<3;t++)if(s[t]!==o[t])return s[t]>o[t];return!1}export{u as newerVersion,n as stableVersion,i as versionFromOutput};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{record as i}from"../../acp/providers/workbuddy/config.js";const h=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",hour:"2-digit",hourCycle:"h23"});function d(t){const e=Number(h.format(t));return e>=7&&e<19}async function w(t){try{const e=t.now??Date.now;if(!d(e()))return;const r=AbortSignal.timeout(8e3),o=async s=>{const n=await(t.fetch??fetch)(`https://www.codebuddy.cn/v2/billing/meter/${s}`,{method:"POST",headers:t.headers,redirect:"error",signal:r,body:"{}"});if(!n.ok){await n.body?.cancel();return}const c=i(await n.json());if(c.code===0)return i(c.data)},a=await o("checkin-activity-status");if(a?.active!==!0||a.today_checked_in!==!1||r.aborted||!d(e()))return;await o("daily-checkin")}catch{}}export{w as checkinWorkBuddy,d as inWorkBuddyCheckinWindow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createWorkBuddyAuthTransport as
|
|
1
|
+
import{createWorkBuddyAuthTransport as T}from"../../acp/providers/workbuddy/auth-transport.js";import{enterWorkBuddyTask as _}from"../../acp/providers/workbuddy/auth-gate.js";import{workBuddyRegion as R,workBuddyEnvironmentCredentials as S}from"../../acp/providers/workbuddy/auth-environment.js";import{record as s}from"../../acp/providers/workbuddy/config.js";import{checkinWorkBuddy as P}from"./checkin.js";function m(n,t=null){return{state:n,account:t,remaining:null,total:null,unlimited:!1,resources:[]}}function h(n){if(typeof n!="number"&&(typeof n!="string"||!/^-?\d+(?:\.\d+)?$/.test(n)))return;const t=Number(n);return Number.isFinite(t)?t:void 0}function A(n){const t=[];for(const r of n){const e=s(r);if(e.Status!==void 0&&![0,3].includes(Number(e.Status)))continue;const a=h(e.CycleCapacityRemainPrecise??e.CycleCapacityRemain??e.CapacityRemainPrecise??e.CapacityRemain),i=h(e.CycleCapacitySizePrecise??e.CycleCapacitySize??e.CapacitySizePrecise??e.CapacitySize),c=e.Unlimited===!0||e.Unlimited===1||i===-1;if(a===void 0||i===void 0||!c&&(i<0||a<0))throw new Error("invalid_credits");const g=typeof e.CycleEndTime=="string"&&e.CycleEndTime.length<=100?e.CycleEndTime:null;t.push({name:typeof e.PackageName=="string"?e.PackageName.slice(0,200):"积分套餐",remaining:a,total:i,unlimited:c,cycleEnd:g})}const o=t.some(r=>r.unlimited),l=r=>Math.round(t.reduce((e,a)=>e+a[r],0)*100)/100;return{remaining:o?null:l("remaining"),total:o?null:l("total"),unlimited:o,resources:t}}async function U(n={}){let t=null,o,l;try{l=_();const r=R();o=(n.transport??T)(),await o.initialize();const e=await o.billingIdentity();if(!e.account)return m(S()?"unsupported":"signed_out");if(t={...e.account,region:r,scope:e.enterpriseId.slice(0,200)},r==="ioa"||!e.token)return m("unsupported",t);const a=r==="internal"?"https://www.codebuddy.cn":"https://www.codebuddy.ai",i={Authorization:`Bearer ${e.token}`,"Content-Type":"application/json",Accept:"application/json","X-User-Id":t.id};e.enterpriseId&&(i["X-Enterprise-Id"]=e.enterpriseId,i["X-Tenant-Id"]=e.enterpriseId),n.allowCheckin&&r==="internal"&&await P({headers:i,fetch:n.fetch,now:n.now});const c=[],g=AbortSignal.timeout(25e3),C=new Date,w=new Date(C);w.setUTCFullYear(w.getUTCFullYear()+101);const b=p=>p.toISOString().slice(0,19).replace("T"," ");for(let p=1;p<=10;p++){const d=await(n.fetch??fetch)(`${a}/v2/billing/meter/get-user-resource`,{method:"POST",headers:i,redirect:"error",signal:g,body:JSON.stringify({PageNumber:p,PageSize:100,ProductCode:"p_tcaca",Status:[0,3],PackageEndTimeRangeBegin:b(C),PackageEndTimeRangeEnd:b(w)})});if(d.status===429){const f=d.headers.get("Retry-After"),E=f&&/^\d+$/.test(f)?Number(f)*1e3:Date.parse(f||"")-Date.now();return{...m("error",t),retryAfterMs:Number.isFinite(E)?Math.max(0,E):3e5}}if(d.status===401||d.status===403)return m("signed_out");if(!d.ok)throw new Error("credits_http_error");const u=s(await d.json());if(u.code!==void 0&&![0,"0"].includes(u.code))throw new Error("credits_business_error");const y=s(s(s(u.data).Response??u.Response).Data);if(s(s(u.data).Response??u.Response).Error||!Array.isArray(y.Accounts))throw new Error("invalid_credits_response");c.push(...y.Accounts);const k=h(y.TotalCount);if(y.Accounts.length<100||k!==void 0&&c.length>=k)return{state:"ready",account:t,...A(c)}}throw new Error("credits_page_limit")}catch{return m("error",t)}finally{try{await o?.close()}finally{l?.()}}}export{m as emptyCredits,A as parseCreditsResources,U as queryWorkBuddyCredits};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{emptyCredits as r}from"./query.js";import{ACTIVE_CREDITS_INTERVAL_MS as n,IDLE_CREDITS_INTERVAL_MS as u}from"./types.js";class y{query;changed;now;value={...r("error"),fetchedAtMs:null,checkedAtMs:null,revision:0};lastAttempt=-1/0;retryAt=0;limitedUntil=0;failures=0;dirty=!1;active=0;epoch=0;timer;pending;running=!1;constructor(t,s,e=Date.now){this.query=t,this.changed=s,this.now=e}snapshot(){return this.value}start(){this.running||(this.running=!0,this.tick())}async stop(){this.running=!1,clearTimeout(this.timer),await this.pending}beginUsage(){this.active++,this.dirty=!0,this.running&&this.tick();let t=!1;return()=>{t||(t=!0,this.active--,this.dirty=!0,this.running&&this.tick())}}reset(){this.epoch++,this.lastAttempt=-1/0,this.retryAt=0,this.limitedUntil=0,this.failures=0,this.dirty=!1,this.value={...r("error"),fetchedAtMs:null,checkedAtMs:null,revision:this.value.revision+1},this.changed(this.value),this.running&&(this.pending??Promise.resolve()).then(()=>{if(this.running)return this.tick()})}nextDue(){const t=this.dirty||this.active||this.failures?n:u;return Math.max(this.lastAttempt+t,this.retryAt,this.limitedUntil)}async tick(){
|
|
1
|
+
import{emptyCredits as r}from"./query.js";import{ACTIVE_CREDITS_INTERVAL_MS as n,IDLE_CREDITS_INTERVAL_MS as u}from"./types.js";class y{query;changed;now;value={...r("error"),fetchedAtMs:null,checkedAtMs:null,revision:0};lastAttempt=-1/0;retryAt=0;limitedUntil=0;failures=0;dirty=!1;active=0;epoch=0;timer;pending;running=!1;constructor(t,s,e=Date.now){this.query=t,this.changed=s,this.now=e}snapshot(){return this.value}start(){this.running||(this.running=!0,this.tick())}async stop(){this.running=!1,clearTimeout(this.timer),await this.pending}beginUsage(){this.active++,this.dirty=!0,this.running&&this.tick();let t=!1;return()=>{t||(t=!0,this.active--,this.dirty=!0,this.running&&this.tick())}}reset(){this.epoch++,this.lastAttempt=-1/0,this.retryAt=0,this.limitedUntil=0,this.failures=0,this.dirty=!1,this.value={...r("error"),fetchedAtMs:null,checkedAtMs:null,revision:this.value.revision+1},this.changed(this.value),this.running&&(this.pending??Promise.resolve()).then(()=>{if(this.running)return this.tick()})}nextDue(){const t=this.dirty||this.active||this.failures?n:u;return Math.max(this.lastAttempt+t,this.retryAt,this.limitedUntil)}async tick(){if(this.pending)return this.pending;if(this.now()>=this.nextDue()){const t=Number.isFinite(this.lastAttempt)?this.failures?"retry":this.dirty||this.active?"usage":"hourly":"initial";return this.collect(t)}return this.arm(),this.value}refresh(t=!1){return this.pending?this.pending:t&&this.now()<this.limitedUntil?Promise.resolve(this.value):this.collect("manual")}collect(t){const s=this.epoch,e=this.now();this.lastAttempt=e;const l=this.dirty;return this.dirty=!1,this.pending=Promise.resolve().then(()=>this.query(t)).catch(()=>r("error")).then(i=>{if(s!==this.epoch)return this.value;const o=i.state==="error"&&!i.account||JSON.stringify(i.account)===JSON.stringify(this.value.account),h=i.state==="error";h?(this.failures++,this.dirty||=l,this.retryAt=this.now()+Math.max(n,Math.min(u,n*2**Math.min(4,this.failures-1)))):(this.failures=0,this.retryAt=0,this.limitedUntil=0),i.retryAfterMs&&(this.limitedUntil=this.now()+i.retryAfterMs);const{retryAfterMs:f,...c}=i,a=h&&o&&this.value.fetchedAtMs!==null;return this.value={...c,...a?{account:this.value.account,remaining:this.value.remaining,total:this.value.total,unlimited:this.value.unlimited,resources:this.value.resources}:{},fetchedAtMs:i.state==="ready"?this.now():a?this.value.fetchedAtMs:null,checkedAtMs:e,revision:this.value.revision+1},this.changed(this.value),this.value}).finally(()=>{this.pending=void 0,this.arm()}),this.pending}arm(){clearTimeout(this.timer),!(!this.running||this.pending)&&(this.timer=setTimeout(()=>{this.tick()},Math.min(2147483647,Math.max(1,this.nextDue()-this.now()))),this.timer.unref())}}export{y as WorkBuddyCreditsScheduler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{acaServerRequest as u}from"../aca-server-client.js";import{loadAcaConfig as a}from"../aca-config.js";import{managementActivity as i}from"../management/activity.js";import{emptyCredits as f,queryWorkBuddyCredits as
|
|
1
|
+
import{acaServerRequest as u}from"../aca-server-client.js";import{loadAcaConfig as a}from"../aca-config.js";import{managementActivity as i}from"../management/activity.js";import{emptyCredits as f,queryWorkBuddyCredits as l}from"./query.js";import{WorkBuddyCreditsScheduler as p}from"./scheduler.js";let r=!1,s=!1,d="",o=Promise.resolve();const n=new p(async e=>{const t=i.enter("workbuddy-credits");if(!t)return f("error");try{return await l({allowCheckin:e==="hourly"})}finally{t()}},()=>{c()});function c(){const e=a();if(!e.token||!r)return Promise.resolve();const t=n.snapshot();return o=o.catch(()=>{}).then(()=>u("POST","/api/client/workbuddy-credits",{machineId:e.machineId,instanceId:process.env.ACA_WORKER_INSTANCE_ID||String(process.pid),snapshot:t},{serverUrl:e.serverUrl,token:e.token})).catch(()=>{}),o}function w(){r=!0,s&&m()}function m(){if(s=!0,!r||i.paused||i.stopping)return;const e=a(),t=`${e.serverUrl}\0${e.machineId}\0${e.token}`;d&&d!==t&&n.reset(),d=t,n.start(),c()}async function g(){r=!1,s=!1,await n.stop(),await o}export{w as activateWorkBuddyCredits,g as stopWorkBuddyCredits,n as workBuddyCredits,m as workBuddyCreditsConnected};
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const o="0.1.
|
|
1
|
+
const o="0.1.94";export{o as AICA_VERSION};
|